Skip to content

Instantly share code, notes, and snippets.

@nineinchnick
Forked from FSX/randwp.py
Created June 12, 2011 13:20
Show Gist options
  • Save nineinchnick/1021544 to your computer and use it in GitHub Desktop.
Save nineinchnick/1021544 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\.org\/[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.cc/toplist/%(page)s/%(boards)s/%(size)s/' \
'%(resolution)s/%(aspect_ratio)s/%(level)s/%(thumbs)s'
WB_WP_URL = 'http://wallbase.cc/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',
'Cookie': 'is_adult=1'
})
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()
@FSX
Copy link

FSX commented Jun 12, 2011

Ok. I'll do some tests.

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