Bing wallpapers on Linux (python version)

Earlier I made a post with the script which pulls wallpapers from Bing. Here I show my Python script, which is doing the same:

  • Saves new image from the Bing server.
  • Adds watermark with the copyright information to it.
  • Sets this image the lock screen tool and/or as a desktop wallpaper.

Script logic

  1. To store wallpapers I use ~/wallpapers/bing/ folder.
  2. In order to detect if image on the Bing server is the new one, I do the following:
    • I save copyright information of the last saved (and currently used) image in the ~/wallpapers/bing/bing_wallpaper_copyright.txt file.
    • On each request to Bing I compare copyright information of the image on server with the one in the file.
    • If copyright is the same - then I don’t update image.
    • If copyright differs - then I download the image.
    • Every image with the copyright watermark I save in the ~/wallpapers/bing/ folder.
      • This is not necessary to do. If you want - you can omit this step.

        Image with copyright watermark

  3. Then I use downloaded image as:
    • As a background picture for the [slick-greeter] for LightDM.
      • Because slick-greeter has panel on top, I use image without copyright watermark for it.
      • For that I am saving it under the /mnt/data/greeter-wallpapers/bing_image.jpg name.
      • This image is always overwritten with the latest downloaded one. I do not save images without copyright watermark.
    • Lock screen picture for betterlockscreen.
      • Picture with the watermark copyright on it.
    • Lock screen picture for slock-bgimage:
      • I take picture with the copyright watermark on it as a source and I add small locker icon to its corner. Source www.flaticon.com.

        Lock icon for watermark

      • Then I save this image under ~/wallpapers/bing/current_lock_image.jpg name.

        Image with watermark and lock

I am not using /tmp folder for storing my images for screen locker and for my greeter program. I do it because locker and greeter shall work properly after reboot.

I stopped using betterlockscreen because it leaks pop up and notification windows in my setup. I tried to fix it but I could not find solution. And I switched to slock which is much simpler, faster and has no issues with leaking windows.

Python script itself

Expand to see full script

  1#!/bin/python
  2
  3import requests
  4import json
  5import sys
  6import os
  7from PIL import Image
  8from PIL import ImageDraw
  9from PIL import ImageFont
 10
 11# Defining URL for pulling the data
 12bing_url="https://www.bing.com/HPImageArchive.aspx?format=js&idx=0&n=1&mkt=de-DE"
 13
 14# Path to the text file with the copyright text
 15local_copyright_file = '/home/alexgum/wallpapers/bing/bing_wallpaper_copyright.txt'
 16
 17# Path to the font I am using
 18local_font = '/usr/share/fonts/TTF/Arial.TTF'
 19
 20# Folder where I store wallpapers
 21wallpaper_folder = '/home/alexgum/wallpapers/bing/'
 22
 23# Path to the temporary file
 24# Firstly, image is downloaded there
 25temp_file_path = '/tmp/bing_image_temp.jpg'
 26
 27# Path to the final file which is going to be used by slick-greeter
 28greeter_file_path = '/mnt/data/greeter-wallpapers/bing_image.jpg'
 29
 30# Icon I use to add locker watermark on the image for slock
 31lock_logo_file = '/home/alexgum/.config/icons/lock_64.png'
 32
 33# Path to the image for slock
 34slock_file = '/home/alexgum/wallpapers/bing/current_lock_image.jpg'
 35
 36# Function to extract file name from the JSON data
 37def make_img_file_name(full_json: dict) -> str:
 38    try:
 39        url_temp = full_json['images'][0]['url'].split('&')
 40        return url_temp[0].split('.')[1] + '.jpg'
 41    except Exception as e:
 42        print("make_img_file_name(): Error. Cannot produce file name.")
 43        print(e)
 44        sys.exit(1)
 45
 46# Function to get URL for downloading picture
 47# Input - full JSON response, returns string with URL
 48def get_picture_url_from_json(full_json: dict) -> str:
 49    try:
 50        return 'https://bing.com/' + full_json['images'][0]['url']
 51    except Exception as e:
 52        print("get_picture_url(): Error. Cannot get picture url.")
 53        print(e)
 54        sys.exit(1)
 55
 56# Function to get copyright information from the file on disk
 57# Input - path to a file with the copyright data of the current image
 58# Returns string with the copyright text, or "None"
 59def get_copyright_from_file(local_file_name: str) -> str:
 60    try:
 61        with open(local_file_name, 'rt') as f:
 62            return f.readline()
 63    except Exception:
 64        return "None"
 65
 66# Function to get copyright information from the JSON data
 67# Input - full JSON response, returns string with the copyright text
 68def get_copyright_from_json(full_json: dict) -> str:
 69    try:
 70        return full_json['images'][0]['copyright']
 71    except Exception as e:
 72        print("get_copyright_from_json(): Error. Cannot get copyright from url.")
 73        print(e)
 74        sys.exit(1)
 75
 76# Function to download image
 77# Input - URL and path to file where image to be stored
 78def img_download(url: str,
 79                 target_file: str = '/tmp/bing_image_temp.jpg') -> None:
 80    try:
 81        image_file = requests.get(url)
 82        with open(target_file, 'wb') as f:
 83            f.write(image_file.content)
 84    except Exception as e:
 85        print(e)
 86        sys.exit(1)
 87
 88# Function to make wallper image with the copyright watermark
 89def make_new_wallpaper(source_file_path: str,
 90                       target_wallpaper_name: str,
 91                       copyright_text: str,
 92                       font_path: str = '/usr/share/fonts/TTF/Arial.TTF') -> None:
 93
 94    # Code is based on this blog post:
 95    ##   https://betterprogramming.pub/add-copyright-or-watermark-to-photos-using-python-a3773c71d431
 96
 97    # Preparing image for drawing (open canvas)
 98    img = Image.open(source_file_path)
 99    w, h = img.size
