zoukankan      html  css  js  c++  java
  • 【开源小软件 】Bing每日壁纸 让桌面壁纸保持更新

    发布一个开源小软件,Bing每日壁纸

    该小软件可以自动获取Bing的精美图片设置为壁纸,并且支持随机切换历史壁纸,查看壁纸故事。

    欢迎大家下载使用,点star!有问题请留言或者提issue。

    开源地址: https://github.com/jadepeng/bing-wallpaper ,想了解技术原理的请看 技术方案

    gecko

    如何使用

    该程序没有主窗口,是托盘程序,点击托盘图标,操作相关菜单即可。

    功能特性

    • 自动获取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/ 有最近两年多的数据,我们可以爬取下来作为离线数据,这样数据就全了。

    通过自研的爬虫平台,简单配置下:

    enter description here

    下载得到898条数据,应该包含2年多的数据:

    enter description here

    导出为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 PanelDesktop", 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);
            }
        }
    

    壁纸故事

    enter description here

    一个简单的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("
    ");
                        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
    您的支持是对博主最大的鼓励,感谢您的认真阅读。
    本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

  • 相关阅读:
    [RxJS] throwIfEmpty
    [Kotlin] I/O readline
    [Kotlin] Generic Functions
    [Kotlin] Generics basic
    [CSS 3] Use Multiple Background Images to Create Single Element CSS Art
    [Kotlin] Visibilities
    [Kotlin] Getter and Setter
    [Kotlin] Enum class
    [Kotlin] Singleton Object
    面试问Redis集群,被虐的不行了......
  • 原文地址:https://www.cnblogs.com/xiaoqi/p/bing-wallpaper.html
Copyright © 2011-2022 走看看