Skip to content

Instantly share code, notes, and snippets.

@andras-tim
Last active August 22, 2016 09:26
Show Gist options
  • Save andras-tim/60f4921fd93035b2d6d1 to your computer and use it in GitHub Desktop.
Save andras-tim/60f4921fd93035b2d6d1 to your computer and use it in GitHub Desktop.
Random wallpaper from Google Image search on Xfce4

Random wallpaper from Google Image search on Xfce4

This is a toolchain, what written for set a random single & dual monitor wallpapers on multiple monitors.

The set-a-random-wallpaper.sh wraps the whole process: download a random wallpaper with tool-1, crop for multi monitor config with tool-2, and set properly on all displays with tool-3.

Feel free, write your own walpaper setter "tool-3" and use this toolchain on non-Xfce desktop too!


Check my UserScript what can change New Tab background in Google Chrome.

Usage

  • Set a random wallpaper (search query: "dual background OR wallpaper"):

    set-a-random-wallpaper.sh
  • Set a random wallpaper (search query: "funny"):

    set-a-random-wallpaper.sh 'funny'

Tools

Download random double-wide wallpaper from Google Image search

Usage

download-random-double-wide-wallpaper.py <output_image_path> [<custom__query>]

  • Download a random search result for "dual background OR wallpaper" query:

    download-random-double-wide-wallpaper.py /tmp/test.jpg
  • Download a random search result for "funny" query:

    download-random-double-wide-wallpaper.py /tmp/test.jpg 'funny'

Crop double-wide wallpaper to left, center, right parts

Usage

crop-wallpaper-for-multi-monitors.py <source_path> <destination_path_prefix>

  • example input:

    • wide_wallpaper.jpg 3840x1080 image file
  • example output:

    • test-wallpaper_a-left.jpg 1920x1080, left crop of input file
    • test-wallpaper_b-right.jpg 1920x1080, right crop of input file
    • test-wallpaper_c-center.jpg 1920x1080, center crop of input file
crop-wallpaper-for-multi-monitors.py 'wide_wallpaper.jpg' 'test-wallpaper'

Set Xfce4 wallpapers on multiple monitors

Configuration

Set placement of monitors by output in OUTPUT_POSITIONS variable. The not specified monitors will use the common wallpaper.

Usage

set-multi-wallpapers.py <common> [<left> <right>]

  • Set the common wallpaper on all outputs:

    set-multi-wallpapers.py '/path/common_wallpaper.jpg'
  • Set wallpapers on all monitor according to OUTPUT_POSITIONS:

    set-multi-wallpapers.py '/path/common_wallpaper.jpg' '/path/left_monitor_wallpaper.jpg' '/path/right_monitor_wallpaper.jpg'
