Skip to content

Instantly share code, notes, and snippets.

@FSX
Created October 22, 2010 21:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save FSX/641377 to your computer and use it in GitHub Desktop.
Save FSX/641377 to your computer and use it in GitHub Desktop.
Grabs a random wallpaper from the wallbase.net toplist.
#!/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()
@nineinchnick
Copy link

Hi, I've made a fork with 2 changes:

  • updated domain in the urls and regex
  • added cookie

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment