Created
October 22, 2010 21:08
-
-
Save FSX/641377 to your computer and use it in GitHub Desktop.
Grabs a random wallpaper from the wallbase.net toplist.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
""" | |
randwp | |
~~~~~~ | |
Fetches random wallpapers from the wallbase.net toplist and sets it as the | |
background. | |
This script needs Python 3.*. Windows people need to install the `pywin32`_ | |
and Mac OS X people need to install `py-appscript`_. | |
.. _pywin32: http://sourceforge.net/projects/pywin32/ | |
.. _py-appscript: http://appscript.sourceforge.net/py-appscript/index.html | |
:copyright: (c) 2010 by Frank Smit. | |
:license: BSD, see LICENSE for more details. | |
""" | |
__author__ = 'Frank Smit' | |
__version__ = '0.1.0' | |
import re | |
import sys | |
import json | |
import shlex | |
import random | |
import os.path | |
import subprocess | |
import urllib.parse | |
import urllib.request | |
from os.path import basename | |
from optparse import OptionParser | |
# Platform specific stuff | |
if sys.platform == 'win32': | |
import win32api, win32con, win32gui | |
DATA_DIR = os.path.join(os.getenv('AppData'), 'randwp') | |
elif sys.platform == 'darwin': | |
import appscript | |
DATA_DIR = os.path.join(os.path.expanduser('~'), '.randwp') | |
else: | |
DATA_DIR = os.path.join(os.getenv('XDG_DATA_HOME', | |
os.path.expanduser('~/.local/share')), 'randwp') | |
REGEX_IMAGE = re.compile("(http:\/\/wallbase2\.net\/[a-zA-Z0-9_-]+\/" | |
"[a-zA-Z0-9]+\/wallpaper-[0-9]+\.(?:jpg|png))") | |
PAGE_LIMIT = 325 | |
THUMBS_PER_PAGE = 60 | |
RESOLUTIONS = ( | |
'0x0', # Everything | |
# Standard | |
'800x600', '1024x768', | |
'1280x960', '1280x1024', | |
'1400x1050', '1600x1200', | |
'2560x2048', | |
# Widescreen | |
'1024x600', '1280x800', | |
'1366x768', '1440x900', | |
'1600x900', '1680x1050', | |
'1920x1080', '1920x1200', | |
'2560x1440', '2560x1600' | |
) | |
ASPECT_RATIOS = { | |
'all': '0', # All aspect ratios | |
'4:3': '1.33', | |
'5:4': '1.25', | |
'16:9': '1.77', | |
'16:10': '1.60', | |
'netbook': '1.70', | |
'dual': '2.50', | |
'dual_wide': '3.20', | |
'portrait': '0.99' | |
} | |
WB_OVERVIEW_URL = 'http://wallbase.net/toplist/%(page)s/%(boards)s/%(size)s/' \ | |
'%(resolution)s/%(aspect_ratio)s/%(level)s/%(thumbs)s' | |
WB_WP_URL = 'http://wallbase.net/wallpaper/%d' | |
class Grabber: | |
"""A simple class that grabs a random wallpaper from wallbase.net | |
:param url: The URL to a wallbase.net gallery. | |
""" | |
def __init__(self, url, callback): | |
wpid = [] | |
json_data = self._get_json(url) | |
if json_data: | |
for data in json_data: | |
wpid.append(data['id']) | |
wallpaper_url = self._get_wallpaper_url( | |
WB_WP_URL % random.choice(wpid)) | |
if wallpaper_url: | |
path = self._download_wallpaper(wallpaper_url) | |
callback(path) | |
else: | |
print('Could not find wallpapers!') | |
def _get_json(self, url): | |
req = urllib.request.Request(url, b'', { | |
'x-requested-with': 'XMLHttpRequest' | |
}) | |
response = urllib.request.urlopen(req) | |
data = response.read().decode('utf-8') | |
try: | |
return json.loads(data) | |
except ValueError: | |
return [] | |
def _get_wallpaper_url(self, url): | |
response = urllib.request.urlopen(url) | |
html = response.read().decode('utf-8') | |
matches = REGEX_IMAGE.search(html) | |
if matches: | |
return matches.group(1) | |
def _download_wallpaper(self, url): | |
path = os.path.join(DATA_DIR, basename(url)) | |
if os.path.exists(path): | |
return path | |
return urllib.request.urlretrieve(url, path)[0] | |
class BackgroundSetter(object): | |
"""A simple background setter. At this moment is only accepts a CLI command. | |
More options are planned in the future. | |
:param command: The CLI command. %(path)s is replaced with the path to | |
the wallpaper, which is saved in ``~/.local/share``. | |
""" | |
def __init__(self, command): | |
self.setters = { | |
'win32': self._win32_setter, | |
'macosx': self._mac_osx_setter | |
} | |
self.command = command | |
def set(self, path): | |
"""Sets the wallpaper to the background by executing the CLI command. | |
:param path: The path to the wallpaper. | |
""" | |
if self.command in self.setters: | |
self.command = self.setters[self.command](path) | |
else: | |
self.command = self._cli_setter(path) | |
def _cli_setter(self, path): | |
subprocess.call(shlex.split(self.command.replace('%path%', path))) | |
# Source: http://www.daniweb.com/code/post969627.html | |
def _win32_setter(self, path): | |
key = win32api.RegOpenKeyEx(win32con.HKEY_CURRENT_USER, | |
'Control Panel\\Desktop', 0, win32con.KEY_SET_VALUE) | |
win32api.RegSetValueEx(key, 'WallpaperStyle', 0, win32con.REG_SZ, '0') | |
win32api.RegSetValueEx(key, 'TileWallpaper', 0, win32con.REG_SZ, '0') | |
win32gui.SystemParametersInfo(win32con.SPI_SETDESKWALLPAPER, path, 1+2) | |
def _mac_osx_setter(self, path): | |
appscript.app('Finder').desktop_picture.set( | |
appscript.mactypes.File(path)) | |
def main(): | |
if not os.path.exists(DATA_DIR): | |
os.makedirs(DATA_DIR) | |
# Set up CLI arguments parser and CLI options | |
opt = OptionParser() | |
opt.add_option('-s', '--bg-setter', dest='setter', | |
help='Set a background setter. Available values: win32, macosx. ' | |
'When no suitable value is available a CLI command can be used. ' | |
'Example: randwp.py -s \'feh --bg-tile "%path%"\'. %path% will ' | |
'be replaced with the path to the wallpaper.', | |
metavar='BGSETTER') | |
opt.add_option('--gt', action='store_true', dest='gt', | |
default=False, help='Use wallpapers with the specified resolution or ' | |
'greater.') | |
opt.add_option('-p', '--page', dest='page', | |
help='The pagenumber of the results from wallbase.net. A range can ' | |
'also be used. Examples: 1..5, 5..10, etc. The first number can ' | |
'not be zero. And the last number must be higher than the first ' | |
'one.', | |
metavar='PAGE', default='1') | |
opt.add_option('--no-w', action='store_false', dest='w', default=True, | |
help='No wallpapers from /W/ (Manga / Anime).') | |
opt.add_option('--no-wg', action='store_false', dest='wg', default=True, | |
help='No wallpapers from /WG/ (Wallpapers / General).') | |
opt.add_option('--no-hr', action='store_false', dest='hr', default=True, | |
help='No wallpapers from /HR/ (High Resolution. Contains not only ' | |
'wallpapers, but also other high-res pictures).') | |
opt.add_option('-r', '--resolution', dest='resolution', | |
help='Specify a resolution (default is 0x0): %s' % \ | |
', '.join(RESOLUTIONS), | |
metavar='RESOLUTION', default='0x0') | |
opt.add_option('-a', '--aspect-ratio', dest='aspect_ratio', | |
help='Specify an aspect ratio (default is all): %s' % \ | |
', '.join(ASPECT_RATIOS.keys()), | |
metavar='ASPECT_RATIO', default='all') | |
opt.add_option('--no-sfw', action='store_false', dest='sfw', default=True, | |
help='Don\'t use Safe For Work wallpapers.') | |
opt.add_option('--sketchy', action='store_true', dest='sketchy', | |
default=False, help='Sketchy wallpapers.') | |
opt.add_option('--nsfw', action='store_true', dest='nsfw', default=False, | |
help='Not Safe For Work wallpapers.') | |
opt.add_option('--clear-cache', action='store_true', dest='clear', | |
default=False, help='Clear all the cached wallpapers.') | |
(options, args) = opt.parse_args() | |
# Check for a background setter | |
if not options.setter: | |
print('A background setter must be specified.') | |
sys.exit() | |
# Clear cache and exit | |
if options.clear: | |
for f in os.listdir(DATA_DIR): | |
os.remove(os.path.join(DATA_DIR, f)) | |
os.rmdir(DATA_DIR) | |
sys.exit() | |
# Check page range or number | |
p_range_match = re.match('([1-9]|[0-9]{2,})\.\.([0-9]+)', options.page) | |
if p_range_match: | |
ps, pr = p_range_match.groups() | |
ps, pr = int(ps), int(pr) | |
if pr < ps: | |
print('Invalid page range!') | |
sys.exit() | |
options.page = random.randint(ps, pr) | |
else: | |
try: | |
options.page = int(options.page) | |
except ValueError: | |
print('Invalid page number!') | |
sys.exit() | |
# Check page limit | |
if options.page > PAGE_LIMIT: | |
print('Page number exceeds page limit (%d)!' % PAGE_LIMIT) | |
sys.exit() | |
# Check which boards to use | |
boards = '%s%s%s' % ( | |
options.w and '1' or '', | |
options.wg and '2' or '', | |
options.hr and '3' or '' | |
) | |
# Check resolution | |
if not options.resolution in RESOLUTIONS: | |
options.resolution = '0x0' | |
# Check aspect ratio | |
if not options.aspect_ratio in ASPECT_RATIOS: | |
options.aspect_ratio = 'all' | |
# Set level (SFW, Sketchy, NSFW) | |
level = '%d%d%d' % (int(options.sfw), int(options.sketchy), | |
int(options.nsfw)) | |
setter = BackgroundSetter(options.setter) | |
Grabber(WB_OVERVIEW_URL % { | |
'page': (options.page - 1) * THUMBS_PER_PAGE, | |
'boards': boards, | |
'size': options.gt and 'gteq' or 'eqeq', | |
'resolution': options.resolution, | |
'aspect_ratio': ASPECT_RATIOS[options.aspect_ratio], | |
'level': level, | |
'thumbs': THUMBS_PER_PAGE | |
}, setter.set) | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi, I've made a fork with 2 changes: