Vital Vialas

A python script using Reddit's API to download most upvoted wallpaper and change it

# -*- coding: utf-8 -*-

import argparse
import praw
import urllib
import os
import subprocess
from bs4 import BeautifulSoup
import re
import sys

The praw.Reddit connection requires these:
my_user = 'reddit_user_name'
my_password = ''
user_agent='pc:r_wallpapers_sets_my_wallpaper:0.1 '
1 either provide them here or in a praw.ini file residing in the same directory (or ~/.config/)
reddit = praw.Reddit(client_id=client_id,
2 or read required parameters from praw.ini under [user_data]

parser = argparse.ArgumentParser()
parser.add_argument("--subreddit", required=True,
help="name of the subreddit to fetch image from. E.g: 'wallpapers' or 'EarthPorn'")
parser.add_argument("--top", required=True,
help="subreddit Top time-limit submission: 'day', 'week', 'year'")

home_dir = os.path.expanduser('~')
wallpapers_dir = os.path.join(home_dir, ".wallpapers")

def get_submission(subreddit, time, limit):

for submission in, limit=limit):
title = submission.title
url = submission.url
return url, title

def configure_wallpaper_path(title):

if not os.path.isdir(wallpapers_dir):
wallpaper_path = os.path.join(wallpapers_dir, str(title)+".jpg")
return wallpaper_path

def get_screen_dimensions():
#sys.stdout.isatty() -> True if executed from console, False if executed from cron

runs xrandr to get screen dimension from console call.
Can't get it to work when executed from cron (Is it even possible?)
since cron is not tty-based so I can't capture stdout from xrandr call.
Just provide an argument file with screen dimensions when executing from cron?

screen_dim = subprocess.Popen("xrandr | grep \* | awk '/x/{print $1}'", shell=True,
screen_w, screen_h = int(screen_dim.split("x")[0]), int(screen_dim.split("x")[1])
return (screen_w, screen_h)

def check_img_fits_screen(original_title, screen_dimensions):

checks the image is more or less rectangular (width/height ratio) to be used as wallpaper
by comparing to local screen dimensions
Uses the original title, bc it's subreddit rules to include image resolution

screen_w, screen_h = screen_dimensions[0], screen_dimensions[1]
original_title = original_title.replace(",", '').replace(".",'')
pattern = "[\[\(]\d+?[ ]?[*xX][ ]?\d+?[\]\)]"
img_dimensions =, original_title).group(0)
w_by_h = re.compile("[*xX]").split(img_dimensions)
img_w, img_h = int(w_by_h[0][1:]), int(w_by_h[1][:-1])
ratio_img = (img_w + .0) / img_h
ratio_screen = (screen_w + .0) / screen_h
if (screen_w - img_w < 200) and (ratio_screen - ratio_img < 0.5):
return True
return False
except AttributeError:
#'NoneType' object has no attribute 'group' when original title doesnt comply
return False

def get_imgur_image_url(url):

works either for (album) or just a regular imgur page
with just one picture
in the first case just grabs url for first picture in the album,
otherwise grabs 'the' image url

html = urllib.urlopen(url).read()
soup = BeautifulSoup(html, "lxml")
matches = soup.find_all('img', attrs={"class": "post-image-placeholder"})
#pick first image in album:
url ="\")", str(matches[0])).group(0).strip("\"")
return "http://"+url

def download_wallpaper(url, path):

first checks the url respnds OK(200), then check it's not html

if urllib.urlopen(url).getcode() == 200:
if not 'html' in urllib.urlopen(url).read():
urllib.urlretrieve(url, path)
return urllib.urlopen(url).getcode()

def change_local_wallpaper(wallpaper_path):

gsettings set org.gnome.desktop.background picture-uri file://" + wallpaper_path
or dconf write if gsettings gives the dreaded "GLib-GIO-Message:
Using the 'memory' GSettings backend" error message

file = 'file://%s'%wallpaper_path
p = subprocess.Popen(['gsettings', 'set', 'org.gnome.desktop.background',
'picture-uri', file], stderr=subprocess.PIPE)
err = p.communicate()[1]
if "GLib-GIO-Message: Using the 'memory' GSettings backend" in err:
p = subprocess.Popen(['dconf', 'write',
"\"%s\""%file], stderr=subprocess.PIPE)
out, err = p.communicate()

def main():

subreddit_arg = args.subreddit #subreddit_arg = 'EarthPorn'

if subreddit_arg.lower() not in ["wallpapers", "earthporn"]:
sys.exit('supported subreddits: wallpapers, EarthPorn')

time = #time = 'day'
reddit = praw.Reddit('user_data')

subreddit = reddit.subreddit(subreddit_arg)
url, original_title = get_submission(subreddit, time, limit)

screen_dimensions = get_screen_dimensions()

img_fits_screen = check_img_fits_screen(original_title, screen_dimensions)

while img_fits_screen == False:
url, original_title = get_submission(subreddit, time, limit)
img_fits_screen = check_img_fits_screen(original_title, screen_dimensions)

short_title = original_title.replace(" ", "_").strip(".")[0:30]
#replace non-ascii for '?'
short_title = ''.join([i if ord(i) < 128 else '?' for i in short_title])

wallpaper_path = configure_wallpaper_path(short_title) and are images, not html
if '' in url and not '' in url:
if 'html' in urllib.urlopen(url).read():
url = get_imgur_image_url(url)

if download_wallpaper(str(url), wallpaper_path):
print "\nDownloaded \"" + short_title + "\" from " + str(url)

print "Set \"" + short_title + "\" as wallpaper"

if __name__ == "__main__":

args = parser.parse_args()