Ubuntu 使用 Python 自動更換桌布

Ubuntu

在 Ubuntu 中使用 Python 每 5 分鐘自動更換桌布。

gsettings 指令

Ubuntu 用了一陣子,這幾天突然想說手動換桌布好麻煩,可不可以自動更換呢?就找了一下指令,只要一行:

gsettings set org.gnome.desktop.background picture-uri file:/home/tony/Pictures/wallpaper/123.jpg

使用 gsettings 指令,後面搭配設定桌布的參數 set org.gnome.desktop.background picture-uri file:,接上圖檔的完整(絕對)路徑。

註:這裡的 Ubuntu 是 20.04 版。

Python 程式碼

接著用 Python 寫個簡單的程式 wallpaper.py,把我的桌布目錄裡面全部的檔案記下來,然後隨機挑一個將它設定為桌布:

import os
import random

# 桌布目錄的完整路徑
path = "/home/tony/Pictures/wallpaper/"

# 用來儲存所有圖檔的陣列
pic_url_list = []

# 把桌布目錄底下包含子目錄全跑一遍
for (root, dirs, files) in os.walk(path):
    for f in files:
        # 去掉"."開頭的隱藏檔,只挑選 png 及 jpg 檔
        if not f.startswith(".") and (f.endswith(".png") or f.endswith(".jpg")):
            pic_url_list.append(os.path.join(root, f))
            
# for p in pic_url_list:
#    print(p)

# print(len(pic_url_list))

max_index = len(pic_url_list) - 1
random_index = random.randint(0, max_index)
wallpaper_url = pic_url_list[random_index]
# print(wallpaper_url)

cmd = "gsettings set org.gnome.desktop.background picture-uri file:"
os.system(cmd + wallpaper_url)
附圖比較好看:

直接測試看看能不能正常執行:

python3 wallpaper.py

使用 shell 來執行

如果直接在 crontab 上排程 wallpaper.py 會無法正常執行,我找了好久才找到原因,因為使用 gsettings 的關係,我們必須額外設定環境變數 DBUS_SESSION_BUS_ADDRESS ,所以必須寫一個簡單的 wallpaper.sh

#!/bin/bash

# 使用 gsettings 必須設定 DBUS_SESSION_BUS_ADDRESS 環境變數
PID=$(pgrep -f 'gnome-session' | head -n1)
export DBUS_SESSION_BUS_ADDRESS=$(grep -z DBUS_SESSION_BUS_ADDRESS /proc/$PID/environ|cut -d= -f2-)

# 執行 wallpaper.py
/usr/bin/python3 /home/tony/Pictures/wallpaper/wallpaper.py

立即測試

sh ./wallpaper.sh

成功的話就可以來設定排程了。

設定排程 Crontab

指令:

crontab -e

會開啟預設編輯器,如果出現錯誤無法開啟,請先設定預設編輯器:

# === bash shell ===
# 編輯
vim ~/.bashrc
# 加入
export EDITOR=vim

# === fish shell ===
# 編輯
vim ~/.config/fish/config.fish
# 加入
set -gx EDITOR vim 

排程內容:

# 每隔 5 分鐘換新桌布
*/5 * * * * /home/tony/Pictures/wallpaper/wallpaper.sh > /dev/null 2>&1

這樣就完成了。

Unsplash 版

後來寫了一個進階版,自動抓取 Unsplash 上的圖片做為桌布。必須先註冊 Unsplash 並且成為開發者,然後取得 ACCESS_KEY 就能呼叫 Unsplash API 了,程式碼如下:

import requests
import json
import os
import datetime

wallpaper_path = "/home/tony/Pictures/wallpaper/"

# 讀取 keyword 檔
def read_keyword():
	keywords = []
	with open(wallpaper_path + "keyword.txt", "r") as f:
		for line in f.read().splitlines():
			keywords.append(line)

	return keywords

# 請求 json 內容
def request_unsplash_json(keywords = ["wallpaper"]):
	query_string = "+".join(keywords)
	url = "https://api.unsplash.com/photos/random?client_id=這裡放你自己的ACCESS_KEY&orientation=landscape&query=" + query_string
	req_json = requests.get(url)
	return req_json.text

# 解析 json 回傳圖片 id 及網址
def parse_json_get_pic_id_and_url(json_string, pref_width = "3840"):
	obj = json.loads(json_string)	
	
	pic_id = obj["id"]
	# print(pic_id)
	
	# 可用的預設尺寸: raw,full,regular(w1080),small(w400),thumb(w200)
	# 使用 full 可以自訂寬度
	pic_url = obj["urls"]["full"] 

	pic_url_w = pic_url + "&w=" + pref_width
	# print(pic_url)

	return (pic_id, pic_url_w)

