├── screenshot.jpg ├── Assets ├── Ini │ ├── glitter.txt │ └── config.txt ├── Images │ ├── default.png │ ├── tip_menu.jpg │ ├── donate_alipay.png │ └── donate_wechat.png ├── BadgeLogo.scale-100.png ├── BadgeLogo.scale-125.png ├── BadgeLogo.scale-150.png ├── BadgeLogo.scale-200.png ├── BadgeLogo.scale-400.png ├── LargeTile.scale-100.png ├── LargeTile.scale-125.png ├── LargeTile.scale-150.png ├── LargeTile.scale-200.png ├── LargeTile.scale-400.png ├── SmallTile.scale-100.png ├── SmallTile.scale-125.png ├── SmallTile.scale-150.png ├── SmallTile.scale-200.png ├── SmallTile.scale-400.png ├── StoreLogo.scale-100.png ├── StoreLogo.scale-125.png ├── StoreLogo.scale-150.png ├── StoreLogo.scale-200.png ├── StoreLogo.scale-400.png ├── SplashScreen.scale-100.png ├── SplashScreen.scale-125.png ├── SplashScreen.scale-150.png ├── SplashScreen.scale-200.png ├── SplashScreen.scale-400.png ├── Icons │ └── Segoe-Fluent-Icons.ttf ├── LockScreenLogo.scale-200.png ├── Square150x150Logo.scale-100.png ├── Square150x150Logo.scale-125.png ├── Square150x150Logo.scale-150.png ├── Square150x150Logo.scale-200.png ├── Square150x150Logo.scale-400.png ├── Square44x44Logo.scale-100.png ├── Square44x44Logo.scale-125.png ├── Square44x44Logo.scale-150.png ├── Square44x44Logo.scale-200.png ├── Square44x44Logo.scale-400.png ├── Wide310x150Logo.scale-100.png ├── Wide310x150Logo.scale-125.png ├── Wide310x150Logo.scale-150.png ├── Wide310x150Logo.scale-200.png ├── Wide310x150Logo.scale-400.png ├── Square44x44Logo.targetsize-16.png ├── Square44x44Logo.targetsize-24.png ├── Square44x44Logo.targetsize-32.png ├── Square44x44Logo.targetsize-48.png ├── Square44x44Logo.targetsize-256.png ├── Square44x44Logo.altform-unplated_targetsize-16.png ├── Square44x44Logo.altform-unplated_targetsize-256.png ├── Square44x44Logo.altform-unplated_targetsize-32.png ├── Square44x44Logo.altform-unplated_targetsize-48.png ├── Square44x44Logo.targetsize-24_altform-unplated.png ├── Square44x44Logo.altform-lightunplated_targetsize-16.png ├── Square44x44Logo.altform-lightunplated_targetsize-24.png ├── Square44x44Logo.altform-lightunplated_targetsize-256.png ├── Square44x44Logo.altform-lightunplated_targetsize-32.png └── Square44x44Logo.altform-lightunplated_targetsize-48.png ├── Beans ├── MtyApiItem.cs ├── DmoeApiItem.cs ├── ToubiecApiItem.cs ├── ContributeApiReq.cs ├── RankApiReq.cs ├── CrashApiReq.cs ├── StatsApiReq.cs ├── BingApi.cs ├── OneApi.cs ├── NasaApiItem.cs ├── QingbzApi.cs ├── Meta.cs ├── ObzhiApi.cs ├── WallhereApi.cs ├── OneplusApi.cs ├── YmyouliApi.cs ├── TimelineApi.cs ├── InfinityApi.cs └── ReleaseApi.cs ├── App.xaml ├── Properties ├── AssemblyInfo.cs └── Default.rd.xml ├── ReviewDlg.xaml.cs ├── DonateDlg.xaml ├── ContributeDlg.xaml.cs ├── ReviewDlg.xaml ├── DonateDlg.xaml.cs ├── ContributeDlg.xaml ├── Providers ├── DaihanProvider.cs ├── SeovxProvider.cs ├── MtyProvider.cs ├── ToubiecProvider.cs ├── DmoeProvider.cs ├── QingbzProvider.cs ├── ObzhiProvider.cs ├── WallhereProvider.cs ├── YmyouliProvider.cs ├── AbyssProvider.cs ├── TimelineProvider.cs ├── InfinityProvider.cs ├── OneplusProvider.cs ├── G3Provider.cs ├── Himawari8Provider.cs ├── BingProvider.cs ├── OneProvider.cs ├── BaseProvider.cs └── NasaProvider.cs ├── .gitattributes ├── Package.appxmanifest ├── README.md ├── TimelineWallpaper.sln ├── App.xaml.cs ├── .gitignore ├── Services └── ApiService.cs ├── Utils └── Ini.cs └── TimelineWallpaper.csproj /screenshot.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nguaduot/TimelineWallpaper/HEAD/screenshot.jpg -------------------------------------------------------------------------------- /Assets/Ini/glitter.txt: -------------------------------------------------------------------------------- 1 | 但从今、记取楚楼风,裴台月 2 | 羡青山有思,白鹤忘机 3 | 与谁同坐,明月清风我 4 | 连雨不知春去,一晴方觉夏深 5 | 最是人间留不住,朱颜辞镜花辞树 -------------------------------------------------------------------------------- /Assets/Images/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nguaduot/TimelineWallpaper/HEAD/Assets/Images/default.png -------------------------------------------------------------------------------- /Assets/Images/tip_menu.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nguaduot/TimelineWallpaper/HEAD/Assets/Images/tip_menu.jpg -------------------------------------------------------------------------------- /Assets/BadgeLogo.scale-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nguaduot/TimelineWallpaper/HEAD/Assets/BadgeLogo.scale-100.png -------------------------------------------------------------------------------- /Assets/BadgeLogo.scale-125.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nguaduot/TimelineWallpaper/HEAD/Assets/BadgeLogo.scale-125.png -------------------------------------------------------------------------------- /Assets/BadgeLogo.scale-150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nguaduot/TimelineWallpaper/HEAD/Assets/BadgeLogo.scale-150.png -------------------------------------------------------------------------------- /Assets/BadgeLogo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nguaduot/TimelineWallpaper/HEAD/Assets/BadgeLogo.scale-200.png -------------------------------------------------------------------------------- /Assets/BadgeLogo.scale-400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nguaduot/TimelineWallpaper/HEAD/Assets/BadgeLogo.scale-400.png -------------------------------------------------------------------------------- /Assets/LargeTile.scale-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nguaduot/TimelineWallpaper/HEAD/Assets/LargeTile.scale-100.png -------------------------------------------------------------------------------- /Assets/LargeTile.scale-125.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nguaduot/TimelineWallpaper/HEAD/Assets/LargeTile.scale-125.png -------------------------------------------------------------------------------- /Assets/LargeTile.scale-150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nguaduot/TimelineWallpaper/HEAD/Assets/LargeTile.scale-150.png -------------------------------------------------------------------------------- /Assets/LargeTile.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nguaduot/TimelineWallpaper/HEAD/Assets/LargeTile.scale-200.png -------------------------------------------------------------------------------- /Assets/LargeTile.scale-400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nguaduot/TimelineWallpaper/HEAD/Assets/LargeTile.scale-400.png -------------------------------------------------------------------------------- /Assets/SmallTile.scale-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nguaduot/TimelineWallpaper/HEAD/Assets/SmallTile.scale-100.png -------------------------------------------------------------------------------- /Assets/SmallTile.scale-125.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nguaduot/TimelineWallpaper/HEAD/Assets/SmallTile.scale-125.png -------------------------------------------------------------------------------- /Assets/SmallTile.scale-150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nguaduot/TimelineWallpaper/HEAD/Assets/SmallTile.scale-150.png -------------------------------------------------------------------------------- /Assets/SmallTile.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nguaduot/TimelineWallpaper/HEAD/Assets/SmallTile.scale-200.png -------------------------------------------------------------------------------- /Assets/SmallTile.scale-400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nguaduot/TimelineWallpaper/HEAD/Assets/SmallTile.scale-400.png -------------------------------------------------------------------------------- /Assets/StoreLogo.scale-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nguaduot/TimelineWallpaper/HEAD/Assets/StoreLogo.scale-100.png -------------------------------------------------------------------------------- /Assets/StoreLogo.scale-125.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nguaduot/TimelineWallpaper/HEAD/Assets/StoreLogo.scale-125.png -------------------------------------------------------------------------------- /Assets/StoreLogo.scale-150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nguaduot/TimelineWallpaper/HEAD/Assets/StoreLogo.scale-150.png -------------------------------------------------------------------------------- /Assets/StoreLogo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nguaduot/TimelineWallpaper/HEAD/Assets/StoreLogo.scale-200.png -------------------------------------------------------------------------------- /Assets/StoreLogo.scale-400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nguaduot/TimelineWallpaper/HEAD/Assets/StoreLogo.scale-400.png -------------------------------------------------------------------------------- /Assets/Images/donate_alipay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nguaduot/TimelineWallpaper/HEAD/Assets/Images/donate_alipay.png -------------------------------------------------------------------------------- /Assets/Images/donate_wechat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nguaduot/TimelineWallpaper/HEAD/Assets/Images/donate_wechat.png -------------------------------------------------------------------------------- /Assets/SplashScreen.scale-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nguaduot/TimelineWallpaper/HEAD/Assets/SplashScreen.scale-100.png -------------------------------------------------------------------------------- /Assets/SplashScreen.scale-125.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nguaduot/TimelineWallpaper/HEAD/Assets/SplashScreen.scale-125.png -------------------------------------------------------------------------------- /Assets/SplashScreen.scale-150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nguaduot/TimelineWallpaper/HEAD/Assets/SplashScreen.scale-150.png -------------------------------------------------------------------------------- /Assets/SplashScreen.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nguaduot/TimelineWallpaper/HEAD/Assets/SplashScreen.scale-200.png -------------------------------------------------------------------------------- /Assets/SplashScreen.scale-400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nguaduot/TimelineWallpaper/HEAD/Assets/SplashScreen.scale-400.png -------------------------------------------------------------------------------- /Assets/Icons/Segoe-Fluent-Icons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nguaduot/TimelineWallpaper/HEAD/Assets/Icons/Segoe-Fluent-Icons.ttf -------------------------------------------------------------------------------- /Assets/LockScreenLogo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nguaduot/TimelineWallpaper/HEAD/Assets/LockScreenLogo.scale-200.png -------------------------------------------------------------------------------- /Assets/Square150x150Logo.scale-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nguaduot/TimelineWallpaper/HEAD/Assets/Square150x150Logo.scale-100.png -------------------------------------------------------------------------------- /Assets/Square150x150Logo.scale-125.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nguaduot/TimelineWallpaper/HEAD/Assets/Square150x150Logo.scale-125.png -------------------------------------------------------------------------------- /Assets/Square150x150Logo.scale-150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nguaduot/TimelineWallpaper/HEAD/Assets/Square150x150Logo.scale-150.png -------------------------------------------------------------------------------- /Assets/Square150x150Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nguaduot/TimelineWallpaper/HEAD/Assets/Square150x150Logo.scale-200.png -------------------------------------------------------------------------------- /Assets/Square150x150Logo.scale-400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nguaduot/TimelineWallpaper/HEAD/Assets/Square150x150Logo.scale-400.png -------------------------------------------------------------------------------- /Assets/Square44x44Logo.scale-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nguaduot/TimelineWallpaper/HEAD/Assets/Square44x44Logo.scale-100.png -------------------------------------------------------------------------------- /Assets/Square44x44Logo.scale-125.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nguaduot/TimelineWallpaper/HEAD/Assets/Square44x44Logo.scale-125.png -------------------------------------------------------------------------------- /Assets/Square44x44Logo.scale-150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nguaduot/TimelineWallpaper/HEAD/Assets/Square44x44Logo.scale-150.png -------------------------------------------------------------------------------- /Assets/Square44x44Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nguaduot/TimelineWallpaper/HEAD/Assets/Square44x44Logo.scale-200.png -------------------------------------------------------------------------------- /Assets/Square44x44Logo.scale-400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nguaduot/TimelineWallpaper/HEAD/Assets/Square44x44Logo.scale-400.png -------------------------------------------------------------------------------- /Assets/Wide310x150Logo.scale-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nguaduot/TimelineWallpaper/HEAD/Assets/Wide310x150Logo.scale-100.png -------------------------------------------------------------------------------- /Assets/Wide310x150Logo.scale-125.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nguaduot/TimelineWallpaper/HEAD/Assets/Wide310x150Logo.scale-125.png -------------------------------------------------------------------------------- /Assets/Wide310x150Logo.scale-150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nguaduot/TimelineWallpaper/HEAD/Assets/Wide310x150Logo.scale-150.png -------------------------------------------------------------------------------- /Assets/Wide310x150Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nguaduot/TimelineWallpaper/HEAD/Assets/Wide310x150Logo.scale-200.png -------------------------------------------------------------------------------- /Assets/Wide310x150Logo.scale-400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nguaduot/TimelineWallpaper/HEAD/Assets/Wide310x150Logo.scale-400.png -------------------------------------------------------------------------------- /Assets/Square44x44Logo.targetsize-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nguaduot/TimelineWallpaper/HEAD/Assets/Square44x44Logo.targetsize-16.png -------------------------------------------------------------------------------- /Assets/Square44x44Logo.targetsize-24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nguaduot/TimelineWallpaper/HEAD/Assets/Square44x44Logo.targetsize-24.png -------------------------------------------------------------------------------- /Assets/Square44x44Logo.targetsize-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nguaduot/TimelineWallpaper/HEAD/Assets/Square44x44Logo.targetsize-32.png -------------------------------------------------------------------------------- /Assets/Square44x44Logo.targetsize-48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nguaduot/TimelineWallpaper/HEAD/Assets/Square44x44Logo.targetsize-48.png -------------------------------------------------------------------------------- /Assets/Square44x44Logo.targetsize-256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nguaduot/TimelineWallpaper/HEAD/Assets/Square44x44Logo.targetsize-256.png -------------------------------------------------------------------------------- /Assets/Square44x44Logo.altform-unplated_targetsize-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nguaduot/TimelineWallpaper/HEAD/Assets/Square44x44Logo.altform-unplated_targetsize-16.png -------------------------------------------------------------------------------- /Assets/Square44x44Logo.altform-unplated_targetsize-256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nguaduot/TimelineWallpaper/HEAD/Assets/Square44x44Logo.altform-unplated_targetsize-256.png -------------------------------------------------------------------------------- /Assets/Square44x44Logo.altform-unplated_targetsize-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nguaduot/TimelineWallpaper/HEAD/Assets/Square44x44Logo.altform-unplated_targetsize-32.png -------------------------------------------------------------------------------- /Assets/Square44x44Logo.altform-unplated_targetsize-48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nguaduot/TimelineWallpaper/HEAD/Assets/Square44x44Logo.altform-unplated_targetsize-48.png -------------------------------------------------------------------------------- /Assets/Square44x44Logo.targetsize-24_altform-unplated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nguaduot/TimelineWallpaper/HEAD/Assets/Square44x44Logo.targetsize-24_altform-unplated.png -------------------------------------------------------------------------------- /Assets/Square44x44Logo.altform-lightunplated_targetsize-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nguaduot/TimelineWallpaper/HEAD/Assets/Square44x44Logo.altform-lightunplated_targetsize-16.png -------------------------------------------------------------------------------- /Assets/Square44x44Logo.altform-lightunplated_targetsize-24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nguaduot/TimelineWallpaper/HEAD/Assets/Square44x44Logo.altform-lightunplated_targetsize-24.png -------------------------------------------------------------------------------- /Assets/Square44x44Logo.altform-lightunplated_targetsize-256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nguaduot/TimelineWallpaper/HEAD/Assets/Square44x44Logo.altform-lightunplated_targetsize-256.png -------------------------------------------------------------------------------- /Assets/Square44x44Logo.altform-lightunplated_targetsize-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nguaduot/TimelineWallpaper/HEAD/Assets/Square44x44Logo.altform-lightunplated_targetsize-32.png -------------------------------------------------------------------------------- /Assets/Square44x44Logo.altform-lightunplated_targetsize-48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nguaduot/TimelineWallpaper/HEAD/Assets/Square44x44Logo.altform-lightunplated_targetsize-48.png -------------------------------------------------------------------------------- /Beans/MtyApiItem.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | namespace TimelineWallpaper.Beans { 4 | public class MtyApiItem { 5 | // 图片URL 6 | [JsonProperty(PropertyName = "imgurl")] 7 | public string ImgUrl { set; get; } 8 | 9 | // ... 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Beans/DmoeApiItem.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | namespace TimelineWallpaper.Beans { 4 | public class DmoeApiItem { 5 | // 图片URL 6 | [JsonProperty(PropertyName = "imgurl")] 7 | public string ImgUrl { set; get; } 8 | 9 | // ... 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Beans/ToubiecApiItem.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | namespace TimelineWallpaper.Beans { 4 | public class ToubiecApiItem { 5 | // ID 6 | [JsonProperty(PropertyName = "id")] 7 | public int Id { set; get; } 8 | 9 | // 图片URL 10 | [JsonProperty(PropertyName = "imgurl")] 11 | public string ImgUrl { set; get; } 12 | 13 | // ... 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /App.xaml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /Beans/ContributeApiReq.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | namespace TimelineWallpaper.Beans { 4 | public class ContributeApiReq { 5 | [JsonProperty(PropertyName = "url")] 6 | public string Url { set; get; } 7 | 8 | [JsonProperty(PropertyName = "title")] 9 | public string Title { set; get; } 10 | 11 | [JsonProperty(PropertyName = "story")] 12 | public string Story { set; get; } 13 | 14 | [JsonProperty(PropertyName = "contact")] 15 | public string Contact { set; get; } 16 | 17 | [JsonProperty(PropertyName = "appver")] 18 | public string AppVer { set; get; } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Beans/RankApiReq.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | namespace TimelineWallpaper.Beans { 4 | public class RankApiReq { 5 | [JsonProperty(PropertyName = "provider")] 6 | public string Provider { set; get; } 7 | 8 | [JsonProperty(PropertyName = "imgid")] 9 | public string ImgId { set; get; } 10 | 11 | [JsonProperty(PropertyName = "imgurl")] 12 | public string ImgUrl { set; get; } 13 | 14 | [JsonProperty(PropertyName = "action")] 15 | public string Action { set; get; } 16 | 17 | [JsonProperty(PropertyName = "deviceid")] 18 | public string DeviceId { set; get; } 19 | 20 | [JsonProperty(PropertyName = "region")] 21 | public string Region { set; get; } 22 | 23 | [JsonProperty(PropertyName = "undo")] 24 | public bool Undo { set; get; } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // 有关程序集的一般信息由以下 6 | // 控制。更改这些特性值可修改 7 | // 与程序集关联的信息。 8 | [assembly: AssemblyTitle("拾光 for Windows 11")] 9 | [assembly: AssemblyDescription("时光如歌,岁月如诗。拾光,每日一景")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("拾光 for Windows 11")] 13 | [assembly: AssemblyCopyright("Copyright © nguaduot 2021-2022")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // 程序集的版本信息由下列四个值组成: 18 | // 19 | // 主版本 20 | // 次版本 21 | // 生成号 22 | // 修订号 23 | // 24 | //可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值 25 | //通过使用 "*",如下所示: 26 | // [assembly: AssemblyVersion("1.0.*")] 27 | [assembly: AssemblyVersion("4.0")] 28 | [assembly: AssemblyFileVersion("4.0")] 29 | [assembly: ComVisible(false)] -------------------------------------------------------------------------------- /ReviewDlg.xaml.cs: -------------------------------------------------------------------------------- 1 | using TimelineWallpaper.Utils; 2 | using Windows.ApplicationModel.Resources; 3 | using Windows.UI.Xaml; 4 | using Windows.UI.Xaml.Controls; 5 | 6 | // https://go.microsoft.com/fwlink/?LinkId=234238 上介绍了“内容对话框”项模板 7 | 8 | namespace TimelineWallpaper { 9 | public sealed partial class ReviewDlg : ContentDialog { 10 | public ReviewDlg() { 11 | this.InitializeComponent(); 12 | 13 | this.Title = ResourceLoader.GetForCurrentView().GetString("AppNameShort") + " " + VerUtil.GetPkgVer(true); 14 | } 15 | 16 | private async void LinkDonate_Click(object sender, RoutedEventArgs e) { 17 | this.Hide(); 18 | Ini ini = await IniUtil.GetIniAsync(); 19 | _ = new DonateDlg { 20 | RequestedTheme = ThemeUtil.ParseTheme(ini.Theme) // 修复未响应主题切换的BUG 21 | }.ShowAsync(); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Beans/CrashApiReq.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | namespace TimelineWallpaper.Beans { 4 | public class CrashApiReq { 5 | [JsonProperty(PropertyName = "app")] 6 | public string App { set; get; } 7 | 8 | [JsonProperty(PropertyName = "pkg")] 9 | public string Package { set; get; } 10 | 11 | [JsonProperty(PropertyName = "ver")] 12 | public string Version { set; get; } 13 | 14 | [JsonProperty(PropertyName = "os")] 15 | public string Os { set; get; } 16 | 17 | [JsonProperty(PropertyName = "osver")] 18 | public string OsVersion { set; get; } 19 | 20 | [JsonProperty(PropertyName = "device")] 21 | public string Device { set; get; } 22 | 23 | [JsonProperty(PropertyName = "deviceid")] 24 | public string DeviceId { set; get; } 25 | 26 | [JsonProperty(PropertyName = "exception")] 27 | public string Exception { set; get; } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Properties/Default.rd.xml: -------------------------------------------------------------------------------- 1 | 17 | 18 | 19 | 20 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /Beans/StatsApiReq.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | namespace TimelineWallpaper.Beans { 4 | public class StatsApiReq { 5 | [JsonProperty(PropertyName = "app")] 6 | public string App { set; get; } 7 | 8 | [JsonProperty(PropertyName = "pkg")] 9 | public string Package { set; get; } 10 | 11 | [JsonProperty(PropertyName = "ver")] 12 | public string Version { set; get; } 13 | 14 | [JsonProperty(PropertyName = "api")] 15 | public string Api { set; get; } 16 | 17 | [JsonProperty(PropertyName = "status")] 18 | public int Status { set; get; } 19 | 20 | [JsonProperty(PropertyName = "os")] 21 | public string Os { set; get; } 22 | 23 | [JsonProperty(PropertyName = "osver")] 24 | public string OsVersion { set; get; } 25 | 26 | [JsonProperty(PropertyName = "device")] 27 | public string Device { set; get; } 28 | 29 | [JsonProperty(PropertyName = "deviceid")] 30 | public string DeviceId { set; get; } 31 | 32 | [JsonProperty(PropertyName = "region")] 33 | public string Region { set; get; } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /DonateDlg.xaml: -------------------------------------------------------------------------------- 1 | 17 | 18 | 19 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /Beans/BingApi.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System.Collections.Generic; 3 | 4 | namespace TimelineWallpaper.Beans { 5 | public class BingApi { 6 | // 图片信息数组 7 | [JsonProperty(PropertyName = "images")] 8 | public List Images { set; get; } 9 | } 10 | 11 | public class BingApiImg { 12 | // ID 13 | [JsonProperty(PropertyName = "hsh")] 14 | public string Hsh { set; get; } 15 | 16 | // 根链接,如:/az/hprichbg/rb/Shanghai_ZH-CN10665657954 17 | // 前接 http://s.cn.bing.net 或 https://cn.bing.com,后接 _1920x1080.jpg 等 18 | [JsonProperty(PropertyName = "urlbase")] 19 | public string UrlBase { set; get; } 20 | 21 | // 日期 22 | [JsonProperty(PropertyName = "enddate")] 23 | public string EndDate { set; get; } 24 | 25 | // 说明+版权 26 | [JsonProperty(PropertyName = "copyright")] 27 | public string Copyright { set; get; } 28 | 29 | // 标题 30 | [JsonProperty(PropertyName = "title")] 31 | public string Title { set; get; } 32 | 33 | // 描述 34 | [JsonProperty(PropertyName = "desc")] 35 | public string Desc { set; get; } 36 | 37 | // ... 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Beans/OneApi.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System.Collections.Generic; 3 | 4 | namespace TimelineWallpaper.Beans { 5 | public class OneApi { 6 | // 图片信息数组 7 | [JsonProperty(PropertyName = "data")] 8 | public List Data { set; get; } 9 | } 10 | 11 | public class OneApiData { 12 | // ID 13 | [JsonProperty(PropertyName = "id")] 14 | public string Id { set; get; } 15 | 16 | // 图片URL 17 | [JsonProperty(PropertyName = "img_url")] 18 | public string ImgUrl { set; get; } 19 | 20 | // 标题 21 | [JsonProperty(PropertyName = "title")] 22 | public string Title { set; get; } 23 | 24 | // 图文故事 25 | [JsonProperty(PropertyName = "content")] 26 | public string Content { set; get; } 27 | 28 | // 摄影作者 29 | [JsonProperty(PropertyName = "picture_author")] 30 | public string PictureAuthor { set; get; } 31 | 32 | // 文字作者 33 | [JsonProperty(PropertyName = "text_authors")] 34 | public string TextAuthors { set; get; } 35 | 36 | // 日期 37 | [JsonProperty(PropertyName = "date")] 38 | public string Date { set; get; } 39 | 40 | // ... 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Beans/NasaApiItem.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | namespace TimelineWallpaper.Beans { 4 | public class NasaApiItem { 5 | // 日期 6 | [JsonProperty(PropertyName = "date")] 7 | public string Date { set; get; } 8 | 9 | // 作者&版权(可能缺失) 10 | [JsonProperty(PropertyName = "copyright")] 11 | public string Copyright { set; get; } 12 | 13 | // 标题 14 | [JsonProperty(PropertyName = "title")] 15 | public string Title { set; get; } 16 | 17 | // 描述 18 | [JsonProperty(PropertyName = "explanation")] 19 | public string Explanation { set; get; } 20 | 21 | // 媒体类型 22 | [JsonProperty(PropertyName = "media_type")] 23 | public string MediaType { set; get; } 24 | 25 | // 原图URL(media_type为“video”时缺失) 26 | [JsonProperty(PropertyName = "hdurl")] 27 | public string HdUrl { set; get; } 28 | 29 | // 缩略图URL(media_type为“video”时是视频链接) 30 | [JsonProperty(PropertyName = "url")] 31 | public string Url { set; get; } 32 | 33 | // 视频封面URL(media_type非“video”时缺失) 34 | [JsonProperty(PropertyName = "thumbnail_url")] 35 | public string ThumbnailUrl { set; get; } 36 | 37 | // ... 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /ContributeDlg.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Runtime.InteropServices.WindowsRuntime; 7 | using TimelineWallpaper.Beans; 8 | using TimelineWallpaper.Services; 9 | using Windows.ApplicationModel.Resources; 10 | using Windows.Foundation; 11 | using Windows.Foundation.Collections; 12 | using Windows.UI.Xaml; 13 | using Windows.UI.Xaml.Controls; 14 | using Windows.UI.Xaml.Controls.Primitives; 15 | using Windows.UI.Xaml.Data; 16 | using Windows.UI.Xaml.Input; 17 | using Windows.UI.Xaml.Media; 18 | using Windows.UI.Xaml.Navigation; 19 | 20 | // https://go.microsoft.com/fwlink/?LinkId=234238 上介绍了“内容对话框”项模板 21 | 22 | namespace TimelineWallpaper { 23 | public sealed partial class ContributeDlg : ContentDialog { 24 | public ContributeDlg() { 25 | this.InitializeComponent(); 26 | } 27 | 28 | public ContributeApiReq GetContent() { 29 | return new ContributeApiReq { 30 | Url = BoxUrl.Text.Trim(), 31 | Title = BoxTitle.Text.Trim(), 32 | Story = BoxStory.Text.Trim(), 33 | Contact = BoxContact.Text.Trim() 34 | }; 35 | } 36 | 37 | private void BoxUrl_TextChanged(object sender, TextChangedEventArgs e) { 38 | this.IsPrimaryButtonEnabled = BoxUrl.Text.Trim().Length > 0; 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Beans/QingbzApi.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System.Collections.Generic; 3 | 4 | namespace TimelineWallpaper.Beans { 5 | public class QingbzApi { 6 | // 图片信息数组 7 | [JsonProperty(PropertyName = "data")] 8 | public List Data { set; get; } 9 | } 10 | 11 | public class QingbzApiData { 12 | // 类别内排序序号 13 | [JsonProperty(PropertyName = "catealtno")] 14 | public int CateAltNo { set; get; } 15 | 16 | // 类别ID 17 | [JsonProperty(PropertyName = "cateidalt")] 18 | public string CateIdAlt { set; get; } 19 | 20 | // 类别 21 | [JsonProperty(PropertyName = "catealt")] 22 | public string CateAlt { set; get; } 23 | 24 | // 图片ID 25 | [JsonProperty(PropertyName = "imgid")] 26 | public int ImgId { set; get; } 27 | 28 | // 图片URL 29 | [JsonProperty(PropertyName = "imgurl")] 30 | public string ImgUrl { set; get; } 31 | 32 | // 缩略图URL 33 | [JsonProperty(PropertyName = "thumburl")] 34 | public string ThumbUrl { set; get; } 35 | 36 | // 发布日期 37 | [JsonProperty(PropertyName = "reldate")] 38 | public string RelDate { set; get; } 39 | 40 | // 热度分 41 | [JsonProperty(PropertyName = "score")] 42 | public float Score { set; get; } 43 | 44 | // R18内容 45 | [JsonProperty(PropertyName = "r18")] 46 | public int R18 { set; get; } 47 | 48 | // ... 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Beans/Meta.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Drawing; 3 | using Windows.Networking.BackgroundTransfer; 4 | using Windows.Storage; 5 | 6 | namespace TimelineWallpaper.Beans { 7 | public class Meta { 8 | // ID(非空) 9 | public string Id { set; get; } 10 | 11 | // 原图URL 12 | public string Uhd { set; get; } 13 | 14 | // 缩略图URL 15 | public string Thumb { set; get; } 16 | 17 | // 标题 18 | public string Title { set; get; } 19 | 20 | // 副标题 21 | public string Caption { set; get; } 22 | 23 | // 类别 24 | public string Cate { set; get; } 25 | 26 | // 位置 27 | public string Location { set; get; } 28 | 29 | // 描述/图文故事 30 | public string Story { set; get; } 31 | 32 | // 版权所有者/作者 33 | public string Copyright { set; get; } 34 | 35 | // 展示日期(非空) 36 | public DateTime? Date { set; get; } 37 | 38 | // 文件格式 39 | public string Format { set; get; } = ".jpg"; 40 | 41 | // 原图/视频尺寸 42 | public Size Dimen { set; get; } 43 | 44 | // 原图本地缓存文件 45 | public StorageFile CacheUhd { set; get; } 46 | 47 | public DownloadOperation Do { set; get; } 48 | 49 | // 主题色笔刷 50 | //public SolidColorBrush Dominant { set; get; } 51 | 52 | // 人像位置 53 | public float FaceOffset { set; get; } = 0.5f; 54 | 55 | public double SortFactor { set; get; } 56 | 57 | public bool IsValid() { 58 | return !string.IsNullOrEmpty(Id) && Date != null && Uhd != null; 59 | } 60 | 61 | public string GetTitleOrCaption() { 62 | return Title ?? Caption; 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /Beans/ObzhiApi.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System.Collections.Generic; 3 | 4 | namespace TimelineWallpaper.Beans { 5 | public class ObzhiApi { 6 | // 图片信息数组 7 | [JsonProperty(PropertyName = "data")] 8 | public List Data { set; get; } 9 | } 10 | 11 | public class ObzhiApiData { 12 | // 类别ID 13 | [JsonProperty(PropertyName = "cateidalt")] 14 | public string CateIdAlt { set; get; } 15 | 16 | // 类别 17 | [JsonProperty(PropertyName = "catealt")] 18 | public string CateAlt { set; get; } 19 | 20 | // 标题 21 | [JsonProperty(PropertyName = "title")] 22 | public string Title { set; get; } 23 | 24 | // 图文故事 25 | [JsonProperty(PropertyName = "story")] 26 | public string Story { set; get; } 27 | 28 | // 作者 29 | [JsonProperty(PropertyName = "author")] 30 | public string Author { set; get; } 31 | 32 | // 图片ID 33 | [JsonProperty(PropertyName = "imgid")] 34 | public int ImgId { set; get; } 35 | 36 | // 图片URL 37 | [JsonProperty(PropertyName = "imgurl")] 38 | public string ImgUrl { set; get; } 39 | 40 | // 缩略图URL 41 | [JsonProperty(PropertyName = "thumburl")] 42 | public string ThumbUrl { set; get; } 43 | 44 | // 发布日期 45 | [JsonProperty(PropertyName = "reldate")] 46 | public string RelDate { set; get; } 47 | 48 | // 热度分 49 | [JsonProperty(PropertyName = "score")] 50 | public float Score { set; get; } 51 | 52 | // R18内容 53 | [JsonProperty(PropertyName = "r18")] 54 | public int R18 { set; get; } 55 | 56 | // ... 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /Beans/WallhereApi.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System.Collections.Generic; 3 | 4 | namespace TimelineWallpaper.Beans { 5 | public class WallhereApi { 6 | // 图片信息数组 7 | [JsonProperty(PropertyName = "data")] 8 | public List Data { set; get; } 9 | } 10 | 11 | public class WallhereApiData { 12 | // 排序编号 13 | [JsonProperty(PropertyName = "no")] 14 | public int No { set; get; } 15 | 16 | // 类别内排序序号 17 | [JsonProperty(PropertyName = "catealtno")] 18 | public int CateAltNo { set; get; } 19 | 20 | // 类别ID 21 | [JsonProperty(PropertyName = "cateidalt")] 22 | public string CateIdAlt { set; get; } 23 | 24 | // 类别 25 | [JsonProperty(PropertyName = "catealt")] 26 | public string CateAlt { set; get; } 27 | 28 | // 图片ID 29 | [JsonProperty(PropertyName = "imgid")] 30 | public int ImgId { set; get; } 31 | 32 | // 图片URL 33 | [JsonProperty(PropertyName = "imgurl")] 34 | public string ImgUrl { set; get; } 35 | 36 | // 缩略图URL 37 | [JsonProperty(PropertyName = "thumburl")] 38 | public string ThumbUrl { set; get; } 39 | 40 | // 作者 41 | [JsonProperty(PropertyName = "author")] 42 | public string Author { set; get; } 43 | 44 | // TAG 45 | [JsonProperty(PropertyName = "tag")] 46 | public string Tag { set; get; } 47 | 48 | // 热度分 49 | [JsonProperty(PropertyName = "score")] 50 | public float Score { set; get; } 51 | 52 | // R18内容 53 | [JsonProperty(PropertyName = "r18")] 54 | public int R18 { set; get; } 55 | 56 | // ... 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /ReviewDlg.xaml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 15 | 16 | 17 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /Beans/OneplusApi.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System.Collections.Generic; 3 | 4 | namespace TimelineWallpaper.Beans { 5 | public class OneplusApi { 6 | // 图片信息数组 7 | [JsonProperty(PropertyName = "data")] 8 | public List Items { set; get; } 9 | } 10 | 11 | public class OneplusApiItem { 12 | // ID 13 | [JsonProperty(PropertyName = "photoCode")] 14 | public string PhotoCode { set; get; } 15 | 16 | // URL 17 | [JsonProperty(PropertyName = "photoUrl")] 18 | public string PhotoUrl { set; get; } 19 | 20 | // 日期 21 | [JsonProperty(PropertyName = "scheduleTime")] 22 | public string ScheduleTime { set; get; } 23 | 24 | // 作者 25 | [JsonProperty(PropertyName = "author")] 26 | public string Author { set; get; } 27 | 28 | // 标题 29 | [JsonProperty(PropertyName = "photoTopic")] 30 | public string PhotoTopic { set; get; } 31 | 32 | // 描述 33 | [JsonProperty(PropertyName = "remark")] 34 | public string Remark { set; get; } 35 | 36 | // 国家 37 | [JsonProperty(PropertyName = "countryCodeStr")] 38 | public string CountryCodeStr { set; get; } 39 | 40 | // 地点 41 | [JsonProperty(PropertyName = "photoLocation")] 42 | public string PhotoLocation { set; get; } 43 | 44 | // ... 45 | } 46 | 47 | public class OneplusRequest { 48 | [JsonProperty(PropertyName = "pageSize")] 49 | public int PageSize { set; get; } 50 | 51 | [JsonProperty(PropertyName = "currentPage")] 52 | public int CurrentPage { set; get; } 53 | 54 | [JsonProperty(PropertyName = "sortMethod")] 55 | public string SortMethod { set; get; } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Beans/YmyouliApi.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System.Collections.Generic; 3 | 4 | namespace TimelineWallpaper.Beans { 5 | public class YmyouliApi { 6 | // 图片信息数组 7 | [JsonProperty(PropertyName = "data")] 8 | public List Data { set; get; } 9 | } 10 | 11 | public class YmyouliApiData { 12 | // 排序编号 13 | [JsonProperty(PropertyName = "no")] 14 | public int No { set; get; } 15 | 16 | // 类别内排序序号 17 | [JsonProperty(PropertyName = "catealtno")] 18 | public int CateAltNo { set; get; } 19 | 20 | // 类别ID 21 | [JsonProperty(PropertyName = "cateidalt")] 22 | public string CateIdAlt { set; get; } 23 | 24 | // 类别 25 | [JsonProperty(PropertyName = "catealt")] 26 | public string CateAlt { set; get; } 27 | 28 | // 类别 29 | [JsonProperty(PropertyName = "cate")] 30 | public string Cate { set; get; } 31 | 32 | // 组 33 | [JsonProperty(PropertyName = "group")] 34 | public string Group { set; get; } 35 | 36 | // 图片ID 37 | [JsonProperty(PropertyName = "imgid")] 38 | public string ImgId { set; get; } 39 | 40 | // 图片URL 41 | [JsonProperty(PropertyName = "imgurl")] 42 | public string ImgUrl { set; get; } 43 | 44 | // 缩略图URL 45 | [JsonProperty(PropertyName = "thumburl")] 46 | public string ThumbUrl { set; get; } 47 | 48 | // 版权所有 49 | [JsonProperty(PropertyName = "copyright")] 50 | public string Copyright { set; get; } 51 | 52 | // 热度分 53 | [JsonProperty(PropertyName = "score")] 54 | public float Score { set; get; } 55 | 56 | // R18内容 57 | [JsonProperty(PropertyName = "r18")] 58 | public int R18 { set; get; } 59 | 60 | // ... 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /Beans/TimelineApi.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System.Collections.Generic; 3 | 4 | namespace TimelineWallpaper.Beans { 5 | public class TimelineApi { 6 | // 图片信息数组 7 | [JsonProperty(PropertyName = "data")] 8 | public List Data { set; get; } 9 | } 10 | 11 | public class TimelineApiData { 12 | // ID 13 | [JsonProperty(PropertyName = "id")] 14 | public int Id { set; get; } 15 | 16 | // 图片URL 17 | [JsonProperty(PropertyName = "imgurl")] 18 | public string ImgUrl { set; get; } 19 | 20 | // 缩略图URL 21 | [JsonProperty(PropertyName = "thumburl")] 22 | public string ThumbUrl { set; get; } 23 | 24 | // 标题 25 | [JsonProperty(PropertyName = "title")] 26 | public string Title { set; get; } 27 | 28 | // 图文故事 29 | [JsonProperty(PropertyName = "story")] 30 | public string Story { set; get; } 31 | 32 | // 出处 33 | [JsonProperty(PropertyName = "platform")] 34 | public string Platform { set; get; } 35 | 36 | // 作者 37 | [JsonProperty(PropertyName = "author")] 38 | public string Author { set; get; } 39 | 40 | // 类别 41 | [JsonProperty(PropertyName = "cate")] 42 | public string Cate { set; get; } 43 | 44 | // 发布日期 45 | [JsonProperty(PropertyName = "srcdate")] 46 | public string SrcDate { set; get; } 47 | 48 | // 推送日期 49 | [JsonProperty(PropertyName = "reldate")] 50 | public string RelDate { set; get; } 51 | 52 | // 热度分 53 | [JsonProperty(PropertyName = "score")] 54 | public float Score { set; get; } 55 | 56 | // 隐藏标记 57 | [JsonProperty(PropertyName = "deprecated")] 58 | public int Deprecated { set; get; } 59 | 60 | // ... 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /Beans/InfinityApi.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System.Collections.Generic; 3 | 4 | namespace TimelineWallpaper.Beans { 5 | public class InfinityApi1 { 6 | // 图片信息数组 7 | [JsonProperty(PropertyName = "data")] 8 | public List Data { set; get; } 9 | } 10 | 11 | public class InfinityApi2 { 12 | // 图片信息数组 13 | [JsonProperty(PropertyName = "data")] 14 | public InfinityApiData2 Data { set; get; } 15 | } 16 | 17 | public class InfinityApiData2 { 18 | // 图片信息数组 19 | [JsonProperty(PropertyName = "list")] 20 | public List List { set; get; } 21 | } 22 | 23 | public class InfinityApiData { 24 | // 排序编号 25 | [JsonProperty(PropertyName = "imgId")] 26 | public string No { set; get; } 27 | 28 | // ID 29 | [JsonProperty(PropertyName = "_id")] 30 | public string Id { set; get; } 31 | 32 | [JsonProperty(PropertyName = "src")] 33 | public InfinityApiSrc Src { set; get; } 34 | 35 | // 赞数 36 | [JsonProperty(PropertyName = "rate")] 37 | public int Rate { set; get; } 38 | 39 | // 收藏数 40 | [JsonProperty(PropertyName = "like")] 41 | public int Like { set; get; } 42 | 43 | // 标签 44 | [JsonProperty(PropertyName = "tags")] 45 | public List Tags { set; get; } 46 | 47 | // 壁纸源 48 | [JsonProperty(PropertyName = "source")] 49 | public string Source { set; get; } 50 | 51 | // ... 52 | } 53 | 54 | public class InfinityApiSrc { 55 | // 原图URL 56 | [JsonProperty(PropertyName = "rawSrc")] 57 | public string RawSrc { set; get; } 58 | 59 | //缩略图URL 60 | [JsonProperty(PropertyName = "smallSrc")] 61 | public string SmallSrc { set; get; } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /DonateDlg.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Runtime.InteropServices.WindowsRuntime; 6 | using Windows.Foundation; 7 | using Windows.Foundation.Collections; 8 | using Windows.UI.Xaml; 9 | using Windows.UI.Xaml.Controls.Primitives; 10 | using Windows.UI.Xaml.Data; 11 | using Windows.UI.Xaml.Input; 12 | using Windows.UI.Xaml.Media; 13 | using Windows.UI.Xaml.Media.Imaging; 14 | using Windows.UI.Xaml.Navigation; 15 | using Windows.UI.Xaml.Controls; 16 | 17 | // https://go.microsoft.com/fwlink/?LinkId=234238 上介绍了“内容对话框”项模板 18 | 19 | namespace TimelineWallpaper { 20 | public sealed partial class DonateDlg : ContentDialog { 21 | private bool doNotClose = false; 22 | 23 | public DonateDlg() { 24 | this.InitializeComponent(); 25 | 26 | ChangeCode(); 27 | } 28 | 29 | private void ChangeCode(bool viaAlipay = false) { 30 | ImgDonate.Source = new BitmapImage(new Uri(viaAlipay ? "ms-appx:///Assets/Images/donate_alipay.png" : "ms-appx:///Assets/Images/donate_wechat.png")); 31 | } 32 | 33 | private void Donate_PrimaryButtonClick(ContentDialog sender, ContentDialogButtonClickEventArgs args) { 34 | ChangeCode(); 35 | doNotClose = true; 36 | } 37 | 38 | private void Donate_SecondaryButtonClick(ContentDialog sender, ContentDialogButtonClickEventArgs args) { 39 | ChangeCode(true); 40 | doNotClose = true; 41 | } 42 | 43 | private void Donate_CloseButtonClick(ContentDialog sender, ContentDialogButtonClickEventArgs args) { 44 | doNotClose = false; 45 | } 46 | 47 | private void Donate_Closing(ContentDialog sender, ContentDialogClosingEventArgs args) { 48 | args.Cancel = doNotClose; 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Beans/ReleaseApi.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | 4 | namespace TimelineWallpaper.Beans { 5 | public class ReleaseApi { 6 | public string Version { get; set; } 7 | 8 | public string Url { get; set; } 9 | } 10 | 11 | /// 12 | /// Github的发布响应结果. 13 | /// 14 | public class GithubApi { 15 | /// 16 | /// 网址. 17 | /// 18 | [JsonProperty(NullValueHandling = NullValueHandling.Ignore, PropertyName = "html_url", Required = Required.Default)] 19 | public string Url { get; set; } 20 | 21 | /// 22 | /// 版本标签. 23 | /// 24 | [JsonProperty(NullValueHandling = NullValueHandling.Ignore, PropertyName = "tag_name", Required = Required.Default)] 25 | public string TagName { get; set; } 26 | 27 | /// 28 | /// 标题. 29 | /// 30 | [JsonProperty(NullValueHandling = NullValueHandling.Ignore, PropertyName = "name", Required = Required.Default)] 31 | public string Name { get; set; } 32 | 33 | /// 34 | /// 是否为预发布版本. 35 | /// 36 | [JsonProperty(NullValueHandling = NullValueHandling.Ignore, PropertyName = "prerelease", Required = Required.Default)] 37 | public bool IsPreRelease { get; set; } 38 | 39 | /// 40 | /// 发布时间. 41 | /// 42 | [JsonProperty(NullValueHandling = NullValueHandling.Ignore, PropertyName = "published_at", Required = Required.Default)] 43 | public DateTime PublishTime { get; set; } 44 | 45 | /// 46 | /// 发布说明. 47 | /// 48 | [JsonProperty(NullValueHandling = NullValueHandling.Ignore, PropertyName = "body", Required = Required.Default)] 49 | public string Description { get; set; } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /ContributeDlg.xaml: -------------------------------------------------------------------------------- 1 | 13 | 14 | 20 | 21 | 24 | 27 | 32 | 35 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /Providers/DaihanProvider.cs: -------------------------------------------------------------------------------- 1 | using TimelineWallpaper.Beans; 2 | using System; 3 | using System.Diagnostics; 4 | using System.Net.Http; 5 | using System.Net.NetworkInformation; 6 | using System.Threading.Tasks; 7 | using TimelineWallpaper.Utils; 8 | using System.Text.RegularExpressions; 9 | using System.Collections.Generic; 10 | 11 | namespace TimelineWallpaper.Providers { 12 | public class DaihanProvider : BaseProvider { 13 | // 随机二次元ACG图片-呆憨API 14 | // https://api.daihan.top/html/acg.html 15 | private const string URL_API = "https://api.daihan.top/api/acg/index.php"; 16 | 17 | private Meta ParseBean(Uri uriImg) { 18 | Meta meta = new Meta(); 19 | if (uriImg == null) { 20 | return meta; 21 | } 22 | string[] name = uriImg.Segments[uriImg.Segments.Length - 1].Split("."); 23 | meta.Id = name[0]; 24 | meta.Format = "." + name[1]; 25 | meta.Uhd = Regex.Replace(uriImg.AbsoluteUri, @"(?<=\.sinaimg\.cn/)[^/]+", "large"); 26 | meta.Thumb = Regex.Replace(uriImg.AbsoluteUri, @"(?<=\.sinaimg\.cn/)[^/]+", "middle"); 27 | meta.Date = DateTime.Now; 28 | return meta; 29 | } 30 | 31 | public override async Task LoadData(BaseIni ini, DateTime? date = null) { 32 | // 现有数据未浏览完,无需加载更多,或已无更多数据 33 | if (indexFocus < metas.Count - 1) { 34 | return true; 35 | } 36 | // 无网络连接 37 | if (!NetworkInterface.GetIsNetworkAvailable()) { 38 | return false; 39 | } 40 | await base.LoadData(ini, date); 41 | 42 | Debug.WriteLine("provider url: " + URL_API); 43 | try { 44 | HttpClient client = new HttpClient(new HttpClientHandler { 45 | AllowAutoRedirect = false 46 | }); 47 | HttpResponseMessage msg = await client.GetAsync(URL_API); 48 | List metasAdd = new List { 49 | ParseBean(msg.Headers.Location) 50 | }; 51 | AppendMetas(metasAdd); 52 | } catch (Exception e) { 53 | Debug.WriteLine(e); 54 | } 55 | 56 | return metas.Count > 0; 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /Providers/SeovxProvider.cs: -------------------------------------------------------------------------------- 1 | using TimelineWallpaper.Beans; 2 | using System; 3 | using System.Diagnostics; 4 | using System.Net.Http; 5 | using System.Net.NetworkInformation; 6 | using System.Threading.Tasks; 7 | using TimelineWallpaper.Utils; 8 | using System.Collections.Generic; 9 | 10 | namespace TimelineWallpaper.Providers { 11 | public class SeovxProvider : BaseProvider { 12 | // 在线古风美图二次元API - 夏沫博客 13 | // https://cdn.seovx.com/ 14 | private const string URL_API = "https://cdn.seovx.com/{0}/?mom=302"; 15 | 16 | private Meta ParseBean(Uri uriImg) { 17 | Meta meta = new Meta(); 18 | if (uriImg == null) { 19 | return meta; 20 | } 21 | if (uriImg.ToString().StartsWith("//")) { 22 | uriImg = new Uri("https:" + uriImg.ToString()); 23 | } 24 | string[] name = uriImg.Segments[uriImg.Segments.Length - 1].Split("."); 25 | meta.Id = name[0]; 26 | meta.Format = "." + name[1]; 27 | meta.Uhd = uriImg.AbsoluteUri; 28 | meta.Thumb = uriImg.AbsoluteUri; 29 | meta.Date = DateTime.Now; 30 | return meta; 31 | } 32 | 33 | public override async Task LoadData(BaseIni ini, DateTime? date = null) { 34 | // 现有数据未浏览完,无需加载更多,或已无更多数据 35 | if (indexFocus < metas.Count - 1) { 36 | return true; 37 | } 38 | // 无网络连接 39 | if (!NetworkInterface.GetIsNetworkAvailable()) { 40 | return false; 41 | } 42 | await base.LoadData(ini, date); 43 | 44 | string uriApi = string.Format(URL_API, ((SeovxIni)ini).Cate); 45 | Debug.WriteLine("provider url: " + uriApi); 46 | try { 47 | HttpClient client = new HttpClient(new HttpClientHandler { 48 | AllowAutoRedirect = false 49 | }); 50 | HttpResponseMessage msg = await client.GetAsync(uriApi); 51 | List metasAdd = new List { 52 | ParseBean(msg.Headers.Location) 53 | }; 54 | AppendMetas(metasAdd); 55 | } catch (Exception e) { 56 | Debug.WriteLine(e); 57 | } 58 | 59 | return metas.Count > 0; 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /Providers/MtyProvider.cs: -------------------------------------------------------------------------------- 1 | using TimelineWallpaper.Beans; 2 | using System; 3 | using System.Diagnostics; 4 | using System.Net.Http; 5 | using System.Net.NetworkInformation; 6 | using System.Threading.Tasks; 7 | using TimelineWallpaper.Utils; 8 | using Newtonsoft.Json; 9 | using System.Text.RegularExpressions; 10 | using System.Collections.Generic; 11 | 12 | namespace TimelineWallpaper.Providers { 13 | public class MtyProvider : BaseProvider { 14 | // 墨天逸 - 随机图片API 15 | // https://api.mtyqx.cn/ 16 | private const string URL_API = "https://api.mtyqx.cn/api/random.php?return=json"; 17 | 18 | private Meta ParseBean(DmoeApiItem bean) { 19 | Meta meta = new Meta(); 20 | if (bean?.ImgUrl == null) { 21 | return meta; 22 | } 23 | // 若直接使用字符串需反转义 Regex.Unescape() 24 | // https:\/\/tva2.sinaimg.cn\/large\/0075auPSly1fqb5xmdoa4j31jk0rzds0.jpg 25 | Uri uri = new Uri(bean.ImgUrl); 26 | string[] name = uri.Segments[uri.Segments.Length - 1].Split("."); 27 | meta.Id = name[0]; 28 | meta.Format = "." + name[1]; 29 | meta.Uhd = Regex.Replace(uri.AbsoluteUri, @"(?<=\.sinaimg\.cn/)[^/]+", "large"); 30 | meta.Thumb = Regex.Replace(uri.AbsoluteUri, @"(?<=\.sinaimg\.cn/)[^/]+", "middle"); 31 | meta.Date = DateTime.Now; 32 | return meta; 33 | } 34 | 35 | public override async Task LoadData(BaseIni ini, DateTime? date = null) { 36 | // 现有数据未浏览完,无需加载更多,或已无更多数据 37 | if (indexFocus < metas.Count - 1) { 38 | return true; 39 | } 40 | // 无网络连接 41 | if (!NetworkInterface.GetIsNetworkAvailable()) { 42 | return false; 43 | } 44 | await base.LoadData(ini, date); 45 | 46 | Debug.WriteLine("provider url: " + URL_API); 47 | try { 48 | HttpClient client = new HttpClient(); 49 | string jsonData = await client.GetStringAsync(URL_API); 50 | Debug.WriteLine("provider data: " + jsonData.Trim()); 51 | DmoeApiItem item = JsonConvert.DeserializeObject(jsonData); 52 | List metasAdd = new List { 53 | ParseBean(item) 54 | }; 55 | AppendMetas(metasAdd); 56 | } catch (Exception e) { 57 | Debug.WriteLine(e); 58 | } 59 | 60 | return metas.Count > 0; 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /Providers/ToubiecProvider.cs: -------------------------------------------------------------------------------- 1 | using TimelineWallpaper.Beans; 2 | using System; 3 | using System.Diagnostics; 4 | using System.Net.Http; 5 | using System.Net.NetworkInformation; 6 | using System.Threading.Tasks; 7 | using TimelineWallpaper.Utils; 8 | using Newtonsoft.Json; 9 | using System.Collections.Generic; 10 | using System.Text.RegularExpressions; 11 | 12 | namespace TimelineWallpaper.Providers { 13 | public class ToubiecProvider : BaseProvider { 14 | // 随机二次元图片接口 - 晓晴 15 | // https://acg.toubiec.cn/ 16 | private const string URL_API = "https://acg.toubiec.cn/random.php?ret=json"; 17 | 18 | private Meta ParseBean(ToubiecApiItem bean) { 19 | Meta meta = new Meta { 20 | Id = bean?.Id.ToString(), 21 | Date = DateTime.Now 22 | }; 23 | if (bean?.ImgUrl == null) { 24 | return meta; 25 | } 26 | Uri uri = new Uri(bean.ImgUrl); 27 | meta.Uhd = Regex.Replace(uri.AbsoluteUri, @"(?<=\.sinaimg\.cn/)[^/]+", "large"); 28 | meta.Thumb = Regex.Replace(uri.AbsoluteUri, @"(?<=\.sinaimg\.cn/)[^/]+", "middle"); 29 | string[] name = uri.Segments[uri.Segments.Length - 1].Split("."); 30 | meta.Format = "." + name[1]; 31 | return meta; 32 | } 33 | 34 | public override async Task LoadData(BaseIni ini, DateTime? date = null) { 35 | // 现有数据未浏览完,无需加载更多,或已无更多数据 36 | if (indexFocus + 1 < metas.Count) { 37 | return true; 38 | } 39 | // 无网络连接 40 | if (!NetworkInterface.GetIsNetworkAvailable()) { 41 | return false; 42 | } 43 | await base.LoadData(ini, date); 44 | 45 | Debug.WriteLine("provider url: " + URL_API); 46 | try { 47 | HttpClient client = new HttpClient(); 48 | string jsonData = await client.GetStringAsync(URL_API); 49 | Debug.WriteLine("provider data: " + jsonData.Trim()); 50 | List toubbiecApi = JsonConvert.DeserializeObject>(jsonData); 51 | List metasAdd = new List(); 52 | foreach (ToubiecApiItem item in toubbiecApi) { 53 | metasAdd.Add(ParseBean(item)); 54 | } 55 | AppendMetas(metasAdd); 56 | } catch (Exception e) { 57 | Debug.WriteLine(e); 58 | } 59 | 60 | return metas.Count > 0; 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /Providers/DmoeProvider.cs: -------------------------------------------------------------------------------- 1 | using TimelineWallpaper.Beans; 2 | using System; 3 | using System.Diagnostics; 4 | using System.Net.Http; 5 | using System.Net.NetworkInformation; 6 | using System.Threading.Tasks; 7 | using TimelineWallpaper.Utils; 8 | using Newtonsoft.Json; 9 | using System.Text.RegularExpressions; 10 | using System.Collections.Generic; 11 | 12 | namespace TimelineWallpaper.Providers { 13 | public class DmoeProvider : BaseProvider { 14 | // 随机二次元图片API - 樱花 15 | // https://www.dmoe.cc/ 16 | private const string URL_API = "https://www.dmoe.cc/random.php?return=json&t={0}"; 17 | 18 | private Meta ParseBean(DmoeApiItem bean) { 19 | Meta meta = new Meta(); 20 | if (bean?.ImgUrl == null) { 21 | return meta; 22 | } 23 | // 若直接使用字符串需反转义 Regex.Unescape() 24 | // https:\/\/tva1.sinaimg.cn\/large\/0072Vf1pgy1foxk7r8ic6j31hc0u0k7b.jpg 25 | Uri uri = new Uri(bean.ImgUrl); 26 | string[] name = uri.Segments[uri.Segments.Length - 1].Split("."); 27 | meta.Id = name[0]; 28 | meta.Format = "." + name[1]; 29 | meta.Uhd = Regex.Replace(uri.AbsoluteUri, @"(?<=\.sinaimg\.cn/)[^/]+", "large"); 30 | meta.Thumb = Regex.Replace(uri.AbsoluteUri, @"(?<=\.sinaimg\.cn/)[^/]+", "middle"); 31 | meta.Date = DateTime.Now; 32 | return meta; 33 | } 34 | 35 | public override async Task LoadData(BaseIni ini, DateTime? date = null) { 36 | // 现有数据未浏览完,无需加载更多,或已无更多数据 37 | if (indexFocus < metas.Count - 1) { 38 | return true; 39 | } 40 | // 无网络连接 41 | if (!NetworkInterface.GetIsNetworkAvailable()) { 42 | return false; 43 | } 44 | await base.LoadData(ini, date); 45 | 46 | string url = string.Format(URL_API, DateUtil.CurrentTimeMillis()); 47 | Debug.WriteLine("provider url: " + url); 48 | try { 49 | HttpClient client = new HttpClient(); 50 | string jsonData = await client.GetStringAsync(url); 51 | Debug.WriteLine("provider data: " + jsonData.Trim()); 52 | DmoeApiItem item = JsonConvert.DeserializeObject(jsonData); 53 | List metasAdd = new List { 54 | ParseBean(item) 55 | }; 56 | AppendMetas(metasAdd); 57 | } catch (Exception e) { 58 | Debug.WriteLine(e); 59 | } 60 | 61 | return metas.Count > 0; 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /Package.appxmanifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 13 | 14 | 15 | 16 | 17 | 拾光 for Windows 11 18 | By_syk 19 | Assets\StoreLogo.png 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 34 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /Providers/QingbzProvider.cs: -------------------------------------------------------------------------------- 1 | using TimelineWallpaper.Beans; 2 | using TimelineWallpaper.Utils; 3 | using Newtonsoft.Json; 4 | using System; 5 | using System.Diagnostics; 6 | using System.Net.Http; 7 | using System.Net.NetworkInformation; 8 | using System.Threading.Tasks; 9 | using System.Collections.Generic; 10 | 11 | namespace TimelineWallpaper.Providers { 12 | public class QingbzProvider : BaseProvider { 13 | // 页数据索引(从1开始)(用于按需加载) 14 | private int pageIndex = 0; 15 | 16 | private const string URL_API = "https://api.nguaduot.cn/qingbz?client=timelinewallpaper&cate={0}&order={1}&r18={2}&page={3}"; 17 | 18 | private Meta ParseBean(QingbzApiData bean, string order) { 19 | Meta meta = new Meta { 20 | Id = bean.ImgId.ToString(), 21 | Uhd = bean.ImgUrl, 22 | Thumb = bean.ThumbUrl, 23 | Cate = bean.CateAlt, 24 | Date = DateTime.ParseExact(bean.RelDate, "yyyy-MM-dd", new System.Globalization.CultureInfo("en-US")), 25 | SortFactor = "score".Equals(order) ? bean.Score : bean.ImgId 26 | }; 27 | meta.Title = string.Format("{0} #{1}", bean.CateAlt, bean.CateAltNo); 28 | if (bean.R18 == 1) { 29 | meta.Title = "🚫 " + meta.Title; 30 | } 31 | return meta; 32 | } 33 | 34 | public override async Task LoadData(BaseIni ini, DateTime? date = null) { 35 | // 现有数据未浏览完,无需加载更多 36 | if (indexFocus < metas.Count - 1) { 37 | return true; 38 | } 39 | // 无网络连接 40 | if (!NetworkInterface.GetIsNetworkAvailable()) { 41 | return false; 42 | } 43 | await base.LoadData(ini, date); 44 | 45 | string urlApi = string.Format(URL_API, ((QingbzIni)ini).Cate, ((QingbzIni)ini).Order, 46 | ((QingbzIni)ini).R18, ++pageIndex); 47 | Debug.WriteLine("provider url: " + urlApi); 48 | try { 49 | HttpClient client = new HttpClient(); 50 | string jsonData = await client.GetStringAsync(urlApi); 51 | Debug.WriteLine("provider data: " + jsonData.Trim()); 52 | QingbzApi qingbzApi = JsonConvert.DeserializeObject(jsonData); 53 | List metasAdd = new List(); 54 | foreach (QingbzApiData item in qingbzApi.Data) { 55 | metasAdd.Add(ParseBean(item, ((QingbzIni)ini).Order)); 56 | } 57 | if ("date".Equals(((QingbzIni)ini).Order) || "score".Equals(((QingbzIni)ini).Order)) { // 有序排列 58 | SortMetas(metasAdd); 59 | } else { 60 | AppendMetas(metasAdd); 61 | } 62 | } catch (Exception e) { 63 | Debug.WriteLine(e); 64 | } 65 | 66 | return metas.Count > 0; 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /Providers/ObzhiProvider.cs: -------------------------------------------------------------------------------- 1 | using TimelineWallpaper.Beans; 2 | using TimelineWallpaper.Utils; 3 | using Newtonsoft.Json; 4 | using System; 5 | using System.Diagnostics; 6 | using System.Net.Http; 7 | using System.Net.NetworkInformation; 8 | using System.Threading.Tasks; 9 | using System.Collections.Generic; 10 | 11 | namespace TimelineWallpaper.Providers { 12 | public class ObzhiProvider : BaseProvider { 13 | // 页数据索引(从1开始)(用于按需加载) 14 | private int pageIndex = 0; 15 | 16 | private const string URL_API = "https://api.nguaduot.cn/obzhi?client=timelinewallpaper&cate={0}&order={1}&r18={2}&page={3}"; 17 | 18 | private Meta ParseBean(ObzhiApiData bean, string order) { 19 | Meta meta = new Meta { 20 | Id = bean.ImgId.ToString(), 21 | Uhd = bean.ImgUrl, 22 | Thumb = bean.ThumbUrl, 23 | Title = bean.Title, 24 | Story = bean.Story, 25 | Copyright = "@" + bean.Author, 26 | Cate = bean.CateAlt, 27 | Date = DateTime.ParseExact(bean.RelDate, "yyyy-MM-dd", new System.Globalization.CultureInfo("en-US")), 28 | SortFactor = "score".Equals(order) ? bean.Score : bean.ImgId 29 | }; 30 | if (bean.R18 == 1) { 31 | meta.Title = "🚫 " + meta.Title; 32 | } 33 | return meta; 34 | } 35 | 36 | public override async Task LoadData(BaseIni ini, DateTime? date = null) { 37 | // 现有数据未浏览完,无需加载更多 38 | if (indexFocus < metas.Count - 1) { 39 | return true; 40 | } 41 | // 无网络连接 42 | if (!NetworkInterface.GetIsNetworkAvailable()) { 43 | return false; 44 | } 45 | await base.LoadData(ini, date); 46 | 47 | string urlApi = string.Format(URL_API, ((ObzhiIni)ini).Cate, ((ObzhiIni)ini).Order, 48 | ((ObzhiIni)ini).R18, ++pageIndex); 49 | Debug.WriteLine("provider url: " + urlApi); 50 | try { 51 | HttpClient client = new HttpClient(); 52 | string jsonData = await client.GetStringAsync(urlApi); 53 | Debug.WriteLine("provider data: " + jsonData.Trim()); 54 | ObzhiApi obzhiApi = JsonConvert.DeserializeObject(jsonData); 55 | List metasAdd = new List(); 56 | foreach (ObzhiApiData item in obzhiApi.Data) { 57 | metasAdd.Add(ParseBean(item, ((ObzhiIni)ini).Order)); 58 | } 59 | if ("date".Equals(((ObzhiIni)ini).Order) || "score".Equals(((ObzhiIni)ini).Order)) { // 有序排列 60 | SortMetas(metasAdd); 61 | } else { 62 | AppendMetas(metasAdd); 63 | } 64 | } catch (Exception e) { 65 | Debug.WriteLine(e); 66 | } 67 | 68 | return metas.Count > 0; 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /Providers/WallhereProvider.cs: -------------------------------------------------------------------------------- 1 | using TimelineWallpaper.Beans; 2 | using TimelineWallpaper.Utils; 3 | using Newtonsoft.Json; 4 | using System; 5 | using System.Diagnostics; 6 | using System.Net.Http; 7 | using System.Net.NetworkInformation; 8 | using System.Threading.Tasks; 9 | using System.Collections.Generic; 10 | 11 | namespace TimelineWallpaper.Providers { 12 | public class WallhereProvider : BaseProvider { 13 | // 页数据索引(从1开始)(用于按需加载) 14 | private int pageIndex = 0; 15 | 16 | private const string URL_API = "https://api.nguaduot.cn/wallhere?client=timelinewallpaper&order={0}&cate={1}&r18={2}&page={3}"; 17 | 18 | private Meta ParseBean(WallhereApiData bean, string order) { 19 | Meta meta = new Meta { 20 | Id = bean.ImgId.ToString(), 21 | Uhd = bean.ImgUrl, 22 | Thumb = bean.ThumbUrl, 23 | Cate = bean.CateAlt, 24 | Date = DateTime.Now, 25 | SortFactor = "score".Equals(order) ? bean.Score : bean.No 26 | }; 27 | meta.Title = string.Format("{0} #{1}", bean.CateAlt, bean.CateAltNo); 28 | meta.Story = bean.Tag?.Replace(",", " "); 29 | if (bean.R18 == 1) { 30 | meta.Title = "🚫 " + meta.Title; 31 | } 32 | if (!string.IsNullOrEmpty(bean.Author)) { 33 | meta.Copyright = "@" + bean.Author; 34 | } 35 | return meta; 36 | } 37 | 38 | public override async Task LoadData(BaseIni ini, DateTime? date = null) { 39 | // 现有数据未浏览完,无需加载更多 40 | if (indexFocus < metas.Count - 1) { 41 | return true; 42 | } 43 | // 无网络连接 44 | if (!NetworkInterface.GetIsNetworkAvailable()) { 45 | return false; 46 | } 47 | await base.LoadData(ini, date); 48 | 49 | string urlApi = string.Format(URL_API, ((WallhereIni)ini).Order, ((WallhereIni)ini).Cate, 50 | ((WallhereIni)ini).R18, ++pageIndex); 51 | Debug.WriteLine("provider url: " + urlApi); 52 | try { 53 | HttpClient client = new HttpClient(); 54 | string jsonData = await client.GetStringAsync(urlApi); 55 | Debug.WriteLine("provider data: " + jsonData.Trim()); 56 | WallhereApi api = JsonConvert.DeserializeObject(jsonData); 57 | List metasAdd = new List(); 58 | foreach (WallhereApiData item in api.Data) { 59 | metasAdd.Add(ParseBean(item, ((WallhereIni)ini).Order)); 60 | } 61 | if ("date".Equals(((WallhereIni)ini).Order) || "score".Equals(((WallhereIni)ini).Order)) { // 有序排列 62 | SortMetas(metasAdd); 63 | } else { 64 | AppendMetas(metasAdd); 65 | } 66 | } catch (Exception e) { 67 | Debug.WriteLine(e); 68 | } 69 | 70 | return metas.Count > 0; 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![icon](https://cdn.jsdelivr.net/gh/nguaduot/TimelineWallpaper/Assets/StoreLogo.scale-200.png) 2 | 3 | # 拾光 for Windows 11 4 | 5 | [![release](https://img.shields.io/github/v/release/nguaduot/TimelineWallpaper)](https://github.com/nguaduot/TimelineWallpaper/releases) 6 | [![downloads](https://img.shields.io/github/downloads/nguaduot/TimelineWallpaper/total)](https://github.com/nguaduot/TimelineWallpaper/releases) 7 | 8 | > 拾光如歌,岁月如诗。拾光,每日一景 9 | 10 | `拾光` 是一款壁纸应用,集成丰富图源,支持每日推送桌面/锁屏。使用 UWP 框架开发,遵循 Fluent Design,是原生的 Windows 应用,于 Windows 11 体验最佳,向下兼容 Windows 10。 11 | 12 | ## 停更 13 | 14 | > **重要说明 2022/05/15:** 15 | > 16 | > 本项目 GitHub 源码停止更新,源码托管已转 Gitee:https://gitee.com/nguaduot/timeline 17 | 18 | ## 开始 19 | 20 | 提供以下两种安装方式: 21 | 22 | + 从 Microsoft Store 安装 23 | 24 | 在 Microsoft Store 搜索 `拾光壁纸` 进行安装。直达链接:[拾光壁纸 - Microsoft Store](https://www.microsoft.com/store/apps/9N7VHQ989BB7) 25 | 26 | + 下载安装包手动安装 27 | 28 | 打开右侧的 [Release](https://github.com/nguaduot/TimelineWallpaper/releases) 页面,找到最新版本,下载压缩包,然后解压,找到 `install.ps1` 脚本,右键 **使用 PowerShell 运行**,根据提示即可顺利安装。 29 | 30 | **Watch** 项目,以获取应用的更新动态。 31 | 32 | ## 图源 33 | 34 | 自建图源: 35 | 36 | + [拾光](https://api.nguaduot.cn/timeline/doc) - 时光如歌,岁月如诗 37 | 38 | API 官网:[api.nguaduot.cn/timeline](https://api.nguaduot.cn/timeline/doc) 39 | 40 | 开源:[github.com/nguaduot/timeline-api](https://github.com/nguaduot/timeline-api) 41 | 42 | 三方图源: 43 | 44 | + [Microsoft Bing](https://cn.bing.com) - 每天发现一个新地方 45 | + [NASA](https://apod.nasa.gov/apod) - 每日天文一图 46 | + [OnePlus](https://photos.oneplus.com) - Shot on OnePlus 47 | + [ONE · 一个](http://m.wufazhuce.com/one) - 复杂世界里,一个就够了 48 | + [向日葵8号](https://himawari8.nict.go.jp/) - 实时地球 49 | + [一梦幽黎](https://www.ymyouli.com) - 8K优质壁纸资源 50 | + [轻壁纸](https://bz.qinggongju.com) - 壁纸分享站 51 | + [乌云壁纸](https://www.obzhi.com) - 高清壁纸站 52 | + [WallHere](https://wallhere.com) - 世界著名的壁纸网站之一 53 | + [Infinity](http://cn.infinitynewtab.com) - 精选壁纸 54 | 55 | *特别注明:三方图源均为来自网络,本应用无权且不提供商用授权,所以请勿用于商业用途,仅供学习交流。欢迎分享图源* 56 | 57 | ## 进阶 58 | 59 | + 使用快捷键 60 | + `鼠标右键`:菜单 61 | + `鼠标左键`(双击) / `Enter` / `Esc`:切换全屏/窗口模式 62 | + `鼠标滚轮`:回顾前一天/预览下一天 63 | + `左方向键` / `上方向键`:回顾前一天 64 | + `右方向键` / `下方向键`:预览下一天 65 | + `Backspace` / `Delete`:标记“不喜欢” 66 | + `Space`:切换全图/拉伸 67 | + `Ctrl` + `B`:用作桌面背景 68 | + `Ctrl` + `L`:用作锁屏背景 69 | + `Ctrl` + `S` / `Ctrl` + `D`:保存图片 70 | + `Ctrl` + `R` / `F5`:刷新 71 | + `Ctrl` + `F` / `Ctrl` + `G`:跳转至指定日期 72 | + `Ctrl` + `C`:复制图片元素 73 | 74 | + 如何以2小时/次的周期更换桌面壁纸? 75 | + 开启目标图源的桌面/锁屏推送 76 | + 右键菜单点击“**设置**”图标,导航至“**常规**”组,展开“**配置文件**”,点击“**打开**”,即可编辑配置文件 77 | + 找到当前图源的块 `[xxx]`,将 `desktopperiod` 参数值修改为 `2`,即2h/次,保存即可 78 | 79 | ## 反馈 80 | 81 | 你可以在以下渠道联系到我: 82 | + 邮件 [nguaduot@163.com](mailto:nguaduot@163.com) 83 | + 酷安 [@南瓜多糖](http://www.coolapk.com/u/474144) 84 | + Telegram [@nguaduot](https://t.me/nguaduot) 85 | 86 | ## 截图 87 | 88 | ![截图1](https://cdn.jsdelivr.net/gh/nguaduot/TimelineWallpaper/screenshot.jpg) 89 | 90 | ![截图2](https://s3.bmp.ovh/imgs/2021/12/001241e0a14ef263.gif) 91 | 92 | 自取:[截图1壁纸原图](https://s3.bmp.ovh/imgs/2021/11/5db69c315b1ab3e3.jpg) 93 | 94 | *Copyright © 2021-2022 nguaduot. All rights reserved.* 95 | -------------------------------------------------------------------------------- /Providers/YmyouliProvider.cs: -------------------------------------------------------------------------------- 1 | using TimelineWallpaper.Beans; 2 | using TimelineWallpaper.Utils; 3 | using Newtonsoft.Json; 4 | using System; 5 | using System.Diagnostics; 6 | using System.Net.Http; 7 | using System.Net.NetworkInformation; 8 | using System.Threading.Tasks; 9 | using System.Collections.Generic; 10 | 11 | namespace TimelineWallpaper.Providers { 12 | public class YmyouliProvider : BaseProvider { 13 | // 页数据索引(从1开始)(用于按需加载) 14 | private int pageIndex = 0; 15 | 16 | private const string URL_API = "https://api.nguaduot.cn/ymyouli?client=timelinewallpaper&cate={0}&order={1}&r18={2}&page={3}"; 17 | 18 | private Meta ParseBean(YmyouliApiData bean, string order) { 19 | Meta meta = new Meta { 20 | Id = bean.ImgId, 21 | Uhd = bean.ImgUrl, 22 | Thumb = bean.ThumbUrl, 23 | Cate = bean.CateAlt, 24 | Date = DateTime.Now, 25 | SortFactor = "score".Equals(order) ? bean.Score : bean.No 26 | }; 27 | //meta.Caption = String.Format("{0} · {1}", 28 | // ResourceLoader.GetForCurrentView().GetString("Provider_" + this.Id), bean.Cate); 29 | meta.Title = string.Format("{0} #{1}", bean.CateAlt, bean.CateAltNo); 30 | meta.Caption = string.Format("{0} · {1}", bean.Cate, bean.Group); 31 | if (bean.R18 == 1) { 32 | meta.Title = "🚫 " + meta.Title; 33 | } 34 | if (!string.IsNullOrEmpty(bean.Copyright)) { 35 | meta.Copyright = "© " + bean.Copyright; 36 | } 37 | return meta; 38 | } 39 | 40 | public override async Task LoadData(BaseIni ini, DateTime? date = null) { 41 | // 现有数据未浏览完,无需加载更多 42 | if (indexFocus < metas.Count - 1) { 43 | return true; 44 | } 45 | // 无网络连接 46 | if (!NetworkInterface.GetIsNetworkAvailable()) { 47 | return false; 48 | } 49 | await base.LoadData(ini, date); 50 | 51 | string urlApi = string.Format(URL_API, ((YmyouliIni)ini).Cate, ((YmyouliIni)ini).Order, 52 | ((YmyouliIni)ini).R18, ++pageIndex); 53 | Debug.WriteLine("provider url: " + urlApi); 54 | try { 55 | HttpClient client = new HttpClient(); 56 | string jsonData = await client.GetStringAsync(urlApi); 57 | Debug.WriteLine("provider data: " + jsonData.Trim()); 58 | YmyouliApi ymyouliApi = JsonConvert.DeserializeObject(jsonData); 59 | List metasAdd = new List(); 60 | foreach (YmyouliApiData item in ymyouliApi.Data) { 61 | metasAdd.Add(ParseBean(item, ((YmyouliIni)ini).Order)); 62 | } 63 | if ("date".Equals(((YmyouliIni)ini).Order) || "score".Equals(((YmyouliIni)ini).Order)) { // 有序排列 64 | SortMetas(metasAdd); 65 | } else { 66 | AppendMetas(metasAdd); 67 | } 68 | } catch (Exception e) { 69 | Debug.WriteLine(e); 70 | } 71 | 72 | return metas.Count > 0; 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /Providers/AbyssProvider.cs: -------------------------------------------------------------------------------- 1 | using TimelineWallpaper.Beans; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Diagnostics; 5 | using System.Net.Http; 6 | using System.Net.NetworkInformation; 7 | using System.Threading.Tasks; 8 | using System.Text.RegularExpressions; 9 | using TimelineWallpaper.Utils; 10 | 11 | namespace TimelineWallpaper.Providers { 12 | public class AbyssProvider : BaseProvider { 13 | // 页数据索引(从1开始)(用于按需加载) 14 | private int pageIndex = 0; 15 | 16 | // 近期受欢迎的壁纸(30张每页) 17 | // https://wall.alphacoders.com/popular.php?lang=Chinese 18 | private const string URL_API = "https://wall.alphacoders.com/popular.php?page={0}{1}"; 19 | 20 | private List ParseBeans(string htmlData) { 21 | List metas = new List(); 22 | foreach (Match m in Regex.Matches(htmlData, @"
([^<]+) \- [^>]+>([^<]+)", RegexOptions.Singleline); 34 | if (match.Success) { 35 | meta.Title = match.Groups[1].Value.Trim() + " - " + match.Groups[2].Value.Trim(); 36 | } 37 | match = Regex.Match(m.Groups[0].Value, @"btn\-user.+?>([^<>]+)", RegexOptions.Singleline); 38 | if (match.Success) { 39 | meta.Copyright = "@" + match.Groups[1].Value; 40 | } 41 | metas.Add(meta); 42 | } 43 | return metas; 44 | } 45 | 46 | public override async Task LoadData(BaseIni ini, DateTime? date = null) { 47 | // 现有数据未浏览完,无需加载更多,或已无更多数据 48 | if (indexFocus < metas.Count - 1) { 49 | return true; 50 | } 51 | // 无网络连接 52 | if (!NetworkInterface.GetIsNetworkAvailable()) { 53 | return false; 54 | } 55 | await base.LoadData(ini, date); 56 | 57 | ++pageIndex; 58 | string lang = ""; 59 | if ("zh".Equals(System.Globalization.CultureInfo.CurrentCulture.TwoLetterISOLanguageName)) { 60 | lang = "&lang=Chinese"; 61 | } 62 | string url = string.Format(URL_API, pageIndex, lang); 63 | Debug.WriteLine("provider url: " + url); 64 | try { 65 | HttpClient client = new HttpClient(); 66 | string htmlData = await client.GetStringAsync(url); 67 | //Debug.WriteLine("provider data: " + htmlData); 68 | List metasAdd = ParseBeans(htmlData); 69 | RandomMetas(metasAdd); 70 | } catch (Exception e) { 71 | Debug.WriteLine(e); 72 | } 73 | 74 | return metas.Count > 0; 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /Providers/TimelineProvider.cs: -------------------------------------------------------------------------------- 1 | using TimelineWallpaper.Beans; 2 | using Newtonsoft.Json; 3 | using System; 4 | using System.Diagnostics; 5 | using System.Net.Http; 6 | using System.Net.NetworkInformation; 7 | using System.Threading.Tasks; 8 | using TimelineWallpaper.Utils; 9 | using System.Collections.Generic; 10 | 11 | namespace TimelineWallpaper.Providers { 12 | public class TimelineProvider : BaseProvider { 13 | // 下一页数据索引(从0开始)(用于按需加载) 14 | private DateTime nextPage = DateTime.UtcNow.AddHours(8); 15 | 16 | // 自建图源 17 | // https://github.com/nguaduot/TimelineApi 18 | private const string URL_API = "https://api.nguaduot.cn/timeline?client=timelinewallpaper&cate={0}&enddate={1}&order={2}&authorize={3}"; 19 | 20 | private Meta ParseBean(TimelineApiData bean, string order) { 21 | Meta meta = new Meta { 22 | Id = bean.Id.ToString(), 23 | Uhd = bean.ImgUrl, 24 | Thumb = bean.ThumbUrl, 25 | Title = bean.Title, 26 | Cate = bean.Cate, 27 | Story = bean.Story?.Trim(), 28 | Copyright = "@" + bean.Author?.Trim(), 29 | Date = DateTime.ParseExact(bean.RelDate, "yyyy-MM-dd", new System.Globalization.CultureInfo("en-US")) 30 | }; 31 | meta.SortFactor = "score".Equals(order) ? bean.Score : meta.Date.Value.Subtract(new DateTime(1970, 1, 1)).TotalDays; 32 | if (bean.Deprecated != 0) { 33 | meta.Title = "🚫 " + meta.Title; 34 | } 35 | if (!string.IsNullOrEmpty(bean.Platform)) { 36 | meta.Copyright = bean.Platform + meta.Copyright; 37 | } 38 | if (bean.ImgUrl != null) { 39 | Uri uri = new Uri(bean.ImgUrl); 40 | string[] name = uri.Segments[uri.Segments.Length - 1].Split("."); 41 | meta.Format = "." + name[1]; 42 | } 43 | 44 | return meta; 45 | } 46 | 47 | public override async Task LoadData(BaseIni ini, DateTime? date = null) { 48 | // 现有数据未浏览完,无需加载更多,或已无更多数据 49 | if (indexFocus < metas.Count - 1 && date == null) { 50 | return true; 51 | } 52 | // 无网络连接 53 | if (!NetworkInterface.GetIsNetworkAvailable()) { 54 | return false; 55 | } 56 | await base.LoadData(ini, date); 57 | 58 | nextPage = date ?? nextPage; 59 | string urlApi = string.Format(URL_API, ((TimelineIni)ini).Cate, 60 | nextPage.ToString("yyyyMMdd"), ((TimelineIni)ini).Order, ((TimelineIni)ini).Authorize); 61 | Debug.WriteLine("provider url: " + urlApi); 62 | try { 63 | HttpClient client = new HttpClient(); 64 | string jsonData = await client.GetStringAsync(urlApi); 65 | Debug.WriteLine("provider data: " + jsonData.Trim()); 66 | TimelineApi timelineApi = JsonConvert.DeserializeObject(jsonData); 67 | List metasAdd = new List(); 68 | foreach (TimelineApiData item in timelineApi.Data) { 69 | metasAdd.Add(ParseBean(item, ((TimelineIni)ini).Order)); 70 | } 71 | if ("date".Equals(((TimelineIni)ini).Order) || "score".Equals(((TimelineIni)ini).Order)) { // 有序排列 72 | SortMetas(metasAdd); 73 | } else { 74 | AppendMetas(metasAdd); 75 | } 76 | nextPage = "date".Equals(((TimelineIni)ini).Order) 77 | ? nextPage.AddDays(-timelineApi.Data.Count) : nextPage; 78 | } catch (Exception e) { 79 | Debug.WriteLine(e); 80 | } 81 | return metas.Count > 0; 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /Providers/InfinityProvider.cs: -------------------------------------------------------------------------------- 1 | using TimelineWallpaper.Beans; 2 | using TimelineWallpaper.Utils; 3 | using Newtonsoft.Json; 4 | using System; 5 | using System.Diagnostics; 6 | using System.Net.Http; 7 | using System.Net.NetworkInformation; 8 | using System.Threading.Tasks; 9 | using System.Collections.Generic; 10 | using System.Text.RegularExpressions; 11 | 12 | namespace TimelineWallpaper.Providers { 13 | public class InfinityProvider : BaseProvider { 14 | // 页数据索引(从0开始)(用于按需加载) 15 | private int pageIndex = -1; 16 | 17 | // Infinity新标签页 - 壁纸库 18 | // http://cn.infinitynewtab.com/ 19 | //private const string URL_API = "https://infinity-api.infinitynewtab.com/get-wallpaper?source=&tag=&order=1&page={0}"; 20 | private const string URL_API = "https://api.infinitynewtab.com/v2/get_wallpaper_list?client=pc&order=like&page={0}"; 21 | private const string URL_API_LANDSCAPE = "https://api.infinitynewtab.com/v2/get_wallpaper_list?client=pc&source=InfinityLandscape&page={0}"; 22 | private const string URL_API_ACG = "https://api.infinitynewtab.com/v2/get_wallpaper_list?client=pc&source=Infinity&page={0}"; 23 | private const string URL_API_RANDOM = "https://infinity-api.infinitynewtab.com/random-wallpaper?_={0}"; 24 | 25 | private Meta ParseBean(InfinityApiData bean) { 26 | Meta meta = new Meta { 27 | Id = bean.Id, 28 | Uhd = bean.Src?.RawSrc, 29 | Thumb = bean.Src?.SmallSrc ?? bean.Src?.RawSrc, 30 | Date = DateTime.Now 31 | }; 32 | 33 | string[] nodes = (bean.No ?? "").Split("/"); 34 | meta.Title = string.Format("{0} #{1}", bean.Source, nodes[nodes.Length - 1]); 35 | if (bean.Tags != null) { 36 | meta.Story = string.Join(" ", bean.Tags ?? new List()); 37 | } 38 | if (!string.IsNullOrEmpty(bean.Src?.RawSrc)) { 39 | Uri uri = new Uri(bean.Src.RawSrc); 40 | string[] nameSuffix = uri.Segments[uri.Segments.Length - 1].Split("."); 41 | meta.Format = nameSuffix.Length > 1 ? "." + nameSuffix[nameSuffix.Length - 1] : ".jpg"; 42 | } 43 | return meta; 44 | } 45 | 46 | public override async Task LoadData(BaseIni ini, DateTime? date = null) { 47 | // 现有数据未浏览完,无需加载更多,或已无更多数据 48 | if (indexFocus < metas.Count - 1) { 49 | return true; 50 | } 51 | // 无网络连接 52 | if (!NetworkInterface.GetIsNetworkAvailable()) { 53 | return false; 54 | } 55 | await base.LoadData(ini, date); 56 | 57 | string urlApi = "rate".Equals(((InfinityIni)ini).Order) ? String.Format(URL_API, ++pageIndex) 58 | : string.Format(URL_API_RANDOM, DateUtil.CurrentTimeMillis()); 59 | Debug.WriteLine("provider url: " + urlApi); 60 | try { 61 | HttpClient client = new HttpClient(); 62 | string jsonData = await client.GetStringAsync(urlApi); 63 | Debug.WriteLine("provider data: " + jsonData.Trim()); 64 | List metasAdd = new List(); 65 | if ("rate".Equals(((InfinityIni)ini).Order)) { 66 | InfinityApi2 infinityApi = JsonConvert.DeserializeObject(jsonData); 67 | foreach (InfinityApiData item in infinityApi.Data.List) { 68 | metasAdd.Add(ParseBean(item)); 69 | } 70 | RandomMetas(metasAdd); 71 | } else { 72 | InfinityApi1 infinityApi = JsonConvert.DeserializeObject(jsonData); 73 | foreach (InfinityApiData item in infinityApi.Data) { 74 | metasAdd.Add(ParseBean(item)); 75 | } 76 | AppendMetas(metasAdd); 77 | } 78 | } catch (Exception e) { 79 | Debug.WriteLine(e); 80 | } 81 | 82 | return metas.Count > 0; 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /Providers/OneplusProvider.cs: -------------------------------------------------------------------------------- 1 | using TimelineWallpaper.Beans; 2 | using TimelineWallpaper.Utils; 3 | using Newtonsoft.Json; 4 | using System; 5 | using System.Diagnostics; 6 | using System.Net.NetworkInformation; 7 | using System.Threading.Tasks; 8 | using System.Collections.Generic; 9 | using System.Net.Http; 10 | using System.Text; 11 | 12 | namespace TimelineWallpaper.Providers { 13 | public class OneplusProvider : BaseProvider { 14 | // 页数据索引(从1开始)(用于按需加载) 15 | private int pageIndex = 0; 16 | 17 | private const int PAGE_SIZE = 99; 18 | 19 | private const string URL_API = "https://photos.oneplus.com/cn/shot/photo/schedule"; 20 | 21 | private Meta ParseBean(OneplusApiItem bean) { 22 | Meta meta = new Meta { 23 | Id = bean.PhotoCode, 24 | Uhd = bean.PhotoUrl, 25 | Thumb = bean.PhotoUrl.Replace(".jpg", "_400_0.jpg"), 26 | Title = bean.PhotoTopic?.Trim(), 27 | Copyright = "@" + bean.Author, 28 | Date = DateTime.ParseExact(bean.ScheduleTime, "yyyyMMdd", new System.Globalization.CultureInfo("en-US")) 29 | }; 30 | meta.SortFactor = meta.Date.Value.Subtract(new DateTime(1970, 1, 1)).TotalDays; 31 | 32 | if (!bean.PhotoTopic.Equals(bean.Remark?.Trim())) { 33 | meta.Caption = bean.Remark?.Trim(); 34 | } 35 | if (!bean.PhotoTopic.Equals(bean.PhotoLocation?.Trim())) { 36 | meta.Location = bean.PhotoLocation?.Trim(); 37 | } 38 | if (!string.IsNullOrEmpty(bean.CountryCodeStr)) { 39 | meta.Copyright += " | " + bean.CountryCodeStr; 40 | } 41 | 42 | return meta; 43 | } 44 | 45 | public override async Task LoadData(BaseIni ini, DateTime? date = null) { 46 | // 现有数据未浏览完,无需加载更多 47 | if (date == null || GetFarthest() == null || date.Value.Date >= GetFarthest().Date.Value.Date) { 48 | if (indexFocus < metas.Count - 1) { 49 | return true; 50 | } 51 | } 52 | // 无网络连接 53 | if (!NetworkInterface.GetIsNetworkAvailable()) { 54 | return false; 55 | } 56 | await base.LoadData(ini, date); 57 | 58 | // "1":最新添加,"2":点赞最多,"3":浏览最多 59 | string sort = "rate".Equals(((OneplusIni)ini).Order) ? "2" : ("view".Equals(((OneplusIni)ini).Order) ? "3" : "1"); 60 | OneplusRequest request = new OneplusRequest { 61 | PageSize = PAGE_SIZE, // 不限 62 | CurrentPage = ++pageIndex, 63 | SortMethod = sort 64 | }; 65 | string requestStr = JsonConvert.SerializeObject(request); 66 | Debug.WriteLine("provider url: " + URL_API + " " + requestStr); 67 | try { 68 | HttpClient client = new HttpClient(); 69 | HttpRequestMessage msgReq = new HttpRequestMessage(HttpMethod.Post, URL_API); 70 | //msgReq.Headers.Add("Cookie", "LOCALE=zh_CN; Path=/"); 71 | msgReq.Content = new StringContent(requestStr, Encoding.UTF8, "application/json"); 72 | HttpResponseMessage msgRes = await client.SendAsync(msgReq); 73 | _ = msgRes.EnsureSuccessStatusCode(); 74 | string jsonData = await msgRes.Content.ReadAsStringAsync(); 75 | Debug.WriteLine("provider data: " + jsonData.Trim()); 76 | OneplusApi oneplusApi = JsonConvert.DeserializeObject(jsonData); 77 | List metasAdd = new List(); 78 | foreach (OneplusApiItem item in oneplusApi.Items) { 79 | metasAdd.Add(ParseBean(item)); 80 | } 81 | if ("date".Equals(((OneplusIni)ini).Order)) { // 按时序倒序排列 82 | SortMetas(metasAdd); 83 | } else { 84 | RandomMetas(metasAdd); 85 | } 86 | } catch (Exception e) { 87 | Debug.WriteLine(e); 88 | } 89 | 90 | return metas.Count > 0; 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /Providers/G3Provider.cs: -------------------------------------------------------------------------------- 1 | using TimelineWallpaper.Beans; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Diagnostics; 5 | using System.Net.Http; 6 | using System.Net.NetworkInformation; 7 | using System.Threading.Tasks; 8 | using System.Text.RegularExpressions; 9 | using TimelineWallpaper.Utils; 10 | 11 | namespace TimelineWallpaper.Providers { 12 | public class G3Provider : BaseProvider { 13 | // 页数据索引(从1开始)(用于按需加载) 14 | private int pageIndex = 0; 15 | 16 | // 最新壁纸 17 | private const string URL_API_SORT1 = "https://desk.3gbizhi.com/index_{0}.html"; 18 | // 热门壁纸 19 | private const string URL_API_SORT2 = "https://desk.3gbizhi.com"; 20 | 21 | private List ParseBeans(string htmlData, bool dataHot) { 22 | List metas = new List(); 23 | if (dataHot) { 24 | Match match = Regex.Match(htmlData, @">热门壁纸推荐<.+?", RegexOptions.Singleline); 25 | if (!match.Success) { 26 | return metas; 27 | } 28 | htmlData = match.Value; 29 | } 30 | foreach (Match m in Regex.Matches(htmlData, @"]+?title=""(.+?)"" ?/>")) { 31 | Meta meta = new Meta { 32 | Thumb = m.Groups[1].Value, 33 | Caption = m.Groups[2].Value 34 | }; 35 | Match match = Regex.Match(m.Groups[1].Value, @"https://pic.3gbizhi.com/(\d{4}/\d{4})/(\d+)(\.[^.]+)"); 36 | if (match.Success) { 37 | meta.Id = match.Groups[2].Value; 38 | meta.Uhd = match.Value; 39 | meta.Date = DateTime.ParseExact(match.Groups[1].Value, "yyyy/MMdd", new System.Globalization.CultureInfo("en-US")); 40 | meta.Format = match.Groups[3].Value; 41 | } 42 | meta.SortFactor = meta.Date.Value.Subtract(new DateTime(1970, 1, 1)).TotalDays; 43 | match = Regex.Match(m.Groups[2].Value, @"^(.+?)(?:的)?(?:美图桌面|高清桌面|唯美桌面|桌面|唯美场景|唯美插画|唯美风光景色|创意动漫3D|高清海报|摄影|酷飒游戏|酷飒|搞怪|艺术|唯美|手绘插画|油墨风插画|场景插画|人物插画|插画|高清|风景|动漫)?(?:壁纸)?图片$"); 44 | if (!match.Success) { 45 | match = Regex.Match(m.Groups[2].Value, @"^(.+?)(?:的)?(?:唯美艺术山水画|唯美摄影|唯美意境|唯美|影视插画|插画|静态摄影|静态|创意手绘|个性|创意|玄幻|可爱|霸气|帅气|美图|静态摄影|近距离摄影|唯美摄影|室外摄影|摄影|浪漫|超清.*?|高清.*?)?(?:高清)?(?:手机)?(?:电脑)?(?:桌面)?壁纸$"); 46 | if (!match.Success) { 47 | match = Regex.Match(m.Groups[2].Value, @"^(.+?)(?:桌面.*?下载|静态.*?下载|高清.*?下载|超清.*?下载|插画.*?下载|高清.*?张|唯美动漫壁纸图|唯美创意壁纸美图|壁纸美图|美图|壁纸图)$"); 48 | } 49 | } 50 | meta.Title = match.Success ? match.Groups[1].Value.Trim() : m.Groups[2].Value; 51 | metas.Add(meta); 52 | } 53 | return metas; 54 | } 55 | 56 | public override async Task LoadData(BaseIni ini, DateTime? date = null) { 57 | bool sortByHot = "view".Equals(((G3Ini)ini).Order); 58 | // 现有数据未浏览完,无需加载更多,或已无更多数据 59 | if (indexFocus < metas.Count - 1 || (sortByHot && pageIndex > 0)) { 60 | return true; 61 | } 62 | // 无网络连接 63 | if (!NetworkInterface.GetIsNetworkAvailable()) { 64 | return false; 65 | } 66 | await base.LoadData(ini, date); 67 | 68 | ++pageIndex; 69 | string url = sortByHot ? URL_API_SORT2 : string.Format(URL_API_SORT1, pageIndex); 70 | Debug.WriteLine("provider url: " + url); 71 | try { 72 | HttpClient client = new HttpClient(); 73 | string htmlData = await client.GetStringAsync(url); 74 | //Debug.WriteLine("provider data: " + htmlData); 75 | List metasAdd = ParseBeans(htmlData, sortByHot); 76 | if (sortByHot) { 77 | RandomMetas(metasAdd); 78 | } else { 79 | AppendMetas(metasAdd); 80 | } 81 | } catch (Exception e) { 82 | Debug.WriteLine(e); 83 | } 84 | 85 | return metas.Count > 0; 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /TimelineWallpaper.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.0.32014.148 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TimelineWallpaper", "TimelineWallpaper.csproj", "{C3BF495A-6BF6-4D5B-9ED9-2C3213399FB8}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TimelineWallpaperService", "..\TimelineWallpaperService\TimelineWallpaperService.csproj", "{C8B76130-7DE6-469C-9051-D8CB783329FC}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Debug|ARM = Debug|ARM 14 | Debug|ARM64 = Debug|ARM64 15 | Debug|x64 = Debug|x64 16 | Debug|x86 = Debug|x86 17 | Release|Any CPU = Release|Any CPU 18 | Release|ARM = Release|ARM 19 | Release|ARM64 = Release|ARM64 20 | Release|x64 = Release|x64 21 | Release|x86 = Release|x86 22 | EndGlobalSection 23 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 24 | {C3BF495A-6BF6-4D5B-9ED9-2C3213399FB8}.Debug|Any CPU.ActiveCfg = Debug|x86 25 | {C3BF495A-6BF6-4D5B-9ED9-2C3213399FB8}.Debug|ARM.ActiveCfg = Debug|ARM 26 | {C3BF495A-6BF6-4D5B-9ED9-2C3213399FB8}.Debug|ARM.Build.0 = Debug|ARM 27 | {C3BF495A-6BF6-4D5B-9ED9-2C3213399FB8}.Debug|ARM.Deploy.0 = Debug|ARM 28 | {C3BF495A-6BF6-4D5B-9ED9-2C3213399FB8}.Debug|ARM64.ActiveCfg = Debug|ARM64 29 | {C3BF495A-6BF6-4D5B-9ED9-2C3213399FB8}.Debug|ARM64.Build.0 = Debug|ARM64 30 | {C3BF495A-6BF6-4D5B-9ED9-2C3213399FB8}.Debug|ARM64.Deploy.0 = Debug|ARM64 31 | {C3BF495A-6BF6-4D5B-9ED9-2C3213399FB8}.Debug|x64.ActiveCfg = Debug|x64 32 | {C3BF495A-6BF6-4D5B-9ED9-2C3213399FB8}.Debug|x64.Build.0 = Debug|x64 33 | {C3BF495A-6BF6-4D5B-9ED9-2C3213399FB8}.Debug|x64.Deploy.0 = Debug|x64 34 | {C3BF495A-6BF6-4D5B-9ED9-2C3213399FB8}.Debug|x86.ActiveCfg = Debug|x86 35 | {C3BF495A-6BF6-4D5B-9ED9-2C3213399FB8}.Debug|x86.Build.0 = Debug|x86 36 | {C3BF495A-6BF6-4D5B-9ED9-2C3213399FB8}.Debug|x86.Deploy.0 = Debug|x86 37 | {C3BF495A-6BF6-4D5B-9ED9-2C3213399FB8}.Release|Any CPU.ActiveCfg = Release|x86 38 | {C3BF495A-6BF6-4D5B-9ED9-2C3213399FB8}.Release|ARM.ActiveCfg = Release|ARM 39 | {C3BF495A-6BF6-4D5B-9ED9-2C3213399FB8}.Release|ARM.Build.0 = Release|ARM 40 | {C3BF495A-6BF6-4D5B-9ED9-2C3213399FB8}.Release|ARM.Deploy.0 = Release|ARM 41 | {C3BF495A-6BF6-4D5B-9ED9-2C3213399FB8}.Release|ARM64.ActiveCfg = Release|ARM64 42 | {C3BF495A-6BF6-4D5B-9ED9-2C3213399FB8}.Release|ARM64.Build.0 = Release|ARM64 43 | {C3BF495A-6BF6-4D5B-9ED9-2C3213399FB8}.Release|ARM64.Deploy.0 = Release|ARM64 44 | {C3BF495A-6BF6-4D5B-9ED9-2C3213399FB8}.Release|x64.ActiveCfg = Release|x64 45 | {C3BF495A-6BF6-4D5B-9ED9-2C3213399FB8}.Release|x64.Build.0 = Release|x64 46 | {C3BF495A-6BF6-4D5B-9ED9-2C3213399FB8}.Release|x64.Deploy.0 = Release|x64 47 | {C3BF495A-6BF6-4D5B-9ED9-2C3213399FB8}.Release|x86.ActiveCfg = Release|x86 48 | {C3BF495A-6BF6-4D5B-9ED9-2C3213399FB8}.Release|x86.Build.0 = Release|x86 49 | {C3BF495A-6BF6-4D5B-9ED9-2C3213399FB8}.Release|x86.Deploy.0 = Release|x86 50 | {C8B76130-7DE6-469C-9051-D8CB783329FC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 51 | {C8B76130-7DE6-469C-9051-D8CB783329FC}.Debug|Any CPU.Build.0 = Debug|Any CPU 52 | {C8B76130-7DE6-469C-9051-D8CB783329FC}.Debug|ARM.ActiveCfg = Debug|ARM 53 | {C8B76130-7DE6-469C-9051-D8CB783329FC}.Debug|ARM.Build.0 = Debug|ARM 54 | {C8B76130-7DE6-469C-9051-D8CB783329FC}.Debug|ARM64.ActiveCfg = Debug|ARM64 55 | {C8B76130-7DE6-469C-9051-D8CB783329FC}.Debug|ARM64.Build.0 = Debug|ARM64 56 | {C8B76130-7DE6-469C-9051-D8CB783329FC}.Debug|x64.ActiveCfg = Debug|x64 57 | {C8B76130-7DE6-469C-9051-D8CB783329FC}.Debug|x64.Build.0 = Debug|x64 58 | {C8B76130-7DE6-469C-9051-D8CB783329FC}.Debug|x86.ActiveCfg = Debug|x86 59 | {C8B76130-7DE6-469C-9051-D8CB783329FC}.Debug|x86.Build.0 = Debug|x86 60 | {C8B76130-7DE6-469C-9051-D8CB783329FC}.Release|Any CPU.ActiveCfg = Release|Any CPU 61 | {C8B76130-7DE6-469C-9051-D8CB783329FC}.Release|Any CPU.Build.0 = Release|Any CPU 62 | {C8B76130-7DE6-469C-9051-D8CB783329FC}.Release|ARM.ActiveCfg = Release|ARM 63 | {C8B76130-7DE6-469C-9051-D8CB783329FC}.Release|ARM.Build.0 = Release|ARM 64 | {C8B76130-7DE6-469C-9051-D8CB783329FC}.Release|ARM64.ActiveCfg = Release|ARM64 65 | {C8B76130-7DE6-469C-9051-D8CB783329FC}.Release|ARM64.Build.0 = Release|ARM64 66 | {C8B76130-7DE6-469C-9051-D8CB783329FC}.Release|x64.ActiveCfg = Release|x64 67 | {C8B76130-7DE6-469C-9051-D8CB783329FC}.Release|x64.Build.0 = Release|x64 68 | {C8B76130-7DE6-469C-9051-D8CB783329FC}.Release|x86.ActiveCfg = Release|x86 69 | {C8B76130-7DE6-469C-9051-D8CB783329FC}.Release|x86.Build.0 = Release|x86 70 | EndGlobalSection 71 | GlobalSection(SolutionProperties) = preSolution 72 | HideSolutionNode = FALSE 73 | EndGlobalSection 74 | GlobalSection(ExtensibilityGlobals) = postSolution 75 | SolutionGuid = {DCEE2FD0-0D0F-4F98-B7EB-E17C093E05E4} 76 | EndGlobalSection 77 | EndGlobal 78 | -------------------------------------------------------------------------------- /Providers/Himawari8Provider.cs: -------------------------------------------------------------------------------- 1 | using TimelineWallpaper.Beans; 2 | using Newtonsoft.Json; 3 | using System; 4 | using System.Diagnostics; 5 | using System.Net.Http; 6 | using System.Net.NetworkInformation; 7 | using System.Threading.Tasks; 8 | using TimelineWallpaper.Utils; 9 | using System.Net; 10 | using Microsoft.Graphics.Canvas; 11 | using Windows.UI; 12 | using Windows.Storage; 13 | using System.Drawing; 14 | using System.Collections.Generic; 15 | 16 | namespace TimelineWallpaper.Providers { 17 | public class Himawari8Provider : BaseProvider { 18 | // 下一页索引(从0开始)(用于按需加载) 19 | private DateTime nextPage = DateTime.UtcNow.AddMinutes(-15).AddMinutes(-DateTime.UtcNow.AddMinutes(-15).Minute % 10); 20 | 21 | // 地球偏移位置(0 为居中,-1~0 偏左,0~1 偏右) 22 | private float offsetEarth = 0; 23 | 24 | // 向日葵-8号即時網頁 - NICT 25 | // https://himawari8.nict.go.jp/zh/himawari8-image.htm 26 | //private const string URL_API = "https://himawari8.nict.go.jp/img/D531106/1d/550/{0}/{1}_0_0.png"; 27 | private const string URL_API = "https://himawari8.nict.go.jp/img/D531106/thumbnail/550/{0}/{1}_0_0.png"; 28 | 29 | private Meta ParseBean(DateTime time) { 30 | string index = string.Format("{0}{1}000", time.ToString("HH"), (time.Minute / 10)); 31 | Meta meta = new Meta { 32 | Id = time.ToString("yyyyMMdd") + index, 33 | Uhd = string.Format(URL_API, time.ToString(@"yyyy\/MM\/dd"), index), 34 | Format = ".png" 35 | }; 36 | meta.Thumb = meta.Uhd; 37 | meta.Date = time.ToLocalTime(); 38 | meta.SortFactor = meta.Date.Value.Subtract(new DateTime(1970, 1, 1)).TotalMinutes; 39 | meta.Caption = meta.Date.Value.ToString("M") + " " + meta.Date.Value.ToString("t"); 40 | return meta; 41 | } 42 | 43 | public override async Task LoadData(BaseIni ini, DateTime? date = null) { 44 | offsetEarth = ((Himawari8Ini)ini).Offset; 45 | // 无需加载更多 46 | if (indexFocus < metas.Count - 1) { 47 | return true; 48 | } 49 | // 无网络连接 50 | if (!NetworkInterface.GetIsNetworkAvailable()) { 51 | return false; 52 | } 53 | await base.LoadData(ini, date); 54 | 55 | try { 56 | for (int i = 0; i < 5; i++) { 57 | string urlApi = string.Format(URL_API, 58 | nextPage.AddMinutes(-10 * i).ToString(@"yyyy\/MM\/dd"), 59 | string.Format("{0}{1}000", nextPage.AddMinutes(-10 * i).ToString("HH"), 60 | (nextPage.AddMinutes(-10 * i).Minute / 10))); 61 | Debug.WriteLine("provider url: " + urlApi); 62 | HttpWebRequest req = (HttpWebRequest)WebRequest.CreateDefault(new Uri(urlApi)); 63 | req.Method = HttpMethod.Head.Method; 64 | var res = (HttpWebResponse)await req.GetResponseAsync(); 65 | if (res.StatusCode == HttpStatusCode.OK && res.ContentLength > 10 * 1024) { 66 | List metasAdd = new List { 67 | ParseBean(nextPage.AddMinutes(-10 * i)) 68 | }; 69 | SortMetas(metasAdd); 70 | break; 71 | } 72 | res.Close(); 73 | } 74 | nextPage = nextPage.AddHours(-1); 75 | } catch (Exception e) { 76 | Debug.WriteLine(e); 77 | } 78 | return metas.Count > 0; 79 | } 80 | 81 | public override async Task Cache(Meta meta) { 82 | _ = await base.Cache(meta); 83 | string offsetTag = (offsetEarth >= 0 ? "-offset+" : "-offset-") + Math.Abs(offsetEarth * 100).ToString("000"); 84 | if (meta?.CacheUhd == null || meta.CacheUhd.Path.Contains(offsetTag)) { 85 | return meta; 86 | } 87 | 88 | CanvasDevice device = CanvasDevice.GetSharedDevice(); 89 | CanvasBitmap bitmap = null; 90 | using (var stream = await meta.CacheUhd.OpenReadAsync()) { 91 | bitmap = await CanvasBitmap.LoadAsync(device, stream); 92 | } 93 | if (bitmap == null) { 94 | return meta; 95 | } 96 | meta.Dimen = new Size(1920, 1080); 97 | float offsetWidthPixels = (meta.Dimen.Width + bitmap.SizeInPixels.Width) / 2.0f * offsetEarth; 98 | CanvasRenderTarget target = new CanvasRenderTarget(device, meta.Dimen.Width, meta.Dimen.Height, 96); 99 | using (var session = target.CreateDrawingSession()) { 100 | session.Clear(Colors.Black); 101 | session.DrawImage(bitmap, (meta.Dimen.Width - bitmap.SizeInPixels.Width) / 2.0f + offsetWidthPixels, 102 | (meta.Dimen.Height - bitmap.SizeInPixels.Height) / 2.0f); 103 | } 104 | 105 | meta.CacheUhd = await ApplicationData.Current.TemporaryFolder 106 | .CreateFileAsync(Id + "-" + meta.Id + offsetTag + meta.Format, CreationCollisionOption.OpenIfExists); 107 | await target.SaveAsync(meta.CacheUhd.Path, CanvasBitmapFileFormat.Png); 108 | return meta; 109 | } 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /Providers/BingProvider.cs: -------------------------------------------------------------------------------- 1 | using TimelineWallpaper.Beans; 2 | using TimelineWallpaper.Utils; 3 | using Newtonsoft.Json; 4 | using System; 5 | using System.Diagnostics; 6 | using System.Net.Http; 7 | using System.Net.NetworkInformation; 8 | using System.Text.RegularExpressions; 9 | using System.Threading.Tasks; 10 | using System.Collections.Generic; 11 | 12 | namespace TimelineWallpaper.Providers { 13 | public class BingProvider : BaseProvider { 14 | // 页数据索引(从0开始)(用于按需加载) 15 | private int pageIndex = -1; 16 | 17 | private const int PAGE_SIZE = 8; 18 | 19 | // http://s.cn.bing.net 20 | // https://cn.bing.com 21 | private const string URL_API_HOST = "https://global.bing.com"; 22 | // Bing搜索 官方提供的 API 23 | // GET 参数: 24 | // pid: hp(缺省会导致数据不全) 25 | // format:hp-HTML,js-JSON,xml/其他值-XML(默认) 26 | // ensearch:国际版置1,国内版置0(默认) 27 | // setmkt: HOST为“global.bing.com”时生效,zh-cn、en-us、ja-jp、de-de、fr-fr 28 | // idx:回溯天数,0为当天,-1为明天,1为昨天,依次类推(最大值7) 29 | // n:返回数据的条数。若为2,会包含前一天的数据,依次类推(最大值8) 30 | // uhd:0-1920x1080,1-uhdwidth/uhdheight生效 31 | // uhdwidth:uhd置1时生效,最大值3840 32 | // uhdheight:uhd置1时生效 33 | // API 第三方文档:http://www.lib4dev.in/info/facefruit/daily-bing-wallpaper/209719167 34 | // 语言代码表:http://www.lingoes.net/zh/translator/langcode.htm 35 | private readonly string[] URL_API_PAGES = new string[] { 36 | URL_API_HOST + "/HPImageArchive.aspx?pid=hp&format=js&uhd=1&idx=0&n=" + PAGE_SIZE, 37 | URL_API_HOST + "/HPImageArchive.aspx?pid=hp&format=js&uhd=1&idx=7&n=" + PAGE_SIZE 38 | }; 39 | 40 | private Meta ParseBean(BingApiImg bean) { 41 | Meta meta = new Meta { 42 | Id = bean.Hsh, 43 | Uhd = string.Format("{0}{1}_UHD.jpg", URL_API_HOST, bean.UrlBase), 44 | Thumb = string.Format("{0}{1}_400x240.jpg", URL_API_HOST, bean.UrlBase), 45 | Date = DateTime.ParseExact(bean.EndDate, "yyyyMMdd", new System.Globalization.CultureInfo("en-US")), 46 | Caption = bean.Copyright 47 | }; 48 | meta.SortFactor = meta.Date.Value.Subtract(new DateTime(1970, 1, 1)).TotalDays; 49 | 50 | if (!string.IsNullOrEmpty(bean.Title)) { 51 | if (!bean.Title.Equals("Info")) { // ko-kr等未支持的地区 52 | meta.Title = bean.Title; 53 | } 54 | } 55 | if (!string.IsNullOrEmpty(bean.Desc)) { 56 | meta.Story = bean.Desc; 57 | } 58 | 59 | // zh-cn: 正爬上唐娜·诺克沙滩的灰海豹,英格兰北林肯郡 (© Frederic Desmette/Minden Pictures) 60 | // en-us: Aerial view of the island of Mainau on Lake Constance, Germany (© Amazing Aerial Agency/Offset by Shutterstock) 61 | // ja-jp: 「ドナヌックのハイイロアザラシ」英国, ノースリンカーンシャー (© Frederic Desmette/Minden Pictures) 62 | Match match = Regex.Match(meta.Caption, @"(.+)[\((]©(.+)[\))]"); 63 | if (match.Success) { 64 | meta.Caption = match.Groups[1].Value.Trim(); 65 | meta.Copyright = "© " + match.Groups[2].Value.Trim(); 66 | match = Regex.Match(meta.Caption, @"「(.+)」(.+)"); 67 | if (match.Success) { // 国内版(日本) 68 | meta.Caption = match.Groups[1].Value.Trim(); 69 | meta.Location = match.Groups[2].Value.Trim(); 70 | } else { // 国内版(中国) 71 | match = Regex.Match(meta.Caption, @"(.+)[,](.+)"); 72 | if (match.Success) { 73 | meta.Caption = match.Groups[1].Value.Trim(); 74 | meta.Location = match.Groups[2].Value.Trim(); 75 | } 76 | } 77 | } 78 | 79 | return meta; 80 | } 81 | 82 | public override async Task LoadData(BaseIni ini, DateTime? date = null) { 83 | // 已无更多数据 84 | if (pageIndex >= URL_API_PAGES.Length - 1) { 85 | return true; 86 | } 87 | // 现有数据未浏览完,无需加载更多 88 | if (date == null || GetFarthest() == null || date.Value.Date >= GetFarthest().Date.Value.Date) { 89 | if (indexFocus < metas.Count - 1) { 90 | return true; 91 | } 92 | } 93 | // 无网络连接 94 | if (!NetworkInterface.GetIsNetworkAvailable()) { 95 | return false; 96 | } 97 | await base.LoadData(ini, date); 98 | 99 | string urlApi = URL_API_PAGES[++pageIndex]; 100 | if (((BingIni)ini).Lang.Length > 0) { 101 | urlApi += "&setmkt=" + ((BingIni)ini).Lang; 102 | } 103 | Debug.WriteLine("provider url: " + urlApi); 104 | try { 105 | HttpClient client = new HttpClient(); 106 | string jsonData = await client.GetStringAsync(urlApi); 107 | Debug.WriteLine("provider data: " + jsonData.Trim()); 108 | BingApi bingApi = JsonConvert.DeserializeObject(jsonData); 109 | List metasAdd = new List(); 110 | foreach (BingApiImg img in bingApi.Images) { 111 | metasAdd.Add(ParseBean(img)); 112 | } 113 | SortMetas(metasAdd); // 按时序倒序排列 114 | } catch (Exception e) { 115 | Debug.WriteLine(e); 116 | } 117 | 118 | return metas.Count > 0; 119 | } 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /Providers/OneProvider.cs: -------------------------------------------------------------------------------- 1 | using TimelineWallpaper.Beans; 2 | using Newtonsoft.Json; 3 | using System; 4 | using System.Diagnostics; 5 | using System.Net.Http; 6 | using System.Net.NetworkInformation; 7 | using System.Threading.Tasks; 8 | using TimelineWallpaper.Utils; 9 | using System.Collections.Generic; 10 | using System.Text.RegularExpressions; 11 | using System.Net; 12 | 13 | namespace TimelineWallpaper.Providers { 14 | public class OneProvider : BaseProvider { 15 | // 下一页数据索引(从0开始)(用于按需加载) 16 | private string nextPage = "0"; 17 | 18 | private string cookie = null; 19 | private string token = null; 20 | 21 | // 图文 - 「ONE · 一个」 22 | // http://m.wufazhuce.com/one 23 | private const string URL_TOKEN = "http://m.wufazhuce.com/one"; 24 | private const string URL_API = "http://m.wufazhuce.com/one/ajaxlist/{0}?_token={1}"; 25 | 26 | private Meta ParseBean(OneApiData bean) { 27 | Meta meta = new Meta { 28 | Id = bean.Id, 29 | Uhd = bean.ImgUrl, 30 | Thumb = bean.ImgUrl, 31 | Title = bean.Title, 32 | Story = bean.Content, 33 | Copyright = bean.PictureAuthor, 34 | Date = DateTime.ParseExact(bean.Date, "yyyy / MM / dd", new System.Globalization.CultureInfo("en-US")), 35 | }; 36 | meta.SortFactor = meta.Date.Value.Subtract(new DateTime(1970, 1, 1)).TotalDays; 37 | if (!string.IsNullOrEmpty(bean.Content)) { 38 | meta.Title = ""; 39 | foreach (Match match in Regex.Matches(bean.Content, @"([^ ,、。!?;:(?:——)\n(?:\r\n)]+)([ ,、。!?;:(?:——)\n(?:\r\n)])")) { 40 | meta.Title += match.Groups[1].Value; 41 | if (meta.Title.Length < 6) { 42 | meta.Title += match.Groups[2].Value; 43 | } else { 44 | if (meta.Title.Length > 16) { 45 | meta.Title = meta.Title.Substring(0, 16); 46 | } 47 | break; 48 | } 49 | } 50 | meta.Title += "……"; 51 | } 52 | if (!string.IsNullOrEmpty(bean.TextAuthors)) { 53 | meta.Story += "\n——" + bean.TextAuthors; 54 | } 55 | 56 | return meta; 57 | } 58 | 59 | public override async Task LoadData(BaseIni ini, DateTime? date = null) { 60 | // 现有数据未浏览完,无需加载更多,或已无更多数据 61 | if (indexFocus < metas.Count - 1 && date == null) { 62 | return true; 63 | } 64 | // 无网络连接 65 | if (!NetworkInterface.GetIsNetworkAvailable()) { 66 | return false; 67 | } 68 | await base.LoadData(ini, date); 69 | 70 | if (string.IsNullOrEmpty(cookie) || string.IsNullOrEmpty(token)) { 71 | try { 72 | HttpClient client = new HttpClient(); 73 | HttpResponseMessage msg = await client.GetAsync(URL_TOKEN); 74 | cookie = new List(msg.Headers.GetValues("Set-Cookie"))[0]; 75 | Debug.WriteLine("cookie: " + cookie); 76 | string htmlData = await msg.Content.ReadAsStringAsync(); 77 | Match match = Regex.Match(htmlData, @"One.token ?= ?[""'](.+?)[""']"); 78 | if (match.Success) { 79 | token = match.Groups[1].Value; 80 | Debug.WriteLine("token: " + token); 81 | } 82 | } catch (Exception e) { 83 | Debug.WriteLine(e); 84 | } 85 | } 86 | if (string.IsNullOrEmpty(cookie) || string.IsNullOrEmpty(token)) { 87 | return metas.Count > 0; 88 | } 89 | 90 | if ("random".Equals(((OneIni)ini).Order)) { 91 | nextPage = (3012 + new Random().Next((DateTime.Now - DateTime.Parse("2020-11-10")).Days)).ToString(); 92 | } else { 93 | nextPage = metas.Count > 0 ? metas[metas.Count - 1].Id : "0"; 94 | } 95 | string urlApi = string.Format(URL_API, nextPage, token); 96 | Debug.WriteLine("provider url: " + urlApi); 97 | try { 98 | HttpClientHandler handler = new HttpClientHandler() { 99 | UseCookies = false 100 | }; 101 | HttpClient client = new HttpClient(handler); 102 | HttpRequestMessage msgReq = new HttpRequestMessage(HttpMethod.Get, urlApi); 103 | msgReq.Headers.Add("Cookie", cookie); 104 | HttpResponseMessage msgRes = await client.SendAsync(msgReq); 105 | string jsonData = await msgRes.Content.ReadAsStringAsync(); 106 | Debug.WriteLine("provider data: " + jsonData.Trim()); 107 | OneApi oneApi = JsonConvert.DeserializeObject(jsonData); 108 | List metasAdd = new List(); 109 | foreach (OneApiData item in oneApi.Data) { 110 | metasAdd.Add(ParseBean(item)); 111 | } 112 | if ("date".Equals(((OneIni)ini).Order)) { // 按时序倒序排列 113 | SortMetas(metasAdd); 114 | } else { 115 | RandomMetas(metasAdd); 116 | } 117 | } catch (Exception e) { 118 | Debug.WriteLine(e); 119 | } 120 | return metas.Count > 0; 121 | } 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /App.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using TimelineWallpaper.Services; 4 | using TimelineWallpaper.Utils; 5 | using Windows.ApplicationModel; 6 | using Windows.ApplicationModel.Activation; 7 | using Windows.ApplicationModel.Core; 8 | using Windows.Storage; 9 | using Windows.UI; 10 | using Windows.UI.ViewManagement; 11 | using Windows.UI.Xaml; 12 | using Windows.UI.Xaml.Controls; 13 | using Windows.UI.Xaml.Navigation; 14 | 15 | namespace TimelineWallpaper { 16 | /// 17 | /// 提供特定于应用程序的行为,以补充默认的应用程序类。 18 | /// 19 | sealed partial class App : Application { 20 | /// 21 | /// 初始化单一实例应用程序对象。这是执行的创作代码的第一行, 22 | /// 已执行,逻辑上等同于 main() 或 WinMain()。 23 | /// 24 | public App() { 25 | ChangeTheme(); 26 | 27 | this.InitializeComponent(); 28 | this.Suspending += OnSuspending; 29 | 30 | // 集成崩溃日志反馈 31 | //AppCenter.Start("867dbb71-eaa5-4525-8f70-9877a65d0796", typeof(Crashes)); 32 | // 上传崩溃日志 33 | this.UnhandledException += OnUnhandledException; 34 | TaskScheduler.UnobservedTaskException += OnUnobservedException; 35 | AppDomain.CurrentDomain.UnhandledException += OnBgUnhandledException; 36 | } 37 | 38 | /// 39 | /// 在应用程序由最终用户正常启动时进行调用。 40 | /// 将在启动应用程序以打开特定文件等情况下使用。 41 | /// 42 | /// 有关启动请求和过程的详细信息。 43 | protected override void OnLaunched(LaunchActivatedEventArgs e) { 44 | Frame rootFrame = Window.Current.Content as Frame; 45 | 46 | // 不要在窗口已包含内容时重复应用程序初始化, 47 | // 只需确保窗口处于活动状态 48 | if (rootFrame == null) { 49 | // 创建要充当导航上下文的框架,并导航到第一页 50 | rootFrame = new Frame(); 51 | 52 | rootFrame.NavigationFailed += OnNavigationFailed; 53 | 54 | if (e.PreviousExecutionState == ApplicationExecutionState.Terminated) { 55 | //TODO: 从之前挂起的应用程序加载状态 56 | } 57 | 58 | // 将框架放在当前窗口中 59 | Window.Current.Content = rootFrame; 60 | } 61 | 62 | if (e.PrelaunchActivated == false) { 63 | if (rootFrame.Content == null) { 64 | // 当导航堆栈尚未还原时,导航到第一页, 65 | // 并通过将所需信息作为导航参数传入来配置 66 | // 参数 67 | rootFrame.Navigate(typeof(MainPage), e.Arguments); 68 | } 69 | 70 | // 确保当前窗口处于活动状态 71 | Window.Current.Activate(); 72 | 73 | // 首次启动设置最佳窗口比例:16:10 74 | OptimizeSize(); 75 | // 将内容扩展到标题栏,并使标题栏半透明 76 | TransTitleBar(); 77 | } 78 | } 79 | 80 | /// 81 | /// 导航到特定页失败时调用 82 | /// 83 | ///导航失败的框架 84 | ///有关导航失败的详细信息 85 | void OnNavigationFailed(object sender, NavigationFailedEventArgs e) { 86 | throw new Exception("Failed to load Page " + e.SourcePageType.FullName); 87 | } 88 | 89 | /// 90 | /// 在将要挂起应用程序执行时调用。 在不知道应用程序 91 | /// 无需知道应用程序会被终止还是会恢复, 92 | /// 并让内存内容保持不变。 93 | /// 94 | /// 挂起的请求的源。 95 | /// 有关挂起请求的详细信息。 96 | private void OnSuspending(object sender, SuspendingEventArgs e) { 97 | var deferral = e.SuspendingOperation.GetDeferral(); 98 | //TODO: 保存应用程序状态并停止任何后台活动 99 | deferral.Complete(); 100 | } 101 | 102 | private void ChangeTheme() { 103 | // b注意:ElementTheme.Default 指向该值,非系统主题 104 | switch (IniUtil.GetIni().Theme) { 105 | case "light": 106 | this.RequestedTheme = ApplicationTheme.Light; 107 | break; 108 | case "dark": 109 | this.RequestedTheme = ApplicationTheme.Dark; 110 | break; 111 | } 112 | } 113 | 114 | private void OptimizeSize() { 115 | if (!ApplicationData.Current.LocalSettings.Values.ContainsKey("optimizeSize")) { 116 | ApplicationView.PreferredLaunchViewSize = new Windows.Foundation.Size(960, 600); 117 | ApplicationView.PreferredLaunchWindowingMode = ApplicationViewWindowingMode.PreferredLaunchViewSize; 118 | ApplicationView.PreferredLaunchWindowingMode = ApplicationViewWindowingMode.Auto; 119 | ApplicationData.Current.LocalSettings.Values["optimizeSize"] = true; 120 | } 121 | } 122 | 123 | private void TransTitleBar() { 124 | // https://docs.microsoft.com/zh-cn/windows/apps/design/style/acrylic#extend-acrylic-into-the-title-bar 125 | CoreApplication.GetCurrentView().TitleBar.ExtendViewIntoTitleBar = true; 126 | ApplicationViewTitleBar titleBar = ApplicationView.GetForCurrentView().TitleBar; 127 | titleBar.ButtonBackgroundColor = Colors.Transparent; 128 | titleBar.ButtonInactiveBackgroundColor = Colors.Transparent; 129 | } 130 | 131 | private void OnUnhandledException(object sender, Windows.UI.Xaml.UnhandledExceptionEventArgs e) { 132 | ApiService.Crash(e.Exception); 133 | e.Handled = true; 134 | // TODO 135 | //_ = await new ContentDialog { 136 | // Title = "未知异常1", 137 | // Content = e.Exception.Message, 138 | // CloseButtonText = "关闭", 139 | // DefaultButton = ContentDialogButton.Close 140 | //}.ShowAsync(); 141 | } 142 | 143 | private void OnUnobservedException(object sender, UnobservedTaskExceptionEventArgs e) { 144 | ApiService.Crash(e.Exception); 145 | e.SetObserved(); 146 | // TODO 147 | //_ = await new ContentDialog { 148 | // Title = "未知异常2", 149 | // Content = e.Exception, 150 | // CloseButtonText = "关闭", 151 | // DefaultButton = ContentDialogButton.Close 152 | //}.ShowAsync(); 153 | } 154 | 155 | private void OnBgUnhandledException(object sender, System.UnhandledExceptionEventArgs e) { 156 | ApiService.Crash((Exception)e.ExceptionObject); 157 | // TODO 158 | //_ = await new ContentDialog { 159 | // Title = "未知异常3", 160 | // Content = ((Exception)e.ExceptionObject).Message, 161 | // CloseButtonText = "关闭", 162 | // DefaultButton = ContentDialogButton.Close 163 | //}.ShowAsync(); 164 | } 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /Assets/Ini/config.txt: -------------------------------------------------------------------------------- 1 | ; 拾光 v4.5 2 | ; https://github.com/nguaduot/TimelineWallpaper 3 | ; nguaduot@163.com 4 | 5 | [timelinewallpaper] 6 | 7 | provider=bing 8 | ; provider=bing 图源:Microsoft Bing - 每天发现一个新地方 https://cn.bing.com 9 | ; provider=nasa 图源:NASA - 每日天文一图 https://apod.nasa.gov/apod 10 | ; provider=oneplus 图源:OnePlus - Shot on OnePlus https://photos.oneplus.com 11 | ; provider=timeline 图源:拾光 - 时光如歌,岁月如诗 https://api.nguaduot.cn/timeline 12 | ; provider=one 图源:ONE · 一个 - 复杂世界里,一个就够了 http://m.wufazhuce.com/one 13 | ; provider=himawari8 图源:向日葵8号 - 实时地球 https://himawari8.nict.go.jp 14 | ; provider=ymyouli 图源:一梦幽黎 - 8K优质壁纸资源 https://www.ymyouli.com 15 | ; provider=qingbz 图源:轻壁纸 - 4K壁纸分享站 https://bz.qinggongju.com 16 | ; provider=obzhi 图源:乌云壁纸 - 高清壁纸站 https://www.obzhi.com 17 | ; provider=wallhere 图源:WallHere - 世界著名的壁纸网站之一 https://wallhere.com 18 | ; provider=infinity 图源:Infinity - 精选壁纸 http://cn.infinitynewtab.com 19 | ; provider=3g 图源:3G壁纸 - 电脑壁纸专家 https://desk.3gbizhi.com 20 | ; provider=abyss 图源:Wallpaper Abyss - 壁纸聚集地 https://wall.alphacoders.com 21 | ; provider=daihan 图源:呆憨API - 随机二次元ACG图片 https://api.daihan.top/html/acg.html 22 | ; provider=dmoe 图源:樱花API - 随机二次元图片 https://www.dmoe.cc 23 | ; provider=toubiec 图源:晓晴API - 随机二次元图片 https://acg.toubiec.cn 24 | ; provider=mty 图源:墨天逸API - 随机图片 https://api.mtyqx.cn 25 | ; provider=seovx 图源:夏沫博客API - 在线古风美图二次元 https://cdn.seovx.com 26 | 27 | desktopprovider= 28 | ; desktopprovider={provider} 桌面背景推送图源:参数参考 provider(置空则关闭推送) 29 | 30 | lockprovider= 31 | ; lockprovider={provider} 锁屏背景推送图源:参数参考 provider(置空则关闭推送) 32 | 33 | theme= 34 | ; theme= 主题:跟随系统(默认) 35 | ; theme=light 主题:亮色 36 | ; theme=dark 主题:暗色 37 | 38 | [bing] 39 | 40 | desktopperiod=24 41 | ; desktopperiod={n} 桌面背景推送周期:1~24(默认为24h/次,开启推送后生效) 42 | 43 | lockperiod=24 44 | ; lockperiod={n} 锁屏背景推送周期:1~24(默认为24h/次,开启推送后生效) 45 | 46 | lang= 47 | ; lang= 语言代码:自动识别(默认) 48 | ; lang=zh-cn 语言代码:中文 49 | ; lang=en-us 语言代码:英文 50 | ; lang=ja-jp 语言代码:日语 51 | ; lang=de-de 语言代码:德语 52 | ; lang=fr-fr 语言代码:法国 53 | 54 | [nasa] 55 | 56 | desktopperiod=24 57 | ; desktopperiod={n} 桌面背景推送周期:1~24(默认为24h/次,开启推送后生效) 58 | 59 | lockperiod=24 60 | ; lockperiod={n} 锁屏背景推送周期:1~24(默认为24h/次,开启推送后生效) 61 | 62 | mirror=bjp 63 | ; mirror= 镜像:官方 64 | ; mirror=bjp 镜像:北京天文馆(默认) http://www.bjp.org.cn/mryt 65 | 66 | [oneplus] 67 | 68 | desktopperiod=24 69 | ; desktopperiod={n} 桌面背景推送周期:1~24(默认为24h/次,开启推送后生效) 70 | 71 | lockperiod=24 72 | ; lockperiod={n} 锁屏背景推送周期:1~24(默认为24h/次,开启推送后生效) 73 | 74 | order=date 75 | ; order=date 排序:最新添加(默认) 76 | ; order=rate 排序:点赞最多 77 | ; order=view 排序:浏览最多 78 | 79 | [timeline] 80 | 81 | desktopperiod=24 82 | ; desktopperiod={n} 桌面背景推送周期:1~24(默认为24h/次,开启推送后生效) 83 | 84 | lockperiod=24 85 | ; lockperiod={n} 锁屏背景推送周期:1~24(默认为24h/次,开启推送后生效) 86 | 87 | order=date 88 | ; order=date 排序:日期(默认) 89 | ; order=score 排序:热度 90 | ; order=random 排序:随机 91 | 92 | cate= 93 | ; cate= 类别:全部(默认) 94 | ; cate=landscape 类别:风光摄影 95 | ; cate=portrait 类别:人像摄影 96 | ; cate=culture 类别:人文摄影 97 | ; cate=term 类别:节气摄影 98 | 99 | authorize=1 100 | ; authorize={n} 授权:0或1(默认为1,仅展示已授权图片,若手动修改为0,请勿擅自商用未授权图片) 101 | 102 | [one] 103 | 104 | desktopperiod=24 105 | ; desktopperiod={n} 桌面背景推送周期:1~24(默认为24h/次,开启推送后生效) 106 | 107 | lockperiod=24 108 | ; lockperiod={n} 锁屏背景推送周期:1~24(默认为24h/次,开启推送后生效) 109 | 110 | order=date 111 | ; order=date 排序:日期(默认) 112 | ; order=random 排序:随机 113 | 114 | [himawari8] 115 | 116 | desktopperiod=1 117 | ; desktopperiod={n} 桌面背景推送周期:1~24(默认为1h/次,开启推送后生效) 118 | 119 | lockperiod=2 120 | ; lockperiod={n} 锁屏背景推送周期:1~24(默认为2h/次,开启推送后生效) 121 | 122 | offset=0 123 | ; offset={n} 地球位置:-1.0~1.0(默认为0,居中,-1.0~0偏左,0~1.0偏右) 124 | 125 | [ymyouli] 126 | 127 | desktopperiod=24 128 | ; desktopperiod={n} 桌面背景推送周期:1~24(默认为24h/次,开启推送后生效) 129 | 130 | lockperiod=24 131 | ; lockperiod={n} 锁屏背景推送周期:1~24(默认为24h/次,开启推送后生效) 132 | 133 | order=random 134 | ; order=date 排序:收录 135 | ; order=score 排序:热度 136 | ; order=random 排序:随机(默认) 137 | 138 | cate= 139 | ; cate= 类别:全部(默认) 140 | ; cate=acgcharacter 类别:动漫人物 141 | ; cate=acgscene 类别:动漫场景 142 | ; cate=sky 类别:日暮云天 143 | ; cate=war 类别:战场战争 144 | ; cate=sword 类别:刀光剑影 145 | ; cate=artistry 类别:意境 146 | ; cate=car 类别:机车 147 | ; cate=portrait 类别:人像 148 | ; cate=animal 类别:动物 149 | ; cate=delicacy 类别:美食蔬果 150 | ; cate=nature 类别:山水花草 151 | 152 | r18=0 153 | ; r18={n} R18内容:0或1(默认为0,不含R18内容) 154 | 155 | [qingbz] 156 | 157 | desktopperiod=24 158 | ; desktopperiod={n} 桌面背景推送周期:1~24(默认为24h/次,开启推送后生效) 159 | 160 | lockperiod=24 161 | ; lockperiod={n} 锁屏背景推送周期:1~24(默认为24h/次,开启推送后生效) 162 | 163 | order=random 164 | ; order=date 排序:收录 165 | ; order=score 排序:热度 166 | ; order=random 排序:随机(默认) 167 | 168 | cate= 169 | ; cate= 类别:全部(默认) 170 | ; cate=portrait 类别:人物墙 171 | ; cate=star 类别:明星区 172 | ; cate=nature 类别:自然界 173 | ; cate=acg 类别:二次元 174 | ; cate=color 类别:颜色系 175 | ; cate=car 类别:汽车迷 176 | ; cate=game 类别:游戏迷 177 | ; cate=animal 类别:动物萌宠 178 | 179 | r18=0 180 | ; r18={n} R18内容:0或1(默认为0,不含R18内容) 181 | 182 | [obzhi] 183 | 184 | desktopperiod=24 185 | ; desktopperiod={n} 桌面背景推送周期:1~24(默认为24h/次,开启推送后生效) 186 | 187 | lockperiod=24 188 | ; lockperiod={n} 锁屏背景推送周期:1~24(默认为24h/次,开启推送后生效) 189 | 190 | order=random 191 | ; order=date 排序:收录 192 | ; order=score 排序:热度 193 | ; order=random 排序:随机(默认) 194 | 195 | cate= 196 | ; cate= 类别:全部(默认) 197 | ; cate=acg 类别:动漫 198 | ; cate=specific 类别:另类 199 | ; cate=concise 类别:简约 200 | ; cate=nature 类别:风景 201 | ; cate=portrait 类别:人物 202 | ; cate=game 类别:游戏 203 | ; cate=animal 类别:动物 204 | 205 | r18=0 206 | ; r18={n} R18内容:0或1(默认为0,不含R18内容) 207 | 208 | [infinity] 209 | 210 | desktopperiod=24 211 | ; desktopperiod={n} 桌面背景推送周期:1~24(默认为24h/次,开启推送后生效) 212 | 213 | lockperiod=24 214 | ; lockperiod={n} 锁屏背景推送周期:1~24(默认为24h/次,开启推送后生效) 215 | 216 | order= 217 | ; order= 排序:随机(默认) 218 | ; order=rate 排序:热度 219 | 220 | [3g] 221 | 222 | desktopperiod=24 223 | ; desktopperiod={n} 桌面背景推送周期:1~24(默认为24h/次,开启推送后生效) 224 | 225 | lockperiod=24 226 | ; lockperiod={n} 锁屏背景推送周期:1~24(默认为24h/次,开启推送后生效) 227 | 228 | order=date 229 | ; order=date 排序:最新壁纸(默认) 230 | ; order=view 排序:热门壁纸 231 | 232 | [wallhere] 233 | 234 | desktopperiod=24 235 | ; desktopperiod={n} 桌面背景推送周期:1~24(默认为24h/次,开启推送后生效) 236 | 237 | lockperiod=24 238 | ; lockperiod={n} 锁屏背景推送周期:1~24(默认为24h/次,开启推送后生效) 239 | 240 | order=random 241 | ; order=date 排序:收录 242 | ; order=score 排序:热度 243 | ; order=random 排序:随机(默认) 244 | 245 | cate= 246 | ; cate= 类别:全部(默认) 247 | ; cate=acg 类别:ACG 248 | ; cate=photograph 类别:摄影 249 | 250 | r18=0 251 | ; r18={n} R18内容:0或1(默认为0,不含R18内容) 252 | 253 | [abyss] 254 | 255 | desktopperiod=24 256 | ; desktopperiod={n} 桌面背景推送周期:1~24(默认为24h/次,开启推送后生效) 257 | 258 | lockperiod=24 259 | ; lockperiod={n} 锁屏背景推送周期:1~24(默认为24h/次,开启推送后生效) 260 | 261 | [daihan] 262 | 263 | desktopperiod=24 264 | ; desktopperiod={n} 桌面背景推送周期:1~24(默认为24h/次,开启推送后生效) 265 | 266 | lockperiod=24 267 | ; lockperiod={n} 锁屏背景推送周期:1~24(默认为24h/次,开启推送后生效) 268 | 269 | [dmoe] 270 | 271 | desktopperiod=24 272 | ; desktopperiod={n} 桌面背景推送周期:1~24(默认为24h/次,开启推送后生效) 273 | 274 | lockperiod=24 275 | ; lockperiod={n} 锁屏背景推送周期:1~24(默认为24h/次,开启推送后生效) 276 | 277 | [toubiec] 278 | 279 | desktopperiod=24 280 | ; desktopperiod={n} 桌面背景推送周期:1~24(默认为24h/次,开启推送后生效) 281 | 282 | lockperiod=24 283 | ; lockperiod={n} 锁屏背景推送周期:1~24(默认为24h/次,开启推送后生效) 284 | 285 | [seovx] 286 | 287 | desktopperiod=24 288 | ; desktopperiod={n} 桌面背景推送周期:1~24(默认为24h/次,开启推送后生效) 289 | 290 | lockperiod=24 291 | ; lockperiod={n} 锁屏背景推送周期:1~24(默认为24h/次,开启推送后生效) 292 | 293 | cate=d 294 | ; cate= 类别:美图 295 | ; cate=d 类别:二次元(默认) 296 | ; cate=ha 类别:古风 297 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Ww][Ii][Nn]32/ 27 | [Aa][Rr][Mm]/ 28 | [Aa][Rr][Mm]64/ 29 | bld/ 30 | [Bb]in/ 31 | [Oo]bj/ 32 | [Oo]ut/ 33 | [Ll]og/ 34 | [Ll]ogs/ 35 | 36 | # Visual Studio 2015/2017 cache/options directory 37 | .vs/ 38 | # Uncomment if you have tasks that create the project's static files in wwwroot 39 | #wwwroot/ 40 | 41 | # Visual Studio 2017 auto generated files 42 | Generated\ Files/ 43 | 44 | # MSTest test Results 45 | [Tt]est[Rr]esult*/ 46 | [Bb]uild[Ll]og.* 47 | 48 | # NUnit 49 | *.VisualState.xml 50 | TestResult.xml 51 | nunit-*.xml 52 | 53 | # Build Results of an ATL Project 54 | [Dd]ebugPS/ 55 | [Rr]eleasePS/ 56 | dlldata.c 57 | 58 | # Benchmark Results 59 | BenchmarkDotNet.Artifacts/ 60 | 61 | # .NET Core 62 | project.lock.json 63 | project.fragment.lock.json 64 | artifacts/ 65 | 66 | # ASP.NET Scaffolding 67 | ScaffoldingReadMe.txt 68 | 69 | # StyleCop 70 | StyleCopReport.xml 71 | 72 | # Files built by Visual Studio 73 | *_i.c 74 | *_p.c 75 | *_h.h 76 | *.ilk 77 | *.meta 78 | *.obj 79 | *.iobj 80 | *.pch 81 | *.pdb 82 | *.ipdb 83 | *.pgc 84 | *.pgd 85 | *.rsp 86 | *.sbr 87 | *.tlb 88 | *.tli 89 | *.tlh 90 | *.tmp 91 | *.tmp_proj 92 | *_wpftmp.csproj 93 | *.log 94 | *.vspscc 95 | *.vssscc 96 | .builds 97 | *.pidb 98 | *.svclog 99 | *.scc 100 | 101 | # Chutzpah Test files 102 | _Chutzpah* 103 | 104 | # Visual C++ cache files 105 | ipch/ 106 | *.aps 107 | *.ncb 108 | *.opendb 109 | *.opensdf 110 | *.sdf 111 | *.cachefile 112 | *.VC.db 113 | *.VC.VC.opendb 114 | 115 | # Visual Studio profiler 116 | *.psess 117 | *.vsp 118 | *.vspx 119 | *.sap 120 | 121 | # Visual Studio Trace Files 122 | *.e2e 123 | 124 | # TFS 2012 Local Workspace 125 | $tf/ 126 | 127 | # Guidance Automation Toolkit 128 | *.gpState 129 | 130 | # ReSharper is a .NET coding add-in 131 | _ReSharper*/ 132 | *.[Rr]e[Ss]harper 133 | *.DotSettings.user 134 | 135 | # TeamCity is a build add-in 136 | _TeamCity* 137 | 138 | # DotCover is a Code Coverage Tool 139 | *.dotCover 140 | 141 | # AxoCover is a Code Coverage Tool 142 | .axoCover/* 143 | !.axoCover/settings.json 144 | 145 | # Coverlet is a free, cross platform Code Coverage Tool 146 | coverage*.json 147 | coverage*.xml 148 | coverage*.info 149 | 150 | # Visual Studio code coverage results 151 | *.coverage 152 | *.coveragexml 153 | 154 | # NCrunch 155 | _NCrunch_* 156 | .*crunch*.local.xml 157 | nCrunchTemp_* 158 | 159 | # MightyMoose 160 | *.mm.* 161 | AutoTest.Net/ 162 | 163 | # Web workbench (sass) 164 | .sass-cache/ 165 | 166 | # Installshield output folder 167 | [Ee]xpress/ 168 | 169 | # DocProject is a documentation generator add-in 170 | DocProject/buildhelp/ 171 | DocProject/Help/*.HxT 172 | DocProject/Help/*.HxC 173 | DocProject/Help/*.hhc 174 | DocProject/Help/*.hhk 175 | DocProject/Help/*.hhp 176 | DocProject/Help/Html2 177 | DocProject/Help/html 178 | 179 | # Click-Once directory 180 | publish/ 181 | 182 | # Publish Web Output 183 | *.[Pp]ublish.xml 184 | *.azurePubxml 185 | # Note: Comment the next line if you want to checkin your web deploy settings, 186 | # but database connection strings (with potential passwords) will be unencrypted 187 | *.pubxml 188 | *.publishproj 189 | 190 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 191 | # checkin your Azure Web App publish settings, but sensitive information contained 192 | # in these scripts will be unencrypted 193 | PublishScripts/ 194 | 195 | # NuGet Packages 196 | *.nupkg 197 | # NuGet Symbol Packages 198 | *.snupkg 199 | # The packages folder can be ignored because of Package Restore 200 | **/[Pp]ackages/* 201 | # except build/, which is used as an MSBuild target. 202 | !**/[Pp]ackages/build/ 203 | # Uncomment if necessary however generally it will be regenerated when needed 204 | #!**/[Pp]ackages/repositories.config 205 | # NuGet v3's project.json files produces more ignorable files 206 | *.nuget.props 207 | *.nuget.targets 208 | 209 | # Microsoft Azure Build Output 210 | csx/ 211 | *.build.csdef 212 | 213 | # Microsoft Azure Emulator 214 | ecf/ 215 | rcf/ 216 | 217 | # Windows Store app package directories and files 218 | AppPackages/ 219 | BundleArtifacts/ 220 | Package.StoreAssociation.xml 221 | _pkginfo.txt 222 | *.appx 223 | *.appxbundle 224 | *.appxupload 225 | 226 | # Visual Studio cache files 227 | # files ending in .cache can be ignored 228 | *.[Cc]ache 229 | # but keep track of directories ending in .cache 230 | !?*.[Cc]ache/ 231 | 232 | # Others 233 | ClientBin/ 234 | ~$* 235 | *~ 236 | *.dbmdl 237 | *.dbproj.schemaview 238 | *.jfm 239 | *.pfx 240 | *.publishsettings 241 | orleans.codegen.cs 242 | 243 | # Including strong name files can present a security risk 244 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 245 | #*.snk 246 | 247 | # Since there are multiple workflows, uncomment next line to ignore bower_components 248 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 249 | #bower_components/ 250 | 251 | # RIA/Silverlight projects 252 | Generated_Code/ 253 | 254 | # Backup & report files from converting an old project file 255 | # to a newer Visual Studio version. Backup files are not needed, 256 | # because we have git ;-) 257 | _UpgradeReport_Files/ 258 | Backup*/ 259 | UpgradeLog*.XML 260 | UpgradeLog*.htm 261 | ServiceFabricBackup/ 262 | *.rptproj.bak 263 | 264 | # SQL Server files 265 | *.mdf 266 | *.ldf 267 | *.ndf 268 | 269 | # Business Intelligence projects 270 | *.rdl.data 271 | *.bim.layout 272 | *.bim_*.settings 273 | *.rptproj.rsuser 274 | *- [Bb]ackup.rdl 275 | *- [Bb]ackup ([0-9]).rdl 276 | *- [Bb]ackup ([0-9][0-9]).rdl 277 | 278 | # Microsoft Fakes 279 | FakesAssemblies/ 280 | 281 | # GhostDoc plugin setting file 282 | *.GhostDoc.xml 283 | 284 | # Node.js Tools for Visual Studio 285 | .ntvs_analysis.dat 286 | node_modules/ 287 | 288 | # Visual Studio 6 build log 289 | *.plg 290 | 291 | # Visual Studio 6 workspace options file 292 | *.opt 293 | 294 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 295 | *.vbw 296 | 297 | # Visual Studio LightSwitch build output 298 | **/*.HTMLClient/GeneratedArtifacts 299 | **/*.DesktopClient/GeneratedArtifacts 300 | **/*.DesktopClient/ModelManifest.xml 301 | **/*.Server/GeneratedArtifacts 302 | **/*.Server/ModelManifest.xml 303 | _Pvt_Extensions 304 | 305 | # Paket dependency manager 306 | .paket/paket.exe 307 | paket-files/ 308 | 309 | # FAKE - F# Make 310 | .fake/ 311 | 312 | # CodeRush personal settings 313 | .cr/personal 314 | 315 | # Python Tools for Visual Studio (PTVS) 316 | __pycache__/ 317 | *.pyc 318 | 319 | # Cake - Uncomment if you are using it 320 | # tools/** 321 | # !tools/packages.config 322 | 323 | # Tabs Studio 324 | *.tss 325 | 326 | # Telerik's JustMock configuration file 327 | *.jmconfig 328 | 329 | # BizTalk build output 330 | *.btp.cs 331 | *.btm.cs 332 | *.odx.cs 333 | *.xsd.cs 334 | 335 | # OpenCover UI analysis results 336 | OpenCover/ 337 | 338 | # Azure Stream Analytics local run output 339 | ASALocalRun/ 340 | 341 | # MSBuild Binary and Structured Log 342 | *.binlog 343 | 344 | # NVidia Nsight GPU debugger configuration file 345 | *.nvuser 346 | 347 | # MFractors (Xamarin productivity tool) working folder 348 | .mfractor/ 349 | 350 | # Local History for Visual Studio 351 | .localhistory/ 352 | 353 | # BeatPulse healthcheck temp database 354 | healthchecksdb 355 | 356 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 357 | MigrationBackup/ 358 | 359 | # Ionide (cross platform F# VS Code tools) working folder 360 | .ionide/ 361 | 362 | # Fody - auto-generated XML schema 363 | FodyWeavers.xsd -------------------------------------------------------------------------------- /Services/ApiService.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Diagnostics; 5 | using System.Net.Http; 6 | using System.Net.Http.Headers; 7 | using System.Net.NetworkInformation; 8 | using System.Text; 9 | using System.Threading.Tasks; 10 | using TimelineWallpaper.Beans; 11 | using TimelineWallpaper.Utils; 12 | using Windows.ApplicationModel; 13 | using Windows.Services.Store; 14 | using Windows.System.Profile; 15 | using Windows.System.UserProfile; 16 | 17 | namespace TimelineWallpaper.Services { 18 | public class ApiService { 19 | public const string URI_STORE = "ms-windows-store://pdp/?productid=9N7VHQ989BB7"; 20 | 21 | public static async void Stats(Ini ini, bool status) { 22 | if (!NetworkInterface.GetIsNetworkAvailable()) { 23 | return; 24 | } 25 | const string URL_API = "https://api.nguaduot.cn/appstats"; 26 | StatsApiReq req = new StatsApiReq { 27 | App = Package.Current.DisplayName, // 不会随语言改变 28 | Package = Package.Current.Id.FamilyName, 29 | Version = VerUtil.GetPkgVer(false), 30 | Api = ini?.ToString(), 31 | Status = status ? 1 : 0, 32 | Os = AnalyticsInfo.VersionInfo.DeviceFamily, 33 | OsVersion = VerUtil.GetOsVer(), 34 | Device = VerUtil.GetDevice(), 35 | DeviceId = VerUtil.GetDeviceId(), 36 | Region = GlobalizationPreferences.HomeGeographicRegion 37 | }; 38 | try { 39 | HttpClient client = new HttpClient(); 40 | HttpContent content = new StringContent(JsonConvert.SerializeObject(req), 41 | Encoding.UTF8, "application/json"); 42 | //content.Headers.ContentType = new MediaTypeHeaderValue("application/json"); 43 | HttpResponseMessage response = await client.PostAsync(URL_API, content); 44 | _ = response.EnsureSuccessStatusCode(); 45 | string jsonData = await response.Content.ReadAsStringAsync(); 46 | Debug.WriteLine("stats: " + jsonData.Trim()); 47 | } catch (Exception e) { 48 | Debug.WriteLine(e); 49 | } 50 | } 51 | 52 | public static async void Rank(Ini ini, Meta meta, string action, bool undo = false) { 53 | if (ini == null || meta == null) { 54 | return; 55 | } 56 | if (!NetworkInterface.GetIsNetworkAvailable()) { 57 | return; 58 | } 59 | Debug.WriteLine("Rank() " + action); 60 | const string URL_API = "https://api.nguaduot.cn/appstats/rank"; 61 | RankApiReq req = new RankApiReq { 62 | Provider = ini?.Provider, 63 | ImgId = meta?.Id, 64 | ImgUrl = meta?.Uhd, 65 | Action = action, 66 | Undo = undo, 67 | DeviceId = VerUtil.GetDeviceId(), 68 | Region = GlobalizationPreferences.HomeGeographicRegion 69 | }; 70 | try { 71 | HttpClient client = new HttpClient(); 72 | HttpContent content = new StringContent(JsonConvert.SerializeObject(req), 73 | Encoding.UTF8, "application/json"); 74 | HttpResponseMessage response = await client.PostAsync(URL_API, content); 75 | _ = response.EnsureSuccessStatusCode(); 76 | string jsonData = await response.Content.ReadAsStringAsync(); 77 | Debug.WriteLine("rank: " + jsonData.Trim()); 78 | } catch (Exception e) { 79 | Debug.WriteLine(e); 80 | } 81 | } 82 | 83 | public static async Task Contribute(ContributeApiReq req) { 84 | if (!NetworkInterface.GetIsNetworkAvailable()) { 85 | return false; 86 | } 87 | const string URL_API = "https://api.nguaduot.cn/timeline/contribute"; 88 | req.AppVer = VerUtil.GetPkgVer(false); 89 | try { 90 | HttpClient client = new HttpClient(); 91 | HttpContent content = new StringContent(JsonConvert.SerializeObject(req), 92 | Encoding.UTF8, "application/json"); 93 | //content.Headers.ContentType = new MediaTypeHeaderValue("application/json"); 94 | HttpResponseMessage response = await client.PostAsync(URL_API, content); 95 | _ = response.EnsureSuccessStatusCode(); 96 | string jsonData = await response.Content.ReadAsStringAsync(); 97 | Debug.WriteLine("stats: " + jsonData.Trim()); 98 | return jsonData.Contains(@"""status"":1"); 99 | } catch (Exception e) { 100 | Debug.WriteLine(e); 101 | } 102 | return false; 103 | } 104 | 105 | public static async void Crash(Exception e) { 106 | if (!NetworkInterface.GetIsNetworkAvailable()) { 107 | return; 108 | } 109 | const string URL_API = "https://api.nguaduot.cn/appstats/crash"; 110 | CrashApiReq req = new CrashApiReq { 111 | App = Package.Current.DisplayName, // 不会随语言改变 112 | Package = Package.Current.Id.FamilyName, 113 | Version = VerUtil.GetPkgVer(false), 114 | Os = AnalyticsInfo.VersionInfo.DeviceFamily, 115 | OsVersion = VerUtil.GetOsVer(), 116 | Device = VerUtil.GetDevice(), 117 | DeviceId = VerUtil.GetDeviceId(), 118 | Exception = e.ToString() 119 | }; 120 | try { 121 | HttpClient client = new HttpClient(); 122 | HttpContent content = new StringContent(JsonConvert.SerializeObject(req), 123 | Encoding.UTF8, "application/json"); 124 | //content.Headers.ContentType = new MediaTypeHeaderValue("application/json"); 125 | HttpResponseMessage response = await client.PostAsync(URL_API, content); 126 | _ = response.EnsureSuccessStatusCode(); 127 | string jsonData = await response.Content.ReadAsStringAsync(); 128 | Debug.WriteLine("crash: " + jsonData.Trim()); 129 | } catch (Exception ex) { 130 | Debug.WriteLine(ex); 131 | } 132 | } 133 | 134 | public static async Task CheckUpdate() { 135 | if ("fp51msqsmzpvr".Equals(Package.Current.Id.PublisherId)) { 136 | return await CheckUpdateFromStore(); 137 | } 138 | return await CheckUpdateFromGithub(); 139 | } 140 | 141 | public static async Task CheckUpdateFromStore() { 142 | if (!NetworkInterface.GetIsNetworkAvailable()) { 143 | return null; 144 | } 145 | try { 146 | StoreContext context = StoreContext.GetDefault(); 147 | IReadOnlyList updates = await context.GetAppAndOptionalStorePackageUpdatesAsync(); 148 | if (updates.Count > 0) { 149 | return new ReleaseApi { 150 | Version = "", 151 | Url = URI_STORE 152 | }; 153 | } 154 | } catch (Exception e) { 155 | Debug.WriteLine(e); 156 | } 157 | return null; 158 | } 159 | 160 | public static async Task CheckUpdateFromGithub() { 161 | if (!NetworkInterface.GetIsNetworkAvailable()) { 162 | return null; 163 | } 164 | const string URL_RELEASE = "https://api.github.com/repos/nguaduot/TimelineWallpaper/releases/latest"; 165 | try { 166 | HttpClient client = new HttpClient(); 167 | client.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue("timelinewallpaper", VerUtil.GetPkgVer(true))); 168 | string jsonData = await client.GetStringAsync(URL_RELEASE); 169 | Debug.WriteLine("release: " + jsonData.Trim()); 170 | GithubApi api = JsonConvert.DeserializeObject(jsonData); 171 | string[] versions = api.TagName.Split("."); 172 | if (versions.Length < 2) { 173 | return null; 174 | } 175 | int major = Package.Current.Id.Version.Major; 176 | int minor = Package.Current.Id.Version.Minor; 177 | _ = int.TryParse(versions[0], out int majorNew); 178 | _ = int.TryParse(versions[1], out int minorNew); 179 | if (majorNew < major || (majorNew == major && minorNew <= minor)) { 180 | return null; 181 | } 182 | return new ReleaseApi { 183 | Version = " v" + majorNew + "." + minorNew, 184 | Url = api.Url 185 | }; 186 | } catch (Exception e) { 187 | Debug.WriteLine(e); 188 | } 189 | return null; 190 | } 191 | } 192 | } 193 | -------------------------------------------------------------------------------- /Providers/BaseProvider.cs: -------------------------------------------------------------------------------- 1 | using TimelineWallpaper.Beans; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Diagnostics; 5 | using System.Threading.Tasks; 6 | using Windows.Networking.BackgroundTransfer; 7 | using Windows.Storage; 8 | using Windows.Storage.FileProperties; 9 | using TimelineWallpaper.Utils; 10 | using Windows.Graphics.Imaging; 11 | using System.Drawing; 12 | using Newtonsoft.Json; 13 | using System.Text; 14 | using System.IO; 15 | using System.Linq; 16 | using Windows.Media.FaceAnalysis; 17 | using System.Threading; 18 | 19 | namespace TimelineWallpaper.Providers { 20 | public class BaseProvider { 21 | public string Id { set; get; } 22 | 23 | // 索引顺序为「回顾」顺序 24 | // 注:并非都按时间降序排列,因图源配置而异 25 | protected readonly List metas = new List(); 26 | 27 | // 当前浏览索引 28 | protected int indexFocus = 0; 29 | 30 | protected Dictionary dicHistory = new Dictionary(); 31 | 32 | private BackgroundDownloader downloader = new BackgroundDownloader(); 33 | private Queue activeDownloads = new Queue(); 34 | private CancellationTokenSource cancelToken = new CancellationTokenSource(); 35 | 36 | private static int POOL_CACHE = 5; 37 | 38 | protected void AppendMetas(List metasAdd) { 39 | List list = metas.Select(t => t.Id).ToList(); 40 | foreach (Meta meta in metasAdd) { 41 | if (!list.Contains(meta.Id) && meta.IsValid()) { 42 | metas.Add(meta); 43 | } 44 | } 45 | } 46 | 47 | protected void SortMetas(List metasAdd) { 48 | AppendMetas(metasAdd); 49 | string idFocus = GetFocus()?.Id; 50 | // 按日期降序排列 51 | metas.Sort((m1, m2) => { 52 | if (m1.SortFactor > m2.SortFactor) { 53 | return -1; 54 | } 55 | if (m1.SortFactor < m2.SortFactor) { 56 | return 1; 57 | } 58 | return m1.Id.CompareTo(m2.Id); 59 | }); 60 | // 恢复当前索引 61 | if (indexFocus > 0) { 62 | for (int i = 0; i < metas.Count; i++) { 63 | if (metas[i].Id == idFocus) { 64 | indexFocus = i; 65 | break; 66 | } 67 | } 68 | } 69 | } 70 | 71 | protected void RandomMetas(List metasAdd) { 72 | //List metasNew = new List(); 73 | //Random random = new Random(); 74 | //foreach (Meta meta in metas) { 75 | // metasNew.Insert(random.Next(metasNew.Count + 1), meta); 76 | //} 77 | //metas.Clear(); 78 | //metas.AddRange(metasNew); 79 | Random random = new Random(); 80 | foreach (Meta meta in metasAdd) { 81 | dicHistory.TryGetValue(meta.Id, out int times); 82 | meta.SortFactor = random.NextDouble() + (times / 10.0 > 0.9 ? 0.9 : times / 10.0); 83 | } 84 | // 升序排列,已阅图降低出现在前排的概率 85 | metasAdd.Sort((m1, m2) => m1.SortFactor.CompareTo(m2.SortFactor)); 86 | AppendMetas(metasAdd); 87 | } 88 | 89 | public virtual async Task LoadData(BaseIni ini, DateTime? date = null) { 90 | await Task.Run(() => { 91 | dicHistory = GetHistory(Id); 92 | }); 93 | return false; 94 | } 95 | 96 | public Meta GetFocus() { 97 | if (metas.Count > 0) { 98 | if (dicHistory.ContainsKey(metas[indexFocus].Id)) { 99 | dicHistory[metas[indexFocus].Id] += 1; 100 | } else { 101 | dicHistory[metas[indexFocus].Id] = 1; 102 | } 103 | SaveHistory(Id, dicHistory); 104 | return metas[indexFocus]; 105 | } 106 | return null; 107 | } 108 | 109 | public Meta Yesterday() { 110 | indexFocus = indexFocus < metas.Count - 1 ? indexFocus + 1 : metas.Count - 1; 111 | if (metas.Count > 0) { 112 | if (dicHistory.ContainsKey(metas[indexFocus].Id)) { 113 | dicHistory[metas[indexFocus].Id] += 1; 114 | } else { 115 | dicHistory[metas[indexFocus].Id] = 1; 116 | } 117 | SaveHistory(Id, dicHistory); 118 | return metas[indexFocus]; 119 | } 120 | return null; 121 | } 122 | 123 | public Meta GetYesterday() { 124 | int index = indexFocus < metas.Count - 1 ? indexFocus + 1 : metas.Count - 1; 125 | return metas.Count > 0 ? metas[index] : null; 126 | } 127 | 128 | public Meta Tormorrow() { 129 | indexFocus = indexFocus > 0 ? indexFocus - 1 : 0; 130 | return metas.Count > 0 ? metas[indexFocus] : null; 131 | } 132 | 133 | public Meta GetTormorrow() { 134 | int index = indexFocus > 0 ? indexFocus - 1 : 0; 135 | return metas.Count > 0 ? metas[index] : null; 136 | } 137 | 138 | public Meta Latest() { 139 | indexFocus = 0; 140 | return metas.Count > 0 ? metas[indexFocus] : null; 141 | } 142 | 143 | public Meta GetLatest() { 144 | return metas.Count > 0 ? metas[0] : null; 145 | } 146 | 147 | public Meta Farthest() { 148 | indexFocus = metas.Count - 1; 149 | return metas.Count > 0 ? metas[indexFocus] : null; 150 | } 151 | 152 | public Meta GetFarthest() { 153 | return metas.Count > 0 ? metas[metas.Count - 1] : null; 154 | } 155 | 156 | public Meta Target(DateTime date) { 157 | if (date == null) { 158 | return null; 159 | } 160 | for (int i = 0; i < metas.Count; i++) { 161 | if (date.ToString("yyyyMMdd").Equals(metas[i].Date?.ToString("yyyyMMdd"))) { 162 | indexFocus = i; 163 | return metas[i]; 164 | } 165 | } 166 | return null; 167 | } 168 | 169 | public virtual async Task Cache(Meta meta) { 170 | Debug.WriteLine("Cache() " + meta?.Id); 171 | int index = -1; 172 | for (int i = 0; i < metas.Count; i++) { // 定位索引以便缓存多个 173 | if (meta != null && metas[i].Id.Equals(meta.Id)) { 174 | index = i; 175 | break; 176 | } 177 | } 178 | if (index < 0) { 179 | return null; 180 | } 181 | Debug.WriteLine("Cache() index " + index); 182 | IReadOnlyList historyDownloads = await BackgroundDownloader.GetCurrentDownloadsAsync(); 183 | Debug.WriteLine("Cache() current downloads " + historyDownloads.Count); 184 | for (int i = index; i < Math.Min(metas.Count, index + POOL_CACHE); i++) { // 缓存多个 185 | Meta m = metas[i]; 186 | if (m.CacheUhd != null) { // 无需缓存 187 | continue; 188 | } 189 | string cacheName = string.Format("{0}-{1}{2}", Id, m.Id, m.Format); 190 | StorageFile cacheFile = await ApplicationData.Current.TemporaryFolder.CreateFileAsync(cacheName, CreationCollisionOption.OpenIfExists); 191 | BasicProperties fileProperties = await cacheFile.GetBasicPropertiesAsync(); 192 | if (fileProperties.Size > 0) { // 已缓存过 193 | m.CacheUhd = cacheFile; 194 | Debug.WriteLine("Cache() cached from disk: " + cacheFile.Path); 195 | } else if (m.Uhd != null && m.Do == null) { // 开始缓存 196 | Debug.WriteLine("Cache() cache from network: " + m.Uhd); 197 | foreach (DownloadOperation o in historyDownloads) { // 从历史中恢复任务 198 | if (m.Uhd.Equals(o.RequestedUri)) { 199 | m.Do = o; 200 | break; 201 | } 202 | } 203 | if (m.Do == null) { // 新建下载任务 204 | try { 205 | m.Do = downloader.CreateDownload(new Uri(m.Uhd), cacheFile); 206 | _ = m.Do.StartAsync(); 207 | } catch (Exception e) { 208 | Debug.WriteLine(e); 209 | } 210 | } 211 | if (activeDownloads.Count >= 5) { // 暂停缓存池之外的任务 212 | DownloadOperation o = activeDownloads.Dequeue(); 213 | if (o.Progress.Status == BackgroundTransferStatus.Running) { 214 | o.Pause(); 215 | } 216 | } 217 | activeDownloads.Enqueue(m.Do); 218 | } 219 | } 220 | // 等待当前任务下载完成 221 | if (meta.CacheUhd == null && meta.Do != null) { 222 | Debug.WriteLine("Cache() wait for cache: " + meta.Do.Guid); 223 | try { 224 | if (meta.Do.Progress.Status == BackgroundTransferStatus.PausedByApplication) { 225 | meta.Do.Resume(); 226 | } 227 | _ = await meta.Do.AttachAsync(); 228 | if (meta.Do.Progress.Status == BackgroundTransferStatus.Completed) { 229 | meta.CacheUhd = meta.Do.ResultFile as StorageFile; 230 | } 231 | } catch (Exception e) { 232 | // 未找到(404)。 (Exception from HRESULT: 0x80190194) 233 | Debug.WriteLine(e); 234 | } 235 | } 236 | // 获取图片尺寸&检测人像位置 237 | if (meta.CacheUhd != null && FaceDetector.IsSupported) { 238 | try { 239 | using (var stream = await meta.CacheUhd.OpenAsync(FileAccessMode.Read)) { 240 | var decoder = await BitmapDecoder.CreateAsync(stream); 241 | // 获取图片尺寸 242 | meta.Dimen = new Size((int)decoder.PixelWidth, (int)decoder.PixelHeight); 243 | // 检测人像位置 244 | // TODO: 该行会随机抛出异常 System.Exception: 图像无法识别 245 | SoftwareBitmap bitmap = await decoder.GetSoftwareBitmapAsync(decoder.BitmapPixelFormat, 246 | BitmapAlphaMode.Premultiplied, new BitmapTransform(), 247 | ExifOrientationMode.IgnoreExifOrientation, ColorManagementMode.DoNotColorManage); 248 | if (bitmap.BitmapPixelFormat != BitmapPixelFormat.Gray8) { 249 | bitmap = SoftwareBitmap.Convert(bitmap, BitmapPixelFormat.Gray8); 250 | } 251 | FaceDetector detector = await FaceDetector.CreateAsync(); 252 | IList faces = await detector.DetectFacesAsync(bitmap); 253 | float offset = -1; 254 | foreach (DetectedFace face in faces) { 255 | offset = Math.Max(offset, (face.FaceBox.X + face.FaceBox.Width / 2.0f) / bitmap.PixelWidth); 256 | } 257 | meta.FaceOffset = offset >= 0 ? offset : 0.5f; 258 | bitmap.Dispose(); 259 | } 260 | } catch (Exception ex) { 261 | Debug.WriteLine(ex); 262 | } 263 | } 264 | return meta; 265 | } 266 | 267 | public async Task Download(Meta meta, string appName, string provider) { 268 | if (meta?.CacheUhd == null) { 269 | return null; 270 | } 271 | 272 | try { 273 | StorageFolder folder = await KnownFolders.PicturesLibrary 274 | .CreateFolderAsync(appName, CreationCollisionOption.OpenIfExists); 275 | string name = string.Format("{0}_{1}_{2}{3}", appName, provider, meta.Id, meta.Format); 276 | name = FileUtil.MakeValidFileName(name, ""); 277 | return await meta.CacheUhd.CopyAsync(folder, name, NameCollisionOption.ReplaceExisting); 278 | } catch (Exception) { 279 | Debug.WriteLine("download error"); 280 | } 281 | return null; 282 | } 283 | 284 | public static Dictionary GetHistory(string provider) { 285 | try { 286 | string file = Path.Combine(ApplicationData.Current.LocalFolder.Path, provider + ".json"); 287 | if (File.Exists(file)) { 288 | string content = File.ReadAllText(file, UTF8Encoding.UTF8); 289 | return JsonConvert.DeserializeObject>(content); 290 | } 291 | } catch (Exception) { 292 | Debug.WriteLine("read history error"); 293 | } 294 | return new Dictionary(); 295 | } 296 | 297 | public static void SaveHistory(string provider, Dictionary dic) { 298 | try { 299 | string file = Path.Combine(ApplicationData.Current.LocalFolder.Path, provider + ".json"); 300 | File.WriteAllText(file, JsonConvert.SerializeObject(dic), UTF8Encoding.UTF8); 301 | } catch (Exception) { 302 | Debug.WriteLine("save history error"); 303 | } 304 | } 305 | } 306 | } 307 | -------------------------------------------------------------------------------- /Providers/NasaProvider.cs: -------------------------------------------------------------------------------- 1 | using TimelineWallpaper.Beans; 2 | using Newtonsoft.Json; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Diagnostics; 6 | using System.Net.Http; 7 | using System.Net.NetworkInformation; 8 | using System.Threading.Tasks; 9 | using System.Text.RegularExpressions; 10 | using Windows.Data.Html; 11 | using TimelineWallpaper.Utils; 12 | 13 | namespace TimelineWallpaper.Providers { 14 | public class NasaProvider : BaseProvider { 15 | // 下一页数据索引(日期编号)(用于按需加载) 16 | private DateTime nextPage = DateTime.UtcNow.AddHours(-4); 17 | 18 | private const int PAGE_SIZE = 14; 19 | 20 | // https://api.nasa.gov/ 21 | // Query Parameters 22 | // date: The date of the APOD image to retrieve 23 | // start_date: The start of a date range, when requesting date for a range of dates. Cannot be used with "date". 24 | // end_date: The end of the date range, when used with "start_date". 25 | // count: If this is specified then "count" randomly chosen images will be returned. Cannot be used with "date" or "start_date" and "end_date". 26 | // thumbs: Return the URL of video thumbnail. If an APOD is not a video, this parameter is ignored. 27 | // api_key: api.nasa.gov key for expanded usage 28 | private const string URL_API_PAGE = "https://api.nasa.gov/planetary/apod?api_key=DEMO_KEY&thumbs=True&start_date={0}&end_date={1}"; 29 | 30 | private Meta ParseBean(NasaApiItem bean) { 31 | Meta meta = new Meta { 32 | Title = bean.Title, 33 | Story = bean.Explanation 34 | }; 35 | if ("image".Equals(bean.MediaType)) { 36 | meta.Uhd = bean.HdUrl; 37 | meta.Thumb = bean.Url; 38 | meta.Format = bean.HdUrl.Substring(bean.HdUrl.LastIndexOf(".")); 39 | }/* else if ("video".Equals(bean.MediaType)) { // 放弃,非直链视频地址 40 | meta.Video = bean.Url; 41 | meta.Thumb = bean.ThumbnailUrl; 42 | }*/ 43 | if (!string.IsNullOrEmpty(bean.Date)) { 44 | meta.Date = DateTime.ParseExact(bean.Date, "yyyy-MM-dd", new System.Globalization.CultureInfo("en-US")); 45 | meta.SortFactor = meta.Date.Value.Subtract(new DateTime(1970, 1, 1)).TotalDays; 46 | meta.Id = bean.MediaType + meta.Date?.ToString("yyyyMMdd"); 47 | } 48 | if (!string.IsNullOrEmpty(bean.Copyright)) { 49 | meta.Copyright = "© " + bean.Copyright.Replace("\n", "").Replace(" Music:", ""); 50 | } 51 | 52 | return meta; 53 | } 54 | 55 | public override async Task LoadData(BaseIni ini, DateTime? date = null) { 56 | // 现有数据未浏览完,无需加载更多,或已无更多数据 57 | if (indexFocus < metas.Count - 1 && date == null) { 58 | return true; 59 | } 60 | // 无网络连接 61 | if (!NetworkInterface.GetIsNetworkAvailable()) { 62 | return false; 63 | } 64 | await base.LoadData(ini, date); 65 | 66 | nextPage = date ?? nextPage; 67 | string urlApi = string.Format(URL_API_PAGE, nextPage.AddDays(-PAGE_SIZE + 1).ToString("yyyy-MM-dd"), 68 | nextPage.ToString("yyyy-MM-dd")); 69 | Debug.WriteLine("provider url: " + urlApi); 70 | try { 71 | HttpClient client = new HttpClient(); 72 | string jsonData = await client.GetStringAsync(urlApi); 73 | Debug.WriteLine("provider data: " + jsonData.Trim()); 74 | List items = JsonConvert.DeserializeObject>(jsonData); 75 | List metasAdd = new List(); 76 | foreach (NasaApiItem item in items) { 77 | metasAdd.Add(ParseBean(item)); 78 | } 79 | SortMetas(metasAdd); // 按时序倒序排列 80 | nextPage = nextPage.AddDays(-PAGE_SIZE); 81 | } catch (Exception e) { 82 | Debug.WriteLine(e); 83 | } 84 | return metas.Count > 0; 85 | } 86 | } 87 | 88 | public class NasabjpProvider : BaseProvider { 89 | // 下一页数据索引(从0开始)(用于按需加载) 90 | private int nextPage = 0; 91 | 92 | private readonly List pageUrls = new List(); 93 | 94 | private const string URL_API_HOST = "http://www.bjp.org.cn"; 95 | private const string URL_API_TODAY = URL_API_HOST + "/mryt/list.shtml"; 96 | private const string URL_API_DAY = URL_API_HOST + "/mryt/list_{0}.shtml"; 97 | 98 | private void ParsePages(string html) { 99 | foreach (Match match in Regex.Matches(html, @">([\d-]+):<.+?href=""(.+?)""")) { 100 | pageUrls.Add(URL_API_HOST + match.Groups[2].Value); 101 | } 102 | } 103 | 104 | private Meta ParseBean(string htmlData) { 105 | Meta meta = new Meta(); 106 | Match match = Regex.Match(htmlData, @"contentid ?= ?""(.+?)"";"); 107 | if (match.Success) { 108 | meta.Id = match.Groups[1].Value; 109 | } 110 | match = Regex.Match(htmlData, @"([^=<]+)(<.+?>)说明"); 122 | if (match.Success) { 123 | meta.Title = HtmlUtilities.ConvertToText(match.Groups[1].Value); 124 | meta.Copyright = HtmlUtilities.ConvertToText(match.Groups[2].Value).Trim(new char[] { '\n', ' ' }); 125 | } 126 | match = Regex.Match(htmlData, @">说明:(.+?)

"); 127 | if (match.Success) { 128 | meta.Story = HtmlUtilities.ConvertToText(match.Groups[1].Value).Trim(new char[] { '\n', ' ' }) + "(翻译:北京天文馆)"; 129 | } 130 | match = Regex.Match(htmlData, @">(\d+\-\d+\-\d+)<"); 131 | if (match.Success) { 132 | meta.Date = DateTime.ParseExact(match.Groups[1].Value, "yyyy-MM-dd", new System.Globalization.CultureInfo("en-US")); 133 | meta.SortFactor = meta.Date.Value.Subtract(new DateTime(1970, 1, 1)).TotalDays; 134 | } 135 | return meta; 136 | } 137 | 138 | public override async Task LoadData(BaseIni ini, DateTime? date = null) { 139 | // 现有数据未浏览完,无需加载更多,或已无更多数据 140 | if (indexFocus < metas.Count - 1) { 141 | return true; 142 | } 143 | // 无网络连接 144 | if (!NetworkInterface.GetIsNetworkAvailable()) { 145 | return false; 146 | } 147 | await base.LoadData(ini, date); 148 | 149 | if (nextPage >= pageUrls.Count) { 150 | string urlBjp = nextPage >= 100 ? string.Format(URL_API_DAY, (int)Math.Ceiling((nextPage + 1) / 100.0)) : URL_API_TODAY; 151 | try { 152 | HttpClient client = new HttpClient(); 153 | string htmlData = await client.GetStringAsync(urlBjp); 154 | ParsePages(htmlData); 155 | } catch (Exception e) { 156 | Debug.WriteLine(e); 157 | } 158 | } 159 | if (nextPage >= pageUrls.Count) { 160 | return metas.Count > 0; 161 | } 162 | 163 | string url = pageUrls[nextPage++]; 164 | Debug.WriteLine("provider url: " + url); 165 | try { 166 | HttpClient client = new HttpClient(); 167 | string htmlData = await client.GetStringAsync(url); 168 | List metasAdd = new List { 169 | ParseBean(htmlData) 170 | }; 171 | AppendMetas(metasAdd); 172 | } catch (Exception e) { 173 | Debug.WriteLine(e); 174 | } 175 | 176 | return metas.Count > 0; 177 | } 178 | } 179 | 180 | //public class NasaProvider2 : BaseProvider { 181 | // // 下一页数据索引(日期编号)(用于按需加载) 182 | // private DateTime nextPage = DateTime.Now; 183 | 184 | // private const string URL_API_HOST = "https://apod.nasa.gov/apod/"; 185 | // private const string URL_API_TODAY = URL_API_HOST + "astropix.html"; 186 | // // 注意时差导致404 187 | // private const string URL_API_DAY = URL_API_HOST + "ap{0}.html"; 188 | 189 | // private Meta ParseBean(string htmlData) { 190 | // Meta meta = new Meta(); 191 | // Match match = Regex.Match(htmlData, @"href=""(ap(\d{6}))\.html""> ?< ?"); 192 | // if (match.Success) { 193 | // DateTime dateYesterday = DateTime.ParseExact(match.Groups[2].Value, "yyMMdd", 194 | // new System.Globalization.CultureInfo("en-US")); 195 | // meta.Id = match.Groups[1].Value; 196 | // meta.Date = dateYesterday.AddDays(1); 197 | // } 198 | // if (meta.Id == null || meta.Date == null) { 199 | // return null; 200 | // } 201 | // match = Regex.Match(htmlData, @"href=""(image.+?)"""); 202 | // if (match.Success) { 203 | // meta.Uhd = URL_API_HOST + match.Groups[1].Value; 204 | // } 205 | // match = Regex.Match(htmlData, @"SRC=""(image.+?)"""); 206 | // if (match.Success) { 207 | // meta.Thumb = URL_API_HOST + match.Groups[1].Value; 208 | // } 209 | // match = Regex.Match(htmlData, @"(.+?) ?
"); 210 | // if (match.Success) { 211 | // meta.Title = match.Groups[1].Value.Trim(); 212 | // } 213 | // match = Regex.Match(htmlData, @"( *?Image Credit.+?)", RegexOptions.Singleline); 214 | // if (match.Success) { 215 | // string line = HtmlUtilities.ConvertToText(match.Groups[1].Value); 216 | // Debug.WriteLine(line); 217 | // meta.Copyright = "© " + line.Split(":", 2)[1].Split(";")[0].Trim(); 218 | // } else { 219 | // match = Regex.Match(htmlData, @"(.+?Images:.+?)", RegexOptions.Singleline); 220 | // if (match.Success) { 221 | // string line = HtmlUtilities.ConvertToText(match.Groups[1].Value); 222 | // Debug.WriteLine(line); 223 | // meta.Copyright = "© " + line.Split("Images:", 2)[1].Split(";")[0].Trim(); 224 | // } 225 | // } 226 | // match = Regex.Match(htmlData, @" ?Explanation: ?(.+?)

", RegexOptions.Singleline); 227 | // if (match.Success) { 228 | // meta.Story = HtmlUtilities.ConvertToText(match.Groups[1].Value).Trim(); 229 | // } 230 | 231 | // return meta; 232 | // } 233 | 234 | // public override async Task LoadData(Ini ini, DateTime? date = null) { 235 | // // 现有数据未浏览完,无需加载更多,或已无更多数据 236 | // if (indexFocus < metas.Count - 1) { 237 | // return true; 238 | // } 239 | // // 无网络连接 240 | // if (!NetworkInterface.GetIsNetworkAvailable()) { 241 | // return false; 242 | // } 243 | 244 | // string url = nextPage.DayOfYear == DateTime.Now.DayOfYear ? URL_API_TODAY 245 | // : string.Format(URL_API_DAY, nextPage.ToString("yyMMdd")); 246 | // nextPage = nextPage.AddDays(-1); 247 | // try { 248 | // HttpClient client = new HttpClient(); 249 | // string htmlData = await client.GetStringAsync(url); 250 | // Meta metaNew = ParseBean(htmlData); 251 | // if (metaNew == null) { 252 | // return metas.Count > 0; 253 | // } 254 | // bool exists = false; 255 | // foreach (Meta meta in metas) { 256 | // exists |= metaNew.Id == meta.Id; 257 | // } 258 | // if (!exists) { 259 | // metas.Add(metaNew); 260 | // } 261 | // if (nextPage.DayOfYear == metaNew.Date.DayOfYear) { // 解决时差问题 262 | // nextPage = nextPage.AddDays(-1); 263 | // } 264 | // } catch (Exception e) { 265 | // Debug.WriteLine(e); 266 | // } 267 | 268 | // return metas.Count > 0; 269 | // } 270 | //} 271 | 272 | //public class NasachinaProvider : BaseProvider { 273 | // // 下一页数据索引(从1开始)(用于按需加载) 274 | // private int nextPage = 1; 275 | 276 | // private const string URL_API = "https://www.nasachina.cn/apod/page/{0}"; 277 | 278 | // private List ParseBeans(string htmlData) { 279 | // List metas = new List(); 280 | // foreach (Match m in Regex.Matches(htmlData, @"", RegexOptions.Singleline)) { 281 | // Meta meta = new Meta(); 282 | // Match match = Regex.Match(m.Value, @"id=""(.+?)"""); 283 | // if (match.Success) { 284 | // meta.Id = match.Groups[1].Value; 285 | // } 286 | // match = Regex.Match(m.Value, @"published.+?datetime=""(.+?)T"); 287 | // if (match.Success) { 288 | // meta.Date = Convert.ToDateTime(match.Groups[1].Value); 289 | // } 290 | // if (meta.Id == null || meta.Date == null) { 291 | // continue; 292 | // } 293 | // //match = Regex.Match(m.Value, @"srcset=""(.+?)"""); 294 | // //if (match.Success) { // TODO 295 | // // string[] urls = match.Groups[1].Value.Split(","); 296 | // // Array.Sort(urls, (p1, p2) => p2.Split(" ")[1].CompareTo(p1.Split(" ")[1])); 297 | // // Debug.WriteLine(string.Join(", ", urls)); 298 | // // meta.Uhd = urls[0].Trim().Split(" ")[0]; 299 | // // meta.Thumb = urls[urls.Length - 1].Trim().Split(" ")[0]; 300 | // //} 301 | // match = Regex.Match(m.Value, @"src=""(.+?)"""); 302 | // if (match.Success) { 303 | // meta.Thumb = match.Groups[1].Value; 304 | // meta.Uhd = match.Groups[1].Value; // TODO 305 | // } 306 | // match = Regex.Match(m.Value, @"", RegexOptions.Singleline); 307 | // if (match.Success) { 308 | // meta.Title = HtmlUtilities.ConvertToText(match.Value).Trim(); 309 | // } 310 | // metas.Add(meta); 311 | // } 312 | 313 | // return metas; 314 | // } 315 | 316 | // public override async Task LoadData(Ini ini) { 317 | // // 现有数据未浏览完,无需加载更多,或已无更多数据 318 | // if (indexFocus < metas.Count - 1) { 319 | // return true; 320 | // } 321 | // // 无网络连接 322 | // if (!NetworkInterface.GetIsNetworkAvailable()) { 323 | // return false; 324 | // } 325 | 326 | // string url = string.Format(URL_API, nextPage++); 327 | // Debug.WriteLine("provider url: " + url); 328 | // try { 329 | // HttpClient client = new HttpClient(); 330 | // string htmlData = await client.GetStringAsync(url); 331 | // //Debug.WriteLine("provider data: " + htmlData); 332 | // List metasNew = ParseBeans(htmlData); 333 | // foreach (Meta metaNew in metasNew) { 334 | // bool exists = false; 335 | // foreach (Meta meta in metas) { 336 | // exists |= metaNew.Id == meta.Id; 337 | // } 338 | // if (!exists) { 339 | // metas.Add(metaNew); 340 | // } 341 | // } 342 | // } catch (Exception e) { 343 | // Debug.WriteLine(e); 344 | // } 345 | 346 | // return metas.Count > 0; 347 | // } 348 | //} 349 | } 350 | -------------------------------------------------------------------------------- /Utils/Ini.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using TimelineWallpaper.Providers; 3 | 4 | namespace TimelineWallpaper.Utils { 5 | public class Ini { 6 | private readonly Dictionary Inis = new Dictionary() { 7 | { BingIni.ID, new BingIni() }, 8 | { NasaIni.ID, new NasaIni() }, 9 | { OneplusIni.ID, new OneplusIni() }, 10 | { TimelineIni.ID, new TimelineIni() }, 11 | { Himawari8Ini.ID, new Himawari8Ini() }, 12 | { YmyouliIni.ID, new YmyouliIni() }, 13 | { InfinityIni.ID, new InfinityIni() }, 14 | { OneIni.ID, new OneIni() }, 15 | { QingbzIni.ID, new QingbzIni() }, 16 | { ObzhiIni.ID, new ObzhiIni() }, 17 | { G3Ini.ID, new G3Ini() }, 18 | { WallhereIni.ID, new WallhereIni() }, 19 | { AbyssIni.ID, new AbyssIni() }, 20 | { DaihanIni.ID, new DaihanIni() }, 21 | { DmoeIni.ID, new DmoeIni() }, 22 | { ToubiecIni.ID, new ToubiecIni() }, 23 | { MtyIni.ID, new MtyIni() }, 24 | { SeovxIni.ID, new SeovxIni() } 25 | }; 26 | 27 | private readonly HashSet THEME = new HashSet() { "", "light", "dark" }; 28 | 29 | private string provider = BingIni.ID; 30 | public string Provider { 31 | set => provider = Inis.ContainsKey(value) ? value : BingIni.ID; 32 | get => provider; 33 | } 34 | 35 | private string desktopProvider = ""; 36 | public string DesktopProvider { 37 | set => desktopProvider = Inis.ContainsKey(value) ? value : ""; 38 | get => desktopProvider; 39 | } 40 | 41 | private string lockProvider = ""; 42 | public string LockProvider { 43 | set => lockProvider = Inis.ContainsKey(value) ? value : ""; 44 | get => lockProvider; 45 | } 46 | 47 | private string theme = ""; 48 | public string Theme { 49 | set => theme = THEME.Contains(value) ? value : ""; 50 | get => theme; 51 | } 52 | 53 | public bool SetIni(string provider, BaseIni ini) { 54 | if (Inis.ContainsKey(provider) && ini != null) { 55 | Inis[provider] = ini; 56 | return true; 57 | } 58 | return false; 59 | } 60 | 61 | public BaseIni GetIni(string provider = null) { 62 | return provider != null && Inis.ContainsKey(provider) 63 | ? Inis[provider] : Inis[this.provider]; 64 | } 65 | 66 | public BaseProvider GenerateProvider(string provider = null) { 67 | return provider != null && Inis.ContainsKey(provider) 68 | ? Inis[provider].GenerateProvider() : Inis[this.provider].GenerateProvider(); 69 | } 70 | 71 | override public string ToString() { 72 | string paras = Inis[provider].ToString(); 73 | return $"/{Provider}?desktopprovider={DesktopProvider}&lockprovider={LockProvider}" + (paras.Length > 0 ? "&" : "") + paras; 74 | } 75 | } 76 | 77 | public class BaseIni { 78 | private int desktopPeriod = 24; 79 | public int DesktopPeriod { 80 | set => desktopPeriod = value <= 0 || value > 24 ? 24 : value; 81 | get => desktopPeriod; 82 | } 83 | 84 | private int lockPeriod = 24; 85 | public int LockPeriod { 86 | set => lockPeriod = value <= 0 || value > 24 ? 24 : value; 87 | get => lockPeriod; 88 | } 89 | 90 | // 时序图源 91 | public virtual bool IsSequential() => true; 92 | 93 | public virtual BaseProvider GenerateProvider() => new BingProvider(); 94 | } 95 | 96 | public class BingIni : BaseIni { 97 | public const string ID = "bing"; 98 | public static readonly List LANG = new List() { "", "zh-cn", "en-us", "ja-jp", "de-de", "fr-fr" }; 99 | 100 | private string lang = ""; 101 | public string Lang { 102 | set => lang = LANG.Contains(value) ? value : ""; 103 | get => lang; 104 | } 105 | 106 | public override BaseProvider GenerateProvider() => new BingProvider() { Id = ID }; 107 | 108 | override public string ToString() => $"desktopperiod={DesktopPeriod}&lockperiod={LockPeriod}&lang={Lang}"; 109 | } 110 | 111 | public class NasaIni : BaseIni { 112 | public const string ID = "nasa"; 113 | public static readonly List MIRROR = new List() { "", "bjp" }; 114 | 115 | private string mirror = ""; 116 | public string Mirror { 117 | set => mirror = MIRROR.Contains(value) ? value : ""; 118 | get => mirror; 119 | } 120 | 121 | public override BaseProvider GenerateProvider() { 122 | switch (mirror) { 123 | case "bjp": 124 | return new NasabjpProvider() { Id = ID }; 125 | default: 126 | return new NasaProvider() { Id = ID }; 127 | } 128 | } 129 | 130 | override public string ToString() => $"desktopperiod={DesktopPeriod}&lockperiod={LockPeriod}&mirror={Mirror}"; 131 | } 132 | 133 | public class OneplusIni : BaseIni { 134 | public const string ID = "oneplus"; 135 | public static readonly List ORDER = new List() { "date", "rate", "view" }; 136 | 137 | private string order = "date"; 138 | public string Order { 139 | set => order = ORDER.Contains(value) ? value : "date"; 140 | get => order; 141 | } 142 | 143 | public override bool IsSequential() => "date".Equals(order); 144 | 145 | public override BaseProvider GenerateProvider() => new OneplusProvider() { Id = ID }; 146 | 147 | override public string ToString() => $"desktopperiod={DesktopPeriod}&lockperiod={LockPeriod}&order={Order}"; 148 | } 149 | 150 | public class TimelineIni : BaseIni { 151 | public const string ID = "timeline"; 152 | public static readonly List ORDER = new List() { "date", "score", "random" }; 153 | public static readonly List CATE = new List() { "", "landscape", "portrait", "culture", "term" }; 154 | 155 | private string order = "date"; 156 | public string Order { 157 | set => order = ORDER.Contains(value) ? value : "date"; 158 | get => order; 159 | } 160 | 161 | private string cate = ""; 162 | public string Cate { 163 | set => cate = CATE.Contains(value) ? value : ""; 164 | get => cate; 165 | } 166 | 167 | public int Authorize { set; get; } = 1; 168 | 169 | public override bool IsSequential() => "date".Equals(order); 170 | 171 | public override BaseProvider GenerateProvider() => new TimelineProvider() { Id = ID }; 172 | 173 | override public string ToString() => $"desktopperiod={DesktopPeriod}&lockperiod={LockPeriod}&order={Order}&cate={Cate}&authorize={Authorize}"; 174 | } 175 | 176 | public class Himawari8Ini : BaseIni { 177 | public const string ID = "himawari8"; 178 | 179 | private float offset = 0; 180 | public float Offset { 181 | set => offset = value < -1 ? -1 : (value > 1 ? 1 : value); 182 | get => offset; 183 | } 184 | 185 | public Himawari8Ini() { 186 | DesktopPeriod = 1; 187 | LockPeriod = 2; 188 | } 189 | 190 | public override bool IsSequential() => false; 191 | 192 | public override BaseProvider GenerateProvider() => new Himawari8Provider() { Id = ID }; 193 | 194 | override public string ToString() => $"desktopperiod={DesktopPeriod}&lockperiod={LockPeriod}"; 195 | } 196 | 197 | public class YmyouliIni : BaseIni { 198 | public const string ID = "ymyouli"; 199 | public static readonly List ORDER = new List() { "date", "score", "random" }; 200 | public static readonly List CATE = new List() { "", "acgcharacter", "acgscene", "sky", 201 | "war", "sword", "artistry", "car", "portrait", "animal", "delicacy", "nature" }; 202 | 203 | private string order = "random"; 204 | public string Order { 205 | set => order = ORDER.Contains(value) ? value : "random"; 206 | get => order; 207 | } 208 | 209 | private string cate = ""; 210 | public string Cate { 211 | set => cate = CATE.Contains(value) ? value : ""; 212 | get => cate; 213 | } 214 | 215 | public int R18 { set; get; } = 0; 216 | 217 | public override bool IsSequential() => false; 218 | 219 | public override BaseProvider GenerateProvider() => new YmyouliProvider() { Id = ID }; 220 | 221 | override public string ToString() => $"desktopperiod={DesktopPeriod}&lockperiod={LockPeriod}&order={Order}&cate={Cate}&r18={R18}"; 222 | } 223 | 224 | public class InfinityIni : BaseIni { 225 | public const string ID = "infinity"; 226 | public static readonly List ORDER = new List() { "", "rate" }; 227 | 228 | private string order = ""; 229 | public string Order { 230 | set => order = ORDER.Contains(value) ? value : ""; 231 | get => order; 232 | } 233 | 234 | public override bool IsSequential() => false; 235 | 236 | public override BaseProvider GenerateProvider() => new InfinityProvider() { Id = ID }; 237 | 238 | override public string ToString() => $"desktopperiod={DesktopPeriod}&lockperiod={LockPeriod}&order={Order}"; 239 | } 240 | 241 | public class OneIni : BaseIni { 242 | public const string ID = "one"; 243 | public static readonly List ORDER = new List() { "date", "random" }; 244 | 245 | private string order = "date"; 246 | public string Order { 247 | set => order = ORDER.Contains(value) ? value : "date"; 248 | get => order; 249 | } 250 | 251 | public override bool IsSequential() => "date".Equals(order); 252 | 253 | public override BaseProvider GenerateProvider() => new OneProvider() { Id = ID }; 254 | 255 | override public string ToString() => $"desktopperiod={DesktopPeriod}&lockperiod={LockPeriod}&order={Order}"; 256 | } 257 | 258 | public class QingbzIni : BaseIni { 259 | public const string ID = "qingbz"; 260 | public static readonly List ORDER = new List() { "date", "score", "random" }; 261 | public static readonly List CATE = new List() { "", "portrait", "acg", "nature", 262 | "star", "color", "car", "game", "animal" }; 263 | 264 | private string order = "random"; 265 | public string Order { 266 | set => order = ORDER.Contains(value) ? value : "random"; 267 | get => order; 268 | } 269 | 270 | private string cate = ""; 271 | public string Cate { 272 | set => cate = CATE.Contains(value) ? value : ""; 273 | get => cate; 274 | } 275 | 276 | public int R18 { set; get; } = 0; 277 | 278 | public override bool IsSequential() => false; 279 | 280 | public override BaseProvider GenerateProvider() => new QingbzProvider() { Id = ID }; 281 | 282 | override public string ToString() => $"desktopperiod={DesktopPeriod}&lockperiod={LockPeriod}&order={Order}&cate={Cate}&r18={R18}"; 283 | } 284 | 285 | public class ObzhiIni : BaseIni { 286 | public const string ID = "obzhi"; 287 | public static readonly List ORDER = new List() { "date", "score", "random" }; 288 | public static readonly List CATE = new List() { "", "acg", "specific", "concise", 289 | "nature", "portrait", "game", "animal" }; 290 | 291 | private string order = "random"; 292 | public string Order { 293 | set => order = ORDER.Contains(value) ? value : "random"; 294 | get => order; 295 | } 296 | 297 | private string cate = ""; 298 | public string Cate { 299 | set => cate = CATE.Contains(value) ? value : ""; 300 | get => cate; 301 | } 302 | 303 | public int R18 { set; get; } = 0; 304 | 305 | public override bool IsSequential() => false; 306 | 307 | public override BaseProvider GenerateProvider() => new ObzhiProvider() { Id = ID }; 308 | 309 | override public string ToString() => $"desktopperiod={DesktopPeriod}&lockperiod={LockPeriod}&order={Order}&cate={Cate}&r18={R18}"; 310 | } 311 | 312 | public class G3Ini : BaseIni { 313 | public const string ID = "3g"; 314 | private readonly HashSet ORDER = new HashSet() { "date", "view" }; 315 | 316 | private string order = "date"; 317 | public string Order { 318 | set => order = ORDER.Contains(value) ? value : "date"; 319 | get => order; 320 | } 321 | 322 | public override bool IsSequential() => false; 323 | 324 | public override BaseProvider GenerateProvider() => new G3Provider() { Id = ID }; 325 | 326 | override public string ToString() => $"desktopperiod={DesktopPeriod}&lockperiod={LockPeriod}&order={Order}"; 327 | } 328 | 329 | public class WallhereIni : BaseIni { 330 | public const string ID = "wallhere"; 331 | public static readonly List ORDER = new List() { "date", "score", "random" }; 332 | public static readonly List CATE = new List() { "", "acg", "photograph" }; 333 | 334 | private string order = "random"; 335 | public string Order { 336 | set => order = ORDER.Contains(value) ? value : "random"; 337 | get => order; 338 | } 339 | 340 | private string cate = ""; 341 | public string Cate { 342 | set => cate = CATE.Contains(value) ? value : ""; 343 | get => cate; 344 | } 345 | 346 | public int R18 { set; get; } = 0; 347 | 348 | public override bool IsSequential() => false; 349 | 350 | public override BaseProvider GenerateProvider() => new WallhereProvider() { Id = ID }; 351 | 352 | override public string ToString() => $"desktopperiod={DesktopPeriod}&lockperiod={LockPeriod}&order={Order}&cate={Cate}&r18={R18}"; 353 | } 354 | 355 | public class AbyssIni : BaseIni { 356 | public const string ID = "abyss"; 357 | 358 | public override bool IsSequential() => false; 359 | 360 | public override BaseProvider GenerateProvider() => new AbyssProvider() { Id = ID }; 361 | 362 | override public string ToString() => $"desktopperiod={DesktopPeriod}&lockperiod={LockPeriod}"; 363 | } 364 | 365 | public class DaihanIni : BaseIni { 366 | public const string ID = "daihan"; 367 | 368 | public override bool IsSequential() => false; 369 | 370 | public override BaseProvider GenerateProvider() => new DaihanProvider() { Id = ID }; 371 | 372 | override public string ToString() => $"desktopperiod={DesktopPeriod}&lockperiod={LockPeriod}"; 373 | } 374 | 375 | public class DmoeIni : BaseIni { 376 | public const string ID = "dmoe"; 377 | 378 | public override bool IsSequential() => false; 379 | 380 | public override BaseProvider GenerateProvider() => new DmoeProvider() { Id = ID }; 381 | 382 | override public string ToString() => $"desktopperiod={DesktopPeriod}&lockperiod={LockPeriod}"; 383 | } 384 | 385 | public class ToubiecIni : BaseIni { 386 | public const string ID = "toubiec"; 387 | 388 | public override bool IsSequential() => false; 389 | 390 | public override BaseProvider GenerateProvider() => new ToubiecProvider() { Id = ID }; 391 | 392 | override public string ToString() => $"desktopperiod={DesktopPeriod}&lockperiod={LockPeriod}"; 393 | } 394 | 395 | public class MtyIni : BaseIni { 396 | public const string ID = "mty"; 397 | 398 | public override bool IsSequential() => false; 399 | 400 | public override BaseProvider GenerateProvider() => new MtyProvider() { Id = ID }; 401 | 402 | override public string ToString() => $"desktopperiod={DesktopPeriod}&lockperiod={LockPeriod}"; 403 | } 404 | 405 | public class SeovxIni : BaseIni { 406 | public const string ID = "seovx"; 407 | private readonly HashSet CATE = new HashSet() { "", "d", "ha" }; 408 | 409 | private string cate = "d"; 410 | public string Cate { 411 | set => cate = CATE.Contains(value) ? value : "d"; 412 | get => cate; 413 | } 414 | 415 | public override bool IsSequential() => false; 416 | 417 | public override BaseProvider GenerateProvider() => new SeovxProvider() { Id = ID }; 418 | 419 | override public string ToString() => $"desktopperiod={DesktopPeriod}&lockperiod={LockPeriod}&cate={Cate}"; 420 | } 421 | } 422 | -------------------------------------------------------------------------------- /TimelineWallpaper.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | x86 7 | {C3BF495A-6BF6-4D5B-9ED9-2C3213399FB8} 8 | AppContainerExe 9 | Properties 10 | TimelineWallpaper 11 | TimelineWallpaper 12 | en-US 13 | UAP 14 | 10.0.22000.0 15 | 10.0.19041.0 16 | 14 17 | 512 18 | {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 19 | true 20 | True 21 | False 22 | TimelineWallpaper_TemporaryKey.pfx 23 | SHA256 24 | True 25 | False 26 | Auto 27 | x64 28 | D:\uwp\TimelineWallpaper\AppPackages 29 | 0 30 | True 31 | True 32 | D:\uwp\TimelineWallpaper\AppPackages\ 33 | 34 | 35 | true 36 | bin\x86\Debug\ 37 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP 38 | ;2008 39 | full 40 | x86 41 | false 42 | prompt 43 | true 44 | 45 | 46 | bin\x86\Release\ 47 | TRACE;NETFX_CORE;WINDOWS_UWP 48 | true 49 | ;2008 50 | pdbonly 51 | x86 52 | false 53 | prompt 54 | true 55 | true 56 | 57 | 58 | true 59 | bin\ARM\Debug\ 60 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP 61 | ;2008 62 | full 63 | ARM 64 | false 65 | prompt 66 | true 67 | 68 | 69 | bin\ARM\Release\ 70 | TRACE;NETFX_CORE;WINDOWS_UWP 71 | true 72 | ;2008 73 | pdbonly 74 | ARM 75 | false 76 | prompt 77 | true 78 | true 79 | 80 | 81 | true 82 | bin\ARM64\Debug\ 83 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP 84 | ;2008 85 | full 86 | ARM64 87 | false 88 | prompt 89 | true 90 | true 91 | 92 | 93 | bin\ARM64\Release\ 94 | TRACE;NETFX_CORE;WINDOWS_UWP 95 | true 96 | ;2008 97 | pdbonly 98 | ARM64 99 | false 100 | prompt 101 | true 102 | true 103 | 104 | 105 | true 106 | bin\x64\Debug\ 107 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP 108 | ;2008 109 | full 110 | x64 111 | false 112 | prompt 113 | true 114 | true 115 | false 116 | 117 | 118 | bin\x64\Release\ 119 | TRACE;NETFX_CORE;WINDOWS_UWP 120 | true 121 | ;2008 122 | pdbonly 123 | x64 124 | false 125 | prompt 126 | true 127 | true 128 | 129 | 130 | PackageReference 131 | 132 | 133 | 134 | App.xaml 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | ContributeDlg.xaml 153 | 154 | 155 | DonateDlg.xaml 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | ReviewDlg.xaml 174 | 175 | 176 | 177 | SettingsView.xaml 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | MainPage.xaml 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | Designer 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | Designer 267 | 268 | 269 | 270 | 271 | MSBuild:Compile 272 | Designer 273 | 274 | 275 | Designer 276 | MSBuild:Compile 277 | 278 | 279 | Designer 280 | MSBuild:Compile 281 | 282 | 283 | MSBuild:Compile 284 | Designer 285 | 286 | 287 | Designer 288 | MSBuild:Compile 289 | 290 | 291 | Designer 292 | MSBuild:Compile 293 | 294 | 295 | 296 | 297 | 6.2.13 298 | 299 | 300 | 2.7.1 301 | 302 | 303 | 13.0.1 304 | 305 | 306 | 1.26.0 307 | 308 | 309 | 310 | 311 | Designer 312 | 313 | 314 | 315 | 316 | {c8b76130-7de6-469c-9051-d8cb783329fc} 317 | TimelineWallpaperService 318 | 319 | 320 | 321 | 14.0 322 | 323 | 324 | 331 | --------------------------------------------------------------------------------