100
101    # Preparing text for drawing
102    ## Making drawing canvas
103    drawing = ImageDraw.Draw(img)
104    
105    ## Creating text image
106    cprw_font = ImageFont.truetype(font_path, 14)
107    copyright_text_with_margins = " " + copyright_text + " "
108
109    ## Identifying its dimensions
110    text_w, text_h = drawing.textsize(copyright_text_with_margins,cprw_font)
111
112    # Drawing new image from the text object
113    c_text = Image.new('RGBA', (text_w, text_h), color = '#000000')
114    drawing = ImageDraw.Draw(c_text)
115    drawing.text((0,0),copyright_text_with_margins,fill = '#FFFFFF',font = cprw_font)
116    # Adding Alpha channel value
117    c_text.putalpha(130)
118
119    # Identifying text position on the target picture
120    # 10 pixels from top and 10 pixels from the right edge
121    text_position = (w - text_w - 10), 10
122
123    # Pasting this object into the image
124    img.paste(c_text,text_position,mask=c_text)
125
126    # Saving new image
127    try:
128        img.save(target_wallpaper_name)
129    except Exception as e:
130        print('make_new_wallpaper() function cannot save new picture.')
131        print(e)
132        sys.exit(1)
133
134def add_logo(source_file_path: str,
135             target_lock_file: str,
136             logo: str) -> None:
137
138    # Preparing image for drawing (open canvas)
139    img = Image.open(source_file_path)
140    w, h = img.size
141    logo_img = Image.open(logo).convert('RGBA')
142    logo_w, logo_h = logo_img.size
143
144    # converting logo background to transparent and adding alpha channel 178 (80%) to black
145    newImage = []
146    for item in logo_img.getdata():
147        if item[:3] == (255, 255, 255):
148            newImage.append((255, 255, 255, 0))
149        else:
150            newImage.append((0,0,0,178))
151    logo_img.putdata(newImage)
152    logo_position = 10, (h - logo_h - 16)
153    img.paste(logo_img,logo_position,mask=logo_img)
154
155    # Saving new image
156    try:
157        img.save(target_lock_file)
158    except Exception as e:
159        print('add_logo() function cannot save new picture.')
160        print(e)
161        sys.exit(1)
162
163# Main function to assemble it all
164def main() -> None:
165    try:
166        # Getting the JSON data
167        json_data = requests.get(bing_url).json()
168
169        # Extracting new copyright text
170        new_copyright_text = get_copyright_from_json(json_data)
171
172        # Comparing the new copyright text with the stored in the file
173        # If texts are different, then go on
174        if get_copyright_from_file(local_copyright_file) != new_copyright_text:
175
176            # Extracting new image file name from JSON
177            file_name = wallpaper_folder + make_img_file_name(json_data)
178
179            # Extracting URL for image download
180            file_url = get_picture_url_from_json(json_data)
181
182            # Downloading the image and saving it in the /tmp folder
183            img_download(file_url, temp_file_path)
184
185            # Creating wallpaper image with the copyright watermark
186            # and saving it in the ~/wallpapers/bing/ folder
187            make_new_wallpaper(temp_file_path, file_name, new_copyright_text, local_font)
188
189            # Updating copyright information in the local file
190            open(local_copyright_file,'wt').write(new_copyright_text)
191
192            # Adding locker logo to make image for slock
193            # this image is stored in the ~/wallpapers/bing/current_lock_image.jpg
194            add_logo(file_name, slock_file, lock_logo_file)
195
196            # Copy orignal image from /tmp to the /mnt/data/greeter-wallpapers/bing_image.jpg
197            # for being used with slick-greeter
198            os.system('cp ' + temp_file_path + ' ' + greeter_file_path)
199
200            # Setting up betterlockscreen 
201            ## Optional part I don't use anymore. 
202            os.system('DISPLAY=:0 /usr/bin/betterlockscreen -u ' + file_name)
203            
204    except Exception as e:
205        print(e)
206
207if __name__ == '__main__':
208    main()

Runnig the script

Use simple cronjob:

1# {min} {hour} {day of month} {moth} {day of week}  command to be executed
20,30 6-19 * * * /home/alexgum/.scripts/lockscreenpicture.py > /tmp/lockscreen.log