# 取得目前日期時間
def current_date_time():
	return datetime.datetime.now().strftime("%Y%m%d%H%M")

# 下載圖片並儲存
def download_picture(pic_id, pic_url):
	dt = current_date_time()
	file_name = dt + "_" + pic_id + ".jpg"
	wallpaper_url = wallpaper_path + file_name
	pic = requests.get(pic_url)
	with open(wallpaper_url, "wb") as f:
		f.write(pic.content)

	return wallpaper_url

# 設定桌布
def set_wallpaper(wallpaper_url):
	cmd = "gsettings set org.gnome.desktop.background picture-uri file:"
	os.system(cmd + wallpaper_url)

keywords = read_keyword()
json_string = request_unsplash_json(keywords)
(pic_id, pic_url) = parse_json_get_pic_id_and_url(json_string)
wallpaper_url = download_picture(pic_id, pic_url)
set_wallpaper(wallpaper_url)

附圖 (連結)

API 會回傳 json 格式的內容。

我指定一組 keyword 給 Unsplash API ,讓它找到的一張隨機 (random) 圖片。圖片尺寸可以依自己的螢幕選擇寬度,例如指定 regular 就會回傳寬 1080px 的圖片尺寸,如果要指定寬度可以用 full 然後給 w 參數。

圖片名稱我用「日期 + 時間 + _ + id」的方式組合,會像這樣 202205231555_gaBANnWdDc8.jpg

另外,要新增一個關鍵字檔案 keyword.txt,內容就是一行一個關鍵字:

travel
city
car
cat
sky
architecture

改了一個防止重覆並重抓的版本

加註日期的方式雖然方便確認順序,但是 Unsplash 給的隨機圖片會重覆,所以改了一個單純只用 id 來命名的版本,並且在重覆時重新抓一個新的,總共試三次,程式碼有一半不動:

import time

# ... 略過重覆程式碼

# 產生準備儲存在本地的桌布完整路徑
def make_wallpaper_full_path(pic_id):
	# dt = current_date_time()
	# file_name = dt + "_" + pic_id + ".jpg"
	# 
	file_name = pic_id + ".jpg"
	return wallpaper_path + file_name

# 下載圖片並儲存
def download_picture(pic_url, wallpaper_full_path):
	pic = requests.get(pic_url)
	with open(wallpaper_full_path, "wb") as f:
		f.write(pic.content)

# 設定桌布
def set_wallpaper(wallpaper_full_path):
	cmd = "gsettings set org.gnome.desktop.background picture-uri file:"
	os.system(cmd + wallpaper_full_path)

# 主程式
def main():
	keywords = read_keyword()
	wallpaper_full_path = ""
	pic_url = ""

	# 重抓次數: 3
	retry = 3
	while retry > 0:
		json_string = request_unsplash_json(keywords)
		(pic_id, pic_url) = parse_json_get_pic_id_and_url(json_string)
		wallpaper_full_path = make_wallpaper_full_path(pic_id)
		# 已存在就重抓
		if os.path.exists(wallpaper_full_path):
			wallpaper_full_path = ""
			pic_url = ""
			retry -= 1
			print("sleep 3 seconds then retry")
			time.sleep(3)
		else:
			break
	# 
	if len(wallpaper_full_path) != 0:
		download_picture(pic_url, wallpaper_full_path)
		set_wallpaper(wallpaper_full_path)

main()

另外,每五分鐘換一次桌布下載的圖片太多了,硬碟可能沒多久就爆了,改成 20 分鐘一次。關鍵字調整到現在拿到的圖片比較喜歡:

house
city
building
road
ocean

參考資料: https://askubuntu.com/questions/742870/background-not-changing-using-gsettings-from-cron

本文網址:https://blog.tonycube.com/2022/05/ubuntu-auto-refresh-wallpaper.html
Tony Blog 撰寫,請勿全文複製,轉載時請註明出處及連結,謝謝 😀

我要留言

留言小提醒:
1.回覆時間通常在晚上,如果太忙可能要等幾天。
2.請先瀏覽一下其他人的留言,也許有人問過同樣的問題。
3.程式碼請先將它編碼後再貼上。(線上編碼:http://bit.ly/1DL6yog)
4.文字請加上標點符號及斷行,難以閱讀者恕難回覆。
5.感謝您的留言,您的問題也可能幫助到其他有相同問題的人。