發布一個開源小軟件,Bing每日壁紙。
該小軟件可以自動獲取Bing的精美圖片設置為壁紙,並且支持隨機切換歷史壁紙,查看壁紙故事。
歡迎大家下載使用,點star!有問題請留言或者提issue。
開源地址: https://github.com/jadepeng/bing-wallpaper ,想了解技術原理的請看 技術方案
如何使用
該程序沒有主窗口,是托盤程序,點擊托盤圖標,操作相關菜單即可。
功能特性
- 自動獲取Bing最新圖片並設置為壁紙
- 壁紙故事, 你還可以查看壁紙后面的故事
- 歷史壁紙,支持查看最近兩年的壁紙
- 隨機切換,隨機獲取幾年的壁紙,穿梭時光之中
- 定時切換,開啟后每一小時自動切換壁紙
壁紙故事
你還可以查看壁紙后面的故事,支持上下切換
隨機切換
點擊后,會隨機從歷史數據中挑選一張並顯示
定時切換
開啟后,每1小時自動切換,相當於自動點擊隨機切換。
開發緣起
后知后覺的發現,搜狗壁紙助手已經關閉服務,不能獲取新的壁紙,回想起Bing每日提供精美的圖片,因此考慮寫一個小工具,可以自動從bing獲取圖片並設置為壁紙。
Usage
自己編譯
- 下載代碼
git clone https://github.com/jadepeng/bing-wallpaper.git
-
Open .sln file in Visual Studio
-
Build
-
Run
.../BingWallpaper/bin/Release/BingWallpaper.exe
下載二進制
從Release下載最新的構建包,筆者是win10 X64。不能運行的自己下載代碼編譯。
兼容性
This only works on Windows systems.
I've tested it on Windows 7 and Windows 10 as an admin user. If you face any problems please open an issue!
技術方案
接口
https://github.com/kompiuter/bing-wallpaper
已經有一個雛形了,因此基於這個修改下就可以滿足需求了。因此直接fork這個工程。
首先是新數據問題,http://www.bing.com/HPImageArchive.aspx?format=js&idx=0&n=1&mkt=en-US
接口可以獲取json格式的數據。其中idx可以調整,最多獲取10幾天的數據。
{
"images": [
{
"startdate": "20180819",
"fullstartdate": "201808191600",
"enddate": "20180820",
"url": "/az/hprichbg/rb/PineMartenScotland_ZH-CN10077017107_1920x1080.jpg",
"urlbase": "/az/hprichbg/rb/PineMartenScotland_ZH-CN10077017107",
"copyright": "凱恩戈姆山國家公園里的一只松貂,蘇格蘭 (© SCOTLAND: The Big Picture/Minden Pictures)",
"copyrightlink": "http://www.bing.com/search?q=%E6%9D%BE%E8%B2%82&form=hpcapt&mkt=zh-cn",
"quiz": "/search?q=Bing+homepage+quiz&filters=WQOskey:%22HPQuiz_20180819_PineMartenScotland%22&FORM=HPQUIZ",
"wp": true,
"hsh": "997ecf7cb73e47b55617ce44f1097373",
"drk": 1,
"top": 1,
"bot": 1,
"hs": []
}
],
"tooltips": {
"loading": "正在加載...",
"previous": "上一個圖像",
"next": "下一個圖像",
"walle": "此圖片不能下載用作壁紙。",
"walls": "下載今日美圖。僅限用作桌面壁紙。"
}
}
然后可以通過https://cn.bing.com/cnhp/coverstory/
獲取壁紙故事:
{
"date": "August 20",
"title": "鼠類終結者",
"attribute": "英國,凱恩戈姆山國家公園",
"para1": "凱恩戈姆山國家公園坐落於蘇格蘭高地中心地區,是英國最大的國家公園。喜歡刺激的人將這里視為天堂,蘇格蘭的五個滑雪勝地中有三座位於這里,此外這里還有兩處水上活動中心、進行飛釣和跟蹤雄鹿的區域。這里也是景觀壯麗的野生區域,內有水獺、獾、紅松鼠、鹿以及鶚等。你瞧,那粗壯的樹干后面還藏着一個可愛的小家伙——松貂,它無憂無慮的在這里生存着!",
"para2": "",
"provider": "© SCOTLAND: The Big Picture/Minden Pictures",
"imageUrl": "http://hpimges.blob.core.chinacloudapi.cn/coverstory/watermark_pinemartenscotland_zh-cn10077017107_1920x1080.jpg",
"primaryImageUrl": "http://hpimges.blob.core.chinacloudapi.cn/coverstory/watermark_pinemartenscotland_zh-cn10077017107_1920x1080.jpg",
"Country": "英國",
"City": "凱恩戈姆山國家公園",
"Longitude": "-3.538737",
"Latitude": "57.037787",
"Continent": "歐洲",
"CityInEnglish": "Cairngorms National Park",
"CountryCode": ""
}
因此,調用這兩個接口就可以獲取到最新的一天的數據。
上面提到了,bing的接口只能獲取10幾天的數據,且只能獲取1天的壁紙故事,因此需要從其他途徑獲取。通過搜索,可以輕松發現https://bing.ioliu.cn/ 有最近兩年多的數據,我們可以爬取下來作為離線數據,這樣數據就全了。
通過自研的爬蟲平台,簡單配置下:
下載得到898條數據,應該包含2年多的數據:
導出為json,放入工程。
設置壁紙
設置壁紙,需要調用user32.dll中的SystemParametersInfo方法,
public sealed class Wallpaper
{
const int SPI_SETDESKWALLPAPER = 20;
const int SPIF_UPDATEINIFILE = 0x01;
const int SPIF_SENDWININICHANGE = 0x02;
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern int SystemParametersInfo(int uAction, int uParam, string lpvParam, int fuWinIni);
public enum Style : int
{
Tiled,
Centered,
Stretched
}
public static void Set(Image img, Style style)
{
string tempPath = Path.Combine(Path.GetTempPath(), "wallpaper.bmp");
img.Save(tempPath, System.Drawing.Imaging.ImageFormat.Bmp);
RegistryKey key = Registry.CurrentUser.OpenSubKey(@"Control Panel\Desktop", true);
if (style == Style.Stretched)
{
key.SetValue(@"WallpaperStyle", 2.ToString());
key.SetValue(@"TileWallpaper", 0.ToString());
}
if (style == Style.Centered)
{
key.SetValue(@"WallpaperStyle", 1.ToString());
key.SetValue(@"TileWallpaper", 0.ToString());
}
if (style == Style.Tiled)
{
key.SetValue(@"WallpaperStyle", 1.ToString());
key.SetValue(@"TileWallpaper", 1.ToString());
}
var a = SystemParametersInfo(SPI_SETDESKWALLPAPER,
0,
tempPath,
SPIF_UPDATEINIFILE | SPIF_SENDWININICHANGE);
}
}
壁紙故事
一個簡單的winform頁面,背景是圖片,左右兩個圖片作為按鈕,下方一個panel顯示詳情。
隨機切換
程序開始,從json里加載歷史數據,放到一個list里,隨機從里面獲取一個即可。
static string DataFile = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "history.json");
static string BakDataFile = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "history.json.bak");
static HistoryImageProvider()
{
historyImages = LoadHistoryImages();
historyImages.ForEach(image =>
{
date2Image.Add(image.Date, image);
});
}
static List<HistoryImage> historyImages;
static Dictionary<string, HistoryImage> date2Image = new Dictionary<string, HistoryImage>();
static List<HistoryImage> LoadHistoryImages()
{
try {
string[] lines = File.ReadAllLines(DataFile);
List<HistoryImage> images = new List<HistoryImage>();
var ser = new DataContractJsonSerializer(typeof(HistoryImage));
foreach(var line in lines)
{
if (line.Trim().Length > 0)
{
images.Add((HistoryImage)ser.ReadObject(new MemoryStream(System.Text.Encoding.UTF8.GetBytes(line))));
}
}
return images;
}
catch
{
if (File.Exists(BakDataFile))
{
File.Copy(BakDataFile, DataFile);
return LoadHistoryImages();
}
return new List<HistoryImage>();
}
}
/// <summary>
/// 隨機圖片
/// </summary>
/// <returns></returns>
public static HistoryImage getRandom()
{
return historyImages[new Random().Next(0, historyImages.Count - 1)];
}
新數據保存
從接口獲取到新數據后,加入List,並且持久化到硬盤。
public static void AddImage(HistoryImage image)
{
if (date2Image.ContainsKey(image.Date))
{
historyImages.Add(image);
date2Image.Add(image.Date, image);
Save();
}
}
public static void Save()
{
if (File.Exists(DataFile))
{
File.Delete(BakDataFile);
File.Move(DataFile, BakDataFile);
}
try
{
using (var stream = new FileStream(DataFile, FileMode.Create))
{
var ser = new DataContractJsonSerializer(typeof(HistoryImage));
var line = System.Text.Encoding.UTF8.GetBytes("\r\n");
historyImages.ForEach(image =>
{
ser.WriteObject(stream, image);
stream.Write(line, 0, line.Length);
});
}
}
catch
{
if (File.Exists(BakDataFile))
{
File.Copy(BakDataFile, DataFile);
}
}
}
作者:Jadepeng
出處:jqpeng的技術記事本--http://www.cnblogs.com/xiaoqi
您的支持是對博主最大的鼓勵,感謝您的認真閱讀。
本文版權歸作者所有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利。