每日必应壁纸的自动化

必应搜索 bing.com 每天都会提供一张精美的背景图像,这些背景图像多以自然风光为主,质量上乘,因此经常被拿来做壁纸。Github 上有很多自动获取每天必应壁纸的程序,此外也有很多提供这种服务的网站,更有甚者,微软中国还推出了一款 Windows 和 macOS 应用,每天自动为桌面换上当日高清壁纸。当然,这一“福利”并不是免费的,其本质是必应搜索程序的一项附加功能,且后台随时需要挂着这样一个闭源的 damon 应用。

根据一些资料,我找到了每日壁纸的 4K 高清下载地址,将其部署在自己的短链接跳转服务中:go.mazhangjing.com/bing-today-url 可获取此地址,/bing-today-image 可直接 301 跳转并下载此 4K 高清壁纸。

Rust Impl

我鼓捣了一个 Rust 应用,其解析此地址并将其设置为当日壁纸(虽然在 macOS 和 Linux 下,Shell 也能干好这件事,不过其需要配合其他工具以访问操作系统 API 去设置壁纸到桌面系统,不太具有可移植性),对于 MacBook 这类笔记本设备,还需要考虑到每天多次定时执行重复下载的问题,因此此 Rust 应用使用了缓存,可配合 crontab 定期执行,如果当日已更换过壁纸,则直接结束执行,避免重复的下载导致网络带宽和 CPU 资源浪费。

此项目地址参见:Github,Github Action 自动打包生成的二进制程序(Windows、macOS 和 Linux)参见 Release

下面给出了爬虫代码和此设置壁纸的程序代码:

// [dependencies]
// wallpaper = { version = "3", features = ["from_url"] }
// chrono = "0.4.24"
// reqwest = { version = "0.11.6", features = ["blocking"] }
// serde_json = "1.0"
use wallpaper;
use chrono;
use reqwest;
use serde_json;

fn parse_get_url() -> String {
    let resp = reqwest::blocking::get("https://cn.bing.com/HPImageArchive.aspx?format=js&idx=0&n=1").unwrap();
    let json: serde_json::Value = serde_json::from_str(&resp.text().unwrap()).unwrap();
    let images = json["images"].as_array().unwrap();
    let image = images[0].as_object().unwrap();
    let url = image["urlbase"].as_str().unwrap();
    let url = format!("https://www.bing.com{}_UHD.jpg&rf=LaDigue_UHD.jpg&pid=hp&rs=1&c=4&qlt=100&uhd=1&uhdwidth=3840&uhdheight=2160", url);
    return url;
}

fn main() {
    let mut _url: String = "".to_string();
    let args: Vec<String> = std::env::args().collect();
    if args.len() > 1 {
        if args[1] == "-h" || args[1] == "--help" {
            println!("Usage: download and set wallpaper from a url (or `default-server`), 
       rm *.set to download again.
       pass nothing to auto parse url from cn.bing.com");
            return;
        } else {
            let content = &args[1];
            if content.eq_ignore_ascii_case("default-server") {
                _url = "https://go.mazhangjing.com/bing-today-image".to_string();
            } else {
                _url = content.to_string();
            }
        }
    }
    if _url.is_empty() {
        _url = parse_get_url();
    }
    println!("setting wallpaper from {}", _url);
    let now = chrono::Local::now();
    let date = now.format("%Y%m%d").to_string();
    if std::path::Path::new(&format!("{}.set", date)).exists() {
        println!("{} already set", date);
        return;
    } 
    wallpaper::set_from_url(_url.as_str()).unwrap();
    wallpaper::set_mode(wallpaper::Mode::Crop).unwrap();
    std::fs::File::create(format!("{}.set", date)).unwrap();
}

Clojure Impl

Clojure 版本的实现用于提供我自己的 Web 服务,另外也可搭配 babashka 作为本地程序使用。

(defn handle-bing
  [normal?]
  (let [config {:4KImageURL "https://www.bing.com%s_UHD.jpg&rf=LaDigue_UHD.jpg&pid=hp&rs=1&c=4&qlt=100&uhd=1&uhdwidth=3840&uhdheight=2160"
                :1080PImageUrl "https://www.bing.com%s_1920x1080.jpg&rf=LaDigue_1920x1080.jpg&pid=hp"}
        image-id (->> (-> (http/request {:url "https://cn.bing.com/"}) deref :body)
                      (re-find #"background-image: url\(&quot;.*net(.*?)\_1920.*?&.*?\)")
                      second)]
     {:url (if normal?
             (format (:1080PImageUrl config) image-id)
             (format (:4KImageURL config) image-id))}))

配合 Windows 台式机开机更换壁纸的方法

方法1:按下 Windows + R 按键打开“运行”应用,输入 shell:startup 并点击“确定”按钮,在弹出的文件夹中,将下载的 bing_wallpaper.exe 拖拽到其中即可。

方法2:按下 Windows 按键,输入并搜索“任务计划程序”,打开后左上角:操作 > 创建任务,随意输入名称和描述,选中“使用最高权限运行”,在“触发器”栏添加一个系统启动的触发器,在“操作”栏添加启动的程序:bing_wallpaper.exe,之后点击确定即可。

配合 MacBook 笔记本更换壁纸的方法

下载二进制文件,打开命令行,执行此程序一次,并在设置中允许未知来源应用执行,之后执行:

crontab -e

输入如下命令定期执行程序:

0,30 * * * * ~/bing_wallpaper

配合 iOS/iPadOS 每天早上更换壁纸的方法

通过 快捷指令 获取 URL 内容,将其作为图像格式,选择其内容并将其设置为墙纸(对于较新版本的 iOS/iPadOS,可以选择是否使用主体居中功能)。之后配合自动化自动执行,比如早上闹钟响后执行此自动化设置壁纸。

更新历史: 2024年2月18日 增加了 Clojure 实现。