#!/usr/bin/env python
import sys
from PIL import Image
def main(*args):
source_image_path, destination_jpg_path_prefix = args
print('Loading image... {}'.format(source_image_path))
image = Image.open(source_image_path)
new_width = image.size[0] / 2
save_a_crop('{}_a-left'.format(destination_jpg_path_prefix), image, width=new_width)
save_a_crop('{}_b-right'.format(destination_jpg_path_prefix), image, left=new_width)
save_a_crop('{}_c-center'.format(destination_jpg_path_prefix), image, left=new_width / 2, width=new_width)
def save_a_crop(destination_path, image, left=0, top=0, width=None, height=None):
orig_width, orig_height = image.size
if left is None:
left = 0
if top is None:
top = 0
if width is None:
width = orig_width - left
if height is None:
height = orig_height - top
cropped_image = image.crop((left, top, left + width, top + height))
destination_path = '{}.jpg'.format(destination_path)
print('Cropping image... {orig} >> {new} @ {path}'.format(
orig=get_dimension(0, 0, orig_width, orig_height),
new=get_dimension(left, top, width, height),
path=destination_path
))
cropped_image.save(destination_path, format='jpeg')
def get_dimension(left, top, width, height):
return '[ {left:d}x{top:d}, {width:d}x{height:d} ]'.format(
left=left, top=top, width=width, height=height
)
if __name__ == '__main__':
main(*sys.argv[1:])
#!/usr/bin/env python
import os
import random
import requests
import sys
from datetime import date, timedelta
from lxml import etree
from urlparse import urlparse, parse_qsl
USER_AGENT = 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.75 Safari/537.36'
MIN_FILE_SIZE_KB = 500
def main(*args):
image_path = args[0]
query = 'dual background OR wallpaper'
if len(args) > 1:
query = args[1]
requests.packages.urllib3.disable_warnings()
print_state('Fetching wallpapers... {query!r} '.format(query=query))
response = search_for_image(query=query, safe=True, photo_only=True, width=2 * 1920, height=1080, age_days=30)
images = parse_images(response.content)
print_state('>> {} pcs\n'.format(len(images)))
while True:
random_image = random.choice(images)
print_state('Downloading wallpaper... {!r} >> {!r} '.format(random_image['url'], image_path))
download_image(random_image, image_path)
file_size_kb = os.path.getsize(image_path) / 1024
print_state('[{} kb]\n'.format(file_size_kb))
if file_size_kb >= MIN_FILE_SIZE_KB:
break
print_state('File size is too low; min={}\n\n'.format(MIN_FILE_SIZE_KB))
print_state('Done\n')
def parse_images(html):
images_xpath = './/div/a'
image_url_xpath = './@href'
xml = etree.fromstring(html, parser=etree.HTMLParser())
results = []
for image_element in xml.xpath(images_xpath):
urls = image_element.xpath(image_url_xpath)
if not urls:
continue
split_url = urlparse(urls[0])
if not split_url.path == '/imgres':
continue
query = dict(parse_qsl(split_url.query))
results.append({
'referer': query['imgrefurl'],
'url': query['imgurl'],
})
return results
def search_for_image(query, safe=False, photo_only=False, width=None, height=None, age_days=None):
query_params = {
'q': query,
'safe': 'on' if safe else 'off',
'site': 'webhp',
'tbm': 'isch',
'source': 'lnt',
'tbs': ','.join(['{}:{}'.format(k, v) for k, v in get_image_params(photo_only, width, height, age_days).items()])
}
headers = {
'User-Agent': USER_AGENT,
'Referer': 'https://www.google.com',
}
return requests.get('https://www.google.com/search', params=query_params, headers=headers)
def download_image(image, destination_path):
headers = {
'User-Agent': USER_AGENT,
'Referer': image['referer'],
}
response = requests.get(image['url'], headers=headers, stream=True, verify=False)
with open(destination_path, 'wb') as fd:
for chunk in response.iter_content(chunk_size=1024):
if chunk:
fd.write(chunk)
fd.flush()
def get_image_params(photo_only=False, width=None, height=None, age_days=None):
params = {}
if photo_only:
params['itp'] = 'photo'
if not width:
width = height
if not height:
height = width
if height and width:
params['isz'] = 'ex'
params['iszw'] = width
params['iszh'] = height
if age_days:
today = date.today()
params['cdr'] = 1
params['cd_min'] = format_date(today - timedelta(days=age_days))
params['cd_max'] = format_date(today)
return params
def format_date(date):
return date.strftime('%Y. %m. %d.')
def print_state(text):
sys.stdout.write(text)
sys.stdout.flush()
if __name__ == '__main__':
main(*sys.argv[1:])
lxml
Pillow
requests
#!/bin/bash
set -e
BASEDIR="$(dirname "$0")"
OUTDIR="${HOME}/Pictures/wallpapers/random"
NAME_PREFIX="$(date +%Y-%m-%d)"
OUTFILE_PREFIX="${OUTDIR}/${NAME_PREFIX}"
# Main
mkdir -p "${OUTDIR}"
python "${BASEDIR}/download-random-double-wide-wallpaper.py" "${OUTFILE_PREFIX}.jpg" "$@"
echo
python "${BASEDIR}/crop-wallpaper-for-multi-monitors.py" "${OUTFILE_PREFIX}.jpg" "${OUTFILE_PREFIX}"
rm "${OUTFILE_PREFIX}.jpg"
ln -sf "${NAME_PREFIX}_a-left.jpg" "${OUTDIR}/last_a-left.jpg"
ln -sf "${NAME_PREFIX}_b-right.jpg" "${OUTDIR}/last_b-right.jpg"
ln -sf "${NAME_PREFIX}_c-center.jpg" "${OUTDIR}/last_c-center.jpg"
echo
python "${BASEDIR}/set-multi-xfce4-wallpapers.py" "${OUTFILE_PREFIX}_c-center.jpg" "${OUTFILE_PREFIX}_a-left.jpg" "${OUTFILE_PREFIX}_b-right.jpg"
xfdesktop --reload
echo -e '\nAll done'
#!/usr/bin/env python
import os
import re
import subprocess
import sys
OUTPUT_POSITIONS = {
'DP2': 'left',
'DP3': 'right',
}
class Xrandr(object):
OUTPUT_PATTERN = re.compile('^(?P<name>[^ ]+) (?P<state>[^ ]+) (|(?P<options>[^(]+) )\(.*$')
@classmethod
def run_xrandr(cls):
stdout = subprocess.check_output(['xrandr']).decode("utf-8")
return stdout.splitlines()
@classmethod
def get_outputs(cls):
lines = cls.run_xrandr()
outputs = []
for line in lines:
matches = Xrandr.OUTPUT_PATTERN.match(str(line))
if matches:
outputs.append(matches.groupdict())
return outputs
@classmethod
def get_connected_outputs(cls):
return [output for output in cls.get_outputs() if output['state'] == 'connected']
@classmethod
def get_active_outputs(cls):
return [output for output in cls.get_connected_outputs() if output['options']]
class Desktop(object):
@classmethod
def set_wallpaper(cls, output_name, wallpaper_path):
print('Set wallpaper of {output_name!r} to {wallpaper_path!r}'.format(
output_name=output_name,
wallpaper_path=wallpaper_path,
))
cls._run_set_wallpaper(output_name, None)
cls._run_set_wallpaper(output_name, wallpaper_path)
@classmethod
def _run_set_wallpaper(cls, output_name, wallpaper_path):
subprocess.check_call([
'xfconf-query',
'-c', 'xfce4-desktop',
'-p', '/backdrop/screen0/monitor{output_name}/workspace0/last-image'.format(output_name=output_name),
'-n',
'-t', 'string',
'-s', '' if wallpaper_path is None else wallpaper_path,
])
def main(*args):
def get_wallpaper_for_output(output_name):
wallpaper_id = OUTPUT_POSITIONS.get(output_name, 'common')
return wallpapers[wallpaper_id]
wallpapers = {
'common': os.path.abspath(args[0]),
'left': os.path.abspath(args[1] if len(args) >= 3 else args[0]),
'right': os.path.abspath(args[2] if len(args) >= 3 else args[0]),
}
# outputs = Xrandr.get_active_outputs()
outputs = Xrandr.get_outputs()
for output in outputs:
wallpaper_path = get_wallpaper_for_output(output['name'])
Desktop.set_wallpaper(output['name'], wallpaper_path)
if __name__ == '__main__':
main(*sys.argv[1:])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment