commit face3bfa69c288e24c93fa1697b721669d12dfb9 Author: 姚彪 <1315508912@qq.com> Date: Sat Nov 25 21:59:48 2023 +0800 feat: 首次完成测试 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7d5a1ed --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +.idea/ +.vs/ +.vs_code/ +**/.DS_Store + +*/**/obj +*/**/bin + +DownKyi.sln.DotSettings.user \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Bangumi/BangumiInfo.cs b/DownKyi.Core/BiliApi/Bangumi/BangumiInfo.cs new file mode 100644 index 0000000..65d9a86 --- /dev/null +++ b/DownKyi.Core/BiliApi/Bangumi/BangumiInfo.cs @@ -0,0 +1,86 @@ +using DownKyi.Core.BiliApi.Bangumi.Models; +using DownKyi.Core.Logging; +using Newtonsoft.Json; +using Console = DownKyi.Core.Utils.Debugging.Console; + +namespace DownKyi.Core.BiliApi.Bangumi; + +public static class BangumiInfo +{ + /// + /// 剧集基本信息(mediaId方式) + /// + /// + /// + public static BangumiMedia BangumiMediaInfo(long mediaId) + { + string url = $"https://api.bilibili.com/pgc/review/user?media_id={mediaId}"; + string referer = "https://www.bilibili.com"; + string response = WebClient.RequestWeb(url, referer); + + try + { + var media = JsonConvert.DeserializeObject(response); + if (media != null && media.Result != null) + { + return media.Result.Media; + } + else + { + return null; + } + } + catch (Exception e) + { + Console.PrintLine("BangumiMediaInfo()发生异常: {0}", e); + LogManager.Error("BangumiInfo", e); + return null; + } + } + + /// + /// 获取剧集明细(web端)(seasonId/episodeId方式) + /// + /// + /// + /// + public static BangumiSeason BangumiSeasonInfo(long seasonId = -1, long episodeId = -1) + { + string baseUrl = "https://api.bilibili.com/pgc/view/web/season"; + string referer = "https://www.bilibili.com"; + string url; + if (seasonId > -1) + { + url = $"{baseUrl}?season_id={seasonId}"; + } + else if (episodeId > -1) + { + url = $"{baseUrl}?ep_id={episodeId}"; + } + else + { + return null; + } + + string response = WebClient.RequestWeb(url, referer); + + try + { + var bangumiSeason = JsonConvert.DeserializeObject(response); + if (bangumiSeason != null) + { + return bangumiSeason.Result; + } + else + { + return null; + } + } + catch (Exception e) + { + Console.PrintLine("BangumiSeasonInfo()发生异常: {0}", e); + LogManager.Error("BangumiInfo", e); + return null; + } + } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Bangumi/BangumiType.cs b/DownKyi.Core/BiliApi/Bangumi/BangumiType.cs new file mode 100644 index 0000000..99d233e --- /dev/null +++ b/DownKyi.Core/BiliApi/Bangumi/BangumiType.cs @@ -0,0 +1,32 @@ +namespace DownKyi.Core.BiliApi.Bangumi; + +public static class BangumiType +{ + public static Dictionary Type = new Dictionary() + { + { 1, "Anime" }, + { 2, "Movie" }, + { 3, "Documentary" }, + { 4, "Guochuang" }, + { 5, "TV" }, + { 6, "Unknown" }, + { 7, "Entertainment" }, + { 8, "Unknown" }, + { 9, "Unknown" }, + { 10, "Unknown" } + }; + + public static Dictionary TypeId = new Dictionary() + { + { 1, 13 }, + { 2, 23 }, + { 3, 177 }, + { 4, 167 }, + { 5, 11 }, + { 6, -1 }, + { 7, -1 }, + { 8, -1 }, + { 9, -1 }, + { 10, -1 } + }; +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Bangumi/Models/BangumiArea.cs b/DownKyi.Core/BiliApi/Bangumi/Models/BangumiArea.cs new file mode 100644 index 0000000..065a778 --- /dev/null +++ b/DownKyi.Core/BiliApi/Bangumi/Models/BangumiArea.cs @@ -0,0 +1,10 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Bangumi.Models; + +public class BangumiArea : BaseModel +{ + [JsonProperty("id")] public int Id { get; set; } + [JsonProperty("name")] public string Name { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Bangumi/Models/BangumiEpisode.cs b/DownKyi.Core/BiliApi/Bangumi/Models/BangumiEpisode.cs new file mode 100644 index 0000000..348f3ca --- /dev/null +++ b/DownKyi.Core/BiliApi/Bangumi/Models/BangumiEpisode.cs @@ -0,0 +1,39 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Bangumi.Models; + +public class BangumiEpisode : BaseModel +{ + [JsonProperty("aid")] public long Aid { get; set; } + + [JsonProperty("badge")] public string Badge { get; set; } + + // badge_info + // badge_type + [JsonProperty("bvid")] public string Bvid { get; set; } + [JsonProperty("cid")] public long Cid { get; set; } + [JsonProperty("cover")] public string Cover { get; set; } + [JsonProperty("dimension")] public Dimension Dimension { get; set; } + [JsonProperty("duration")] public long Duration { get; set; } + [JsonProperty("from")] public string From { get; set; } + [JsonProperty("id")] public long Id { get; set; } + [JsonProperty("link")] public string Link { get; set; } + [JsonProperty("long_title")] public string LongTitle { get; set; } + + [JsonProperty("pub_time")] public long PubTime { get; set; } + + // pv + // release_date + // rights + [JsonProperty("share_copy")] public string ShareCopy { get; set; } + [JsonProperty("share_url")] public string ShareUrl { get; set; } + + [JsonProperty("short_link")] public string ShortLink { get; set; } + + // stat + [JsonProperty("status")] public int Status { get; set; } + [JsonProperty("subtitle")] public string Subtitle { get; set; } + [JsonProperty("title")] public string Title { get; set; } + [JsonProperty("vid")] public string Vid { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Bangumi/Models/BangumiMedia.cs b/DownKyi.Core/BiliApi/Bangumi/Models/BangumiMedia.cs new file mode 100644 index 0000000..59e5003 --- /dev/null +++ b/DownKyi.Core/BiliApi/Bangumi/Models/BangumiMedia.cs @@ -0,0 +1,36 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Bangumi.Models; + +// https://api.bilibili.com/pgc/review/user +public class BangumiMediaOrigin : BaseModel +{ + //[JsonProperty("code")] + //public int Code { get; set; } + //[JsonProperty("message")] + //public string Message { get; set; } + //[JsonProperty("ttl")] + //public int Ttl { get; set; } + [JsonProperty("result")] public BangumiMediaData Result { get; set; } +} + +public class BangumiMediaData : BaseModel +{ + [JsonProperty("media")] public BangumiMedia Media { get; set; } +} + +public class BangumiMedia : BaseModel +{ + [JsonProperty("areas")] public List Areas { get; set; } + [JsonProperty("cover")] public string Cover { get; set; } + + [JsonProperty("media_id")] public long MediaId { get; set; } + + // new_ep + // rating + [JsonProperty("season_id")] public long SeasonId { get; set; } + [JsonProperty("share_url")] public string ShareUrl { get; set; } + [JsonProperty("title")] public string Title { get; set; } + [JsonProperty("type_name")] public string TypeName { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Bangumi/Models/BangumiPositive.cs b/DownKyi.Core/BiliApi/Bangumi/Models/BangumiPositive.cs new file mode 100644 index 0000000..473a7bd --- /dev/null +++ b/DownKyi.Core/BiliApi/Bangumi/Models/BangumiPositive.cs @@ -0,0 +1,10 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Bangumi.Models; + +public class BangumiPositive : BaseModel +{ + [JsonProperty("id")] public long Id { get; set; } + [JsonProperty("title")] public string Title { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Bangumi/Models/BangumiSeason.cs b/DownKyi.Core/BiliApi/Bangumi/Models/BangumiSeason.cs new file mode 100644 index 0000000..8788532 --- /dev/null +++ b/DownKyi.Core/BiliApi/Bangumi/Models/BangumiSeason.cs @@ -0,0 +1,65 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Bangumi.Models; + +// https://api.bilibili.com/pgc/view/web/season +public class BangumiSeasonOrigin : BaseModel +{ + //[JsonProperty("code")] + //public int Code { get; set; } + //[JsonProperty("message")] + //public string Message { get; set; } + //[JsonProperty("ttl")] + //public int Ttl { get; set; } + [JsonProperty("result")] public BangumiSeason Result { get; set; } +} + +public class BangumiSeason : BaseModel +{ + // activity + // alias + [JsonProperty("areas")] public List Areas { get; set; } + [JsonProperty("bkg_cover")] public string BkgCover { get; set; } + [JsonProperty("cover")] public string Cover { get; set; } + [JsonProperty("episodes")] public List Episodes { get; set; } + + [JsonProperty("evaluate")] public string Evaluate { get; set; } + + // freya + // jp_title + [JsonProperty("link")] public string Link { get; set; } + + [JsonProperty("media_id")] public long MediaId { get; set; } + + // mode + // new_ep + // payment + [JsonProperty("positive")] public BangumiPositive Positive { get; set; } + + // publish + // rating + // record + // rights + [JsonProperty("season_id")] public long SeasonId { get; set; } + [JsonProperty("season_title")] public string SeasonTitle { get; set; } + [JsonProperty("seasons")] public List Seasons { get; set; } + + [JsonProperty("section")] public List Section { get; set; } + + // series + // share_copy + // share_sub_title + // share_url + // show + [JsonProperty("square_cover")] public string SquareCover { get; set; } + + [JsonProperty("stat")] public BangumiStat Stat { get; set; } + + // status + [JsonProperty("subtitle")] public string Subtitle { get; set; } + [JsonProperty("title")] public string Title { get; set; } + [JsonProperty("total")] public int Total { get; set; } + [JsonProperty("type")] public int Type { get; set; } + [JsonProperty("up_info")] public BangumiUpInfo UpInfo { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Bangumi/Models/BangumiSeasonInfo.cs b/DownKyi.Core/BiliApi/Bangumi/Models/BangumiSeasonInfo.cs new file mode 100644 index 0000000..5b820d8 --- /dev/null +++ b/DownKyi.Core/BiliApi/Bangumi/Models/BangumiSeasonInfo.cs @@ -0,0 +1,22 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Bangumi.Models; + +public class BangumiSeasonInfo : BaseModel +{ + [JsonProperty("badge")] public string Badge { get; set; } + + // badge_info + // badge_type + [JsonProperty("cover")] public string Cover { get; set; } + + [JsonProperty("media_id")] public long MediaId { get; set; } + + // new_ep + [JsonProperty("season_id")] public long SeasonId { get; set; } + [JsonProperty("season_title")] public string SeasonTitle { get; set; } + + [JsonProperty("season_type")] public int SeasonType { get; set; } + // stat +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Bangumi/Models/BangumiSection.cs b/DownKyi.Core/BiliApi/Bangumi/Models/BangumiSection.cs new file mode 100644 index 0000000..e383c49 --- /dev/null +++ b/DownKyi.Core/BiliApi/Bangumi/Models/BangumiSection.cs @@ -0,0 +1,13 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Bangumi.Models; + +public class BangumiSection : BaseModel +{ + [JsonProperty("episode_id")] public long EpisodeId { get; set; } + [JsonProperty("episodes")] public List Episodes { get; set; } + [JsonProperty("id")] public long Id { get; set; } + [JsonProperty("title")] public string Title { get; set; } + [JsonProperty("type")] public int Type { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Bangumi/Models/BangumiStat.cs b/DownKyi.Core/BiliApi/Bangumi/Models/BangumiStat.cs new file mode 100644 index 0000000..6e7121a --- /dev/null +++ b/DownKyi.Core/BiliApi/Bangumi/Models/BangumiStat.cs @@ -0,0 +1,16 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Bangumi.Models; + +public class BangumiStat : BaseModel +{ + [JsonProperty("coins")] public long Coins { get; set; } + [JsonProperty("danmakus")] public long Danmakus { get; set; } + [JsonProperty("favorite")] public long Favorite { get; set; } + [JsonProperty("favorites")] public long Favorites { get; set; } + [JsonProperty("likes")] public long Likes { get; set; } + [JsonProperty("reply")] public long Reply { get; set; } + [JsonProperty("share")] public long Share { get; set; } + [JsonProperty("views")] public long Views { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Bangumi/Models/BangumiUpInfo.cs b/DownKyi.Core/BiliApi/Bangumi/Models/BangumiUpInfo.cs new file mode 100644 index 0000000..d6ee4d1 --- /dev/null +++ b/DownKyi.Core/BiliApi/Bangumi/Models/BangumiUpInfo.cs @@ -0,0 +1,20 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Bangumi.Models; + +public class BangumiUpInfo : BaseModel +{ + [JsonProperty("avatar")] public string Avatar { get; set; } + + // follower + // is_follow + [JsonProperty("mid")] public long Mid { get; set; } + + // pendant + // theme_type + [JsonProperty("uname")] public string Name { get; set; } + // verify_type + // vip_status + // vip_type +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/BiliUtils/BvId.cs b/DownKyi.Core/BiliApi/BiliUtils/BvId.cs new file mode 100644 index 0000000..bf63532 --- /dev/null +++ b/DownKyi.Core/BiliApi/BiliUtils/BvId.cs @@ -0,0 +1,59 @@ +namespace DownKyi.Core.BiliApi.BiliUtils; + +public static class BvId +{ + private const string tableStr = "fZodR9XQDSUm21yCkr6zBqiveYah8bt4xsWpHnJE7jL5VG3guMTKNPAwcF"; //码表 + private static readonly char[] table = tableStr.ToCharArray(); + + private static readonly char[] tr = new char[124]; //反查码表 + private const ulong Xor = 177451812; //固定异或值 + private const ulong add = 8728348608; //固定加法值 + private static readonly int[] s = { 11, 10, 3, 8, 4, 6 }; //位置编码表 + + static BvId() + { + Tr_init(); + } + + //初始化反查码表 + private static void Tr_init() + { + for (int i = 0; i < 58; i++) + tr[table[i]] = (char)i; + } + + /// + /// bvid转avid + /// + /// + /// + public static ulong Bv2Av(string bvid) + { + char[] bv = bvid.ToCharArray(); + + ulong r = 0; + ulong av; + for (int i = 0; i < 6; i++) + r += tr[bv[s[i]]] * (ulong)Math.Pow(58, i); + av = (r - add) ^ Xor; + return av; + } + + /// + /// avid转bvid + /// + /// + /// + public static string Av2Bv(ulong av) + { + //编码结果 + string res = "BV1 4 1 7 "; + char[] result = res.ToCharArray(); + + av = (av ^ Xor) + add; + for (int i = 0; i < 6; i++) + result[s[i]] = table[av / (ulong)Math.Pow(58, i) % 58]; + string bv = new string(result); + return bv; + } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/BiliUtils/Constant.cs b/DownKyi.Core/BiliApi/BiliUtils/Constant.cs new file mode 100644 index 0000000..47ac3ca --- /dev/null +++ b/DownKyi.Core/BiliApi/BiliUtils/Constant.cs @@ -0,0 +1,74 @@ +namespace DownKyi.Core.BiliApi.BiliUtils; + +public static class Constant +{ + private static readonly List resolutions = new List + { + new() { Name = "360P 流畅", Id = 16 }, + new() { Name = "480P 清晰", Id = 32 }, + new() { Name = "720P 高清", Id = 64 }, + new() { Name = "720P 60帧", Id = 74 }, + new() { Name = "1080P 高清", Id = 80 }, + new() { Name = "1080P 高码率", Id = 112 }, + new() { Name = "1080P 60帧", Id = 116 }, + new() { Name = "4K 超清", Id = 120 }, + new() { Name = "HDR 真彩", Id = 125 }, + new() { Name = "杜比视界", Id = 126 }, + new() { Name = "超高清 8K", Id = 127 }, + }; + + private static readonly List codecIds = new List + { + new() { Name = "H.264/AVC", Id = 7 }, + new() { Name = "H.265/HEVC", Id = 12 }, + new() { Name = "AV1", Id = 13 }, + }; + + private static readonly List qualities = new List + { + //new Quality { Name = "64K", Id = 30216 }, + //new Quality { Name = "132K", Id = 30232 }, + //new Quality { Name = "192K", Id = 30280 }, + new() { Name = "低质量", Id = 30216 }, + new() { Name = "中质量", Id = 30232 }, + new() { Name = "高质量", Id = 30280 }, + new() { Name = "Dolby Atmos", Id = 30250 }, + new() { Name = "Hi-Res无损", Id = 30251 }, + }; + + /// + /// 获取支持的视频画质 + /// + /// + public static List GetResolutions() + { + // 使用深复制, + // 保证外部修改list后, + // 不会影响其他调用处 + return new List(resolutions); + } + + /// + /// 获取视频编码代码 + /// + /// + public static List GetCodecIds() + { + // 使用深复制, + // 保证外部修改list后, + // 不会影响其他调用处 + return new List(codecIds); + } + + /// + /// 获取支持的视频音质 + /// + /// + public static List GetAudioQualities() + { + // 使用深复制, + // 保证外部修改list后, + // 不会影响其他调用处 + return new List(qualities); + } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/BiliUtils/DanmakuSender.cs b/DownKyi.Core/BiliApi/BiliUtils/DanmakuSender.cs new file mode 100644 index 0000000..0ede811 --- /dev/null +++ b/DownKyi.Core/BiliApi/BiliUtils/DanmakuSender.cs @@ -0,0 +1,157 @@ +namespace DownKyi.Core.BiliApi.BiliUtils; + +public static class DanmakuSender +{ + private const uint CRCPOLYNOMIAL = 0xEDB88320; + private static readonly uint[] crctable = new uint[256]; + + static DanmakuSender() + { + CreateTable(); + } + + private static void CreateTable() + { + for (int i = 0; i < 256; i++) + { + uint crcreg = (uint)i; + + for (int j = 0; j < 8; j++) + { + if ((crcreg & 1) != 0) + { + crcreg = CRCPOLYNOMIAL ^ (crcreg >> 1); + } + else + { + crcreg >>= 1; + } + } + + crctable[i] = crcreg; + } + } + + private static uint Crc32(string userId) + { + uint crcstart = 0xFFFFFFFF; + for (int i = 0; i < userId.Length; i++) + { + uint index = (uint)(crcstart ^ (int)userId[i]) & 255; + crcstart = (crcstart >> 8) ^ crctable[index]; + } + + return crcstart; + } + + private static uint Crc32LastIndex(string userId) + { + uint index = 0; + uint crcstart = 0xFFFFFFFF; + for (int i = 0; i < userId.Length; i++) + { + index = (uint)((crcstart ^ (int)userId[i]) & 255); + crcstart = (crcstart >> 8) ^ crctable[index]; + } + + return index; + } + + private static int GetCrcIndex(long t) + { + for (int i = 0; i < 256; i++) + { + if ((crctable[i] >> 24) == t) + { + return i; + } + } + + return -1; + } + + private static object[] DeepCheck(int i, int[] index) + { + object[] resultArray = new object[2]; + + string result = ""; + uint tc; // = 0x00; + var hashcode = Crc32(i.ToString()); + tc = (uint)(hashcode & 0xff ^ index[2]); + + if (!(tc <= 57 && tc >= 48)) + { + resultArray[0] = 0; + return resultArray; + } + + result += (tc - 48).ToString(); + hashcode = crctable[index[2]] ^ (hashcode >> 8); + tc = (uint)(hashcode & 0xff ^ index[1]); + + if (!(tc <= 57 && tc >= 48)) + { + resultArray[0] = 0; + return resultArray; + } + + result += (tc - 48).ToString(); + hashcode = crctable[index[1]] ^ (hashcode >> 8); + tc = (uint)(hashcode & 0xff ^ index[0]); + + if (!(tc <= 57 && tc >= 48)) + { + resultArray[0] = 0; + return resultArray; + } + + result += (tc - 48).ToString(); + //hashcode = crctable[index[0]] ^ (hashcode >> 8); + + resultArray[0] = 1; + resultArray[1] = result; + return resultArray; + } + + /// + /// 查询弹幕发送者 + /// + /// + /// + public static string FindDanmakuSender(string userId) + { + object[] deepCheckData = new object[2]; + + int[] index = new int[4]; + uint ht = (uint)Convert.ToInt32($"0x{userId}", 16); + ht ^= 0xffffffff; + + int i; + for (i = 3; i > -1; i--) + { + index[3 - i] = GetCrcIndex(ht >> (i * 8)); + uint snum = crctable[index[3 - i]]; + ht ^= snum >> ((3 - i) * 8); + } + + for (i = 0; i < 100000000; i++) + { + uint lastindex = Crc32LastIndex(i.ToString()); + if (lastindex == index[3]) + { + deepCheckData = DeepCheck(i, index); + if ((int)deepCheckData[0] != 0) + { + break; + } + } + } + + if (i == 100000000) + { + return "-1"; + } + + return $"{i}{deepCheckData[1]}"; + } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/BiliUtils/ParseEntrance.cs b/DownKyi.Core/BiliApi/BiliUtils/ParseEntrance.cs new file mode 100644 index 0000000..2d20a96 --- /dev/null +++ b/DownKyi.Core/BiliApi/BiliUtils/ParseEntrance.cs @@ -0,0 +1,575 @@ +using DownKyi.Core.Utils.Validator; +using System.Text.RegularExpressions; + +namespace DownKyi.Core.BiliApi.BiliUtils; + +/// +/// 解析输入的字符串 +/// 支持的格式有: +/// av号:av170001, AV170001, https://www.bilibili.com/video/av170001 +/// BV号:BV17x411w7KC, https://www.bilibili.com/video/BV17x411w7KC, https://b23.tv/BV17x411w7KC +/// 番剧(电影、电视剧)ss号:ss32982, SS32982, https://www.bilibili.com/bangumi/play/ss32982 +/// 番剧(电影、电视剧)ep号:ep317925, EP317925, https://www.bilibili.com/bangumi/play/ep317925 +/// 番剧(电影、电视剧)md号:md28228367, MD28228367, https://www.bilibili.com/bangumi/media/md28228367 +/// 课程ss号:https://www.bilibili.com/cheese/play/ss205 +/// 课程ep号:https://www.bilibili.com/cheese/play/ep3489 +/// 收藏夹:ml1329019876, ML1329019876, https://www.bilibili.com/medialist/detail/ml1329019876, https://www.bilibili.com/medialist/play/ml1329019876/ +/// 用户空间:uid928123, UID928123, uid:928123, UID:928123, https://space.bilibili.com/928123 +/// +public static class ParseEntrance +{ + public static readonly string WwwUrl = "https://www.bilibili.com"; + public static readonly string ShareWwwUrl = "https://www.bilibili.com/s"; + public static readonly string ShortUrl = "https://b23.tv/"; + public static readonly string MobileUrl = "https://m.bilibili.com"; + + public static readonly string SpaceUrl = "https://space.bilibili.com"; + + public static readonly string VideoUrl = $"{WwwUrl}/video/"; + public static readonly string BangumiUrl = $"{WwwUrl}/bangumi/play/"; + public static readonly string BangumiMediaUrl = $"{WwwUrl}/bangumi/media/"; + public static readonly string CheeseUrl = $"{WwwUrl}/cheese/play/"; + public static readonly string FavoritesUrl1 = $"{WwwUrl}/medialist/detail/"; + public static readonly string FavoritesUrl2 = $"{WwwUrl}/medialist/play/"; + + #region 视频 + + /// + /// 是否为av id + /// + /// + /// + public static bool IsAvId(string input) + { + return IsIntId(input, "av"); + } + + /// + /// 是否为av url + /// + /// + /// + public static bool IsAvUrl(string input) + { + string id = GetVideoId(input); + return IsAvId(id); + } + + /// + /// 获取av id + /// + /// + /// + public static long GetAvId(string input) + { + if (IsAvId(input)) + { + return Number.GetInt(input.Remove(0, 2)); + } + else if (IsAvUrl(input)) + { + return Number.GetInt(GetVideoId(input).Remove(0, 2)); + } + else + { + return -1; + } + } + + /// + /// 是否为bv id + /// + /// + /// + public static bool IsBvId(string input) + { + return input.StartsWith("BV") && input.Length == 12; + } + + /// + /// 是否为bv url + /// + /// + /// + public static bool IsBvUrl(string input) + { + string id = GetVideoId(input); + return IsBvId(id); + } + + /// + /// 获取bv id + /// + /// + /// + public static string GetBvId(string input) + { + if (IsBvId(input)) + { + return input; + } + else if (IsBvUrl(input)) + { + return GetVideoId(input); + } + else + { + return ""; + } + } + + #endregion + + #region 番剧(电影、电视剧) + + /// + /// 是否为番剧season id + /// + /// + /// + public static bool IsBangumiSeasonId(string input) + { + return IsIntId(input, "ss"); + } + + /// + /// 是否为番剧season url + /// + /// + /// + public static bool IsBangumiSeasonUrl(string input) + { + string id = GetBangumiId(input); + return IsBangumiSeasonId(id); + } + + /// + /// 获取番剧season id + /// + /// + /// + public static long GetBangumiSeasonId(string input) + { + if (IsBangumiSeasonId(input)) + { + return Number.GetInt(input.Remove(0, 2)); + } + else if (IsBangumiSeasonUrl(input)) + { + return Number.GetInt(GetBangumiId(input).Remove(0, 2)); + } + else + { + return -1; + } + } + + /// + /// 是否为番剧episode id + /// + /// + /// + public static bool IsBangumiEpisodeId(string input) + { + return IsIntId(input, "ep"); + } + + /// + /// 是否为番剧episode url + /// + /// + /// + public static bool IsBangumiEpisodeUrl(string input) + { + string id = GetBangumiId(input); + return IsBangumiEpisodeId(id); + } + + /// + /// 获取番剧episode id + /// + /// + /// + public static long GetBangumiEpisodeId(string input) + { + if (IsBangumiEpisodeId(input)) + { + return Number.GetInt(input.Remove(0, 2)); + } + else if (IsBangumiEpisodeUrl(input)) + { + return Number.GetInt(GetBangumiId(input).Remove(0, 2)); + } + else + { + return -1; + } + } + + /// + /// 是否为番剧media id + /// + /// + /// + public static bool IsBangumiMediaId(string input) + { + return IsIntId(input, "md"); + } + + /// + /// 是否为番剧media url + /// + /// + /// + public static bool IsBangumiMediaUrl(string input) + { + string id = GetBangumiId(input); + return IsBangumiMediaId(id); + } + + /// + /// 获取番剧media id + /// + /// + /// + public static long GetBangumiMediaId(string input) + { + if (IsBangumiMediaId(input)) + { + return Number.GetInt(input.Remove(0, 2)); + } + else if (IsBangumiMediaUrl(input)) + { + return Number.GetInt(GetBangumiId(input).Remove(0, 2)); + } + else + { + return -1; + } + } + + #endregion + + #region 课程 + + /// + /// 是否为课程season url + /// + /// + /// + public static bool IsCheeseSeasonUrl(string input) + { + string id = GetCheeseId(input); + return IsIntId(id, "ss"); + } + + /// + /// 获取课程season id + /// + /// + /// + public static long GetCheeseSeasonId(string input) + { + return IsCheeseSeasonUrl(input) ? Number.GetInt(GetCheeseId(input).Remove(0, 2)) : -1; + } + + /// + /// 是否为课程episode url + /// + /// + /// + public static bool IsCheeseEpisodeUrl(string input) + { + string id = GetCheeseId(input); + return IsIntId(id, "ep"); + } + + /// + /// 获取课程episode id + /// + /// + /// + public static long GetCheeseEpisodeId(string input) + { + return IsCheeseEpisodeUrl(input) ? Number.GetInt(GetCheeseId(input).Remove(0, 2)) : -1; + } + + #endregion + + #region 收藏夹 + + /// + /// 是否为收藏夹id + /// + /// + /// + public static bool IsFavoritesId(string input) + { + return IsIntId(input, "ml"); + } + + /// + /// 是否为收藏夹url + /// + /// + /// + public static bool IsFavoritesUrl(string input) + { + return IsFavoritesUrl1(input) || IsFavoritesUrl2(input); + } + + /// + /// 是否为收藏夹url1 + /// + /// + /// + private static bool IsFavoritesUrl1(string input) + { + string favoritesId = GetId(input, FavoritesUrl1); + return IsFavoritesId(favoritesId); + } + + /// + /// 是否为收藏夹ur2 + /// + /// + /// + private static bool IsFavoritesUrl2(string input) + { + string favoritesId = GetId(input, FavoritesUrl2); + return IsFavoritesId(favoritesId.Split('/')[0]); + } + + /// + /// 获取收藏夹id + /// + /// + /// + public static long GetFavoritesId(string input) + { + if (IsFavoritesId(input)) + { + return Number.GetInt(input.Remove(0, 2)); + } + else if (IsFavoritesUrl1(input)) + { + return Number.GetInt(GetId(input, FavoritesUrl1).Remove(0, 2)); + } + else if (IsFavoritesUrl2(input)) + { + return Number.GetInt(GetId(input, FavoritesUrl2).Remove(0, 2).Split('/')[0]); + } + else + { + return -1; + } + } + + #endregion + + #region 用户空间 + + /// + /// 是否为用户id + /// + /// + /// + public static bool IsUserId(string input) + { + if (input.ToLower().StartsWith("uid:")) + { + return Regex.IsMatch(input.Remove(0, 4), @"^\d+$"); + } + else if (input.ToLower().StartsWith("uid")) + { + return Regex.IsMatch(input.Remove(0, 3), @"^\d+$"); + } + else + { + return false; + } + } + + /// + /// 是否为用户空间url + /// + /// + /// + public static bool IsUserUrl(string input) + { + if (!IsUrl(input)) + { + return false; + } + + if (input.Contains("space.bilibili.com")) + { + return true; + } + else + { + return false; + } + } + + /// + /// 获取用户mid + /// + /// + /// + public static long GetUserId(string input) + { + if (input.ToLower().StartsWith("uid:")) + { + return Number.GetInt(input.Remove(0, 4)); + } + else if (input.ToLower().StartsWith("uid")) + { + return Number.GetInt(input.Remove(0, 3)); + } + else if (IsUserUrl(input)) + { + string url = EnableHttps(input); + url = DeleteUrlParam(url); + var match = Regex.Match(url, @"\d+"); + if (match.Success) + { + return long.Parse(match.Value); + } + else + { + return -1; + } + } + else + { + return -1; + } + } + + #endregion + + /// + /// 是否为网址 + /// + /// + /// + private static bool IsUrl(string input) + { + return input.StartsWith("http://") || input.StartsWith("https://"); + } + + /// + /// 将http转为https + /// + /// + private static string EnableHttps(string url) + { + if (!IsUrl(url)) + { + return null; + } + + return url.Replace("http://", "https://"); + } + + /// + /// 去除url中的参数 + /// + /// + /// + private static string DeleteUrlParam(string url) + { + string[] strList = url.Split('?'); + + return strList[0].EndsWith("/") ? strList[0].TrimEnd('/') : strList[0]; + } + + /// + /// 从url中获取视频id(avid/bvid) + /// + /// + /// + private static string GetVideoId(string input) + { + return GetId(input, VideoUrl); + } + + /// + /// 从url中获取番剧id(ss/ep/md) + /// + /// + /// + private static string GetBangumiId(string input) + { + string id = GetId(input, BangumiUrl); + if (id != "") + { + return id; + } + + return GetId(input, BangumiMediaUrl); + } + + /// + /// 从url中获取课程id(ss/ep) + /// + /// + /// + private static string GetCheeseId(string input) + { + return GetId(input, CheeseUrl); + } + + /// + /// 是否为数字型id + /// + /// + /// + /// + private static bool IsIntId(string input, string prefix) + { + if (input.ToLower().StartsWith(prefix)) + { + return Regex.IsMatch(input.Remove(0, 2), @"^\d+$"); + } + + return false; + } + + /// + /// 从url中获取id + /// + /// + /// + /// + private static string GetId(string input, string baseUrl) + { + if (!IsUrl(input)) + { + return ""; + } + + string url = EnableHttps(input); + url = DeleteUrlParam(url); + + url = url.Replace(ShareWwwUrl, WwwUrl); + url = url.Replace(MobileUrl, WwwUrl); + + if (url.Contains("b23.tv/ss") || url.Contains("b23.tv/ep")) + { + url = url.Replace(ShortUrl, BangumiUrl); + } + else + { + url = url.Replace(ShortUrl, VideoUrl); + } + + if (!url.StartsWith(baseUrl)) + { + return ""; + } + + return url.Replace(baseUrl, ""); + } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/BiliUtils/Quality.cs b/DownKyi.Core/BiliApi/BiliUtils/Quality.cs new file mode 100644 index 0000000..3640f37 --- /dev/null +++ b/DownKyi.Core/BiliApi/BiliUtils/Quality.cs @@ -0,0 +1,8 @@ +namespace DownKyi.Core.BiliApi.BiliUtils; + +[Serializable] +public class Quality +{ + public string Name { get; set; } + public int Id { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/BilibiliImages.axaml b/DownKyi.Core/BiliApi/BilibiliImages.axaml new file mode 100644 index 0000000..70f2345 --- /dev/null +++ b/DownKyi.Core/BiliApi/BilibiliImages.axaml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Cheese/CheeseInfo.cs b/DownKyi.Core/BiliApi/Cheese/CheeseInfo.cs new file mode 100644 index 0000000..1b85dba --- /dev/null +++ b/DownKyi.Core/BiliApi/Cheese/CheeseInfo.cs @@ -0,0 +1,88 @@ +using DownKyi.Core.BiliApi.Cheese.Models; +using DownKyi.Core.Logging; +using Newtonsoft.Json; +using Console = DownKyi.Core.Utils.Debugging.Console; + +namespace DownKyi.Core.BiliApi.Cheese; + +public static class CheeseInfo +{ + /// + /// 获取课程基本信息 + /// + /// + /// + /// + public static CheeseView CheeseViewInfo(long seasonId = -1, long episodeId = -1) + { + string baseUrl = "https://api.bilibili.com/pugv/view/web/season"; + string referer = "https://www.bilibili.com"; + string url; + if (seasonId > -1) + { + url = $"{baseUrl}?season_id={seasonId}"; + } + else if (episodeId > -1) + { + url = $"{baseUrl}?ep_id={episodeId}"; + } + else + { + return null; + } + + string response = WebClient.RequestWeb(url, referer); + + try + { + CheeseViewOrigin cheese = JsonConvert.DeserializeObject(response); + if (cheese != null) + { + return cheese.Data; + } + else + { + return null; + } + } + catch (Exception e) + { + Console.PrintLine("CheeseViewInfo()发生异常: {0}", e); + LogManager.Error("CheeseInfo", e); + return null; + } + } + + /// + /// 获取课程分集列表 + /// + /// + /// + /// + /// + public static CheeseEpisodeList CheeseEpisodeList(long seasonId, int ps = 50, int pn = 1) + { + string url = $"https://api.bilibili.com/pugv/view/web/ep/list?season_id={seasonId}&pn={pn}&ps={ps}"; + string referer = "https://www.bilibili.com"; + string response = WebClient.RequestWeb(url, referer); + + try + { + CheeseEpisodeListOrigin cheese = JsonConvert.DeserializeObject(response); + if (cheese != null) + { + return cheese.Data; + } + else + { + return null; + } + } + catch (Exception e) + { + Console.PrintLine("CheeseEpisodeList()发生异常: {0}", e); + LogManager.Error("CheeseInfo", e); + return null; + } + } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Cheese/Models/CheeseBrief.cs b/DownKyi.Core/BiliApi/Cheese/Models/CheeseBrief.cs new file mode 100644 index 0000000..5ba20c0 --- /dev/null +++ b/DownKyi.Core/BiliApi/Cheese/Models/CheeseBrief.cs @@ -0,0 +1,12 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Cheese.Models; + +public class CheeseBrief : BaseModel +{ + // content + [JsonProperty("img")] public List Img { get; set; } + [JsonProperty("title")] public string Title { get; set; } + [JsonProperty("type")] public int Type { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Cheese/Models/CheeseEpisode.cs b/DownKyi.Core/BiliApi/Cheese/Models/CheeseEpisode.cs new file mode 100644 index 0000000..c5dfa37 --- /dev/null +++ b/DownKyi.Core/BiliApi/Cheese/Models/CheeseEpisode.cs @@ -0,0 +1,25 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Cheese.Models; + +public class CheeseEpisode : BaseModel +{ + [JsonProperty("aid")] public long Aid { get; set; } + [JsonProperty("catalogue_index")] public int CatalogueIndex { get; set; } + [JsonProperty("cid")] public long Cid { get; set; } + [JsonProperty("cover")] public string Cover { get; set; } + [JsonProperty("duration")] public long Duration { get; set; } + [JsonProperty("from")] public string From { get; set; } + [JsonProperty("id")] public long Id { get; set; } + [JsonProperty("index")] public int Index { get; set; } + [JsonProperty("page")] public int Page { get; set; } + [JsonProperty("play")] public long Play { get; set; } + [JsonProperty("play_way")] public int PlayWay { get; set; } + [JsonProperty("play_way_format")] public string PlayWayFormat { get; set; } + [JsonProperty("release_date")] public long ReleaseDate { get; set; } + [JsonProperty("status")] public int Status { get; set; } + [JsonProperty("title")] public string Title { get; set; } + [JsonProperty("watched")] public bool Watched { get; set; } + [JsonProperty("watchedHistory")] public int WatchedHistory { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Cheese/Models/CheeseEpisodeList.cs b/DownKyi.Core/BiliApi/Cheese/Models/CheeseEpisodeList.cs new file mode 100644 index 0000000..4f028a6 --- /dev/null +++ b/DownKyi.Core/BiliApi/Cheese/Models/CheeseEpisodeList.cs @@ -0,0 +1,20 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Cheese.Models; + +// https://api.bilibili.com/pugv/view/web/ep/list +public class CheeseEpisodeListOrigin : BaseModel +{ + //[JsonProperty("code")] + //public int Code { get; set; } + //[JsonProperty("message")] + //public string Message { get; set; } + [JsonProperty("data")] public CheeseEpisodeList Data { get; set; } +} + +public class CheeseEpisodeList : BaseModel +{ + [JsonProperty("items")] public List Items { get; set; } + [JsonProperty("page")] public CheeseEpisodePage Page { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Cheese/Models/CheeseEpisodePage.cs b/DownKyi.Core/BiliApi/Cheese/Models/CheeseEpisodePage.cs new file mode 100644 index 0000000..c876eea --- /dev/null +++ b/DownKyi.Core/BiliApi/Cheese/Models/CheeseEpisodePage.cs @@ -0,0 +1,12 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Cheese.Models; + +public class CheeseEpisodePage : BaseModel +{ + [JsonProperty("next")] public bool Next { get; set; } + [JsonProperty("num")] public int Num { get; set; } + [JsonProperty("size")] public int Size { get; set; } + [JsonProperty("total")] public int Total { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Cheese/Models/CheeseImg.cs b/DownKyi.Core/BiliApi/Cheese/Models/CheeseImg.cs new file mode 100644 index 0000000..b630576 --- /dev/null +++ b/DownKyi.Core/BiliApi/Cheese/Models/CheeseImg.cs @@ -0,0 +1,10 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Cheese.Models; + +public class CheeseImg : BaseModel +{ + [JsonProperty("aspect_ratio")] public double AspectRatio { get; set; } + [JsonProperty("url")] public string Url { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Cheese/Models/CheeseStat.cs b/DownKyi.Core/BiliApi/Cheese/Models/CheeseStat.cs new file mode 100644 index 0000000..55b2168 --- /dev/null +++ b/DownKyi.Core/BiliApi/Cheese/Models/CheeseStat.cs @@ -0,0 +1,10 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Cheese.Models; + +public class CheeseStat : BaseModel +{ + [JsonProperty("play")] public long Play { get; set; } + [JsonProperty("play_desc")] public string PlayDesc { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Cheese/Models/CheeseUpInfo.cs b/DownKyi.Core/BiliApi/Cheese/Models/CheeseUpInfo.cs new file mode 100644 index 0000000..296ca9f --- /dev/null +++ b/DownKyi.Core/BiliApi/Cheese/Models/CheeseUpInfo.cs @@ -0,0 +1,15 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Cheese.Models; + +public class CheeseUpInfo : BaseModel +{ + [JsonProperty("avatar")] public string Avatar { get; set; } + [JsonProperty("brief")] public string Brief { get; set; } + [JsonProperty("follower")] public long Follower { get; set; } + [JsonProperty("is_follow")] public int IsFollow { get; set; } + [JsonProperty("link")] public string Link { get; set; } + [JsonProperty("mid")] public long Mid { get; set; } + [JsonProperty("uname")] public string Name { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Cheese/Models/CheeseView.cs b/DownKyi.Core/BiliApi/Cheese/Models/CheeseView.cs new file mode 100644 index 0000000..e98f229 --- /dev/null +++ b/DownKyi.Core/BiliApi/Cheese/Models/CheeseView.cs @@ -0,0 +1,63 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Cheese.Models; + +// https://api.bilibili.com/pugv/view/web/season +public class CheeseViewOrigin : BaseModel +{ + //[JsonProperty("code")] + //public int Code { get; set; } + //[JsonProperty("message")] + //public string Message { get; set; } + [JsonProperty("data")] public CheeseView Data { get; set; } +} + +public class CheeseView : BaseModel +{ + // active_market + // activity_list + [JsonProperty("brief")] public CheeseBrief Brief { get; set; } + + // cooperation + // coupon + // course_content + // courses + [JsonProperty("cover")] public string Cover { get; set; } + + // ep_catalogue + // ep_count + // episode_page + // episode_sort + // episode_tag + [JsonProperty("episodes")] public List Episodes { get; set; } + + // faq + // faq1 + // live_ep_count + // opened_ep_count + // payment + // previewed_purchase_note + // purchase_format_note + // purchase_note + // purchase_protocol + // recommend_seasons 推荐课程 + // release_bottom_info + // release_info + // release_info2 + // release_status + [JsonProperty("season_id")] public long SeasonId { get; set; } + + [JsonProperty("share_url")] public string ShareUrl { get; set; } + + // short_link + [JsonProperty("stat")] public CheeseStat Stat { get; set; } + + // status + [JsonProperty("subtitle")] public string Subtitle { get; set; } + [JsonProperty("title")] public string Title { get; set; } + + [JsonProperty("up_info")] public CheeseUpInfo UpInfo { get; set; } + // update_status + // user_status +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Danmaku/DanmakuProtobuf.cs b/DownKyi.Core/BiliApi/Danmaku/DanmakuProtobuf.cs new file mode 100644 index 0000000..c65234b --- /dev/null +++ b/DownKyi.Core/BiliApi/Danmaku/DanmakuProtobuf.cs @@ -0,0 +1,107 @@ +using Bilibili.Community.Service.Dm.V1; +using DownKyi.Core.BiliApi.Danmaku.Models; +using DownKyi.Core.Storage; +using Console = DownKyi.Core.Utils.Debugging.Console; + +namespace DownKyi.Core.BiliApi.Danmaku; + +public static class DanmakuProtobuf +{ + /// + /// 下载6分钟内的弹幕,返回弹幕列表 + /// + /// 稿件avID + /// 视频CID + /// 分包,每6分钟一包 + /// + public static List GetDanmakuProto(long avid, long cid, int segmentIndex) + { + string url = + $"https://api.bilibili.com/x/v2/dm/web/seg.so?type=1&oid={cid}&pid={avid}&segment_index={segmentIndex}"; + //string referer = "https://www.bilibili.com"; + + string directory = Path.Combine(StorageManager.GetDanmaku(), $"{cid}"); + string filePath = Path.Combine(directory, $"{segmentIndex}.proto"); + if (!Directory.Exists(directory)) + { + Directory.CreateDirectory(directory); + } + + try + { + System.Net.WebClient mywebclient = new System.Net.WebClient(); + mywebclient.DownloadFile(url, filePath); + } + catch (Exception e) + { + Console.PrintLine("GetDanmakuProto()发生异常: {0}", e); + //Logging.LogManager.Error(e); + } + + var danmakuList = new List(); + try + { + using (var input = File.OpenRead(filePath)) + { + DmSegMobileReply danmakus = DmSegMobileReply.Parser.ParseFrom(input); + if (danmakus == null || danmakus.Elems == null) + { + return danmakuList; + } + + foreach (var dm in danmakus.Elems) + { + var danmaku = new BiliDanmaku + { + Id = dm.Id, + Progress = dm.Progress, + Mode = dm.Mode, + Fontsize = dm.Fontsize, + Color = dm.Color, + MidHash = dm.MidHash, + Content = dm.Content, + Ctime = dm.Ctime, + Weight = dm.Weight, + //Action = dm.Action, + Pool = dm.Pool + }; + danmakuList.Add(danmaku); + } + } + } + catch (Exception e) + { + Console.PrintLine("GetDanmakuProto()发生异常: {0}", e); + //Logging.LogManager.Error(e); + return null; + } + + return danmakuList; + } + + /// + /// 下载所有弹幕,返回弹幕列表 + /// + /// 稿件avID + /// 视频CID + /// + public static List GetAllDanmakuProto(long avid, long cid) + { + var danmakuList = new List(); + + int segmentIndex = 0; + while (true) + { + segmentIndex += 1; + var danmakus = GetDanmakuProto(avid, cid, segmentIndex); + if (danmakus == null) + { + break; + } + + danmakuList.AddRange(danmakus); + } + + return danmakuList; + } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Danmaku/Models/BiliDanmaku.cs b/DownKyi.Core/BiliApi/Danmaku/Models/BiliDanmaku.cs new file mode 100644 index 0000000..b33bc00 --- /dev/null +++ b/DownKyi.Core/BiliApi/Danmaku/Models/BiliDanmaku.cs @@ -0,0 +1,34 @@ +namespace DownKyi.Core.BiliApi.Danmaku.Models; + +public class BiliDanmaku +{ + public long Id { get; set; } //弹幕dmID + public int Progress { get; set; } //出现时间 + public int Mode { get; set; } //弹幕类型 + public int Fontsize { get; set; } //文字大小 + public uint Color { get; set; } //弹幕颜色 + public string MidHash { get; set; } //发送者UID的HASH + public string Content { get; set; } //弹幕内容 + public long Ctime { get; set; } //发送时间 + + public int Weight { get; set; } //权重 + + //public string Action { get; set; } //动作? + public int Pool { get; set; } //弹幕池 + + public override string ToString() + { + string separator = "\n"; + return $"id: {Id}{separator}" + + $"progress: {Progress}{separator}" + + $"mode: {Mode}{separator}" + + $"fontsize: {Fontsize}{separator}" + + $"color: {Color}{separator}" + + $"midHash: {MidHash}{separator}" + + $"content: {Content}{separator}" + + $"ctime: {Ctime}{separator}" + + $"weight: {Weight}{separator}" + + //$"action: {Action}{separator}" + + $"pool: {Pool}"; + } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Favorites/FavoritesInfo.cs b/DownKyi.Core/BiliApi/Favorites/FavoritesInfo.cs new file mode 100644 index 0000000..6274e9b --- /dev/null +++ b/DownKyi.Core/BiliApi/Favorites/FavoritesInfo.cs @@ -0,0 +1,155 @@ +using DownKyi.Core.BiliApi.Favorites.Models; +using DownKyi.Core.Logging; +using Newtonsoft.Json; +using Console = DownKyi.Core.Utils.Debugging.Console; + +namespace DownKyi.Core.BiliApi.Favorites; + +public static class FavoritesInfo +{ + /// + /// 获取收藏夹元数据 + /// + /// + public static FavoritesMetaInfo GetFavoritesInfo(long mediaId) + { + string url = $"https://api.bilibili.com/x/v3/fav/folder/info?media_id={mediaId}"; + string referer = "https://www.bilibili.com"; + string response = WebClient.RequestWeb(url, referer); + + try + { + var info = JsonConvert.DeserializeObject(response); + if (info != null) + { + return info.Data; + } + else + { + return null; + } + } + catch (Exception e) + { + Console.PrintLine("GetFavoritesInfo()发生异常: {0}", e); + LogManager.Error("FavoritesInfo", e); + return null; + } + } + + /// + /// 查询用户创建的视频收藏夹 + /// + /// 目标用户UID + /// 页码 + /// 每页项数 + /// + public static List GetCreatedFavorites(long mid, int pn, int ps) + { + string url = $"https://api.bilibili.com/x/v3/fav/folder/created/list?up_mid={mid}&pn={pn}&ps={ps}"; + string referer = "https://www.bilibili.com"; + string response = WebClient.RequestWeb(url, referer); + + try + { + var favorites = JsonConvert.DeserializeObject(response); + if (favorites == null || favorites.Data == null || favorites.Data.List == null) + { + return null; + } + + return favorites.Data.List; + } + catch (Exception e) + { + Console.PrintLine("GetCreatedFavorites()发生异常: {0}", e); + LogManager.Error("FavoritesInfo", e); + return null; + } + } + + /// + /// 查询所有的用户创建的视频收藏夹 + /// + /// 目标用户UID + /// + public static List GetAllCreatedFavorites(long mid) + { + List result = new List(); + + int i = 0; + while (true) + { + i++; + int ps = 50; + + var data = GetCreatedFavorites(mid, i, ps); + if (data == null || data.Count == 0) + { + break; + } + + result.AddRange(data); + } + + return result; + } + + /// + /// 查询用户收藏的视频收藏夹 + /// + /// 目标用户UID + /// 页码 + /// 每页项数 + /// + public static List GetCollectedFavorites(long mid, int pn, int ps) + { + string url = $"https://api.bilibili.com/x/v3/fav/folder/collected/list?up_mid={mid}&pn={pn}&ps={ps}"; + string referer = "https://www.bilibili.com"; + string response = WebClient.RequestWeb(url, referer); + + try + { + var favorites = JsonConvert.DeserializeObject(response); + if (favorites == null || favorites.Data == null || favorites.Data.List == null) + { + return null; + } + + return favorites.Data.List; + } + catch (Exception e) + { + Console.PrintLine("GetCollectedFavorites()发生异常: {0}", e); + LogManager.Error("FavoritesInfo", e); + return null; + } + } + + /// + /// 查询所有的用户收藏的视频收藏夹 + /// + /// 目标用户UID + /// + public static List GetAllCollectedFavorites(long mid) + { + List result = new List(); + + int i = 0; + while (true) + { + i++; + int ps = 50; + + var data = GetCollectedFavorites(mid, i, ps); + if (data == null || data.Count == 0) + { + break; + } + + result.AddRange(data); + } + + return result; + } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Favorites/FavoritesResource.cs b/DownKyi.Core/BiliApi/Favorites/FavoritesResource.cs new file mode 100644 index 0000000..1142df3 --- /dev/null +++ b/DownKyi.Core/BiliApi/Favorites/FavoritesResource.cs @@ -0,0 +1,96 @@ +using DownKyi.Core.BiliApi.Favorites.Models; +using DownKyi.Core.Logging; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Favorites; + +public static class FavoritesResource +{ + /// + /// 获取收藏夹内容明细列表 + /// + /// 收藏夹ID + /// 页码 + /// 每页项数 + /// + public static List GetFavoritesMedia(long mediaId, int pn, int ps) + { + string url = + $"https://api.bilibili.com/x/v3/fav/resource/list?media_id={mediaId}&pn={pn}&ps={ps}&platform=web"; + string referer = "https://www.bilibili.com"; + string response = WebClient.RequestWeb(url, referer); + + try + { + var resource = JsonConvert.DeserializeObject(response); + if (resource == null || resource.Data == null || resource.Data.Medias == null) + { + return null; + } + + return resource.Data.Medias; + } + catch (Exception e) + { + Console.WriteLine("GetFavoritesMedia()发生异常: {0}", e); + LogManager.Error("FavoritesResource", e); + return null; + } + } + + /// + /// 获取收藏夹内容明细列表(全部) + /// + /// 收藏夹ID + /// + public static List GetAllFavoritesMedia(long mediaId) + { + List result = new List(); + + int i = 0; + while (true) + { + i++; + int ps = 20; + + var data = GetFavoritesMedia(mediaId, i, ps); + if (data == null || data.Count == 0) + { + break; + } + + result.AddRange(data); + } + + return result; + } + + /// + /// 获取收藏夹全部内容id + /// + /// + /// + public static List GetFavoritesMediaId(long mediaId) + { + string url = $"https://api.bilibili.com/x/v3/fav/resource/ids?media_id={mediaId}"; + string referer = "https://www.bilibili.com"; + string response = WebClient.RequestWeb(url, referer); + + try + { + var media = JsonConvert.DeserializeObject(response); + if (media == null || media.Data == null) + { + return null; + } + + return media.Data; + } + catch (Exception e) + { + Console.WriteLine("GetFavoritesMediaId()发生异常: {0}", e); + LogManager.Error("FavoritesResource", e); + return null; + } + } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Favorites/Models/FavStatus.cs b/DownKyi.Core/BiliApi/Favorites/Models/FavStatus.cs new file mode 100644 index 0000000..2af2685 --- /dev/null +++ b/DownKyi.Core/BiliApi/Favorites/Models/FavStatus.cs @@ -0,0 +1,12 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Favorites.Models; + +public class FavStatus : BaseModel +{ + [JsonProperty("collect")] public long Collect { get; set; } + [JsonProperty("play")] public long Play { get; set; } + [JsonProperty("thumb_up")] public long ThumbUp { get; set; } + [JsonProperty("share")] public long Share { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Favorites/Models/FavUpper.cs b/DownKyi.Core/BiliApi/Favorites/Models/FavUpper.cs new file mode 100644 index 0000000..166e83d --- /dev/null +++ b/DownKyi.Core/BiliApi/Favorites/Models/FavUpper.cs @@ -0,0 +1,15 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Favorites.Models; + +public class FavUpper : BaseModel +{ + [JsonProperty("mid")] public long Mid { get; set; } + [JsonProperty("name")] public string Name { get; set; } + [JsonProperty("face")] public string Face { get; set; } + + [JsonProperty("followed")] public bool Followed { get; set; } + // vip_type + // vip_statue +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Favorites/Models/FavoritesList.cs b/DownKyi.Core/BiliApi/Favorites/Models/FavoritesList.cs new file mode 100644 index 0000000..1665a2b --- /dev/null +++ b/DownKyi.Core/BiliApi/Favorites/Models/FavoritesList.cs @@ -0,0 +1,25 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Favorites.Models; + +// https://api.bilibili.com/x/v3/fav/folder/collected/list +public class FavoritesListOrigin : BaseModel +{ + //[JsonProperty("code")] + //public int Code { get; set; } + //[JsonProperty("message")] + //public string Message { get; set; } + //[JsonProperty("ttl")] + //public int Ttl { get; set; } + [JsonProperty("data")] public FavoritesList Data { get; set; } +} + +public class FavoritesList : BaseModel +{ + [JsonProperty("count")] public int Count { get; set; } + + [JsonProperty("list")] public List List { get; set; } + //[JsonProperty("has_more")] + //public bool HasMore { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Favorites/Models/FavoritesMedia.cs b/DownKyi.Core/BiliApi/Favorites/Models/FavoritesMedia.cs new file mode 100644 index 0000000..fe176fe --- /dev/null +++ b/DownKyi.Core/BiliApi/Favorites/Models/FavoritesMedia.cs @@ -0,0 +1,30 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Favorites.Models; + +public class FavoritesMedia : BaseModel +{ + [JsonProperty("id")] public long Id { get; set; } + [JsonProperty("type")] public int Type { get; set; } + [JsonProperty("title")] public string Title { get; set; } + [JsonProperty("cover")] public string Cover { get; set; } + [JsonProperty("intro")] public string Intro { get; set; } + [JsonProperty("page")] public int Page { get; set; } + [JsonProperty("duration")] public long Duration { get; set; } + + [JsonProperty("upper")] public FavUpper Upper { get; set; } + + // attr + [JsonProperty("cnt_info")] public MediaStatus CntInfo { get; set; } + [JsonProperty("link")] public string Link { get; set; } + [JsonProperty("ctime")] public long Ctime { get; set; } + [JsonProperty("pubtime")] public long Pubtime { get; set; } + [JsonProperty("fav_time")] public long FavTime { get; set; } + [JsonProperty("bv_id")] public string BvId { get; set; } + + [JsonProperty("bvid")] public string Bvid { get; set; } + // season + // ogv + // ugc +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Favorites/Models/FavoritesMediaId.cs b/DownKyi.Core/BiliApi/Favorites/Models/FavoritesMediaId.cs new file mode 100644 index 0000000..7e54bb5 --- /dev/null +++ b/DownKyi.Core/BiliApi/Favorites/Models/FavoritesMediaId.cs @@ -0,0 +1,24 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Favorites.Models; + +// https://api.bilibili.com/x/v3/fav/resource/ids +public class FavoritesMediaIdOrigin : BaseModel +{ + //[JsonProperty("code")] + //public int Code { get; set; } + //[JsonProperty("message")] + //public string Message { get; set; } + //[JsonProperty("ttl")] + //public int Ttl { get; set; } + [JsonProperty("data")] public List Data { get; set; } +} + +public class FavoritesMediaId : BaseModel +{ + [JsonProperty("id")] public long Id { get; set; } + [JsonProperty("type")] public int Type { get; set; } + [JsonProperty("bv_id")] public string BvId { get; set; } + [JsonProperty("bvid")] public string Bvid { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Favorites/Models/FavoritesMediaResource.cs b/DownKyi.Core/BiliApi/Favorites/Models/FavoritesMediaResource.cs new file mode 100644 index 0000000..316ca3b --- /dev/null +++ b/DownKyi.Core/BiliApi/Favorites/Models/FavoritesMediaResource.cs @@ -0,0 +1,23 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Favorites.Models; + +// https://api.bilibili.com/x/v3/fav/resource/list +public class FavoritesMediaResourceOrigin : BaseModel +{ + //[JsonProperty("code")] + //public int Code { get; set; } + //[JsonProperty("message")] + //public string Message { get; set; } + //[JsonProperty("ttl")] + //public int Ttl { get; set; } + [JsonProperty("data")] public FavoritesMediaResource Data { get; set; } +} + +public class FavoritesMediaResource : BaseModel +{ + [JsonProperty("info")] public FavoritesMetaInfo Info { get; set; } + [JsonProperty("medias")] public List Medias { get; set; } + [JsonProperty("has_more")] public bool HasMore { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Favorites/Models/FavoritesMetaInfo.cs b/DownKyi.Core/BiliApi/Favorites/Models/FavoritesMetaInfo.cs new file mode 100644 index 0000000..705c6f5 --- /dev/null +++ b/DownKyi.Core/BiliApi/Favorites/Models/FavoritesMetaInfo.cs @@ -0,0 +1,44 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Favorites.Models; + +// https://api.bilibili.com/x/v3/fav/folder/info +public class FavoritesMetaInfoOrigin : BaseModel +{ + //[JsonProperty("code")] + //public int Code { get; set; } + //[JsonProperty("message")] + //public string Message { get; set; } + //[JsonProperty("ttl")] + //public int Ttl { get; set; } + [JsonProperty("data")] public FavoritesMetaInfo Data { get; set; } +} + +public class FavoritesMetaInfo : BaseModel +{ + [JsonProperty("id")] public long Id { get; set; } + [JsonProperty("fid")] public long Fid { get; set; } + + [JsonProperty("mid")] public long Mid { get; set; } + + // attr + [JsonProperty("title")] public string Title { get; set; } + [JsonProperty("cover")] public string Cover { get; set; } + + [JsonProperty("upper")] public FavUpper Upper { get; set; } + + // cover_type + [JsonProperty("cnt_info")] public FavStatus CntInfo { get; set; } + + // type + [JsonProperty("intro")] public string Intro { get; set; } + [JsonProperty("ctime")] public long Ctime { get; set; } + + [JsonProperty("mtime")] public long Mtime { get; set; } + + // state + [JsonProperty("fav_state")] public int FavState { get; set; } + [JsonProperty("like_state")] public int LikeState { get; set; } + [JsonProperty("media_count")] public int MediaCount { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Favorites/Models/MediaStatus.cs b/DownKyi.Core/BiliApi/Favorites/Models/MediaStatus.cs new file mode 100644 index 0000000..d56c16e --- /dev/null +++ b/DownKyi.Core/BiliApi/Favorites/Models/MediaStatus.cs @@ -0,0 +1,11 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Favorites.Models; + +public class MediaStatus : BaseModel +{ + [JsonProperty("collect")] public long Collect { get; set; } + [JsonProperty("play")] public long Play { get; set; } + [JsonProperty("danmaku")] public long Danmaku { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/History/History.cs b/DownKyi.Core/BiliApi/History/History.cs new file mode 100644 index 0000000..1bfd2bd --- /dev/null +++ b/DownKyi.Core/BiliApi/History/History.cs @@ -0,0 +1,63 @@ +using DownKyi.Core.BiliApi.History.Models; +using DownKyi.Core.Logging; +using Newtonsoft.Json; +using System; + +namespace DownKyi.Core.BiliApi.History +{ + /// + /// 历史记录 + /// + public static class History + { + /// + /// 获取历史记录列表(视频、直播、专栏) + /// startId和startTime必须同时使用才有效,分别对应结果中的max和view_at,默认为0 + /// + /// 历史记录开始目标ID + /// 历史记录开始时间 + /// 每页项数 + /// 历史记录ID类型 + /// + public static HistoryData GetHistory(long startId, long startTime, int ps = 30, HistoryBusiness business = HistoryBusiness.ARCHIVE) + { + string businessStr = string.Empty; + switch (business) + { + case HistoryBusiness.ARCHIVE: + businessStr = "archive"; + break; + case HistoryBusiness.PGC: + businessStr = "pgc"; + break; + case HistoryBusiness.LIVE: + businessStr = "live"; + break; + case HistoryBusiness.ARTICLE_LIST: + businessStr = "article-list"; + break; + case HistoryBusiness.ARTICLE: + businessStr = "article"; + break; + } + + string url = $"https://api.bilibili.com/x/web-interface/history/cursor?max={startId}&view_at={startTime}&ps={ps}&business={businessStr}"; + string referer = "https://www.bilibili.com"; + string response = WebClient.RequestWeb(url, referer); + + try + { + var history = JsonConvert.DeserializeObject(response); + if (history == null || history.Data == null) { return null; } + return history.Data; + } + catch (Exception e) + { + Utils.Debugging.Console.PrintLine("GetHistory()发生异常: {0}", e); + LogManager.Error("History", e); + return null; + } + } + + } +} diff --git a/DownKyi.Core/BiliApi/History/Models/HistoryBusiness.cs b/DownKyi.Core/BiliApi/History/Models/HistoryBusiness.cs new file mode 100644 index 0000000..0b40257 --- /dev/null +++ b/DownKyi.Core/BiliApi/History/Models/HistoryBusiness.cs @@ -0,0 +1,11 @@ +namespace DownKyi.Core.BiliApi.History.Models +{ + public enum HistoryBusiness + { + ARCHIVE = 1, // 稿件 + PGC, // 番剧(影视) + LIVE, // 直播 + ARTICLE_LIST, // 文集 + ARTICLE, // 文章 + } +} diff --git a/DownKyi.Core/BiliApi/History/Models/HistoryCursor.cs b/DownKyi.Core/BiliApi/History/Models/HistoryCursor.cs new file mode 100644 index 0000000..c6641e7 --- /dev/null +++ b/DownKyi.Core/BiliApi/History/Models/HistoryCursor.cs @@ -0,0 +1,17 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.History.Models +{ + public class HistoryCursor : BaseModel + { + [JsonProperty("max")] + public long Max { get; set; } + [JsonProperty("view_at")] + public long ViewAt { get; set; } + [JsonProperty("business")] + public string Business { get; set; } + [JsonProperty("ps")] + public int Ps { get; set; } + } +} diff --git a/DownKyi.Core/BiliApi/History/Models/HistoryData.cs b/DownKyi.Core/BiliApi/History/Models/HistoryData.cs new file mode 100644 index 0000000..ca58a5b --- /dev/null +++ b/DownKyi.Core/BiliApi/History/Models/HistoryData.cs @@ -0,0 +1,28 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; +using System.Collections.Generic; + +namespace DownKyi.Core.BiliApi.History.Models +{ + // https://api.bilibili.com/x/web-interface/history/cursor?max={startId}&view_at={startTime}&ps={ps}&business={businessStr} + public class HistoryOrigin : BaseModel + { + //[JsonProperty("code")] + //public int Code { get; set; } + //[JsonProperty("message")] + //public string Message { get; set; } + //[JsonProperty("ttl")] + //public int Ttl { get; set; } + [JsonProperty("data")] + public HistoryData Data { get; set; } + } + + public class HistoryData : BaseModel + { + [JsonProperty("cursor")] + public HistoryCursor Cursor { get; set; } + //public List tab { get; set; } + [JsonProperty("list")] + public List List { get; set; } + } +} diff --git a/DownKyi.Core/BiliApi/History/Models/HistoryList.cs b/DownKyi.Core/BiliApi/History/Models/HistoryList.cs new file mode 100644 index 0000000..5ac7372 --- /dev/null +++ b/DownKyi.Core/BiliApi/History/Models/HistoryList.cs @@ -0,0 +1,46 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.History.Models +{ + public class HistoryList : BaseModel + { + [JsonProperty("title")] + public string Title { get; set; } + // long_title + [JsonProperty("cover")] + public string Cover { get; set; } + // covers + [JsonProperty("uri")] + public string Uri { get; set; } + [JsonProperty("history")] + public HistoryListHistory History { get; set; } + [JsonProperty("videos")] + public int Videos { get; set; } + [JsonProperty("author_name")] + public string AuthorName { get; set; } + [JsonProperty("author_face")] + public string AuthorFace { get; set; } + [JsonProperty("author_mid")] + public long AuthorMid { get; set; } + [JsonProperty("view_at")] + public long ViewAt { get; set; } + [JsonProperty("progress")] + public long Progress { get; set; } + // badge + [JsonProperty("show_title")] + public string ShowTitle { get; set; } + [JsonProperty("duration")] + public long Duration { get; set; } + // current + // total + [JsonProperty("new_desc")] + public string NewDesc { get; set; } + // is_finish + // is_fav + // kid + [JsonProperty("tag_name")] + public string TagName { get; set; } + // live_status + } +} diff --git a/DownKyi.Core/BiliApi/History/Models/HistoryListHistory.cs b/DownKyi.Core/BiliApi/History/Models/HistoryListHistory.cs new file mode 100644 index 0000000..8ea33f0 --- /dev/null +++ b/DownKyi.Core/BiliApi/History/Models/HistoryListHistory.cs @@ -0,0 +1,25 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.History.Models +{ + public class HistoryListHistory : BaseModel + { + [JsonProperty("oid")] + public long Oid { get; set; } + [JsonProperty("epid")] + public long Epid { get; set; } + [JsonProperty("bvid")] + public string Bvid { get; set; } + [JsonProperty("page")] + public int Page { get; set; } + [JsonProperty("cid")] + public long Cid { get; set; } + [JsonProperty("part")] + public string Part { get; set; } + [JsonProperty("business")] + public string Business { get; set; } + [JsonProperty("dt")] + public int Dt { get; set; } + } +} diff --git a/DownKyi.Core/BiliApi/History/Models/ToViewData.cs b/DownKyi.Core/BiliApi/History/Models/ToViewData.cs new file mode 100644 index 0000000..5c1a7ac --- /dev/null +++ b/DownKyi.Core/BiliApi/History/Models/ToViewData.cs @@ -0,0 +1,27 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; +using System.Collections.Generic; + +namespace DownKyi.Core.BiliApi.History.Models +{ + // https://api.bilibili.com/x/v2/history/toview + public class ToViewOrigin : BaseModel + { + //[JsonProperty("code")] + //public int Code { get; set; } + //[JsonProperty("message")] + //public string Message { get; set; } + //[JsonProperty("ttl")] + //public int Ttl { get; set; } + [JsonProperty("data")] + public ToViewData Data { get; set; } + } + + public class ToViewData : BaseModel + { + [JsonProperty("count")] + public int Count { get; set; } + [JsonProperty("list")] + public List List { get; set; } + } +} diff --git a/DownKyi.Core/BiliApi/History/Models/ToViewList.cs b/DownKyi.Core/BiliApi/History/Models/ToViewList.cs new file mode 100644 index 0000000..4458a94 --- /dev/null +++ b/DownKyi.Core/BiliApi/History/Models/ToViewList.cs @@ -0,0 +1,43 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.History.Models +{ + public class ToViewList : BaseModel + { + [JsonProperty("aid")] + public long Aid { get; set; } + // videos + // tid + // tname + // copyright + [JsonProperty("pic")] + public string Pic { get; set; } + [JsonProperty("title")] + public string Title { get; set; } + // pubdate + // ctime + // desc + // state + // duration + // rights + [JsonProperty("owner")] + public VideoOwner Owner { get; set; } + // stat + // dynamic + // dimension + // short_link_v2 + // first_frame + // page + // count + [JsonProperty("cid")] + public long Cid { get; set; } + // progress + [JsonProperty("add_at")] + public long AddAt { get; set; } + [JsonProperty("bvid")] + public string Bvid { get; set; } + // uri + // viewed + } +} diff --git a/DownKyi.Core/BiliApi/History/ToView.cs b/DownKyi.Core/BiliApi/History/ToView.cs new file mode 100644 index 0000000..354569b --- /dev/null +++ b/DownKyi.Core/BiliApi/History/ToView.cs @@ -0,0 +1,38 @@ +using DownKyi.Core.BiliApi.History.Models; +using DownKyi.Core.Logging; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; + +namespace DownKyi.Core.BiliApi.History +{ + /// + /// 稍后再看 + /// + public static class ToView + { + /// + /// 获取稍后再看视频列表 + /// + /// + public static List GetToView() + { + string url = "https://api.bilibili.com/x/v2/history/toview"; + string referer = "https://www.bilibili.com"; + string response = WebClient.RequestWeb(url, referer); + + try + { + var toView = JsonConvert.DeserializeObject(response); + if (toView == null || toView.Data == null) { return null; } + return toView.Data.List; + } + catch (Exception e) + { + Utils.Debugging.Console.PrintLine("GetToView()发生异常: {0}", e); + LogManager.Error("ToView", e); + return null; + } + } + } +} diff --git a/DownKyi.Core/BiliApi/Login/LoginHelper.cs b/DownKyi.Core/BiliApi/Login/LoginHelper.cs new file mode 100644 index 0000000..1136f3c --- /dev/null +++ b/DownKyi.Core/BiliApi/Login/LoginHelper.cs @@ -0,0 +1,156 @@ +using System.Net; +using DownKyi.Core.Logging; +using DownKyi.Core.Settings; +using DownKyi.Core.Settings.Models; +using DownKyi.Core.Storage; +using DownKyi.Core.Utils; +using Console = DownKyi.Core.Utils.Debugging.Console; + +namespace DownKyi.Core.BiliApi.Login +{ + public static class LoginHelper + { + // 本地位置 + private static readonly string LOCAL_LOGIN_INFO = StorageManager.GetLogin(); + + // 16位密码,ps:密码位数没有限制,可任意设置 + private static readonly string SecretKey = "EsOat*^y1QR!&0J6"; + + /// + /// 保存登录的cookies到文件 + /// + /// + /// + public static bool SaveLoginInfoCookies(string url) + { + string tempFile = LOCAL_LOGIN_INFO + "-" + Guid.NewGuid().ToString("N"); + CookieContainer cookieContainer = ObjectHelper.ParseCookie(url); + + bool isSucceed = ObjectHelper.WriteCookiesToDisk(tempFile, cookieContainer); + if (isSucceed) + { + // 加密密钥,增加机器码 + string password = SecretKey; + + try + { + File.Copy(tempFile, LOCAL_LOGIN_INFO, true); + // Encryptor.EncryptFile(tempFile, LOCAL_LOGIN_INFO, password); + } + catch (Exception e) + { + Console.PrintLine("SaveLoginInfoCookies()发生异常: {0}", e); + LogManager.Error(e); + return false; + } + } + + if (File.Exists(tempFile)) + { + File.Delete(tempFile); + } + + return isSucceed; + } + + + /// + /// 获得登录的cookies + /// + /// + public static CookieContainer GetLoginInfoCookies() + { + string tempFile = LOCAL_LOGIN_INFO + "-" + Guid.NewGuid().ToString("N"); + + if (File.Exists(LOCAL_LOGIN_INFO)) + { + try + { + File.Copy(LOCAL_LOGIN_INFO, tempFile, true); + // 加密密钥,增加机器码 + // string password = SecretKey; + // Encryptor.DecryptFile(LOCAL_LOGIN_INFO, tempFile, password); + } + catch (Exception e) + { + Console.PrintLine("GetLoginInfoCookies()发生异常: {0}", e); + LogManager.Error(e); + if (File.Exists(tempFile)) + { + File.Delete(tempFile); + } + + return null; + } + } + else + { + return null; + } + + CookieContainer cookies = ObjectHelper.ReadCookiesFromDisk(tempFile); + + if (File.Exists(tempFile)) + { + File.Delete(tempFile); + } + + return cookies; + } + + /// + /// 返回登录信息的cookies的字符串 + /// + /// + public static string GetLoginInfoCookiesString() + { + var cookieContainer = GetLoginInfoCookies(); + if (cookieContainer == null) + { + return ""; + } + + var cookies = ObjectHelper.GetAllCookies(cookieContainer); + + string cookie = string.Empty; + foreach (var item in cookies) + { + cookie += item.ToString() + ";"; + } + + return cookie.TrimEnd(';'); + } + + /// + /// 注销登录 + /// + /// + public static bool Logout() + { + if (File.Exists(LOCAL_LOGIN_INFO)) + { + try + { + File.Delete(LOCAL_LOGIN_INFO); + + SettingsManager.GetInstance().SetUserInfo(new UserInfoSettings + { + Mid = -1, + Name = "", + IsLogin = false, + IsVip = false + }); + return true; + } + catch (IOException e) + { + Console.PrintLine("Logout()发生异常: {0}", e); + LogManager.Error(e); + return false; + } + } + + return false; + } + } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Login/LoginQR.cs b/DownKyi.Core/BiliApi/Login/LoginQR.cs new file mode 100644 index 0000000..c2dc09b --- /dev/null +++ b/DownKyi.Core/BiliApi/Login/LoginQR.cs @@ -0,0 +1,87 @@ +using Avalonia.Media.Imaging; +using DownKyi.Core.BiliApi.Login.Models; +using DownKyi.Core.Logging; +using DownKyi.Core.Utils; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Login; + +public static class LoginQR +{ + /// + /// 申请二维码URL及扫码密钥(web端) + /// + /// + public static LoginUrlOrigin? GetLoginUrl() + { + string getLoginUrl = "https://passport.bilibili.com/x/passport-login/web/qrcode/generate"; + string response = WebClient.RequestWeb(getLoginUrl); + Console.Out.WriteLine(response); + try + { + return JsonConvert.DeserializeObject(response); + } + catch (Exception e) + { + Utils.Debugging.Console.PrintLine("GetLoginUrl()发生异常: {0}", e); + LogManager.Error("LoginQR", e); + return null; + } + } + + /// + /// 使用扫码登录(web端) + /// + /// + /// + /// + public static LoginStatus? GetLoginStatus(string qrcodeKey, string goUrl = "https://www.bilibili.com") + { + string url = "https://passport.bilibili.com/x/passport-login/web/qrcode/poll?qrcode_key=" + qrcodeKey; + + string response = WebClient.RequestWeb(url); + + try + { + return JsonConvert.DeserializeObject(response); + } + catch (Exception e) + { + Utils.Debugging.Console.PrintLine("GetLoginInfo()发生异常: {0}", e); + LogManager.Error("LoginQR", e); + return null; + } + } + + /// + /// 获得登录二维码 + /// + /// + public static Bitmap GetLoginQRCode() + { + try + { + string loginUrl = GetLoginUrl().Data.Url; + return GetLoginQRCode(loginUrl); + } + catch (Exception e) + { + Utils.Debugging.Console.PrintLine("GetLoginQRCode()发生异常: {0}", e); + LogManager.Error("LoginQR", e); + return null; + } + } + + /// + /// 根据输入url生成二维码 + /// + /// + /// + public static Bitmap GetLoginQRCode(string url) + { + // 设置的参数影响app能否成功扫码 + Bitmap qrCode = QRCode.EncodeQRCode(url, 10, 10, null, 0, 0, false); + + return qrCode; + } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Login/Models/LoginStatus.cs b/DownKyi.Core/BiliApi/Login/Models/LoginStatus.cs new file mode 100644 index 0000000..4981ff2 --- /dev/null +++ b/DownKyi.Core/BiliApi/Login/Models/LoginStatus.cs @@ -0,0 +1,23 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Login.Models +{ + [JsonObject] + public class LoginStatus : BaseModel + { + [JsonProperty("code")] public int Code { get; set; } + [JsonProperty("message")] public string Message { get; set; } + + [JsonProperty("data")] public LoginStatusData Data { get; set; } + } + + [JsonObject] + public class LoginStatusData : BaseModel + { + [JsonProperty("url")] public string Url { get; set; } + [JsonProperty("refresh_token")] public string RefreshToken { get; set; } + [JsonProperty("code")] public int Code { get; set; } + [JsonProperty("message")] public string Message { get; set; } + } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Login/Models/LoginUrl.cs b/DownKyi.Core/BiliApi/Login/Models/LoginUrl.cs new file mode 100644 index 0000000..ebaff22 --- /dev/null +++ b/DownKyi.Core/BiliApi/Login/Models/LoginUrl.cs @@ -0,0 +1,23 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Login.Models +{ + // https://passport.bilibili.com/qrcode/getLoginUrl + [JsonObject] + public class LoginUrlOrigin : BaseModel + { + //public int code { get; set; } + [JsonProperty("data")] public LoginUrl Data { get; set; } + + [JsonProperty("code")] public int Code { get; set; } + //public long ts { get; set; } + } + + [JsonObject] + public class LoginUrl : BaseModel + { + [JsonProperty("qrcode_key")] public string QrcodeKey { get; set; } + [JsonProperty("url")] public string Url { get; set; } + } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Models/BaseModel.cs b/DownKyi.Core/BiliApi/Models/BaseModel.cs new file mode 100644 index 0000000..674a0a0 --- /dev/null +++ b/DownKyi.Core/BiliApi/Models/BaseModel.cs @@ -0,0 +1,29 @@ +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Models; + +public abstract class BaseModel +{ + public string ToString(string format = "") + { + // 设置为去掉null + var jsonSetting = new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }; + + switch (format) + { + case "": + return JsonConvert.SerializeObject(this); + case "F": + // 整理json格式 + return JsonConvert.SerializeObject(this, Formatting.Indented); + case "N": + // 去掉null后,转换为json字符串 + return JsonConvert.SerializeObject(this, Formatting.None, jsonSetting); + case "FN": + case "NF": + return JsonConvert.SerializeObject(this, Formatting.Indented, jsonSetting); + default: + return ToString(); + } + } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Models/Dimension.cs b/DownKyi.Core/BiliApi/Models/Dimension.cs new file mode 100644 index 0000000..7056f0d --- /dev/null +++ b/DownKyi.Core/BiliApi/Models/Dimension.cs @@ -0,0 +1,10 @@ +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Models; + +public class Dimension : BaseModel +{ + [JsonProperty("width")] public int Width { get; set; } + [JsonProperty("height")] public int Height { get; set; } + [JsonProperty("rotate")] public int Rotate { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Models/Json/SubRipText.cs b/DownKyi.Core/BiliApi/Models/Json/SubRipText.cs new file mode 100644 index 0000000..bab5c86 --- /dev/null +++ b/DownKyi.Core/BiliApi/Models/Json/SubRipText.cs @@ -0,0 +1,10 @@ +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Models.Json; + +public class SubRipText : BaseModel +{ + [JsonProperty("lan")] public string Lan { get; set; } + [JsonProperty("lan_doc")] public string LanDoc { get; set; } + [JsonProperty("srtString")] public string SrtString { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Models/Json/Subtitle.cs b/DownKyi.Core/BiliApi/Models/Json/Subtitle.cs new file mode 100644 index 0000000..ca35b4e --- /dev/null +++ b/DownKyi.Core/BiliApi/Models/Json/Subtitle.cs @@ -0,0 +1,11 @@ +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Models.Json; + +public class Subtitle : BaseModel +{ + [JsonProperty("from")] public float From { get; set; } + [JsonProperty("to")] public float To { get; set; } + [JsonProperty("location")] public int Location { get; set; } + [JsonProperty("content")] public string Content { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Models/Json/SubtitleJson.cs b/DownKyi.Core/BiliApi/Models/Json/SubtitleJson.cs new file mode 100644 index 0000000..8ead11a --- /dev/null +++ b/DownKyi.Core/BiliApi/Models/Json/SubtitleJson.cs @@ -0,0 +1,59 @@ +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Models.Json; + +public class SubtitleJson : BaseModel +{ + [JsonProperty("font_size")] public float FontSize { get; set; } + [JsonProperty("font_color")] public string FontColor { get; set; } + [JsonProperty("background_alpha")] public float BackgroundAlpha { get; set; } + [JsonProperty("background_color")] public string BackgroundColor { get; set; } + [JsonProperty("Stroke")] public string Stroke { get; set; } + [JsonProperty("body")] public List Body { get; set; } + + /// + /// srt格式字幕 + /// + /// + public string ToSubRip() + { + string subRip = string.Empty; + for (int i = 0; i < Body.Count; i++) + { + subRip += $"{i + 1}\n"; + subRip += $"{Second2hms(Body[i].From)} --> {Second2hms(Body[i].To)}\n"; + subRip += $"{Body[i].Content}\n"; + subRip += "\n"; + } + + return subRip; + } + + /// + /// 秒数转 时:分:秒 格式 + /// + /// + /// + private static string Second2hms(float seconds) + { + if (seconds < 0) + { + return "00:00:00,000"; + } + + int i = (int)Math.Floor(seconds / 1.0); + int dec = (int)(Math.Round(seconds % 1.0f, 2) * 100); + if (dec >= 100) + { + dec = 99; + } + + int min = (int)Math.Floor(i / 60.0); + int second = (int)(i % 60.0f); + + int hour = (int)Math.Floor(min / 60.0); + min = (int)Math.Floor(min % 60.0f); + + return $"{hour:D2}:{min:D2}:{second:D2},{dec:D3}"; + } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Models/VideoOwner.cs b/DownKyi.Core/BiliApi/Models/VideoOwner.cs new file mode 100644 index 0000000..92b4112 --- /dev/null +++ b/DownKyi.Core/BiliApi/Models/VideoOwner.cs @@ -0,0 +1,10 @@ +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Models; + +public class VideoOwner : BaseModel +{ + [JsonProperty("mid")] public long Mid { get; set; } + [JsonProperty("name")] public string Name { get; set; } + [JsonProperty("face")] public string Face { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Sign/WbiSign.cs b/DownKyi.Core/BiliApi/Sign/WbiSign.cs new file mode 100644 index 0000000..c950d08 --- /dev/null +++ b/DownKyi.Core/BiliApi/Sign/WbiSign.cs @@ -0,0 +1,116 @@ +using System.Security.Cryptography; +using System.Text; +using System.Text.RegularExpressions; +using DownKyi.Core.Settings; + +namespace DownKyi.Core.BiliApi.Sign; + +public static class WbiSign +{ + /// + /// 打乱重排实时口令 + /// + /// + /// + private static string GetMixinKey(string origin) + { + int[] mixinKeyEncTab = { + 46, 47, 18, 2, 53, 8, 23, 32, 15, 50, 10, 31, 58, 3, 45, 35, 27, 43, 5, 49, + 33, 9, 42, 19, 29, 28, 14, 39, 12, 38, 41, 13, 37, 48, 7, 16, 24, 55, 40, + 61, 26, 17, 0, 1, 60, 51, 30, 4, 22, 25, 54, 21, 56, 59, 6, 63, 57, 62, 11, + 36, 20, 34, 44, 52 + }; + + var temp = new StringBuilder(); + foreach (var i in mixinKeyEncTab) + { + temp.Append(origin[i]); + } + + return temp.ToString().Substring(0, 32); + } + + /// + /// 将字典参数转为字符串 + /// + /// + /// + public static string ParametersToQuery(Dictionary parameters) + { + var keys = parameters.Keys.ToList(); + var queryList = new List(); + foreach (var item in keys) + { + var value = parameters[item]; + queryList.Add($"{item}={value}"); + } + + return string.Join("&", queryList); + } + + /// + /// Wbi签名,返回所有参数字典 + /// + /// + /// + public static Dictionary EncodeWbi(Dictionary parameters) + { + return EncodeWbi(parameters, GetKey().Item1, GetKey().Item2); + } + + /// + /// Wbi签名,返回所有参数字典 + /// + /// + /// + /// + /// + public static Dictionary EncodeWbi(Dictionary parameters, string imgKey, + string subKey) + { + var mixinKey = GetMixinKey(imgKey + subKey); + + var chrFilter = new Regex("[!'()*]"); + + var newParameters = new Dictionary + { + { "wts", (long)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds } + }; + + foreach (var para in parameters) + { + var key = para.Key; + var value = para.Value.ToString(); + + var encodedValue = chrFilter.Replace(value, ""); + + newParameters.Add(Uri.EscapeDataString(key), Uri.EscapeDataString(encodedValue)); + } + + var keys = newParameters.Keys.ToList(); + keys.Sort(); + + var queryList = new List(); + foreach (var item in keys) + { + var value = newParameters[item]; + queryList.Add($"{item}={value}"); + } + + var queryString = string.Join("&", queryList); + var md5Hasher = MD5.Create(); + var hashStr = queryString + mixinKey; + var hashedQueryString = md5Hasher.ComputeHash(Encoding.UTF8.GetBytes(hashStr)); + var wbiSign = BitConverter.ToString(hashedQueryString).Replace("-", "").ToLower(); + + newParameters.Add("w_rid", wbiSign); + return newParameters; + } + + public static Tuple GetKey() + { + var user = SettingsManager.GetInstance().GetUserInfo(); + + return new Tuple(user.ImgKey, user.SubKey); + } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Users/Models/BangumiFollow.cs b/DownKyi.Core/BiliApi/Users/Models/BangumiFollow.cs new file mode 100644 index 0000000..f1eb8b4 --- /dev/null +++ b/DownKyi.Core/BiliApi/Users/Models/BangumiFollow.cs @@ -0,0 +1,65 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Users.Models; + +public class BangumiFollow : BaseModel +{ + [JsonProperty("season_id")] public long SeasonId { get; set; } + [JsonProperty("media_id")] public long MediaId { get; set; } + [JsonProperty("season_type")] public int SeasonType { get; set; } + [JsonProperty("season_type_name")] public string SeasonTypeName { get; set; } + [JsonProperty("title")] public string Title { get; set; } + [JsonProperty("cover")] public string Cover { get; set; } + + [JsonProperty("total_count")] public int TotalCount { get; set; } + + // is_finish + // is_started + // is_play + [JsonProperty("badge")] public string Badge { get; set; } + + [JsonProperty("badge_type")] public int BadgeType { get; set; } + + // rights + // stat + [JsonProperty("new_ep")] public BangumiFollowNewEp NewEp { get; set; } + + // rating + // square_cover + [JsonProperty("season_status")] public int SeasonStatus { get; set; } + [JsonProperty("season_title")] public string SeasonTitle { get; set; } + + [JsonProperty("badge_ep")] public string BadgeEp { get; set; } + + // media_attr + // season_attr + [JsonProperty("evaluate")] public string Evaluate { get; set; } + [JsonProperty("areas")] public List Areas { get; set; } + [JsonProperty("subtitle")] public string Subtitle { get; set; } + + [JsonProperty("first_ep")] public long FirstEp { get; set; } + + // can_watch + // series + // publish + // mode + // section + [JsonProperty("url")] public string Url { get; set; } + + // badge_info + // first_ep_info + // formal_ep_count + // short_url + // badge_infos + // season_version + // horizontal_cover_16_9 + // horizontal_cover_16_10 + // subtitle_14 + // viewable_crowd_type + // producers + // follow_status + // is_new + [JsonProperty("progress")] public string Progress { get; set; } + // both_follow +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Users/Models/BangumiFollowAreas.cs b/DownKyi.Core/BiliApi/Users/Models/BangumiFollowAreas.cs new file mode 100644 index 0000000..853ad76 --- /dev/null +++ b/DownKyi.Core/BiliApi/Users/Models/BangumiFollowAreas.cs @@ -0,0 +1,10 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Users.Models; + +public class BangumiFollowAreas : BaseModel +{ + [JsonProperty("id")] public int Id { get; set; } + [JsonProperty("name")] public string Name { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Users/Models/BangumiFollowNewEp.cs b/DownKyi.Core/BiliApi/Users/Models/BangumiFollowNewEp.cs new file mode 100644 index 0000000..e607591 --- /dev/null +++ b/DownKyi.Core/BiliApi/Users/Models/BangumiFollowNewEp.cs @@ -0,0 +1,15 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Users.Models; + +public class BangumiFollowNewEp : BaseModel +{ + [JsonProperty("id")] public long Id { get; set; } + [JsonProperty("index_show")] public string IndexShow { get; set; } + [JsonProperty("cover")] public string Cover { get; set; } + [JsonProperty("title")] public string Title { get; set; } + [JsonProperty("long_title")] public string LongTitle { get; set; } + [JsonProperty("pub_time")] public string PubTime { get; set; } + [JsonProperty("duration")] public long Duration { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Users/Models/BangumiFollowOrigin.cs b/DownKyi.Core/BiliApi/Users/Models/BangumiFollowOrigin.cs new file mode 100644 index 0000000..bb731ad --- /dev/null +++ b/DownKyi.Core/BiliApi/Users/Models/BangumiFollowOrigin.cs @@ -0,0 +1,18 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Users.Models; + +// https://api.bilibili.com/x/space/bangumi/follow/list?vmid={mid}&type={type:D}&pn={pn}&ps={ps} +public class BangumiFollowOrigin : BaseModel +{ + [JsonProperty("data")] public BangumiFollowData Data { get; set; } +} + +public class BangumiFollowData : BaseModel +{ + [JsonProperty("list")] public List List { get; set; } + [JsonProperty("pn")] public int Pn { get; set; } + [JsonProperty("ps")] public int Ps { get; set; } + [JsonProperty("total")] public int Total { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Users/Models/BangumiType.cs b/DownKyi.Core/BiliApi/Users/Models/BangumiType.cs new file mode 100644 index 0000000..4f63dcd --- /dev/null +++ b/DownKyi.Core/BiliApi/Users/Models/BangumiType.cs @@ -0,0 +1,7 @@ +namespace DownKyi.Core.BiliApi.Users.Models; + +public enum BangumiType +{ + ANIME = 1, // 番剧 + EPISODE = 2 // 剧集、电影 +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Users/Models/FollowingGroup.cs b/DownKyi.Core/BiliApi/Users/Models/FollowingGroup.cs new file mode 100644 index 0000000..c26fbf2 --- /dev/null +++ b/DownKyi.Core/BiliApi/Users/Models/FollowingGroup.cs @@ -0,0 +1,18 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Users.Models; + +// https://api.bilibili.com/x/relation/tags +public class FollowingGroupOrigin : BaseModel +{ + [JsonProperty("data")] public List Data { get; set; } +} + +public class FollowingGroup : BaseModel +{ + [JsonProperty("tagid")] public int TagId { get; set; } + [JsonProperty("name")] public string Name { get; set; } + [JsonProperty("count")] public int Count { get; set; } + [JsonProperty("tip")] public string Tip { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Users/Models/FollowingGroupContent.cs b/DownKyi.Core/BiliApi/Users/Models/FollowingGroupContent.cs new file mode 100644 index 0000000..25a9e10 --- /dev/null +++ b/DownKyi.Core/BiliApi/Users/Models/FollowingGroupContent.cs @@ -0,0 +1,10 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Users.Models; + +// https://api.bilibili.com/x/relation/tag?tagid={tagId}&pn={pn}&ps={ps}&order_type={orderType} +public class FollowingGroupContent : BaseModel +{ + [JsonProperty("data")] public List Data { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Users/Models/FollowingOrder.cs b/DownKyi.Core/BiliApi/Users/Models/FollowingOrder.cs new file mode 100644 index 0000000..90e684d --- /dev/null +++ b/DownKyi.Core/BiliApi/Users/Models/FollowingOrder.cs @@ -0,0 +1,7 @@ +namespace DownKyi.Core.BiliApi.Users.Models; + +public enum FollowingOrder +{ + DEFAULT = 1, // 按照关注顺序排列,默认 + ATTENTION // 按照最常访问排列 +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Users/Models/MyInfo.cs b/DownKyi.Core/BiliApi/Users/Models/MyInfo.cs new file mode 100644 index 0000000..6a19039 --- /dev/null +++ b/DownKyi.Core/BiliApi/Users/Models/MyInfo.cs @@ -0,0 +1,59 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Users.Models; + +// https://api.bilibili.com/x/space/myinfo +public class MyInfoOrigin : BaseModel +{ + //[JsonProperty("code")] + //public int Code { get; set; } + //[JsonProperty("message")] + //public string Message { get; set; } + //[JsonProperty("ttl")] + //public int Ttl { get; set; } + [JsonProperty("data")] public MyInfo Data { get; set; } +} + +public class MyInfo : BaseModel +{ + [JsonProperty("mid")] public long Mid { get; set; } + [JsonProperty("name")] public string Name { get; set; } + [JsonProperty("sex")] public string Sex { get; set; } + [JsonProperty("face")] public string Face { get; set; } + + [JsonProperty("sign")] public string Sign { get; set; } + + // rank + [JsonProperty("level")] public int Level { get; set; } + + // jointime + [JsonProperty("moral")] public int Moral { get; set; } + [JsonProperty("silence")] public int Silence { get; set; } + [JsonProperty("email_status")] public int EmailStatus { get; set; } + [JsonProperty("tel_status")] public int TelStatus { get; set; } + [JsonProperty("identification")] public int Identification { get; set; } + + [JsonProperty("vip")] public UserInfoVip Vip { get; set; } + + // pendant + // nameplate + // official + [JsonProperty("birthday")] public long Birthday { get; set; } + [JsonProperty("is_tourist")] public int IsTourist { get; set; } + [JsonProperty("is_fake_account")] public int IsFakeAccount { get; set; } + [JsonProperty("pin_prompting")] public int PinPrompting { get; set; } + + [JsonProperty("is_deleted")] public int IsDeleted { get; set; } + + // in_reg_audit + // is_rip_user + // profession + // face_nft + // face_nft_new + // is_senior_member + [JsonProperty("level_exp")] public UserInfoLevelExp LevelExp { get; set; } + [JsonProperty("coins")] public float Coins { get; set; } + [JsonProperty("following")] public int Following { get; set; } + [JsonProperty("follower")] public int Follower { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Users/Models/NicknameStatus.cs b/DownKyi.Core/BiliApi/Users/Models/NicknameStatus.cs new file mode 100644 index 0000000..e37e7cd --- /dev/null +++ b/DownKyi.Core/BiliApi/Users/Models/NicknameStatus.cs @@ -0,0 +1,11 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Users.Models; + +// https://api.bilibili.com/x/relation/stat?nickName={nickName} +public class NicknameStatus : BaseModel +{ + [JsonProperty("code")] public int Code { get; set; } + [JsonProperty("message")] public string Message { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Users/Models/PublicationOrder.cs b/DownKyi.Core/BiliApi/Users/Models/PublicationOrder.cs new file mode 100644 index 0000000..afaf859 --- /dev/null +++ b/DownKyi.Core/BiliApi/Users/Models/PublicationOrder.cs @@ -0,0 +1,8 @@ +namespace DownKyi.Core.BiliApi.Users.Models; + +public enum PublicationOrder +{ + PUBDATE = 1, // 最新发布,默认 + CLICK, // 最多播放 + STOW // 最多收藏 +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Users/Models/RelationBlack.cs b/DownKyi.Core/BiliApi/Users/Models/RelationBlack.cs new file mode 100644 index 0000000..b3e4647 --- /dev/null +++ b/DownKyi.Core/BiliApi/Users/Models/RelationBlack.cs @@ -0,0 +1,10 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Users.Models; + +// https://api.bilibili.com/x/relation/blacks?pn={pn}&ps={ps} +public class RelationBlack : BaseModel +{ + [JsonProperty("data")] public List Data { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Users/Models/RelationFollow.cs b/DownKyi.Core/BiliApi/Users/Models/RelationFollow.cs new file mode 100644 index 0000000..efde758 --- /dev/null +++ b/DownKyi.Core/BiliApi/Users/Models/RelationFollow.cs @@ -0,0 +1,20 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Users.Models; + +// https://api.bilibili.com/x/relation/followers?vmid={mid}&pn={pn}&ps={ps} +// https://api.bilibili.com/x/relation/followings?vmid={mid}&pn={pn}&ps={ps}&order_type={orderType} +public class RelationFollowOrigin : BaseModel +{ + [JsonProperty("data")] public RelationFollow Data { get; set; } +} + +public class RelationFollow : BaseModel +{ + [JsonProperty("list")] public List List { get; set; } + + //[JsonProperty("re_version")] + //public long reVersion { get; set; } + [JsonProperty("total")] public int Total { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Users/Models/RelationFollowInfo.cs b/DownKyi.Core/BiliApi/Users/Models/RelationFollowInfo.cs new file mode 100644 index 0000000..61465c5 --- /dev/null +++ b/DownKyi.Core/BiliApi/Users/Models/RelationFollowInfo.cs @@ -0,0 +1,24 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Users.Models; + +public class RelationFollowInfo : BaseModel +{ + [JsonProperty("mid")] public long Mid { get; set; } + [JsonProperty("attribute")] public int Attribute { get; set; } + [JsonProperty("mtime")] public long Mtime { get; set; } + [JsonProperty("tag")] public List Tag { get; set; } + + [JsonProperty("special")] public int Special { get; set; } + + // contract_info + [JsonProperty("uname")] public string Name { get; set; } + [JsonProperty("face")] public string Face { get; set; } + + [JsonProperty("sign")] public string Sign { get; set; } + // face_nft + // official_verify + // vip + // nft_icon +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Users/Models/RelationWhisper.cs b/DownKyi.Core/BiliApi/Users/Models/RelationWhisper.cs new file mode 100644 index 0000000..50b2688 --- /dev/null +++ b/DownKyi.Core/BiliApi/Users/Models/RelationWhisper.cs @@ -0,0 +1,16 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Users.Models; + +// https://api.bilibili.com/x/relation/whispers?pn={pn}&ps={ps} +public class RelationWhisper : BaseModel +{ + [JsonProperty("data")] public RelationWhisperData Data { get; set; } +} + +public class RelationWhisperData : BaseModel +{ + [JsonProperty("list")] public List List { get; set; } + // re_version +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Users/Models/SpaceChannel.cs b/DownKyi.Core/BiliApi/Users/Models/SpaceChannel.cs new file mode 100644 index 0000000..59ed4a0 --- /dev/null +++ b/DownKyi.Core/BiliApi/Users/Models/SpaceChannel.cs @@ -0,0 +1,19 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Users.Models; + +// https://api.bilibili.com/x/space/channel/list?mid={mid} +public class SpaceChannelOrigin : BaseModel +{ + [JsonProperty("data")] + public SpaceChannel Data { get; set; } +} + +public class SpaceChannel : BaseModel +{ + [JsonProperty("count")] + public int Count { get; set; } + [JsonProperty("list")] + public List List { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Users/Models/SpaceChannelArchive.cs b/DownKyi.Core/BiliApi/Users/Models/SpaceChannelArchive.cs new file mode 100644 index 0000000..af3b31b --- /dev/null +++ b/DownKyi.Core/BiliApi/Users/Models/SpaceChannelArchive.cs @@ -0,0 +1,42 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Users.Models; + +public class SpaceChannelArchive : BaseModel +{ + [JsonProperty("aid")] public long Aid { get; set; } + + // videos + [JsonProperty("tid")] public int Tid { get; set; } + + [JsonProperty("tname")] public string Tname { get; set; } + + // copyright + [JsonProperty("pic")] public string Pic { get; set; } + [JsonProperty("title")] public string Title { get; set; } + [JsonProperty("pubdate")] public long Pubdate { get; set; } + [JsonProperty("ctime")] public long Ctime { get; set; } + + [JsonProperty("desc")] public string Desc { get; set; } + + // state + [JsonProperty("duration")] public long Duration { get; set; } + + // mission_id + // rights + [JsonProperty("owner")] public VideoOwner Owner { get; set; } + + [JsonProperty("stat")] public SpaceChannelArchiveStat Stat { get; set; } + + // dynamic + [JsonProperty("cid")] public long Cid { get; set; } + + [JsonProperty("dimension")] public Dimension Dimension { get; set; } + + // season_id + // short_link_v2 + [JsonProperty("bvid")] public string Bvid { get; set; } + // inter_video + // is_live_playback +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Users/Models/SpaceChannelArchiveStat.cs b/DownKyi.Core/BiliApi/Users/Models/SpaceChannelArchiveStat.cs new file mode 100644 index 0000000..f25912d --- /dev/null +++ b/DownKyi.Core/BiliApi/Users/Models/SpaceChannelArchiveStat.cs @@ -0,0 +1,19 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Users.Models; + +public class SpaceChannelArchiveStat : BaseModel +{ + [JsonProperty("aid")] public long Aid { get; set; } + [JsonProperty("view")] public long View { get; set; } + [JsonProperty("danmaku")] public long Danmaku { get; set; } + [JsonProperty("reply")] public long Reply { get; set; } + [JsonProperty("favorite")] public long Favorite { get; set; } + [JsonProperty("coin")] public long Coin { get; set; } + [JsonProperty("share")] public long Share { get; set; } + [JsonProperty("now_rank")] public long NowRank { get; set; } + [JsonProperty("his_rank")] public long HisRank { get; set; } + [JsonProperty("like")] public long Like { get; set; } + [JsonProperty("dislike")] public long Dislike { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Users/Models/SpaceChannelList.cs b/DownKyi.Core/BiliApi/Users/Models/SpaceChannelList.cs new file mode 100644 index 0000000..7dd25fa --- /dev/null +++ b/DownKyi.Core/BiliApi/Users/Models/SpaceChannelList.cs @@ -0,0 +1,17 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Users.Models; + +public class SpaceChannelList : BaseModel +{ + [JsonProperty("cid")] public long Cid { get; set; } + [JsonProperty("mid")] public long Mid { get; set; } + [JsonProperty("name")] public string Name { get; set; } + [JsonProperty("intro")] public string Intro { get; set; } + [JsonProperty("mtime")] public long Mtime { get; set; } + [JsonProperty("count")] public int Count { get; set; } + + [JsonProperty("cover")] public string Cover { get; set; } + // is_live_playback +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Users/Models/SpaceChannelVideo.cs b/DownKyi.Core/BiliApi/Users/Models/SpaceChannelVideo.cs new file mode 100644 index 0000000..31add32 --- /dev/null +++ b/DownKyi.Core/BiliApi/Users/Models/SpaceChannelVideo.cs @@ -0,0 +1,17 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Users.Models; + +// https://api.bilibili.com/x/space/channel/video?mid={mid}&cid={cid}&pn={pn}&ps={ps} +public class SpaceChannelVideoOrigin : BaseModel +{ + [JsonProperty("data")] public SpaceChannelVideo Data { get; set; } +} + +public class SpaceChannelVideo : BaseModel +{ + // episodic_button + [JsonProperty("list")] public SpaceChannelVideoList List { get; set; } + [JsonProperty("page")] public SpaceChannelVideoPage Page { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Users/Models/SpaceChannelVideoList.cs b/DownKyi.Core/BiliApi/Users/Models/SpaceChannelVideoList.cs new file mode 100644 index 0000000..3af26ab --- /dev/null +++ b/DownKyi.Core/BiliApi/Users/Models/SpaceChannelVideoList.cs @@ -0,0 +1,19 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Users.Models; + +public class SpaceChannelVideoList : BaseModel +{ + [JsonProperty("cid")] public long Cid { get; set; } + [JsonProperty("mid")] public long Mid { get; set; } + [JsonProperty("name")] public string Name { get; set; } + [JsonProperty("intro")] public string Intro { get; set; } + [JsonProperty("mtime")] public long Mtime { get; set; } + [JsonProperty("count")] public int Count { get; set; } + + [JsonProperty("cover")] public string Cover { get; set; } + + // is_live_playback + [JsonProperty("archives")] public List Archives { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Users/Models/SpaceChannelVideoPage.cs b/DownKyi.Core/BiliApi/Users/Models/SpaceChannelVideoPage.cs new file mode 100644 index 0000000..cf15156 --- /dev/null +++ b/DownKyi.Core/BiliApi/Users/Models/SpaceChannelVideoPage.cs @@ -0,0 +1,11 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Users.Models; + +public class SpaceChannelVideoPage : BaseModel +{ + [JsonProperty("count")] public int Count { get; set; } + [JsonProperty("num")] public int Num { get; set; } + [JsonProperty("size")] public int Size { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Users/Models/SpaceCheese.cs b/DownKyi.Core/BiliApi/Users/Models/SpaceCheese.cs new file mode 100644 index 0000000..4baf80e --- /dev/null +++ b/DownKyi.Core/BiliApi/Users/Models/SpaceCheese.cs @@ -0,0 +1,17 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Users.Models; + +public class SpaceCheese : BaseModel +{ + [JsonProperty("cover")] public string Cover { get; set; } + [JsonProperty("ep_count")] public int EpCount { get; set; } + [JsonProperty("link")] public string Link { get; set; } + [JsonProperty("page")] public int Page { get; set; } + [JsonProperty("play")] public int Play { get; set; } + [JsonProperty("season_id")] public long SeasonId { get; set; } + [JsonProperty("status")] public string Status { get; set; } + [JsonProperty("subtitle")] public string SubTitle { get; set; } + [JsonProperty("title")] public string Title { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Users/Models/SpaceCheeseOrigin.cs b/DownKyi.Core/BiliApi/Users/Models/SpaceCheeseOrigin.cs new file mode 100644 index 0000000..9dc203b --- /dev/null +++ b/DownKyi.Core/BiliApi/Users/Models/SpaceCheeseOrigin.cs @@ -0,0 +1,16 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Users.Models; + +// https://api.bilibili.com/pugv/app/web/season/page?mid={mid}&pn={pn}&ps={ps} +public class SpaceCheeseOrigin : BaseModel +{ + [JsonProperty("data")] public SpaceCheeseData Data { get; set; } +} + +public class SpaceCheeseData : BaseModel +{ + [JsonProperty("items")] public List Items { get; set; } + [JsonProperty("page")] public SpaceCheesePage Page { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Users/Models/SpaceCheesePage.cs b/DownKyi.Core/BiliApi/Users/Models/SpaceCheesePage.cs new file mode 100644 index 0000000..82cc1b6 --- /dev/null +++ b/DownKyi.Core/BiliApi/Users/Models/SpaceCheesePage.cs @@ -0,0 +1,12 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Users.Models; + +public class SpaceCheesePage : BaseModel +{ + [JsonProperty("next")] public bool Next { get; set; } + [JsonProperty("num")] public int Num { get; set; } + [JsonProperty("size")] public int Size { get; set; } + [JsonProperty("total")] public int Total { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Users/Models/SpacePublication.cs b/DownKyi.Core/BiliApi/Users/Models/SpacePublication.cs new file mode 100644 index 0000000..5d183e4 --- /dev/null +++ b/DownKyi.Core/BiliApi/Users/Models/SpacePublication.cs @@ -0,0 +1,16 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Users.Models; + +// https://api.bilibili.com/x/space/arc/search +public class SpacePublicationOrigin : BaseModel +{ + [JsonProperty("data")] public SpacePublication Data { get; set; } +} + +public class SpacePublication : BaseModel +{ + [JsonProperty("list")] public SpacePublicationList List { get; set; } + [JsonProperty("page")] public SpacePublicationPage Page { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Users/Models/SpacePublicationList.cs b/DownKyi.Core/BiliApi/Users/Models/SpacePublicationList.cs new file mode 100644 index 0000000..03aafeb --- /dev/null +++ b/DownKyi.Core/BiliApi/Users/Models/SpacePublicationList.cs @@ -0,0 +1,10 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Users.Models; + +public class SpacePublicationList : BaseModel +{ + [JsonProperty("tlist")] public SpacePublicationListType Tlist { get; set; } + [JsonProperty("vlist")] public List Vlist { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Users/Models/SpacePublicationListType.cs b/DownKyi.Core/BiliApi/Users/Models/SpacePublicationListType.cs new file mode 100644 index 0000000..33c2184 --- /dev/null +++ b/DownKyi.Core/BiliApi/Users/Models/SpacePublicationListType.cs @@ -0,0 +1,29 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Users.Models; + +public class SpacePublicationListType : BaseModel +{ + [JsonProperty("1")] public SpacePublicationListTypeVideoZone Douga { get; set; } + [JsonProperty("13")] public SpacePublicationListTypeVideoZone Anime { get; set; } + [JsonProperty("167")] public SpacePublicationListTypeVideoZone Guochuang { get; set; } + [JsonProperty("3")] public SpacePublicationListTypeVideoZone Music { get; set; } + [JsonProperty("129")] public SpacePublicationListTypeVideoZone Dance { get; set; } + [JsonProperty("4")] public SpacePublicationListTypeVideoZone Game { get; set; } + [JsonProperty("36")] public SpacePublicationListTypeVideoZone Technology { get; set; } + [JsonProperty("188")] public SpacePublicationListTypeVideoZone Digital { get; set; } + [JsonProperty("234")] public SpacePublicationListTypeVideoZone Sports { get; set; } + [JsonProperty("223")] public SpacePublicationListTypeVideoZone Car { get; set; } + [JsonProperty("160")] public SpacePublicationListTypeVideoZone Life { get; set; } + [JsonProperty("211")] public SpacePublicationListTypeVideoZone Food { get; set; } + [JsonProperty("217")] public SpacePublicationListTypeVideoZone Animal { get; set; } + [JsonProperty("119")] public SpacePublicationListTypeVideoZone Kichiku { get; set; } + [JsonProperty("155")] public SpacePublicationListTypeVideoZone Fashion { get; set; } + [JsonProperty("202")] public SpacePublicationListTypeVideoZone Information { get; set; } + [JsonProperty("5")] public SpacePublicationListTypeVideoZone Ent { get; set; } + [JsonProperty("181")] public SpacePublicationListTypeVideoZone Cinephile { get; set; } + [JsonProperty("177")] public SpacePublicationListTypeVideoZone Documentary { get; set; } + [JsonProperty("23")] public SpacePublicationListTypeVideoZone Movie { get; set; } + [JsonProperty("11")] public SpacePublicationListTypeVideoZone Tv { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Users/Models/SpacePublicationListTypeVideoZone.cs b/DownKyi.Core/BiliApi/Users/Models/SpacePublicationListTypeVideoZone.cs new file mode 100644 index 0000000..b1f068d --- /dev/null +++ b/DownKyi.Core/BiliApi/Users/Models/SpacePublicationListTypeVideoZone.cs @@ -0,0 +1,11 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Users.Models; + +public class SpacePublicationListTypeVideoZone : BaseModel +{ + [JsonProperty("tid")] public int Tid { get; set; } + [JsonProperty("count")] public int Count { get; set; } + [JsonProperty("name")] public string Name { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Users/Models/SpacePublicationListVideo.cs b/DownKyi.Core/BiliApi/Users/Models/SpacePublicationListVideo.cs new file mode 100644 index 0000000..756e5b6 --- /dev/null +++ b/DownKyi.Core/BiliApi/Users/Models/SpacePublicationListVideo.cs @@ -0,0 +1,47 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Users.Models; + +public class SpacePublicationListVideo : BaseModel +{ + //[JsonProperty("comment")] + //public int Comment { get; set; } + [JsonProperty("typeid")] public int Typeid { get; set; } + [JsonProperty("play")] public int Play { get; set; } + + [JsonProperty("pic")] public string Pic { get; set; } + + //[JsonProperty("subtitle")] + //public string Subtitle { get; set; } + //[JsonProperty("description")] + //public string Description { get; set; } + //[JsonProperty("copyright")] + //public string Copyright { get; set; } + [JsonProperty("title")] public string Title { get; set; } + + //[JsonProperty("review")] + //public int Review { get; set; } + //[JsonProperty("author")] + //public string Author { get; set; } + [JsonProperty("mid")] public long Mid { get; set; } + [JsonProperty("created")] public long Created { get; set; } + + [JsonProperty("length")] public string Length { get; set; } + + //[JsonProperty("video_review")] + //public int VideoReview { get; set; } + [JsonProperty("aid")] public long Aid { get; set; } + + [JsonProperty("bvid")] public string Bvid { get; set; } + //[JsonProperty("hide_click")] + //public bool HideClick { get; set; } + //[JsonProperty("is_pay")] + //public int IsPay { get; set; } + //[JsonProperty("is_union_video")] + //public int IsUnionVideo { get; set; } + //[JsonProperty("is_steins_gate")] + //public int IsSteinsGate { get; set; } + //[JsonProperty("is_live_playback")] + //public int IsLivePlayback { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Users/Models/SpacePublicationPage.cs b/DownKyi.Core/BiliApi/Users/Models/SpacePublicationPage.cs new file mode 100644 index 0000000..a3d98ff --- /dev/null +++ b/DownKyi.Core/BiliApi/Users/Models/SpacePublicationPage.cs @@ -0,0 +1,11 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Users.Models; + +public class SpacePublicationPage : BaseModel +{ + [JsonProperty("pn")] public int Pn { get; set; } + [JsonProperty("ps")] public int Ps { get; set; } + [JsonProperty("count")] public int Count { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Users/Models/SpaceSeasonsDetail.cs b/DownKyi.Core/BiliApi/Users/Models/SpaceSeasonsDetail.cs new file mode 100644 index 0000000..7f4eafb --- /dev/null +++ b/DownKyi.Core/BiliApi/Users/Models/SpaceSeasonsDetail.cs @@ -0,0 +1,24 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Users.Models; + +// https://api.bilibili.com/x/polymer/space/seasons_archives_list?mid={mid}&season_id={seasonId}&page_num={pageNum}&page_size={pageSize}&sort_reverse=false +public class SpaceSeasonsDetailOrigin : BaseModel +{ + //[JsonProperty("code")] + //public int Code { get; set; } + //[JsonProperty("message")] + //public string Message { get; set; } + //[JsonProperty("ttl")] + //public int Ttl { get; set; } + [JsonProperty("data")] public SpaceSeasonsDetail Data { get; set; } +} + +public class SpaceSeasonsDetail : BaseModel +{ + [JsonProperty("aids")] public List Aids { get; set; } + [JsonProperty("archives")] public List Archives { get; set; } + [JsonProperty("meta")] public SpaceSeasonsMeta Meta { get; set; } + [JsonProperty("page")] public SpaceSeasonsSeriesPage Page { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Users/Models/SpaceSeasonsSeries.cs b/DownKyi.Core/BiliApi/Users/Models/SpaceSeasonsSeries.cs new file mode 100644 index 0000000..37afc90 --- /dev/null +++ b/DownKyi.Core/BiliApi/Users/Models/SpaceSeasonsSeries.cs @@ -0,0 +1,18 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Users.Models; + +public class SpaceSeasons : BaseModel +{ + [JsonProperty("archives")] public List Archives { get; set; } + [JsonProperty("meta")] public SpaceSeasonsMeta Meta { get; set; } + [JsonProperty("recent_aids")] public List RecentAids { get; set; } +} + +public class SpaceSeries : BaseModel +{ + [JsonProperty("archives")] public List Archives { get; set; } + [JsonProperty("meta")] public SpaceSeriesMeta Meta { get; set; } + [JsonProperty("recent_aids")] public List RecentAids { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Users/Models/SpaceSeasonsSeriesArchives.cs b/DownKyi.Core/BiliApi/Users/Models/SpaceSeasonsSeriesArchives.cs new file mode 100644 index 0000000..0accc4a --- /dev/null +++ b/DownKyi.Core/BiliApi/Users/Models/SpaceSeasonsSeriesArchives.cs @@ -0,0 +1,21 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Users.Models; + +public class SpaceSeasonsSeriesArchives : BaseModel +{ + [JsonProperty("aid")] public long Aid { get; set; } + [JsonProperty("bvid")] public string Bvid { get; set; } + [JsonProperty("ctime")] public long Ctime { get; set; } + [JsonProperty("duration")] public long Duration { get; set; } + [JsonProperty("interactive_video")] public bool InteractiveVideo { get; set; } + [JsonProperty("pic")] public string Pic { get; set; } + [JsonProperty("pubdate")] public long Pubdate { get; set; } + + [JsonProperty("stat")] public SpaceSeasonsSeriesStat Stat { get; set; } + + // state + [JsonProperty("title")] public string Title { get; set; } + // ugc_pay +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Users/Models/SpaceSeasonsSeriesMeta.cs b/DownKyi.Core/BiliApi/Users/Models/SpaceSeasonsSeriesMeta.cs new file mode 100644 index 0000000..d317d63 --- /dev/null +++ b/DownKyi.Core/BiliApi/Users/Models/SpaceSeasonsSeriesMeta.cs @@ -0,0 +1,32 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Users.Models; + +public class SpaceSeasonsSeriesMeta : BaseModel +{ + [JsonProperty("category")] public int Category { get; set; } + [JsonProperty("cover")] public string Cover { get; set; } + [JsonProperty("description")] public string Description { get; set; } + [JsonProperty("mid")] public long Mid { get; set; } + [JsonProperty("name")] public string Name { get; set; } + [JsonProperty("total")] public int Total { get; set; } +} + +public class SpaceSeasonsMeta : SpaceSeasonsSeriesMeta +{ + [JsonProperty("ptime")] public long Ptime { get; set; } + [JsonProperty("season_id")] public long SeasonId { get; set; } +} + +public class SpaceSeriesMeta : SpaceSeasonsSeriesMeta +{ + [JsonProperty("creator")] public string Creator { get; set; } + [JsonProperty("ctime")] public long Ctime { get; set; } + [JsonProperty("keywords")] public List Keywords { get; set; } + [JsonProperty("last_update_ts")] public long LastUpdate { get; set; } + [JsonProperty("mtime")] public long Mtime { get; set; } + [JsonProperty("raw_keywords")] public string RawKeywords { get; set; } + [JsonProperty("series_id")] public long SeriesId { get; set; } + [JsonProperty("state")] public int State { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Users/Models/SpaceSeasonsSeriesOrigin.cs b/DownKyi.Core/BiliApi/Users/Models/SpaceSeasonsSeriesOrigin.cs new file mode 100644 index 0000000..cb3621b --- /dev/null +++ b/DownKyi.Core/BiliApi/Users/Models/SpaceSeasonsSeriesOrigin.cs @@ -0,0 +1,28 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Users.Models; + +// https://api.bilibili.com/x/space/channel/video?mid={mid}&page_num={pageNum}&page_size={pageSize} +public class SpaceSeasonsSeriesOrigin : BaseModel +{ + //[JsonProperty("code")] + //public int Code { get; set; } + //[JsonProperty("message")] + //public string Message { get; set; } + //[JsonProperty("ttl")] + //public int Ttl { get; set; } + [JsonProperty("data")] public SpaceSeasonsSeriesData Data { get; set; } +} + +public class SpaceSeasonsSeriesData : BaseModel +{ + [JsonProperty("items_lists")] public SpaceSeasonsSeries ItemsLists { get; set; } +} + +public class SpaceSeasonsSeries : BaseModel +{ + [JsonProperty("page")] public SpaceSeasonsSeriesPage Page { get; set; } + [JsonProperty("seasons_list")] public List SeasonsList { get; set; } + [JsonProperty("series_list")] public List SeriesList { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Users/Models/SpaceSeasonsSeriesPage.cs b/DownKyi.Core/BiliApi/Users/Models/SpaceSeasonsSeriesPage.cs new file mode 100644 index 0000000..6d86524 --- /dev/null +++ b/DownKyi.Core/BiliApi/Users/Models/SpaceSeasonsSeriesPage.cs @@ -0,0 +1,11 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Users.Models; + +public class SpaceSeasonsSeriesPage : BaseModel +{ + [JsonProperty("page_num")] public int PageNum; + [JsonProperty("page_size")] public int PageSize; + [JsonProperty("total")] public int Total; +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Users/Models/SpaceSeasonsSeriesStat.cs b/DownKyi.Core/BiliApi/Users/Models/SpaceSeasonsSeriesStat.cs new file mode 100644 index 0000000..98bcee8 --- /dev/null +++ b/DownKyi.Core/BiliApi/Users/Models/SpaceSeasonsSeriesStat.cs @@ -0,0 +1,9 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Users.Models; + +public class SpaceSeasonsSeriesStat : BaseModel +{ + [JsonProperty("view")] public long View { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Users/Models/SpaceSeriesDetail.cs b/DownKyi.Core/BiliApi/Users/Models/SpaceSeriesDetail.cs new file mode 100644 index 0000000..2bef4fa --- /dev/null +++ b/DownKyi.Core/BiliApi/Users/Models/SpaceSeriesDetail.cs @@ -0,0 +1,24 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Users.Models; + +// https://api.bilibili.com/x/series/archives?mid={mid}&series_id={seriesId}&only_normal=true&sort=desc&pn={pn}&ps={ps} +public class SpaceSeriesDetailOrigin : BaseModel +{ + //[JsonProperty("code")] + //public int Code { get; set; } + //[JsonProperty("message")] + //public string Message { get; set; } + //[JsonProperty("ttl")] + //public int Ttl { get; set; } + [JsonProperty("data")] public SpaceSeriesDetail Data { get; set; } +} + +public class SpaceSeriesDetail : BaseModel +{ + [JsonProperty("aids")] public List Aids { get; set; } + + // page + [JsonProperty("archives")] public List Archives { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Users/Models/SpaceSeriesMeta.cs b/DownKyi.Core/BiliApi/Users/Models/SpaceSeriesMeta.cs new file mode 100644 index 0000000..38272af --- /dev/null +++ b/DownKyi.Core/BiliApi/Users/Models/SpaceSeriesMeta.cs @@ -0,0 +1,22 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Users.Models; + +// https://api.bilibili.com/x/series/series?series_id={seriesId} +public class SpaceSeriesMetaOrigin : BaseModel +{ + //[JsonProperty("code")] + //public int Code { get; set; } + //[JsonProperty("message")] + //public string Message { get; set; } + //[JsonProperty("ttl")] + //public int Ttl { get; set; } + [JsonProperty("data")] public SpaceSeriesMetaData Data { get; set; } +} + +public class SpaceSeriesMetaData : BaseModel +{ + [JsonProperty("meta")] public SpaceSeriesMeta Meta { get; set; } + [JsonProperty("recent_aids")] public List RecentAids { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Users/Models/SpaceSettings.cs b/DownKyi.Core/BiliApi/Users/Models/SpaceSettings.cs new file mode 100644 index 0000000..cb8f3c7 --- /dev/null +++ b/DownKyi.Core/BiliApi/Users/Models/SpaceSettings.cs @@ -0,0 +1,17 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Users.Models; + +// https://space.bilibili.com/ajax/settings/getSettings?mid={mid} +public class SpaceSettingsOrigin : BaseModel +{ + [JsonProperty("status")] public bool Status { get; set; } + [JsonProperty("data")] public SpaceSettings Data { get; set; } +} + +public class SpaceSettings : BaseModel +{ + // ... + [JsonProperty("toutu")] public SpaceSettingsToutu Toutu { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Users/Models/SpaceSettingsToutu.cs b/DownKyi.Core/BiliApi/Users/Models/SpaceSettingsToutu.cs new file mode 100644 index 0000000..8bdd069 --- /dev/null +++ b/DownKyi.Core/BiliApi/Users/Models/SpaceSettingsToutu.cs @@ -0,0 +1,17 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Users.Models; + +public class SpaceSettingsToutu : BaseModel +{ + [JsonProperty("sid")] public int Sid { get; set; } + [JsonProperty("expire")] public long Expire { get; set; } + [JsonProperty("s_img")] public string Simg { get; set; } // 完整url为http://i0.hdslb.com/+相对路径 + [JsonProperty("l_img")] public string Limg { get; set; } // 完整url为http://i0.hdslb.com/+相对路径 + [JsonProperty("android_img")] public string AndroidImg { get; set; } + [JsonProperty("iphone_img")] public string IphoneImg { get; set; } + [JsonProperty("ipad_img")] public string IpadImg { get; set; } + [JsonProperty("thumbnail_img")] public string ThumbnailImg { get; set; } + [JsonProperty("platform")] public int Platform { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Users/Models/UpStat.cs b/DownKyi.Core/BiliApi/Users/Models/UpStat.cs new file mode 100644 index 0000000..4036b93 --- /dev/null +++ b/DownKyi.Core/BiliApi/Users/Models/UpStat.cs @@ -0,0 +1,22 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Users.Models; + +// https://api.bilibili.com/x/space/upstat?mid={mid} +public class UpStatOrigin : BaseModel +{ + [JsonProperty("data")] public UpStat Data { get; set; } +} + +public class UpStat : BaseModel +{ + [JsonProperty("archive")] public UpStatArchive Archive { get; set; } + [JsonProperty("article")] public UpStatArchive Article { get; set; } + [JsonProperty("likes")] public long Likes { get; set; } +} + +public class UpStatArchive : BaseModel +{ + [JsonProperty("view")] public long View { get; set; } // 视频/文章播放量 +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Users/Models/UserInfoForNavigation.cs b/DownKyi.Core/BiliApi/Users/Models/UserInfoForNavigation.cs new file mode 100644 index 0000000..b6d8090 --- /dev/null +++ b/DownKyi.Core/BiliApi/Users/Models/UserInfoForNavigation.cs @@ -0,0 +1,110 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Users.Models; + +// https://api.bilibili.com/x/web-interface/nav +[JsonObject] +public class UserInfoForNavigationOrigin : BaseModel +{ + //[JsonProperty("code")] + //public int Code { get; set; } + [JsonProperty("data")] public UserInfoForNavigation Data { get; set; } + //[JsonProperty("message")] + //public string Message { get; set; } + //[JsonProperty("ttl")] + //public int Ttl { get; set; } +} + +[JsonObject] +public class UserInfoForNavigation : BaseModel +{ + //public int allowance_count { get; set; } + //public int answer_status { get; set; } + //public int email_verified { get; set; } + [JsonProperty("face")] public string Face { get; set; } + + //public bool has_shop { get; set; } + [JsonProperty("isLogin")] public bool IsLogin { get; set; } + + //public NavDataLevelInfo level_info { get; set; } + [JsonProperty("mid")] public long Mid { get; set; } + + //public int mobile_verified { get; set; } + [JsonProperty("money")] public float Money { get; set; } + + //public int moral { get; set; } + //public NavDataOfficial official { get; set; } + //public NavDataOfficialVerify officialVerify { get; set; } + //public NavDataPendant pendant { get; set; } + //public int scores { get; set; } + //public string shop_url { get; set; } + [JsonProperty("uname")] public string Name { get; set; } + + //public long vipDueDate { get; set; } + [JsonProperty("vipStatus")] public int VipStatus { get; set; } + + //public int vipType { get; set; } + //public int vip_avatar_subscript { get; set; } + //public NavDataVipLabel vip_label { get; set; } + //public string vip_nickname_color { get; set; } + //public int vip_pay_type { get; set; } + //public int vip_theme_type { get; set; } + [JsonProperty("wallet")] public UserInfoWallet Wallet { get; set; } + + [JsonProperty("wbi_img")] public Wbi Wbi { get; set; } +} + +//public class NavDataLevelInfo +//{ +// public int current_exp { get; set; } +// public int current_level { get; set; } +// public int current_min { get; set; } +// //public int next_exp { get; set; } // 当等级为6时,next_exp为string类型,值为"--" +//} + +//public class NavDataOfficial +//{ +// public string desc { get; set; } +// public int role { get; set; } +// public string title { get; set; } +// public int type { get; set; } +//} + +//public class NavDataOfficialVerify +//{ +// public string desc { get; set; } +// public int type { get; set; } +//} + +//public class NavDataPendant +//{ +// public int expire { get; set; } +// public string image { get; set; } +// public string image_enhance { get; set; } +// public string name { get; set; } +// public int pid { get; set; } +//} + +//public class NavDataVipLabel +//{ +// public string label_theme { get; set; } +// public string path { get; set; } +// public string text { get; set; } +//} + +[JsonObject] +public class UserInfoWallet : BaseModel +{ + [JsonProperty("bcoin_balance")] public float BcoinBalance { get; set; } + [JsonProperty("coupon_balance")] public float CouponBalance { get; set; } + [JsonProperty("coupon_due_time")] public long CouponDueTime { get; set; } + [JsonProperty("mid")] public long Mid { get; set; } +} + +[JsonObject] +public class Wbi +{ + [JsonProperty("img_url")] public string ImgUrl { get; set; } + [JsonProperty("sub_url")] public string SubUrl { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Users/Models/UserInfoForSpace.cs b/DownKyi.Core/BiliApi/Users/Models/UserInfoForSpace.cs new file mode 100644 index 0000000..afb97be --- /dev/null +++ b/DownKyi.Core/BiliApi/Users/Models/UserInfoForSpace.cs @@ -0,0 +1,49 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Users.Models; + +// https://api.bilibili.com/x/space/acc/info?mid={mid} +public class UserInfoForSpaceOrigin : BaseModel +{ + //[JsonProperty("code")] + //public int Code { get; set; } + //[JsonProperty("message")] + //public string Message { get; set; } + //[JsonProperty("ttl")] + //public int Ttl { get; set; } + [JsonProperty("data")] public UserInfoForSpace Data { get; set; } +} + +public class UserInfoForSpace : BaseModel +{ + [JsonProperty("mid")] public long Mid { get; set; } + [JsonProperty("name")] public string Name { get; set; } + [JsonProperty("sex")] public string Sex { get; set; } + + [JsonProperty("face")] public string Face { get; set; } + + // face_nft + [JsonProperty("sign")] public string Sign { get; set; } + + // rank + [JsonProperty("level")] public int Level { get; set; } + + // jointime + // moral + // silence + // coins + //[JsonProperty("fans_badge")] + //public bool FansBadge { get; set; } + // fans_medal + // official + [JsonProperty("vip")] public UserInfoVip Vip { get; set; } + + // pendant + // nameplate + // user_honour_info + [JsonProperty("is_followed")] public bool IsFollowed { get; set; } + + [JsonProperty("top_photo")] public string TopPhoto { get; set; } + // ... +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Users/Models/UserInfoLevelExp.cs b/DownKyi.Core/BiliApi/Users/Models/UserInfoLevelExp.cs new file mode 100644 index 0000000..322c213 --- /dev/null +++ b/DownKyi.Core/BiliApi/Users/Models/UserInfoLevelExp.cs @@ -0,0 +1,12 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Users.Models; + +public class UserInfoLevelExp : BaseModel +{ + [JsonProperty("current_level")] public int CurrentLevel { get; set; } + [JsonProperty("current_min")] public int CurrentMin { get; set; } + [JsonProperty("current_exp")] public int CurrentExp { get; set; } + [JsonProperty("next_exp")] public int NextExp { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Users/Models/UserInfoVip.cs b/DownKyi.Core/BiliApi/Users/Models/UserInfoVip.cs new file mode 100644 index 0000000..203296e --- /dev/null +++ b/DownKyi.Core/BiliApi/Users/Models/UserInfoVip.cs @@ -0,0 +1,34 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Users.Models; + +public class UserInfoVip : BaseModel +{ + [JsonProperty("type")] public int Type { get; set; } + [JsonProperty("status")] public int Status { get; set; } + + [JsonProperty("due_date")] public long DueDate { get; set; } + + // vip_pay_type + // theme_type + [JsonProperty("label")] public UserInfoVipLabel Label { get; set; } + [JsonProperty("avatar_subscript")] public int AvatarSubscript { get; set; } + + [JsonProperty("nickname_color")] public string NicknameColor { get; set; } + + // role + [JsonProperty("avatar_subscript_url")] public string AvatarSubscriptUrl { get; set; } +} + +public class UserInfoVipLabel : BaseModel +{ + // path + [JsonProperty("text")] public string Text { get; set; } + [JsonProperty("label_theme")] public string LabelTheme { get; set; } + + [JsonProperty("text_color")] public string TextColor { get; set; } + // bg_style + // bg_color + // border_color +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Users/Models/UserRelationStat.cs b/DownKyi.Core/BiliApi/Users/Models/UserRelationStat.cs new file mode 100644 index 0000000..6ba3404 --- /dev/null +++ b/DownKyi.Core/BiliApi/Users/Models/UserRelationStat.cs @@ -0,0 +1,19 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Users.Models; + +// https://api.bilibili.com/x/relation/stat?vmid={mid} +public class UserRelationStatOrigin : BaseModel +{ + [JsonProperty("data")] public UserRelationStat Data { get; set; } +} + +public class UserRelationStat : BaseModel +{ + [JsonProperty("mid")] public long Mid { get; set; } + [JsonProperty("following")] public long Following { get; set; } // 关注数 + [JsonProperty("whisper")] public long Whisper { get; set; } + [JsonProperty("black")] public long Black { get; set; } + [JsonProperty("follower")] public long Follower { get; set; } // 粉丝数 +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Users/Nickname.cs b/DownKyi.Core/BiliApi/Users/Nickname.cs new file mode 100644 index 0000000..bf24838 --- /dev/null +++ b/DownKyi.Core/BiliApi/Users/Nickname.cs @@ -0,0 +1,36 @@ +using DownKyi.Core.BiliApi.Users.Models; +using DownKyi.Core.Logging; +using Newtonsoft.Json; +using Console = DownKyi.Core.Utils.Debugging.Console; + +namespace DownKyi.Core.BiliApi.Users; + +/// +/// 用户昵称 +/// +public class Nickname +{ + /// + /// 检查昵称 + /// + /// + /// + public static NicknameStatus CheckNickname(string nickName) + { + string url = $"https://api.bilibili.com/x/relation/stat?nickName={nickName}"; + string referer = "https://www.bilibili.com"; + string response = WebClient.RequestWeb(url, referer); + + try + { + NicknameStatus nickname = JsonConvert.DeserializeObject(response); + return nickname; + } + catch (Exception e) + { + Console.PrintLine("CheckNickname()发生异常: {0}", e); + LogManager.Error("Nickname", e); + return null; + } + } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Users/UserInfo.cs b/DownKyi.Core/BiliApi/Users/UserInfo.cs new file mode 100644 index 0000000..39269de --- /dev/null +++ b/DownKyi.Core/BiliApi/Users/UserInfo.cs @@ -0,0 +1,104 @@ +using DownKyi.Core.BiliApi.Sign; +using DownKyi.Core.BiliApi.Users.Models; +using DownKyi.Core.Logging; +using Newtonsoft.Json; +using Console = DownKyi.Core.Utils.Debugging.Console; + +namespace DownKyi.Core.BiliApi.Users; + +/// +/// 用户基本信息 +/// +public static class UserInfo +{ + /// + /// 导航栏用户信息 + /// + /// + public static UserInfoForNavigation GetUserInfoForNavigation() + { + string url = "https://api.bilibili.com/x/web-interface/nav"; + string referer = "https://www.bilibili.com"; + string response = WebClient.RequestWeb(url, referer); + + try + { + UserInfoForNavigationOrigin userInfo = + JsonConvert.DeserializeObject(response); + if (userInfo == null || userInfo.Data == null) + { + return null; + } + + return userInfo.Data; + } + catch (Exception e) + { + Console.PrintLine("GetUserInfoForNavigation()发生异常: {0}", e); + LogManager.Error("UserInfo", e); + return null; + } + } + + /// + /// 用户空间详细信息 + /// + /// + /// + public static UserInfoForSpace GetUserInfoForSpace(long mid) + { + var parameters = new Dictionary + { + { "mid", mid } + }; + string query = WbiSign.ParametersToQuery(WbiSign.EncodeWbi(parameters)); + string url = $"https://api.bilibili.com/x/space/wbi/acc/info?{query}"; + string referer = "https://www.bilibili.com"; + string response = WebClient.RequestWeb(url, referer); + + try + { + UserInfoForSpaceOrigin spaceInfo = JsonConvert.DeserializeObject(response); + if (spaceInfo == null || spaceInfo.Data == null) + { + return null; + } + + return spaceInfo.Data; + } + catch (Exception e) + { + Console.PrintLine("GetInfoForSpace()发生异常: {0}", e); + LogManager.Error("UserInfo", e); + return null; + } + } + + /// + /// 本用户详细信息 + /// + /// + public static MyInfo GetMyInfo() + { + string url = "https://api.bilibili.com/x/space/myinfo"; + string referer = "https://www.bilibili.com"; + string response = WebClient.RequestWeb(url, referer); + + try + { + MyInfoOrigin myInfo = JsonConvert.DeserializeObject(response); + if (myInfo == null || myInfo.Data == null) + { + return null; + } + + return myInfo.Data; + } + catch (Exception e) + { + Console.PrintLine("GetMyInfo()发生异常: {0}", e); + LogManager.Error("UserInfo", e); + return null; + } + } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Users/UserRelation.cs b/DownKyi.Core/BiliApi/Users/UserRelation.cs new file mode 100644 index 0000000..1a2b330 --- /dev/null +++ b/DownKyi.Core/BiliApi/Users/UserRelation.cs @@ -0,0 +1,299 @@ +using DownKyi.Core.BiliApi.Users.Models; +using DownKyi.Core.Logging; +using Newtonsoft.Json; +using Console = DownKyi.Core.Utils.Debugging.Console; + +namespace DownKyi.Core.BiliApi.Users; + +/// +/// 用户关系相关 +/// +public static class UserRelation +{ + /// + /// 查询用户粉丝明细 + /// + /// 目标用户UID + /// 页码 + /// 每页项数 + /// + public static RelationFollow GetFollowers(long mid, int pn, int ps) + { + string url = $"https://api.bilibili.com/x/relation/followers?vmid={mid}&pn={pn}&ps={ps}"; + string referer = "https://www.bilibili.com"; + string response = WebClient.RequestWeb(url, referer); + + try + { + RelationFollowOrigin relationFollower = JsonConvert.DeserializeObject(response); + if (relationFollower == null || relationFollower.Data == null) + { + return null; + } + + return relationFollower.Data; + } + catch (Exception e) + { + Console.PrintLine("GetFollowers()发生异常: {0}", e); + LogManager.Error("UserRelation", e); + return null; + } + } + + /// + /// 查询用户所有的粉丝明细 + /// + /// 目标用户UID + /// + public static List GetAllFollowers(long mid) + { + List result = new List(); + + int i = 0; + while (true) + { + i++; + int ps = 50; + + RelationFollow data = GetFollowers(mid, i, ps); + if (data == null || data.List == null || data.List.Count == 0) + { + break; + } + + result.AddRange(data.List); + } + + return result; + } + + /// + /// 查询用户关注明细 + /// + /// 目标用户UID + /// 页码 + /// 每页项数 + /// 排序方式 + /// + public static RelationFollow GetFollowings(long mid, int pn, int ps, + FollowingOrder order = FollowingOrder.DEFAULT) + { + string orderType = ""; + if (order == FollowingOrder.ATTENTION) + { + orderType = "attention"; + } + + string url = + $"https://api.bilibili.com/x/relation/followings?vmid={mid}&pn={pn}&ps={ps}&order_type={orderType}"; + string referer = "https://www.bilibili.com"; + string response = WebClient.RequestWeb(url, referer); + + try + { + RelationFollowOrigin relationFollower = JsonConvert.DeserializeObject(response); + if (relationFollower == null || relationFollower.Data == null) + { + return null; + } + + return relationFollower.Data; + } + catch (Exception e) + { + Console.PrintLine("GetFollowings()发生异常: {0}", e); + LogManager.Error("UserRelation", e); + return null; + } + } + + /// + /// 查询用户所有的关注明细 + /// + /// 目标用户UID + /// 排序方式 + /// + public static List GetAllFollowings(long mid, FollowingOrder order = FollowingOrder.DEFAULT) + { + List result = new List(); + + int i = 0; + while (true) + { + i++; + int ps = 50; + + RelationFollow data = GetFollowings(mid, i, ps, order); + if (data == null || data.List == null || data.List.Count == 0) + { + break; + } + + result.AddRange(data.List); + } + + return result; + } + + /// + /// 查询悄悄关注明细 + /// + /// 页码 + /// 每页项数 + /// + public static List GetWhispers(int pn, int ps) + { + string url = $"https://api.bilibili.com/x/relation/whispers?pn={pn}&ps={ps}"; + string referer = "https://www.bilibili.com"; + string response = WebClient.RequestWeb(url, referer); + + try + { + RelationWhisper relationWhisper = JsonConvert.DeserializeObject(response); + if (relationWhisper == null || relationWhisper.Data == null || relationWhisper.Data.List == null) + { + return null; + } + + return relationWhisper.Data.List; + } + catch (Exception e) + { + Console.PrintLine("GetWhispers()发生异常: {0}", e); + LogManager.Error("UserRelation", e); + return null; + } + } + + /// + /// 查询黑名单明细 + /// + /// 页码 + /// 每页项数 + /// + public static List GetBlacks(int pn, int ps) + { + string url = $"https://api.bilibili.com/x/relation/blacks?pn={pn}&ps={ps}"; + string referer = "https://www.bilibili.com"; + string response = WebClient.RequestWeb(url, referer); + + try + { + RelationBlack relationBlack = JsonConvert.DeserializeObject(response); + if (relationBlack == null || relationBlack.Data == null) + { + return null; + } + + return relationBlack.Data; + } + catch (Exception e) + { + Console.PrintLine("GetBlacks()发生异常: {0}", e); + LogManager.Error("UserRelation", e); + return null; + } + } + + #region 关注分组相关,只能查询当前登录账户的信息 + + /// + /// 查询关注分组列表 + /// + /// + public static List GetFollowingGroup() + { + string url = $"https://api.bilibili.com/x/relation/tags"; + string referer = "https://www.bilibili.com"; + string response = WebClient.RequestWeb(url, referer); + + try + { + var followingGroup = JsonConvert.DeserializeObject(response); + if (followingGroup == null || followingGroup.Data == null) + { + return null; + } + + return followingGroup.Data; + } + catch (Exception e) + { + Console.PrintLine("GetFollowingGroup()发生异常: {0}", e); + LogManager.Error("UserRelation", e); + return null; + } + } + + /// + /// 查询关注分组明细 + /// + /// 分组ID + /// 页数 + /// 每页项数 + /// 排序方式 + /// + public static List GetFollowingGroupContent(long tagId, int pn, int ps, + FollowingOrder order = FollowingOrder.DEFAULT) + { + string orderType = ""; + if (order == FollowingOrder.ATTENTION) + { + orderType = "attention"; + } + + string url = + $"https://api.bilibili.com/x/relation/tag?tagid={tagId}&pn={pn}&ps={ps}&order_type={orderType}"; + string referer = "https://www.bilibili.com"; + string response = WebClient.RequestWeb(url, referer); + + try + { + FollowingGroupContent content = JsonConvert.DeserializeObject(response); + if (content == null || content.Data == null) + { + return null; + } + + return content.Data; + } + catch (Exception e) + { + Console.PrintLine("GetFollowingGroupContent()发生异常: {0}", e); + LogManager.Error("UserRelation", e); + return null; + } + } + + /// + /// 查询所有的关注分组明细 + /// + /// 分组ID + /// 排序方式 + /// + public static List GetAllFollowingGroupContent(int tagId, + FollowingOrder order = FollowingOrder.DEFAULT) + { + List result = new List(); + + int i = 0; + while (true) + { + i++; + int ps = 50; + + var data = GetFollowingGroupContent(tagId, i, ps, order); + if (data == null || data.Count == 0) + { + break; + } + + result.AddRange(data); + } + + return result; + } + + #endregion +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Users/UserSpace.cs b/DownKyi.Core/BiliApi/Users/UserSpace.cs new file mode 100644 index 0000000..a1409ba --- /dev/null +++ b/DownKyi.Core/BiliApi/Users/UserSpace.cs @@ -0,0 +1,476 @@ +using DownKyi.Core.BiliApi.Sign; +using DownKyi.Core.BiliApi.Users.Models; +using DownKyi.Core.Logging; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Console = DownKyi.Core.Utils.Debugging.Console; + +namespace DownKyi.Core.BiliApi.Users; + +/// +/// 用户空间信息 +/// +public static class UserSpace +{ + /// + /// 查询空间设置 + /// + /// + /// + public static SpaceSettings GetSpaceSettings(long mid) + { + string url = $"https://space.bilibili.com/ajax/settings/getSettings?mid={mid}"; + string referer = "https://www.bilibili.com"; + string response = WebClient.RequestWeb(url, referer); + + try + { + SpaceSettingsOrigin settings = JsonConvert.DeserializeObject(response); + if (settings == null || settings.Data == null || !settings.Status) { return null; } + return settings.Data; + } + catch (Exception e) + { + Console.PrintLine("GetSpaceSettings()发生异常: {0}", e); + LogManager.Error("UserSpace", e); + return null; + } + } + + #region 投稿 + + /// + /// 获取用户投稿视频的所有分区 + /// + /// 用户id + /// + public static List GetPublicationType(long mid) + { + int pn = 1; + int ps = 1; + SpacePublicationList publication = GetPublication(mid, pn, ps); + return GetPublicationType(publication); + } + + /// + /// 获取用户投稿视频的所有分区 + /// + /// 用户id + /// + public static List GetPublicationType(SpacePublicationList publication) + { + if (publication == null || publication.Tlist == null) + { + return null; + } + + List result = new List(); + JObject typeList = JObject.Parse(publication.Tlist.ToString("N")); + foreach (KeyValuePair item in typeList) + { + SpacePublicationListTypeVideoZone value = JsonConvert.DeserializeObject(item.Value.ToString()); + result.Add(value); + } + return result; + } + + /// + /// 查询用户所有的投稿视频明细 + /// + /// 用户id + /// 排序 + /// 视频分区 + /// 搜索关键词 + /// + public static List GetAllPublication(long mid, int tid = 0, PublicationOrder order = PublicationOrder.PUBDATE, string keyword = "") + { + List result = new List(); + + int i = 0; + while (true) + { + i++; + int ps = 100; + + SpacePublicationList data = GetPublication(mid, i, ps, tid, order, keyword); + if (data == null || data.Vlist == null || data.Vlist.Count == 0) + { break; } + + result.AddRange(data.Vlist); + } + + return result; + } + + /// + /// 查询用户投稿视频明细 + /// + /// 用户id + /// 页码 + /// 每页的视频数 + /// 排序 + /// 视频分区 + /// 搜索关键词 + /// + public static SpacePublicationList GetPublication(long mid, int pn, int ps, long tid = 0, PublicationOrder order = PublicationOrder.PUBDATE, string keyword = "") + { + var parameters = new Dictionary + { + { "mid", mid }, + { "pn", pn }, + { "ps", ps }, + { "order", order.ToString("G").ToLower() }, + { "tid", tid }, + { "keyword", keyword }, + }; + string query = WbiSign.ParametersToQuery(WbiSign.EncodeWbi(parameters)); + string url = $"https://api.bilibili.com/x/space/wbi/arc/search?{query}"; + string referer = "https://www.bilibili.com"; + string response = WebClient.RequestWeb(url, referer); + + try + { + // 忽略play的值为“--”时的类型错误 + JsonSerializerSettings settings = new JsonSerializerSettings + { + Error = (sender, args) => + { + if (Equals(args.ErrorContext.Member, "play") && + args.ErrorContext.OriginalObject.GetType() == typeof(SpacePublicationListVideo)) + { + args.ErrorContext.Handled = true; + } + } + }; + + SpacePublicationOrigin spacePublication = JsonConvert.DeserializeObject(response, settings); + if (spacePublication == null || spacePublication.Data == null) { return null; } + return spacePublication.Data.List; + } + catch (Exception e) + { + Console.PrintLine("GetPublication()发生异常: {0}", e); + LogManager.Error("UserSpace", e); + return null; + } + } + + #endregion + + #region 频道 + + /// + /// 查询用户频道列表 + /// + /// 用户id + /// + public static List GetChannelList(long mid) + { + string url = $"https://api.bilibili.com/x/space/channel/list?mid={mid}"; + string referer = "https://www.bilibili.com"; + string response = WebClient.RequestWeb(url, referer); + + try + { + SpaceChannelOrigin spaceChannel = JsonConvert.DeserializeObject(response); + if (spaceChannel == null || spaceChannel.Data == null) { return null; } + return spaceChannel.Data.List; + } + catch (Exception e) + { + Console.PrintLine("GetChannelList()发生异常: {0}", e); + LogManager.Error("UserSpace", e); + return null; + } + } + + /// + /// 查询用户频道中的所有视频 + /// + /// + /// + /// + public static List GetAllChannelVideoList(long mid, long cid) + { + List result = new List(); + + int i = 0; + while (true) + { + i++; + int ps = 100; + + List data = GetChannelVideoList(mid, cid, i, ps); + if (data == null || data.Count == 0) + { break; } + + result.AddRange(data); + } + return result; + } + + /// + /// 查询用户频道中的视频 + /// + /// + /// + /// + /// + /// + public static List GetChannelVideoList(long mid, long cid, int pn, int ps) + { + string url = $"https://api.bilibili.com/x/space/channel/video?mid={mid}&cid={cid}&pn={pn}&ps={ps}"; + string referer = "https://www.bilibili.com"; + string response = WebClient.RequestWeb(url, referer); + + try + { + SpaceChannelVideoOrigin spaceChannelVideo = JsonConvert.DeserializeObject(response); + if (spaceChannelVideo == null || spaceChannelVideo.Data == null || spaceChannelVideo.Data.List == null) + { return null; } + return spaceChannelVideo.Data.List.Archives; + } + catch (Exception e) + { + Console.PrintLine("GetChannelVideoList()发生异常: {0}", e); + LogManager.Error("UserSpace", e); + return null; + } + } + + #endregion + + #region 合集和列表 + + /// + /// 查询用户的合集和列表 + /// + /// + /// 第几页 + /// 每页的数量;最大值为20 + /// + public static SpaceSeasonsSeries GetSeasonsSeries(long mid, int pageNum, int pageSize) + { + // https://api.bilibili.com/x/polymer/space/seasons_series_list?mid=49246269&page_num=1&page_size=18 + string url = $"https://api.bilibili.com/x/polymer/space/seasons_series_list?mid={mid}&page_num={pageNum}&page_size={pageSize}"; + string referer = "https://www.bilibili.com"; + string response = WebClient.RequestWeb(url, referer); + + try + { + SpaceSeasonsSeriesOrigin origin = JsonConvert.DeserializeObject(response); + if (origin == null || origin.Data == null || origin.Data.ItemsLists == null) + { return null; } + return origin.Data.ItemsLists; + } + catch (Exception e) + { + Console.PrintLine("GetSeasonsSeries()发生异常: {0}", e); + LogManager.Error("UserSpace", e); + return null; + } + } + + /// + /// 查询用户的合集的视频详情 + /// + /// + /// + /// + /// + public static SpaceSeasonsDetail GetSeasonsDetail(long mid, long seasonId, int pageNum, int pageSize) + { + // https://api.bilibili.com/x/polymer/space/seasons_archives_list?mid=23947287&season_id=665&sort_reverse=false&page_num=1&page_size=30 + string url = $"https://api.bilibili.com/x/polymer/space/seasons_archives_list?mid={mid}&season_id={seasonId}&page_num={pageNum}&page_size={pageSize}&sort_reverse=false"; + string referer = "https://www.bilibili.com"; + string response = WebClient.RequestWeb(url, referer); + + try + { + SpaceSeasonsDetailOrigin origin = JsonConvert.DeserializeObject(response); + if (origin == null || origin.Data == null) + { return null; } + return origin.Data; + } + catch (Exception e) + { + Console.PrintLine("GetSeasonsDetail()发生异常: {0}", e); + LogManager.Error("UserSpace", e); + return null; + } + } + + /// + /// 查询用户的列表元数据 + /// + /// + /// + public static SpaceSeriesMetaData GetSeriesMeta(long seriesId) + { + // https://api.bilibili.com/x/series/series?series_id=1253087 + string url = $"https://api.bilibili.com/x/series/series?series_id={seriesId}"; + string referer = "https://www.bilibili.com"; + string response = WebClient.RequestWeb(url, referer); + + try + { + SpaceSeriesMetaOrigin origin = JsonConvert.DeserializeObject(response); + if (origin == null || origin.Data == null) + { return null; } + return origin.Data; + } + catch (Exception e) + { + Console.PrintLine("GetSeriesMeta()发生异常: {0}", e); + LogManager.Error("UserSpace", e); + return null; + } + } + + /// + /// 查询用户的列表的视频详情 + /// + /// + /// + /// + /// + /// + public static SpaceSeriesDetail GetSeriesDetail(long mid, long seriesId, int pn, int ps) + { + // https://api.bilibili.com/x/series/archives?mid=27899754&series_id=1253087&only_normal=true&sort=desc&pn=1&ps=30 + + string url = $"https://api.bilibili.com/x/series/archives?mid={mid}&series_id={seriesId}&only_normal=true&sort=desc&pn={pn}&ps={ps}"; + string referer = "https://www.bilibili.com"; + string response = WebClient.RequestWeb(url, referer); + + try + { + SpaceSeriesDetailOrigin origin = JsonConvert.DeserializeObject(response); + if (origin == null || origin.Data == null) + { return null; } + return origin.Data; + } + catch (Exception e) + { + Console.PrintLine("GetSeriesDetail()发生异常: {0}", e); + LogManager.Error("UserSpace", e); + return null; + } + } + + #endregion + + #region 课程 + /// + /// 查询用户发布的课程列表 + /// + /// 目标用户UID + /// 页码 + /// 每页项数 + /// + public static List GetCheese(long mid, int pn, int ps) + { + string url = $"https://api.bilibili.com/pugv/app/web/season/page?mid={mid}&pn={pn}&ps={ps}"; + string referer = "https://www.bilibili.com"; + string response = WebClient.RequestWeb(url, referer); + + try + { + SpaceCheeseOrigin cheese = JsonConvert.DeserializeObject(response); + if (cheese == null || cheese.Data == null || cheese.Data.Items == null) + { return null; } + return cheese.Data.Items; + } + catch (Exception e) + { + Console.PrintLine("GetCheese()发生异常: {0}", e); + LogManager.Error("UserSpace", e); + return null; + } + } + + /// + /// 查询用户发布的所有课程列表 + /// + /// 目标用户UID + /// + public static List GetAllCheese(long mid) + { + List result = new List(); + + int i = 0; + while (true) + { + i++; + int ps = 50; + + List data = GetCheese(mid, i, ps); + if (data == null || data.Count == 0) + { break; } + + result.AddRange(data); + } + return result; + } + + #endregion + + #region 订阅 + + /// + /// 查询用户追番(追剧)明细 + /// + /// 目标用户UID + /// 查询类型 + /// 页码 + /// 每页项数 + /// + public static BangumiFollowData GetBangumiFollow(long mid, BangumiType type, int pn, int ps) + { + string url = $"https://api.bilibili.com/x/space/bangumi/follow/list?vmid={mid}&type={type:D}&pn={pn}&ps={ps}"; + string referer = "https://www.bilibili.com"; + string response = WebClient.RequestWeb(url, referer); + + try + { + BangumiFollowOrigin bangumiFollow = JsonConvert.DeserializeObject(response); + if (bangumiFollow == null || bangumiFollow.Data == null) + { return null; } + return bangumiFollow.Data; + } + catch (Exception e) + { + Console.PrintLine("GetBangumiFollow()发生异常: {0}", e); + LogManager.Error("UserSpace", e); + return null; + } + } + + /// + /// 查询用户所有的追番(追剧)明细 + /// + /// 目标用户UID + /// 查询类型 + /// + public static List GetAllBangumiFollow(long mid, BangumiType type) + { + List result = new List(); + + int i = 0; + while (true) + { + i++; + int ps = 30; + + BangumiFollowData data = GetBangumiFollow(mid, type, i, ps); + if (data == null || data.List == null || data.List.Count == 0) + { break; } + + result.AddRange(data.List); + } + return result; + } + + #endregion + +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Users/UserStatus.cs b/DownKyi.Core/BiliApi/Users/UserStatus.cs new file mode 100644 index 0000000..b17c4be --- /dev/null +++ b/DownKyi.Core/BiliApi/Users/UserStatus.cs @@ -0,0 +1,73 @@ +using DownKyi.Core.BiliApi.Users.Models; +using DownKyi.Core.Logging; +using Newtonsoft.Json; +using Console = DownKyi.Core.Utils.Debugging.Console; + +namespace DownKyi.Core.BiliApi.Users; + +/// +/// 用户状态数 +/// +public static class UserStatus +{ + /// + /// 关系状态数 + /// + /// + /// + public static UserRelationStat GetUserRelationStat(long mid) + { + string url = $"https://api.bilibili.com/x/relation/stat?vmid={mid}"; + string referer = "https://www.bilibili.com"; + string response = WebClient.RequestWeb(url, referer); + + try + { + UserRelationStatOrigin userRelationStat = + JsonConvert.DeserializeObject(response); + if (userRelationStat == null || userRelationStat.Data == null) + { + return null; + } + + return userRelationStat.Data; + } + catch (Exception e) + { + Console.PrintLine("GetUserRelationStat()发生异常: {0}", e); + LogManager.Error("UserStatus", e); + return null; + } + } + + /// + /// UP主状态数 + /// + /// 注:该接口需要任意用户登录,否则不会返回任何数据 + /// + /// + /// + public static UpStat GetUpStat(long mid) + { + string url = $"https://api.bilibili.com/x/space/upstat?mid={mid}"; + string referer = "https://www.bilibili.com"; + string response = WebClient.RequestWeb(url, referer); + + try + { + UpStatOrigin upStat = JsonConvert.DeserializeObject(response); + if (upStat == null || upStat.Data == null) + { + return null; + } + + return upStat.Data; + } + catch (Exception e) + { + Console.PrintLine("GetUpStat()发生异常: {0}", e); + LogManager.Error("UserStatus", e); + return null; + } + } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Video/Dynamic.cs b/DownKyi.Core/BiliApi/Video/Dynamic.cs new file mode 100644 index 0000000..de1e076 --- /dev/null +++ b/DownKyi.Core/BiliApi/Video/Dynamic.cs @@ -0,0 +1,42 @@ +using DownKyi.Core.BiliApi.Video.Models; +using DownKyi.Core.Logging; +using Newtonsoft.Json; +using Console = DownKyi.Core.Utils.Debugging.Console; + +namespace DownKyi.Core.BiliApi.Video; + +public static class Dynamic +{ + /// + /// 获取分区最新视频列表 + /// + /// 目标分区tid + /// 页码 + /// 每页项数(最大50) + /// + public static List RegionDynamicList(int rid, int pn = 1, int ps = 5) + { + string url = $"https://api.bilibili.com/x/web-interface/dynamic/region?rid={rid}&pn={pn}&ps={ps}"; + string referer = "https://www.bilibili.com"; + string response = WebClient.RequestWeb(url, referer); + + try + { + var dynamic = JsonConvert.DeserializeObject(response); + if (dynamic != null && dynamic.Data != null) + { + return dynamic.Data.Archives; + } + else + { + return null; + } + } + catch (Exception e) + { + Console.PrintLine("RegionDynamicList()发生异常: {0}", e); + LogManager.Error("Dynamic", e); + return null; + } + } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Video/Models/DynamicVideoView.cs b/DownKyi.Core/BiliApi/Video/Models/DynamicVideoView.cs new file mode 100644 index 0000000..d685bf6 --- /dev/null +++ b/DownKyi.Core/BiliApi/Video/Models/DynamicVideoView.cs @@ -0,0 +1,31 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Video.Models; + +public class DynamicVideoView : BaseModel +{ + [JsonProperty("aid")] public long Aid { get; set; } + [JsonProperty("videos")] public int Videos { get; set; } + [JsonProperty("tid")] public int Tid { get; set; } + [JsonProperty("tname")] public string Tname { get; set; } + [JsonProperty("copyright")] public int Copyright { get; set; } + [JsonProperty("pic")] public string Pic { get; set; } + [JsonProperty("title")] public string Title { get; set; } + [JsonProperty("pubdate")] public long Pubdate { get; set; } + [JsonProperty("ctime")] public long Ctime { get; set; } + [JsonProperty("desc")] public string Desc { get; set; } + [JsonProperty("state")] public int State { get; set; } + [JsonProperty("duration")] public long Duration { get; set; } + [JsonProperty("owner")] public VideoOwner Owner { get; set; } + [JsonProperty("stat")] public VideoStat Stat { get; set; } + [JsonProperty("dynamic")] public string Dynamic { get; set; } + [JsonProperty("cid")] public long Cid { get; set; } + [JsonProperty("dimension")] public Dimension Dimension { get; set; } + [JsonProperty("short_link")] public string ShortLink { get; set; } + [JsonProperty("short_link_v2")] public string ShortLinkV2 { get; set; } + [JsonProperty("first_frame")] public string FirstFrame { get; set; } + [JsonProperty("bvid")] public string Bvid { get; set; } + [JsonProperty("season_type")] public int SeasonType { get; set; } + [JsonProperty("is_ogv")] public bool IsOgv { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Video/Models/RankingVideoView.cs b/DownKyi.Core/BiliApi/Video/Models/RankingVideoView.cs new file mode 100644 index 0000000..613d25f --- /dev/null +++ b/DownKyi.Core/BiliApi/Video/Models/RankingVideoView.cs @@ -0,0 +1,27 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Video.Models; + +public class RankingVideoView : BaseModel +{ + [JsonProperty("aid")] public long Aid { get; set; } + [JsonProperty("bvid")] public string Bvid { get; set; } + [JsonProperty("typename")] public string TypeName { get; set; } + [JsonProperty("title")] public string Title { get; set; } + [JsonProperty("subtitle")] public string Subtitle { get; set; } + [JsonProperty("play")] public long Play { get; set; } + [JsonProperty("review")] public long Review { get; set; } + [JsonProperty("video_review")] public long VideoReview { get; set; } + [JsonProperty("favorites")] public long Favorites { get; set; } + [JsonProperty("mid")] public long Mid { get; set; } + [JsonProperty("author")] public string Author { get; set; } + [JsonProperty("description")] public string Description { get; set; } + [JsonProperty("create")] public string Create { get; set; } + [JsonProperty("pic")] public string Pic { get; set; } + [JsonProperty("coins")] public long Coins { get; set; } + [JsonProperty("duration")] public string Duration { get; set; } + [JsonProperty("badgepay")] public bool Badgepay { get; set; } + [JsonProperty("pts")] public long Pts { get; set; } + [JsonProperty("redirect_url")] public string RedirectUrl { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Video/Models/RegionDynamic.cs b/DownKyi.Core/BiliApi/Video/Models/RegionDynamic.cs new file mode 100644 index 0000000..c922e42 --- /dev/null +++ b/DownKyi.Core/BiliApi/Video/Models/RegionDynamic.cs @@ -0,0 +1,22 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Video.Models; + +// https://api.bilibili.com/x/web-interface/dynamic/region +public class RegionDynamicOrigin : BaseModel +{ + //[JsonProperty("code")] + //public int Code { get; set; } + //[JsonProperty("message")] + //public string Message { get; set; } + //[JsonProperty("ttl")] + //public int Ttl { get; set; } + [JsonProperty("data")] public RegionDynamic Data { get; set; } +} + +public class RegionDynamic : BaseModel +{ + [JsonProperty("archives")] public List Archives { get; set; } + // page +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Video/Models/RegionRanking.cs b/DownKyi.Core/BiliApi/Video/Models/RegionRanking.cs new file mode 100644 index 0000000..bf7738e --- /dev/null +++ b/DownKyi.Core/BiliApi/Video/Models/RegionRanking.cs @@ -0,0 +1,16 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Video.Models; + +// https://api.bilibili.com/x/web-interface/ranking/region +public class RegionRanking : BaseModel +{ + //[JsonProperty("code")] + //public int Code { get; set; } + //[JsonProperty("message")] + //public string Message { get; set; } + //[JsonProperty("ttl")] + //public int Ttl { get; set; } + [JsonProperty("data")] public List Data { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Video/Models/UgcArc.cs b/DownKyi.Core/BiliApi/Video/Models/UgcArc.cs new file mode 100644 index 0000000..4ef89e0 --- /dev/null +++ b/DownKyi.Core/BiliApi/Video/Models/UgcArc.cs @@ -0,0 +1,28 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Video.Models; + +public class UgcArc : BaseModel +{ + [JsonProperty("aid")] public long Aid { get; set; } + [JsonProperty("videos")] public int Videos { get; set; } + [JsonProperty("type_id")] public int TypeId { get; set; } + [JsonProperty("type_name")] public string TypeName { get; set; } + [JsonProperty("copyright")] public int Copyright { get; set; } + [JsonProperty("pic")] public string Pic { get; set; } + [JsonProperty("title")] public string Title { get; set; } + [JsonProperty("pubdate")] public long Pubdate { get; set; } + [JsonProperty("ctime")] public long Ctime { get; set; } + [JsonProperty("desc")] public string Desc { get; set; } + [JsonProperty("state")] public int State { get; set; } + + [JsonProperty("duration")] public long Duration { get; set; } + + //[JsonProperty("rights")] + //public VideoRights Rights { get; set; } + [JsonProperty("author")] public VideoOwner Author { get; set; } + [JsonProperty("stat")] public VideoStat Stat { get; set; } + [JsonProperty("dynamic")] public string Dynamic { get; set; } + [JsonProperty("dimension")] public Dimension Dimension { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Video/Models/UgcEpisode.cs b/DownKyi.Core/BiliApi/Video/Models/UgcEpisode.cs new file mode 100644 index 0000000..9015de2 --- /dev/null +++ b/DownKyi.Core/BiliApi/Video/Models/UgcEpisode.cs @@ -0,0 +1,18 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Video.Models; + +public class UgcEpisode : BaseModel +{ + [JsonProperty("season_id")] public long SeasonId { get; set; } + [JsonProperty("section_id")] public long SectionId { get; set; } + [JsonProperty("id")] public long Id { get; set; } + [JsonProperty("aid")] public long Aid { get; set; } + [JsonProperty("cid")] public long Cid { get; set; } + [JsonProperty("title")] public string Title { get; set; } + [JsonProperty("attribute")] public int Attribute { get; set; } + [JsonProperty("arc")] public UgcArc Arc { get; set; } + [JsonProperty("page")] public VideoPage Page { get; set; } + [JsonProperty("bvid")] public string Bvid { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Video/Models/UgcSeason.cs b/DownKyi.Core/BiliApi/Video/Models/UgcSeason.cs new file mode 100644 index 0000000..fc89198 --- /dev/null +++ b/DownKyi.Core/BiliApi/Video/Models/UgcSeason.cs @@ -0,0 +1,19 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Video.Models; + +public class UgcSeason : BaseModel +{ + [JsonProperty("id")] public long Id { get; set; } + [JsonProperty("title")] public string Title { get; set; } + [JsonProperty("cover")] public string Cover { get; set; } + [JsonProperty("mid")] public long Mid { get; set; } + [JsonProperty("intro")] public string Intro { get; set; } + [JsonProperty("sign_state")] public int SignState { get; set; } + [JsonProperty("attribute")] public int Attribute { get; set; } + [JsonProperty("sections")] public List Sections { get; set; } + [JsonProperty("stat")] public UgcStat Stat { get; set; } + [JsonProperty("ep_count")] public int EpCount { get; set; } + [JsonProperty("season_type")] public int SeasonType { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Video/Models/UgcSection.cs b/DownKyi.Core/BiliApi/Video/Models/UgcSection.cs new file mode 100644 index 0000000..0484682 --- /dev/null +++ b/DownKyi.Core/BiliApi/Video/Models/UgcSection.cs @@ -0,0 +1,18 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Video.Models; + +public class UgcSection : BaseModel +{ + [JsonProperty("season_id")] + public long SeasonId { get; set; } + [JsonProperty("id")] + public long Id { get; set; } + [JsonProperty("title")] + public string Title { get; set; } + [JsonProperty("type")] + public int Type { get; set; } + [JsonProperty("episodes")] + public List Episodes { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Video/Models/UgcStat.cs b/DownKyi.Core/BiliApi/Video/Models/UgcStat.cs new file mode 100644 index 0000000..8ee29f6 --- /dev/null +++ b/DownKyi.Core/BiliApi/Video/Models/UgcStat.cs @@ -0,0 +1,18 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Video.Models; + +public class UgcStat : BaseModel +{ + [JsonProperty("season_id")] public long SeasonId { get; set; } + [JsonProperty("view")] public long View { get; set; } + [JsonProperty("danmaku")] public long Danmaku { get; set; } + [JsonProperty("reply")] public long Reply { get; set; } + [JsonProperty("fav")] public long Favorite { get; set; } + [JsonProperty("coin")] public long Coin { get; set; } + [JsonProperty("share")] public long Share { get; set; } + [JsonProperty("now_rank")] public long NowRank { get; set; } + [JsonProperty("his_rank")] public long HisRank { get; set; } + [JsonProperty("like")] public long Like { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Video/Models/VideoDescription.cs b/DownKyi.Core/BiliApi/Video/Models/VideoDescription.cs new file mode 100644 index 0000000..2e937ab --- /dev/null +++ b/DownKyi.Core/BiliApi/Video/Models/VideoDescription.cs @@ -0,0 +1,16 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Video.Models; + +// https://api.bilibili.com/x/web-interface/archive/desc +public class VideoDescription : BaseModel +{ + //[JsonProperty("code")] + //public int Code { get; set; } + //[JsonProperty("message")] + //public string Message { get; set; } + //[JsonProperty("ttl")] + //public int Ttl { get; set; } + [JsonProperty("data")] public string Data { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Video/Models/VideoPage.cs b/DownKyi.Core/BiliApi/Video/Models/VideoPage.cs new file mode 100644 index 0000000..a00710b --- /dev/null +++ b/DownKyi.Core/BiliApi/Video/Models/VideoPage.cs @@ -0,0 +1,17 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Video.Models; + +public class VideoPage : BaseModel +{ + [JsonProperty("cid")] public long Cid { get; set; } + [JsonProperty("page")] public int Page { get; set; } + [JsonProperty("from")] public string From { get; set; } + [JsonProperty("part")] public string Part { get; set; } + [JsonProperty("duration")] public long Duration { get; set; } + [JsonProperty("vid")] public string Vid { get; set; } + [JsonProperty("weblink")] public string Weblink { get; set; } + [JsonProperty("dimension")] public Dimension Dimension { get; set; } + [JsonProperty("first_frame")] public string FirstFrame { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Video/Models/VideoPagelist.cs b/DownKyi.Core/BiliApi/Video/Models/VideoPagelist.cs new file mode 100644 index 0000000..9553a32 --- /dev/null +++ b/DownKyi.Core/BiliApi/Video/Models/VideoPagelist.cs @@ -0,0 +1,16 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Video.Models; + +// https://api.bilibili.com/x/player/pagelist +public class VideoPagelist : BaseModel +{ + //[JsonProperty("code")] + //public int Code { get; set; } + //[JsonProperty("message")] + //public string Message { get; set; } + //[JsonProperty("ttl")] + //public int Ttl { get; set; } + [JsonProperty("data")] public List Data { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Video/Models/VideoStat.cs b/DownKyi.Core/BiliApi/Video/Models/VideoStat.cs new file mode 100644 index 0000000..0148f0f --- /dev/null +++ b/DownKyi.Core/BiliApi/Video/Models/VideoStat.cs @@ -0,0 +1,21 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Video.Models; + +public class VideoStat : BaseModel +{ + [JsonProperty("aid")] public long Aid { get; set; } + [JsonProperty("view")] public long View { get; set; } + [JsonProperty("danmaku")] public long Danmaku { get; set; } + [JsonProperty("reply")] public long Reply { get; set; } + [JsonProperty("favorite")] public long Favorite { get; set; } + [JsonProperty("coin")] public long Coin { get; set; } + [JsonProperty("share")] public long Share { get; set; } + [JsonProperty("now_rank")] public long NowRank { get; set; } + [JsonProperty("his_rank")] public long HisRank { get; set; } + [JsonProperty("like")] public long Like { get; set; } + [JsonProperty("dislike")] public long Dislike { get; set; } + [JsonProperty("evaluation")] public string Evaluation { get; set; } + [JsonProperty("argue_msg")] public string ArgueMsg { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Video/Models/VideoSubtitle.cs b/DownKyi.Core/BiliApi/Video/Models/VideoSubtitle.cs new file mode 100644 index 0000000..a3b8ed9 --- /dev/null +++ b/DownKyi.Core/BiliApi/Video/Models/VideoSubtitle.cs @@ -0,0 +1,39 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Video.Models; + +public class VideoSubtitle : BaseModel +{ + [JsonProperty("allow_submit")] public bool AllowSubmit { get; set; } + [JsonProperty("list")] public List List { get; set; } +} + +public class Subtitle : BaseModel +{ + [JsonProperty("id")] public long Id { get; set; } + [JsonProperty("lan")] public string Lan { get; set; } + [JsonProperty("lan_doc")] public string LanDoc { get; set; } + [JsonProperty("is_lock")] public bool IsLock { get; set; } + [JsonProperty("author_mid")] public long AuthorMid { get; set; } + [JsonProperty("subtitle_url")] public string SubtitleUrl { get; set; } + [JsonProperty("author")] public SubtitleAuthor Author { get; set; } +} + +public class SubtitleAuthor : BaseModel +{ + [JsonProperty("mid")] public long Mid { get; set; } + [JsonProperty("name")] public string Name { get; set; } + [JsonProperty("sex")] public string Sex { get; set; } + [JsonProperty("face")] public string Face { get; set; } + + [JsonProperty("sign")] public string Sign { get; set; } + //[JsonProperty("rank")] + //public int Rank { get; set; } + //[JsonProperty("birthday")] + //public int Birthday { get; set; } + //[JsonProperty("is_fake_account")] + //public int IsFakeAccount { get; set; } + //[JsonProperty("is_deleted")] + //public int IsDeleted { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Video/Models/VideoView.cs b/DownKyi.Core/BiliApi/Video/Models/VideoView.cs new file mode 100644 index 0000000..1325fff --- /dev/null +++ b/DownKyi.Core/BiliApi/Video/Models/VideoView.cs @@ -0,0 +1,58 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.Video.Models; + +// https://api.bilibili.com/x/web-interface/view +public class VideoViewOrigin : BaseModel +{ + //[JsonProperty("code")] + //public int Code { get; set; } + //[JsonProperty("message")] + //public string Message { get; set; } + //[JsonProperty("ttl")] + //public int Ttl { get; set; } + [JsonProperty("data")] public VideoView Data { get; set; } +} + +public class VideoView : BaseModel +{ + [JsonProperty("bvid")] public string Bvid { get; set; } + [JsonProperty("aid")] public long Aid { get; set; } + [JsonProperty("videos")] public int Videos { get; set; } + [JsonProperty("tid")] public int Tid { get; set; } + [JsonProperty("tname")] public string Tname { get; set; } + [JsonProperty("copyright")] public int Copyright { get; set; } + [JsonProperty("pic")] public string Pic { get; set; } + [JsonProperty("title")] public string Title { get; set; } + [JsonProperty("pubdate")] public long Pubdate { get; set; } + [JsonProperty("ctime")] public long Ctime { get; set; } + [JsonProperty("desc")] public string Desc { get; set; } + [JsonProperty("state")] public int State { get; set; } + [JsonProperty("duration")] public long Duration { get; set; } + [JsonProperty("redirect_url")] public string RedirectUrl { get; set; } + + [JsonProperty("mission_id")] public long MissionId { get; set; } + + //[JsonProperty("rights")] + //public VideoRights Rights { get; set; } + [JsonProperty("owner")] public VideoOwner Owner { get; set; } + [JsonProperty("stat")] public VideoStat Stat { get; set; } + [JsonProperty("dynamic")] public string Dynamic { get; set; } + [JsonProperty("cid")] public long Cid { get; set; } + [JsonProperty("dimension")] public Dimension Dimension { get; set; } + [JsonProperty("season_id")] public long SeasonId { get; set; } + + [JsonProperty("festival_jump_url")] public string FestivalJumpUrl { get; set; } + + //[JsonProperty("no_cache")] + //public bool no_cache { get; set; } + [JsonProperty("pages")] public List Pages { get; set; } + [JsonProperty("subtitle")] public VideoSubtitle Subtitle { get; set; } + + [JsonProperty("ugc_season")] public UgcSeason UgcSeason { get; set; } + //[JsonProperty("staff")] + //public List staff { get; set; } + //[JsonProperty("user_garb")] + //public user_garb user_garb { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Video/Ranking.cs b/DownKyi.Core/BiliApi/Video/Ranking.cs new file mode 100644 index 0000000..98a43d6 --- /dev/null +++ b/DownKyi.Core/BiliApi/Video/Ranking.cs @@ -0,0 +1,42 @@ +using DownKyi.Core.BiliApi.Video.Models; +using DownKyi.Core.Logging; +using Newtonsoft.Json; +using Console = DownKyi.Core.Utils.Debugging.Console; + +namespace DownKyi.Core.BiliApi.Video; + +public static class Ranking +{ + /// + /// 获取分区视频排行榜列表 + /// + /// 目标分区tid + /// 3日榜或周榜(3/7) + /// + /// + public static List RegionRankingList(int rid, int day = 3, int original = 0) + { + string url = $"https://api.bilibili.com/x/web-interface/ranking/region?rid={rid}&day={day}&ps={original}"; + string referer = "https://www.bilibili.com"; + string response = WebClient.RequestWeb(url, referer); + + try + { + var ranking = JsonConvert.DeserializeObject(response); + if (ranking != null) + { + return ranking.Data; + } + else + { + return null; + } + } + catch (Exception e) + { + Console.PrintLine("RegionRankingList()发生异常: {0}", e); + LogManager.Error("Ranking", e); + return null; + } + } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Video/VideoInfo.cs b/DownKyi.Core/BiliApi/Video/VideoInfo.cs new file mode 100644 index 0000000..bbeb4e8 --- /dev/null +++ b/DownKyi.Core/BiliApi/Video/VideoInfo.cs @@ -0,0 +1,115 @@ +using DownKyi.Core.BiliApi.Sign; +using DownKyi.Core.BiliApi.Video.Models; +using DownKyi.Core.Logging; +using Newtonsoft.Json; +using Console = DownKyi.Core.Utils.Debugging.Console; + +namespace DownKyi.Core.BiliApi.Video; + +public static class VideoInfo +{ + /// + /// 获取视频详细信息(web端) + /// + /// + /// + /// + public static VideoView VideoViewInfo(string bvid = null, long aid = -1) + { + // https://api.bilibili.com/x/web-interface/view/detail?bvid=BV1Sg411F7cb&aid=969147110&need_operation_card=1&web_rm_repeat=1&need_elec=1&out_referer=https%3A%2F%2Fspace.bilibili.com%2F42018135%2Ffavlist%3Ffid%3D94341835 + + var parameters = new Dictionary(); + if (bvid != null) + { + parameters.Add("bvid", bvid); + } + else if (aid > -1) + { + parameters.Add("aid", aid); + } + else + { + return null; + } + string query = WbiSign.ParametersToQuery(WbiSign.EncodeWbi(parameters)); + string url = $"https://api.bilibili.com/x/web-interface/wbi/view?{query}"; + string referer = "https://www.bilibili.com"; + string response = WebClient.RequestWeb(url, referer); + + try + { + var videoView = JsonConvert.DeserializeObject(response); + if (videoView != null) { return videoView.Data; } + else { return null; } + } + catch (Exception e) + { + Console.PrintLine("VideoInfo()发生异常: {0}", e); + LogManager.Error("VideoInfo", e); + return null; + } + } + + /// + /// 获取视频简介 + /// + /// + /// + /// + public static string VideoDescription(string bvid = null, long aid = -1) + { + string baseUrl = "https://api.bilibili.com/x/web-interface/archive/desc"; + string referer = "https://www.bilibili.com"; + string url; + if (bvid != null) { url = $"{baseUrl}?bvid={bvid}"; } + else if (aid >= -1) { url = $"{baseUrl}?aid={aid}"; } + else { return null; } + + string response = WebClient.RequestWeb(url, referer); + + try + { + var desc = JsonConvert.DeserializeObject(response); + if (desc != null) { return desc.Data; } + else { return null; } + } + catch (Exception e) + { + Console.PrintLine("VideoDescription()发生异常: {0}", e); + LogManager.Error("VideoInfo", e); + return null; + } + } + + /// + /// 查询视频分P列表 (avid/bvid转cid) + /// + /// + /// + /// + public static List VideoPagelist(string bvid = null, long aid = -1) + { + string baseUrl = "https://api.bilibili.com/x/player/pagelist"; + string referer = "https://www.bilibili.com"; + string url; + if (bvid != null) { url = $"{baseUrl}?bvid={bvid}"; } + else if (aid > -1) { url = $"{baseUrl}?aid={aid}"; } + else { return null; } + + string response = WebClient.RequestWeb(url, referer); + + try + { + var pagelist = JsonConvert.DeserializeObject(response); + if (pagelist != null) { return pagelist.Data; } + else { return null; } + } + catch (Exception e) + { + Console.PrintLine("VideoPagelist()发生异常: {0}", e); + LogManager.Error("VideoInfo", e); + return null; + } + } + +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/VideoStream/Models/PlayUrl.cs b/DownKyi.Core/BiliApi/VideoStream/Models/PlayUrl.cs new file mode 100644 index 0000000..bcbe573 --- /dev/null +++ b/DownKyi.Core/BiliApi/VideoStream/Models/PlayUrl.cs @@ -0,0 +1,39 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.VideoStream.Models; + +public class PlayUrlOrigin : BaseModel +{ + //[JsonProperty("code")] + //public int Code { get; set; } + //[JsonProperty("message")] + //public string Message { get; set; } + //[JsonProperty("ttl")] + //public int Ttl { get; set; } + [JsonProperty("data")] public PlayUrl Data { get; set; } + [JsonProperty("result")] public PlayUrl Result { get; set; } +} + +public class PlayUrl : BaseModel +{ + // from + // result + // message + // quality + // format + // timelength + // accept_format + [JsonProperty("accept_description")] public List AcceptDescription { get; set; } + + [JsonProperty("accept_quality")] public List AcceptQuality { get; set; } + + // video_codecid + // seek_param + // seek_type + [JsonProperty("durl")] public List Durl { get; set; } + [JsonProperty("dash")] public PlayUrlDash Dash { get; set; } + + [JsonProperty("support_formats")] public List SupportFormats { get; set; } + // high_format +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/VideoStream/Models/PlayUrlDash.cs b/DownKyi.Core/BiliApi/VideoStream/Models/PlayUrlDash.cs new file mode 100644 index 0000000..ba5e191 --- /dev/null +++ b/DownKyi.Core/BiliApi/VideoStream/Models/PlayUrlDash.cs @@ -0,0 +1,18 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.VideoStream.Models; + +public class PlayUrlDash : BaseModel +{ + [JsonProperty("duration")] public long Duration { get; set; } + + //[JsonProperty("minBufferTime")] + //public float minBufferTime { get; set; } + //[JsonProperty("min_buffer_time")] + //public float min_buffer_time { get; set; } + [JsonProperty("video")] public List Video { get; set; } + [JsonProperty("audio")] public List Audio { get; set; } + [JsonProperty("dolby")] public PlayUrlDashDolby Dolby { get; set; } + [JsonProperty("flac")] public PlayUrlDashFlac Flac { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/VideoStream/Models/PlayUrlDashDolby.cs b/DownKyi.Core/BiliApi/VideoStream/Models/PlayUrlDashDolby.cs new file mode 100644 index 0000000..4c53379 --- /dev/null +++ b/DownKyi.Core/BiliApi/VideoStream/Models/PlayUrlDashDolby.cs @@ -0,0 +1,11 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.VideoStream.Models; + +public class PlayUrlDashDolby : BaseModel +{ + // type + [JsonProperty("audio")] + public List Audio { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/VideoStream/Models/PlayUrlDashFlac.cs b/DownKyi.Core/BiliApi/VideoStream/Models/PlayUrlDashFlac.cs new file mode 100644 index 0000000..fee6f6d --- /dev/null +++ b/DownKyi.Core/BiliApi/VideoStream/Models/PlayUrlDashFlac.cs @@ -0,0 +1,10 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.VideoStream.Models; + +public class PlayUrlDashFlac : BaseModel +{ + [JsonProperty("audio")] public PlayUrlDashVideo Audio { get; set; } + //bool display { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/VideoStream/Models/PlayUrlDashVideo.cs b/DownKyi.Core/BiliApi/VideoStream/Models/PlayUrlDashVideo.cs new file mode 100644 index 0000000..8019774 --- /dev/null +++ b/DownKyi.Core/BiliApi/VideoStream/Models/PlayUrlDashVideo.cs @@ -0,0 +1,30 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.VideoStream.Models; + +public class PlayUrlDashVideo : BaseModel +{ + [JsonProperty("id")] public int Id { get; set; } + [JsonProperty("base_url")] public string BaseUrl { get; set; } + + [JsonProperty("backup_url")] public List BackupUrl { get; set; } + + // bandwidth + [JsonProperty("mimeType")] public string MimeType { get; set; } + + // mime_type + [JsonProperty("codecs")] public string Codecs { get; set; } + [JsonProperty("width")] public int Width { get; set; } + [JsonProperty("height")] public int Height { get; set; } + + [JsonProperty("frameRate")] public string FrameRate { get; set; } + + // frame_rate + // sar + // startWithSap + // start_with_sap + // SegmentBase + // segment_base + [JsonProperty("codecid")] public int CodecId { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/VideoStream/Models/PlayUrlDurl.cs b/DownKyi.Core/BiliApi/VideoStream/Models/PlayUrlDurl.cs new file mode 100644 index 0000000..866dc0c --- /dev/null +++ b/DownKyi.Core/BiliApi/VideoStream/Models/PlayUrlDurl.cs @@ -0,0 +1,17 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.VideoStream.Models; + +public class PlayUrlDurl : BaseModel +{ + [JsonProperty("order")] public int Order { get; set; } + [JsonProperty("length")] public long Length { get; set; } + + [JsonProperty("size")] public long Size { get; set; } + + // ahead + // vhead + [JsonProperty("url")] public string Url { get; set; } + [JsonProperty("backup_url")] public List BackupUrl { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/VideoStream/Models/PlayUrlSupportFormat.cs b/DownKyi.Core/BiliApi/VideoStream/Models/PlayUrlSupportFormat.cs new file mode 100644 index 0000000..5891c49 --- /dev/null +++ b/DownKyi.Core/BiliApi/VideoStream/Models/PlayUrlSupportFormat.cs @@ -0,0 +1,13 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.VideoStream.Models; + +public class PlayUrlSupportFormat : BaseModel +{ + [JsonProperty("quality")] public int Quality { get; set; } + [JsonProperty("format")] public string Format { get; set; } + [JsonProperty("new_description")] public string NewDescription { get; set; } + [JsonProperty("display_desc")] public string DisplayDesc { get; set; } + [JsonProperty("superscript")] public string Superscript { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/VideoStream/Models/PlayerV2.cs b/DownKyi.Core/BiliApi/VideoStream/Models/PlayerV2.cs new file mode 100644 index 0000000..206e7cc --- /dev/null +++ b/DownKyi.Core/BiliApi/VideoStream/Models/PlayerV2.cs @@ -0,0 +1,30 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.VideoStream.Models; + +// https://api.bilibili.com/x/player/v2?cid={cid}&aid={avid}&bvid={bvid} +public class PlayerV2Origin : BaseModel +{ + //[JsonProperty("code")] + //public int Code { get; set; } + //[JsonProperty("message")] + //public string Message { get; set; } + //[JsonProperty("ttl")] + //public int Ttl { get; set; } + [JsonProperty("data")] public PlayerV2 Data { get; set; } +} + +public class PlayerV2 : BaseModel +{ + [JsonProperty("aid")] public long Aid { get; set; } + + [JsonProperty("bvid")] public string Bvid { get; set; } + + // allow_bp + // no_share + [JsonProperty("cid")] public long Cid { get; set; } + + // ... + [JsonProperty("subtitle")] public SubtitleInfo Subtitle { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/VideoStream/Models/Subtitle.cs b/DownKyi.Core/BiliApi/VideoStream/Models/Subtitle.cs new file mode 100644 index 0000000..616e094 --- /dev/null +++ b/DownKyi.Core/BiliApi/VideoStream/Models/Subtitle.cs @@ -0,0 +1,16 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.VideoStream.Models; + +public class Subtitle : BaseModel +{ + [JsonProperty("id")] public long Id { get; set; } + [JsonProperty("lan")] public string Lan { get; set; } + [JsonProperty("lan_doc")] public string LanDoc { get; set; } + [JsonProperty("is_lock")] public bool IsLock { get; set; } + [JsonProperty("author_mid")] public long AuthorMid { get; set; } + [JsonProperty("subtitle_url")] public string SubtitleUrl { get; set; } + [JsonProperty("type")] public int Type { get; set; } + [JsonProperty("id_str")] public string IdStr { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/VideoStream/Models/SubtitleInfo.cs b/DownKyi.Core/BiliApi/VideoStream/Models/SubtitleInfo.cs new file mode 100644 index 0000000..7fcd2a1 --- /dev/null +++ b/DownKyi.Core/BiliApi/VideoStream/Models/SubtitleInfo.cs @@ -0,0 +1,12 @@ +using DownKyi.Core.BiliApi.Models; +using Newtonsoft.Json; + +namespace DownKyi.Core.BiliApi.VideoStream.Models; + +public class SubtitleInfo : BaseModel +{ + [JsonProperty("allow_submit")] public bool AllowSubmit { get; set; } + [JsonProperty("lan")] public string Lan { get; set; } + [JsonProperty("lan_doc")] public string LanDoc { get; set; } + [JsonProperty("subtitles")] public List Subtitles { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/VideoStream/PlayStreamType.cs b/DownKyi.Core/BiliApi/VideoStream/PlayStreamType.cs new file mode 100644 index 0000000..0ed9ed6 --- /dev/null +++ b/DownKyi.Core/BiliApi/VideoStream/PlayStreamType.cs @@ -0,0 +1,8 @@ +namespace DownKyi.Core.BiliApi.VideoStream; + +public enum PlayStreamType +{ + VIDEO = 1, // 普通视频 + BANGUMI, // 番剧、电影、电视剧等 + CHEESE, // 课程 +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/VideoStream/VideoStream.cs b/DownKyi.Core/BiliApi/VideoStream/VideoStream.cs new file mode 100644 index 0000000..55227ee --- /dev/null +++ b/DownKyi.Core/BiliApi/VideoStream/VideoStream.cs @@ -0,0 +1,238 @@ +using DownKyi.Core.BiliApi.Models.Json; +using DownKyi.Core.BiliApi.Sign; +using DownKyi.Core.BiliApi.VideoStream.Models; +using DownKyi.Core.Logging; +using Newtonsoft.Json; +using Console = DownKyi.Core.Utils.Debugging.Console; + +namespace DownKyi.Core.BiliApi.VideoStream; + +public static class VideoStream +{ + /// + /// 获取播放器信息(web端) + /// + /// + /// + /// + /// + public static PlayerV2 PlayerV2(long avid, string bvid, long cid) + { + var parameters = new Dictionary + { + { "avid", avid }, + { "bvid", bvid }, + { "cid", cid }, + }; + string query = WbiSign.ParametersToQuery(WbiSign.EncodeWbi(parameters)); + string url = $"https://api.bilibili.com/x/player/wbi/v2?{query}"; + string referer = "https://www.bilibili.com"; + string response = WebClient.RequestWeb(url, referer); + + try + { + var playUrl = JsonConvert.DeserializeObject(response); + return playUrl?.Data; + } + catch (Exception e) + { + Console.PrintLine("PlayerV2()发生异常: {0}", e); + LogManager.Error("PlayerV2()", e); + return null; + } + } + + /// + /// 获取所有字幕
+ /// 若视频没有字幕,返回null + ///
+ /// + /// + /// + /// + public static List GetSubtitle(long avid, string bvid, long cid) + { + List subRipTexts = new List(); + + // 获取播放器信息 + PlayerV2 player = PlayerV2(avid, bvid, cid); + if (player == null) + { + return subRipTexts; + } + + if (player.Subtitle != null && player.Subtitle.Subtitles != null && player.Subtitle.Subtitles.Count == 0) + { + return null; + } + + foreach (var subtitle in player.Subtitle.Subtitles) + { + string referer = "https://www.bilibili.com"; + string response = WebClient.RequestWeb($"https:{subtitle.SubtitleUrl}", referer); + + try + { + var subtitleJson = JsonConvert.DeserializeObject(response); + if (subtitleJson == null) + { + continue; + } + + subRipTexts.Add(new SubRipText + { + Lan = subtitle.Lan, + LanDoc = subtitle.LanDoc, + SrtString = subtitleJson.ToSubRip() + }); + } + catch (Exception e) + { + Console.PrintLine("GetSubtitle()发生异常: {0}", e); + LogManager.Error("GetSubtitle()", e); + } + } + + return subRipTexts; + } + + /// + /// 获取普通视频的视频流 + /// + /// + /// + /// + /// + /// + public static PlayUrl GetVideoPlayUrl(long avid, string bvid, long cid, int quality = 125) + { + var parameters = new Dictionary + { + { "fourk", 1 }, + { "fnver", 0 }, + { "fnval", 4048 }, + { "cid", cid }, + { "qn", quality }, + }; + + if (bvid != null) + { + parameters.Add("bvid", bvid); + } + else if (avid > -1) + { + parameters.Add("aid", avid); + } + else + { + return null; + } + + string query = WbiSign.ParametersToQuery(WbiSign.EncodeWbi(parameters)); + string url = $"https://api.bilibili.com/x/player/wbi/playurl?{query}"; + + return GetPlayUrl(url); + } + + /// + /// 获取番剧的视频流 + /// + /// + /// + /// + /// + /// + public static PlayUrl GetBangumiPlayUrl(long avid, string bvid, long cid, int quality = 125) + { + string baseUrl = + $"https://api.bilibili.com/pgc/player/web/playurl?cid={cid}&qn={quality}&fourk=1&fnver=0&fnval=4048"; + string url; + if (bvid != null) + { + url = $"{baseUrl}&bvid={bvid}"; + } + else if (avid > -1) + { + url = $"{baseUrl}&aid={avid}"; + } + else + { + return null; + } + + return GetPlayUrl(url); + } + + /// + /// 获取课程的视频流 + /// + /// + /// + /// + /// + /// + public static PlayUrl GetCheesePlayUrl(long avid, string bvid, long cid, long episodeId, int quality = 125) + { + string baseUrl = + $"https://api.bilibili.com/pugv/player/web/playurl?cid={cid}&qn={quality}&fourk=1&fnver=0&fnval=4048"; + string url; + if (bvid != null) + { + url = $"{baseUrl}&bvid={bvid}"; + } + else if (avid > -1) + { + url = $"{baseUrl}&aid={avid}"; + } + else + { + return null; + } + + // 必须有episodeId,否则会返回请求错误 + if (episodeId != 0) + { + url += $"&ep_id={episodeId}"; + } + + return GetPlayUrl(url); + } + + /// + /// 获取视频流 + /// + /// + /// + private static PlayUrl GetPlayUrl(string url) + { + string referer = "https://www.bilibili.com"; + string response = WebClient.RequestWeb(url, referer); + + try + { + var playUrl = JsonConvert.DeserializeObject(response); + if (playUrl == null) + { + return null; + } + else if (playUrl.Data != null) + { + return playUrl.Data; + } + else if (playUrl.Result != null) + { + return playUrl.Result; + } + else + { + return null; + } + } + catch (Exception e) + { + Console.PrintLine("GetPlayUrl()发生异常: {0}", e); + LogManager.Error("GetPlayUrl()", e); + return null; + } + } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/WebClient.cs b/DownKyi.Core/BiliApi/WebClient.cs new file mode 100644 index 0000000..9f03a7f --- /dev/null +++ b/DownKyi.Core/BiliApi/WebClient.cs @@ -0,0 +1,146 @@ +using System.IO.Compression; +using System.Net; +using System.Text; +using DownKyi.Core.BiliApi.Login; +using DownKyi.Core.Logging; +using DownKyi.Core.Settings; + +namespace DownKyi.Core.BiliApi; + +internal static class WebClient +{ + /// + /// 发送get或post请求 + /// + /// + /// + /// + /// + /// + public static string RequestWeb(string url, string referer = null, string method = "GET", + Dictionary parameters = null, int retry = 3) + { + // 重试次数 + if (retry <= 0) + { + return ""; + } + + // post请求,发送参数 + if (method == "POST" && parameters != null) + { + StringBuilder builder = new StringBuilder(); + int i = 0; + foreach (var item in parameters) + { + if (i > 0) + { + builder.Append("&"); + } + + builder.AppendFormat("{0}={1}", item.Key, item.Value); + i++; + } + + url += "?" + builder.ToString(); + } + + try + { + HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); + request.Method = method; + request.Timeout = 30 * 1000; + + request.UserAgent = SettingsManager.GetInstance().GetUserAgent(); + + //request.ContentType = "application/json,text/html,application/xhtml+xml,application/xml;charset=UTF-8"; + request.Headers["accept-language"] = "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7"; + request.Headers["accept-encoding"] = "gzip, deflate, br"; + + // referer + if (referer != null) + { + request.Referer = referer; + } + + // 构造cookie + if (!url.Contains("getLogin")) + { + request.Headers["origin"] = "https://www.bilibili.com"; + + CookieContainer cookies = LoginHelper.GetLoginInfoCookies(); + if (cookies != null) + { + request.CookieContainer = cookies; + } + } + + string html = string.Empty; + using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) + { + if (response.ContentEncoding.ToLower().Contains("gzip")) + { + using (GZipStream stream = new GZipStream(response.GetResponseStream(), CompressionMode.Decompress)) + { + using (StreamReader reader = new StreamReader(stream, Encoding.UTF8)) + { + html = reader.ReadToEnd(); + } + } + } + else if (response.ContentEncoding.ToLower().Contains("deflate")) + { + using (DeflateStream stream = + new DeflateStream(response.GetResponseStream(), CompressionMode.Decompress)) + { + using (StreamReader reader = new StreamReader(stream, Encoding.UTF8)) + { + html = reader.ReadToEnd(); + } + } + } + else if (response.ContentEncoding.ToLower().Contains("br")) + { + using (BrotliStream stream = + new BrotliStream(response.GetResponseStream(), CompressionMode.Decompress)) + { + using (StreamReader reader = new StreamReader(stream, Encoding.UTF8)) + { + html = reader.ReadToEnd(); + } + } + } + else + { + using (Stream stream = response.GetResponseStream()) + { + using (StreamReader reader = new StreamReader(stream, Encoding.UTF8)) + { + html = reader.ReadToEnd(); + } + } + } + } + + return html; + } + catch (WebException e) + { + Console.WriteLine("RequestWeb()发生Web异常: {0}", e); + LogManager.Error(e); + return RequestWeb(url, referer, method, parameters, retry - 1); + } + catch (IOException e) + { + Console.WriteLine("RequestWeb()发生IO异常: {0}", e); + LogManager.Error(e); + return RequestWeb(url, referer, method, parameters, retry - 1); + } + catch (Exception e) + { + Console.WriteLine("RequestWeb()发生其他异常: {0}", e); + LogManager.Error(e); + return RequestWeb(url, referer, method, parameters, retry - 1); + } + } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Zone/VideoZone.cs b/DownKyi.Core/BiliApi/Zone/VideoZone.cs new file mode 100644 index 0000000..e0d0a56 --- /dev/null +++ b/DownKyi.Core/BiliApi/Zone/VideoZone.cs @@ -0,0 +1,215 @@ +using System.Collections.Generic; + +namespace DownKyi.Core.BiliApi.Zone; + +public class VideoZone +{ + private static VideoZone that; + private readonly List zones = new(); + + /// + /// 使用单例模式获取分区,注意未搜索到的分区需要额外处理 + /// + /// + public static VideoZone Instance() + { + if (that == null) + { + that = new VideoZone(); + } + + return that; + } + + public List GetZones() + { + return zones; + } + + private VideoZone() + { + // SpacePublicationListType类需要同步更新 + + //动画 + zones.Add(new ZoneAttr(1, "douga", "动画")); // 主分区 + zones.Add(new ZoneAttr(24, "mad", "MAD·AMV", 1)); // 具有一定制作程度的动画或静画的二次创作视频 + zones.Add(new ZoneAttr(25, "mmd", "MMD·3D", 1)); // 使用MMD(MikuMikuDance)和其他3D建模类软件制作的视频 + zones.Add(new ZoneAttr(47, "voice", "短片·手书·配音", 1)); // 追求个人特色和创意表达的自制动画短片、手书(绘)及ACGN相关配音 + zones.Add(new ZoneAttr(210, "garage_kit", "手办·模玩", 1)); // 手办模玩的测评、改造或其他衍生内容 + zones.Add(new ZoneAttr(86, "tokusatsu", "特摄", 1)); // 特摄相关衍生视频 + zones.Add(new ZoneAttr(253, "acgntalks", "动漫杂谈", 1)); // 以谈话形式对ACGN文化圈进行的鉴赏、吐槽、评点、解说、推荐、科普等内容 + zones.Add(new ZoneAttr(27, "other", "综合", 1)); // 以动画及动画相关内容为素材,包括但不仅限于音频替换、恶搞改编、排行榜等内容 + + //番剧 + zones.Add(new ZoneAttr(13, "anime", "番剧")); // 主分区 + zones.Add(new ZoneAttr(33, "serial", "连载动画", 13)); // 当季连载的动画番剧 + zones.Add(new ZoneAttr(32, "finish", "完结动画", 13)); // 已完结的动画番剧合集 + zones.Add(new ZoneAttr(51, "information", "资讯", 13)); // 动画番剧相关资讯视频 + zones.Add(new ZoneAttr(152, "offical", "官方延伸", 13)); // 动画番剧为主题的宣传节目、采访视频,及声优相关视频 + + //国创 + zones.Add(new ZoneAttr(167, "guochuang", "国创")); // 主分区 + zones.Add(new ZoneAttr(153, "chinese", "国产动画", 167)); // 我国出品的PGC动画 + zones.Add(new ZoneAttr(168, "original", "国产原创相关", 167)); // + zones.Add(new ZoneAttr(169, "puppetry", "布袋戏", 167)); // + zones.Add(new ZoneAttr(195, "motioncomic", "动态漫·广播剧", 167)); // + zones.Add(new ZoneAttr(170, "information", "资讯", 167)); // + + //音乐 + zones.Add(new ZoneAttr(3, "music", "音乐")); // 主分区 + zones.Add(new ZoneAttr(28, "original", "原创音乐", 3)); // 原创歌曲及纯音乐,包括改编、重编曲及remix + zones.Add(new ZoneAttr(31, "cover", "翻唱", 3)); // 对曲目的人声再演绎视频 + zones.Add(new ZoneAttr(59, "perform", "演奏", 3)); // 乐器和非传统乐器器材的演奏作品 + zones.Add(new ZoneAttr(30, "vocaloid", "VOCALOID·UTAU", 3)); // 以VOCALOID等歌声合成引擎为基础,运用各类音源进行的创作 + zones.Add(new ZoneAttr(29, "live", "音乐现场", 3)); // 音乐表演的实况视频,包括官方/个人拍摄的综艺节目、音乐剧、音乐节、演唱会等 + zones.Add(new ZoneAttr(193, "mv", "MV", 3)); // 为音乐作品配合拍摄或制作的音乐录影带(Music Video),以及自制拍摄、剪辑、翻拍MV + zones.Add(new ZoneAttr(243, "commentary", "乐评盘点", 3)); // 音乐类新闻、盘点、点评、reaction、榜单、采访、幕后故事、唱片开箱等 + zones.Add(new ZoneAttr(244, "tutorial", "音乐教学", 3)); // 以音乐教学为目的的内容 + zones.Add(new ZoneAttr(130, "other", "音乐综合", 3)); // 所有无法被收纳到其他音乐二级分区的音乐类视频 + + //舞蹈 + zones.Add(new ZoneAttr(129, "dance", "舞蹈")); // 主分区 + zones.Add(new ZoneAttr(20, "otaku", "宅舞", 129)); // 与ACG相关的翻跳、原创舞蹈 + zones.Add(new ZoneAttr(198, "hiphop", "街舞", 129)); // 收录街舞相关内容,包括赛事现场、舞室作品、个人翻跳、FREESTYLE等 + zones.Add(new ZoneAttr(199, "star", "明星舞蹈", 129)); // 国内外明星发布的官方舞蹈及其翻跳内容 + zones.Add(new ZoneAttr(200, "china", "中国舞", 129)); // 传承中国艺术文化的舞蹈内容,包括古典舞、民族民间舞、汉唐舞、古风舞等 + zones.Add(new ZoneAttr(154, "three_d", "舞蹈综合", 129)); // 收录无法定义到其他舞蹈子分区的舞蹈视频 + zones.Add(new ZoneAttr(156, "demo", "舞蹈教程", 129)); // 镜面慢速,动作分解,基础教程等具有教学意义的舞蹈视频 + + //游戏 + zones.Add(new ZoneAttr(4, "game", "游戏")); // 主分区 + zones.Add(new ZoneAttr(17, "stand_alone", "单机游戏", + 4)); // 以所有平台(PC、主机、移动端)的单机或联机游戏为主的视频内容,包括游戏预告、CG、实况解说及相关的评测、杂谈与视频剪辑等 + zones.Add(new ZoneAttr(171, "esports", "电子竞技", 4)); // 具有高对抗性的电子竞技游戏项目,其相关的赛事、实况、攻略、解说、短剧等视频。 + zones.Add(new ZoneAttr(172, "mobile", "手机游戏", 4)); // 以手机及平板设备为主要平台的游戏,其相关的实况、攻略、解说、短剧、演示等视频。 + zones.Add(new ZoneAttr(65, "online", "网络游戏", 4)); // 由网络运营商运营的多人在线游戏,以及电子竞技的相关游戏内容。包括赛事、攻略、实况、解说等相关视频 + zones.Add(new ZoneAttr(173, "board", "桌游棋牌", 4)); // 桌游、棋牌、卡牌对战等及其相关电子版游戏的实况、攻略、解说、演示等视频。 + zones.Add(new ZoneAttr(121, "gmv", "GMV", 4)); // 由游戏素材制作的MV视频。以游戏内容或CG为主制作的,具有一定创作程度的MV类型的视频 + zones.Add(new ZoneAttr(136, "music", "音游", 4)); // 各个平台上,通过配合音乐与节奏而进行的音乐类游戏视频 + zones.Add(new ZoneAttr(19, "mugen", "Mugen", 4)); // 以Mugen引擎为平台制作、或与Mugen相关的游戏视频 + + //知识 + zones.Add(new ZoneAttr(36, "knowledge", "知识")); // 主分区 + zones.Add(new ZoneAttr(201, "science", "科学科普", 36)); // 回答你的十万个为什么 + zones.Add(new ZoneAttr(124, "social_science", "社科·法律·心理", 36)); // 基于社会科学、法学、心理学展开或个人观点输出的知识视频 + zones.Add(new ZoneAttr(228, "humanity_history", "人文历史", 36)); // 看看古今人物,聊聊历史过往,品品文学典籍 + zones.Add(new ZoneAttr(207, "business", "财经商业", 36)); // 说金融市场,谈宏观经济,一起畅聊商业故事 + zones.Add(new ZoneAttr(208, "campus", "校园学习", 36)); // 老师很有趣,学生也有才,我们一起搞学习 + zones.Add(new ZoneAttr(209, "career", "职业职场", 36)); // 职业分享、升级指南,一起成为最有料的职场人 + zones.Add(new ZoneAttr(229, "design", "设计·创意", 36)); // 天马行空,创意设计,都在这里 + zones.Add(new ZoneAttr(122, "skill", "野生技能协会", 36)); // 技能党集合,是时候展示真正的技术了 + + //科技 + zones.Add(new ZoneAttr(188, "tech", "科技")); // 主分区 + zones.Add(new ZoneAttr(95, "digital", "数码", 188)); // 科技数码产品大全,一起来做发烧友 + zones.Add(new ZoneAttr(230, "application", "软件应用", 188)); // 超全软件应用指南 + zones.Add(new ZoneAttr(231, "computer_tech", "计算机技术", 188)); // 研究分析、教学演示、经验分享......有关计算机技术的都在这里 + zones.Add(new ZoneAttr(232, "industry", "科工机械", 188)); // 从小芯片到大工程,一起见证科工力量 + zones.Add(new ZoneAttr(233, "diy", "极客DIY", 188)); // 炫酷技能,极客文化,硬核技巧,准备好你的惊讶 + + //运动 + zones.Add(new ZoneAttr(234, "sports", "运动")); // 主分区 + zones.Add(new ZoneAttr(235, "basketball", "篮球", 234)); // 与篮球相关的视频,包括但不限于篮球赛事、教学、评述、剪辑、剧情等相关内容 + zones.Add(new ZoneAttr(249, "football", "足球", 234)); // 与足球相关的视频,包括但不限于足球赛事、教学、评述、剪辑、剧情等相关内容 + zones.Add(new ZoneAttr(164, "aerobics", "健身", 234)); // 与健身相关的视频,包括但不限于瑜伽、CrossFit、健美、力量举、普拉提、街健等相关内容 + zones.Add(new ZoneAttr(236, "athletic", "竞技体育", + 234)); // 与竞技体育相关的视频,包括但不限于乒乓、羽毛球、排球、赛车等竞技项目的赛事、评述、剪辑、剧情等相关内容 + zones.Add(new ZoneAttr(237, "culture", "运动文化", + 234)); // 与运动文化相关的视频,包络但不限于球鞋、球衣、球星卡等运动衍生品的分享、解读,体育产业的分析、科普等相关内容 + zones.Add(new ZoneAttr(238, "comprehensive", "运动综合", 234)); // 与运动综合相关的视频,包括但不限于钓鱼、骑行、滑板等日常运动分享、教学、Vlog等相关内容 + + //汽车 + zones.Add(new ZoneAttr(223, "car", "汽车")); // 主分区 + zones.Add(new ZoneAttr(245, "racing", "赛车", 223)); // F1等汽车运动相关 + zones.Add(new ZoneAttr(246, "modifiedvehicle", "改装玩车", 223)); // 汽车文化及改装车相关内容,包括改装车、老车修复介绍、汽车聚会分享等内容 + zones.Add(new ZoneAttr(247, "newenergyvehicle", "新能源车", + 223)); // 新能源汽车相关内容,包括电动汽车、混合动力汽车等车型种类,包含不限于新车资讯、试驾体验、专业评测、技术解读、知识科普等内容 + zones.Add(new ZoneAttr(248, "touringcar", "房车", 223)); // 房车及营地相关内容,包括不限于产品介绍、驾驶体验、房车生活和房车旅行等内容 + zones.Add(new ZoneAttr(240, "motorcycle", "摩托车", 223)); // 骑士们集合啦 + zones.Add(new ZoneAttr(227, "strategy", "购车攻略", 223)); // 丰富详实的购车建议和新车体验 + zones.Add(new ZoneAttr(176, "life", "汽车生活", 223)); // 分享汽车及出行相关的生活体验类视频 + + //生活 + zones.Add(new ZoneAttr(160, "life", "生活")); // 主分区 + zones.Add(new ZoneAttr(138, "funny", "搞笑", 160)); // 各种沙雕有趣的搞笑剪辑,挑战,表演,配音等视频 + zones.Add(new ZoneAttr(250, "travel", "Energy", 160)); // 为达到观光游览、休闲娱乐为目的的远途旅行、中近途户外生活、本地探店 + zones.Add(new ZoneAttr(251, "rurallife", "三农", 160)); // 分享美好农村生活 + zones.Add(new ZoneAttr(239, "home", "家居房产", 160)); // 与买房、装修、居家生活相关的分享 + zones.Add(new ZoneAttr(161, "handmake", "手工", 160)); // 手工制品的制作过程或成品展示、教程、测评类视频 + zones.Add(new ZoneAttr(162, "painting", "绘画", 160)); // 绘画过程或绘画教程,以及绘画相关的所有视频 + zones.Add(new ZoneAttr(21, "daily", "日常", 160)); // 记录日常生活,分享生活故事 + + //美食 + zones.Add(new ZoneAttr(211, "food", "美食")); // 主分区 + zones.Add(new ZoneAttr(76, "make", "美食制作", 211)); // 学做人间美味,展示精湛厨艺 + zones.Add(new ZoneAttr(212, "detective", "美食侦探", 211)); // 寻找美味餐厅,发现街头美食 + zones.Add(new ZoneAttr(213, "measurement", "美食测评", 211)); // 吃货世界,品尝世间美味 + zones.Add(new ZoneAttr(214, "rural", "田园美食", 211)); // 品味乡野美食,寻找山与海的味道 + zones.Add(new ZoneAttr(215, "record", "美食记录", 211)); // 记录一日三餐,给生活添一点幸福感 + + //动物圈 + zones.Add(new ZoneAttr(217, "animal", "动物圈")); // 主分区 + zones.Add(new ZoneAttr(218, "cat", "喵星人", 217)); // 喵喵喵喵喵 + zones.Add(new ZoneAttr(219, "dog", "汪星人", 217)); // 汪汪汪汪汪 + zones.Add(new ZoneAttr(220, "panda", "大熊猫", 217)); // 芝麻汤圆营业中 + zones.Add(new ZoneAttr(221, "wild_animal", "野生动物", 217)); // 内有“猛兽”出没 + zones.Add(new ZoneAttr(222, "reptiles", "爬宠", 217)); // 鳞甲有灵 + zones.Add(new ZoneAttr(75, "animal_composite", "动物综合", 217)); // 收录除上述子分区外,其余动物相关视频以及非动物主体或多个动物主体的动物相关延伸内容 + + //鬼畜 + zones.Add(new ZoneAttr(119, "kichiku", "鬼畜")); // 主分区 + zones.Add(new ZoneAttr(22, "guide", "鬼畜调教", 119)); // 使用素材在音频、画面上做一定处理,达到与BGM一定的同步感 + zones.Add(new ZoneAttr(26, "mad", "音MAD", 119)); // 使用素材音频进行一定的二次创作来达到还原原曲的非商业性质稿件 + zones.Add(new ZoneAttr(126, "manual_vocaloid", "人力VOCALOID", + 119)); // 将人物或者角色的无伴奏素材进行人工调音,使其就像VOCALOID一样歌唱的技术 + zones.Add(new ZoneAttr(216, "theatre", "鬼畜剧场", 119)); // 使用素材进行人工剪辑编排的有剧情的作品 + zones.Add(new ZoneAttr(127, "course", "教程演示", 119)); // 鬼畜相关的教程演示 + + //时尚 + zones.Add(new ZoneAttr(155, "fashion", "时尚")); // 主分区 + zones.Add(new ZoneAttr(157, "makeup", "美妆护肤", 155)); // 彩妆护肤、美甲美发、仿妆、医美相关内容分享或产品测评 + zones.Add(new ZoneAttr(252, "cos", "仿妆cos", 155)); // 对二次元、三次元人物角色进行模仿、还原、展示、演绎的内容 + zones.Add(new ZoneAttr(158, "clothing", "穿搭", 155)); // 穿搭风格、穿搭技巧的展示分享,涵盖衣服、鞋靴、箱包配件、配饰(帽子、钟表、珠宝首饰)等 + zones.Add(new ZoneAttr(159, "trend", "时尚潮流", 155)); // 时尚街拍、时装周、时尚大片,时尚品牌、潮流等行业相关记录及知识科普 + + //资讯 + zones.Add(new ZoneAttr(202, "information", "资讯")); // 主分区 + zones.Add(new ZoneAttr(203, "hotspot", "热点", 202)); // 全民关注的时政热门资讯 + zones.Add(new ZoneAttr(204, "global", "环球", 202)); // 全球范围内发生的具有重大影响力的事件动态 + zones.Add(new ZoneAttr(205, "social", "社会", 202)); // 日常生活的社会事件、社会问题、社会风貌的报道 + zones.Add(new ZoneAttr(206, "multiple", "综合", 202)); // 除上述领域外其它垂直领域的综合资讯 + + //娱乐 + zones.Add(new ZoneAttr(5, "ent", "娱乐")); // 主分区 + zones.Add(new ZoneAttr(71, "variety", "综艺", 5)); // 所有综艺相关,全部一手掌握! + zones.Add(new ZoneAttr(241, "talker", "娱乐杂谈", 5)); // 娱乐人物解读、娱乐热点点评、娱乐行业分析 + zones.Add(new ZoneAttr(242, "fans", "粉丝创作", 5)); // 粉丝向创作视频 + zones.Add(new ZoneAttr(137, "celebrity", "明星综合", 5)); // 娱乐圈动态、明星资讯相关 + + //影视 + zones.Add(new ZoneAttr(181, "cinephile", "影视")); // 主分区 + zones.Add(new ZoneAttr(182, "cinecism", "影视杂谈", 181)); // 影视评论、解说、吐槽、科普等 + zones.Add(new ZoneAttr(183, "montage", "影视剪辑", 181)); // 对影视素材进行剪辑再创作的视频 + zones.Add(new ZoneAttr(85, "shortfilm", "小剧场", 181)); // 有场景、有剧情的演绎类内容 + zones.Add(new ZoneAttr(184, "trailer_info", "预告·资讯", 181)); // 影视类相关资讯,预告,花絮等视频 + + //纪录片 + zones.Add(new ZoneAttr(177, "documentary", "纪录片")); // 主分区 + zones.Add(new ZoneAttr(37, "history", "人文·历史", 177)); // + zones.Add(new ZoneAttr(178, "science", "科学·探索·自然", 177)); // + zones.Add(new ZoneAttr(179, "military", "军事", 177)); // + zones.Add(new ZoneAttr(180, "travel", "社会·美食·旅行", 177)); // + + //电影 + zones.Add(new ZoneAttr(23, "movie", "电影")); // 主分区 + zones.Add(new ZoneAttr(147, "chinese", "华语电影", 23)); // + zones.Add(new ZoneAttr(145, "west", "欧美电影", 23)); // + zones.Add(new ZoneAttr(146, "japan", "日本电影", 23)); // + zones.Add(new ZoneAttr(83, "movie", "其他国家", 23)); // + + //电视剧 + zones.Add(new ZoneAttr(11, "tv", "电视剧")); // 主分区 + zones.Add(new ZoneAttr(185, "mainland", "国产剧", 11)); // + zones.Add(new ZoneAttr(187, "overseas", "海外剧", 11)); // + } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Zone/VideoZoneIcon.cs b/DownKyi.Core/BiliApi/Zone/VideoZoneIcon.cs new file mode 100644 index 0000000..15c3c32 --- /dev/null +++ b/DownKyi.Core/BiliApi/Zone/VideoZoneIcon.cs @@ -0,0 +1,89 @@ +namespace DownKyi.Core.BiliApi.Zone; + +/// +/// 视频分区图标 +/// +public class VideoZoneIcon +{ + private static VideoZoneIcon instance; + + /// + /// 获取VideoZoneIcon实例 + /// + /// + public static VideoZoneIcon Instance() + { + if (instance == null) + { + instance = new VideoZoneIcon(); + } + + return instance; + } + + /// + /// 隐藏VideoZoneIcon()方法,必须使用单例模式 + /// + private VideoZoneIcon() + { + } + + /// + /// 根据tid,获取视频分区图标 + /// + /// + /// + public string GetZoneImageKey(int tid) + { + switch (tid) + { + // 课堂 + case -10: + return "Zone.cheeseDrawingImage"; + case 1: + return "Zone.dougaDrawingImage"; + case 13: + return "Zone.animeDrawingImage"; + case 167: + return "Zone.guochuangDrawingImage"; + case 3: + return "Zone.musicDrawingImage"; + case 129: + return "Zone.danceDrawingImage"; + case 4: + return "Zone.gameDrawingImage"; + case 36: + return "Zone.techDrawingImage"; + case 188: + return "Zone.digitalDrawingImage"; + case 234: + return "Zone.sportsDrawingImage"; + case 223: + return "Zone.carDrawingImage"; + case 160: + return "Zone.lifeDrawingImage"; + case 211: + return "Zone.foodDrawingImage"; + case 217: + return "Zone.animalDrawingImage"; + case 119: + return "Zone.kichikuDrawingImage"; + case 155: + return "Zone.fashionDrawingImage"; + case 202: + return "Zone.informationDrawingImage"; + case 5: + return "Zone.entDrawingImage"; + case 181: + return "Zone.cinephileDrawingImage"; + case 177: + return "Zone.documentaryDrawingImage"; + case 23: + return "Zone.movieDrawingImage"; + case 11: + return "Zone.teleplayDrawingImage"; + default: + return "videoUpDrawingImage"; + } + } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Zone/ZoneAttr.cs b/DownKyi.Core/BiliApi/Zone/ZoneAttr.cs new file mode 100644 index 0000000..619b609 --- /dev/null +++ b/DownKyi.Core/BiliApi/Zone/ZoneAttr.cs @@ -0,0 +1,17 @@ +namespace DownKyi.Core.BiliApi.Zone; + +public class ZoneAttr +{ + public int Id { get; } + public string Type { get; } + public string Name { get; } + public int ParentId { get; } + + public ZoneAttr(int id, string type, string name, int parentId = 0) + { + Id = id; + Type = type; + Name = name; + ParentId = parentId; + } +} \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/Zone/ZoneImages.axaml b/DownKyi.Core/BiliApi/Zone/ZoneImages.axaml new file mode 100644 index 0000000..5ba7cee --- /dev/null +++ b/DownKyi.Core/BiliApi/Zone/ZoneImages.axaml @@ -0,0 +1,432 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/DownKyi.Core/BiliApi/protobuf/bilibili/community/service/dm/v1/Dm.cs b/DownKyi.Core/BiliApi/protobuf/bilibili/community/service/dm/v1/Dm.cs new file mode 100644 index 0000000..a423dbb --- /dev/null +++ b/DownKyi.Core/BiliApi/protobuf/bilibili/community/service/dm/v1/Dm.cs @@ -0,0 +1,14819 @@ +// +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: bilibili/community/service/dm/v1/dm.proto +// +#pragma warning disable 1591, 0612, 3021 +#region Designer generated code + +using pb = global::Google.Protobuf; +using pbc = global::Google.Protobuf.Collections; +using pbr = global::Google.Protobuf.Reflection; +using scg = global::System.Collections.Generic; +namespace Bilibili.Community.Service.Dm.V1 { + + /// Holder for reflection information generated from bilibili/community/service/dm/v1/dm.proto + public static partial class DmReflection { + + #region Descriptor + /// File descriptor for bilibili/community/service/dm/v1/dm.proto + public static pbr::FileDescriptor Descriptor { + get { return descriptor; } + } + private static pbr::FileDescriptor descriptor; + + static DmReflection() { + byte[] descriptorData = global::System.Convert.FromBase64String( + string.Concat( + "CiliaWxpYmlsaS9jb21tdW5pdHkvc2VydmljZS9kbS92MS9kbS5wcm90bxIg", + "YmlsaWJpbGkuY29tbXVuaXR5LnNlcnZpY2UuZG0udjEiTAoLRG1TZWdTREtS", + "ZXESCwoDcGlkGAEgASgDEgsKA29pZBgCIAEoAxIMCgR0eXBlGAMgASgFEhUK", + "DXNlZ21lbnRfaW5kZXgYBCABKAMiXQoNRG1TZWdTREtSZXBseRIOCgZjbG9z", + "ZWQYASABKAgSPAoFZWxlbXMYAiADKAsyLS5iaWxpYmlsaS5jb21tdW5pdHku", + "c2VydmljZS5kbS52MS5EYW5tYWt1RWxlbSJMCgtEbVNlZ090dFJlcRILCgNw", + "aWQYASABKAMSCwoDb2lkGAIgASgDEgwKBHR5cGUYAyABKAUSFQoNc2VnbWVu", + "dF9pbmRleBgEIAEoAyJdCg1EbVNlZ090dFJlcGx5Eg4KBmNsb3NlZBgBIAEo", + "CBI8CgVlbGVtcxgCIAMoCzItLmJpbGliaWxpLmNvbW11bml0eS5zZXJ2aWNl", + "LmRtLnYxLkRhbm1ha3VFbGVtImcKDkRtU2VnTW9iaWxlUmVxEgsKA3BpZBgB", + "IAEoAxILCgNvaWQYAiABKAMSDAoEdHlwZRgDIAEoBRIVCg1zZWdtZW50X2lu", + "ZGV4GAQgASgDEhYKDnRlZW5hZ2Vyc19tb2RlGAUgASgFIqEBChBEbVNlZ01v", + "YmlsZVJlcGx5EjwKBWVsZW1zGAEgAygLMi0uYmlsaWJpbGkuY29tbXVuaXR5", + "LnNlcnZpY2UuZG0udjEuRGFubWFrdUVsZW0SDQoFc3RhdGUYAiABKAUSQAoH", + "YWlfZmxhZxgDIAEoCzIvLmJpbGliaWxpLmNvbW11bml0eS5zZXJ2aWNlLmRt", + "LnYxLkRhbm1ha3VBSUZsYWciWAoJRG1WaWV3UmVxEgsKA3BpZBgBIAEoAxIL", + "CgNvaWQYAiABKAMSDAoEdHlwZRgDIAEoBRINCgVzcG1pZBgEIAEoCRIUCgxp", + "c19oYXJkX2Jvb3QYBSABKAUi8AMKC0RtVmlld1JlcGx5Eg4KBmNsb3NlZBgB", + "IAEoCBI5CgRtYXNrGAIgASgLMisuYmlsaWJpbGkuY29tbXVuaXR5LnNlcnZp", + "Y2UuZG0udjEuVmlkZW9NYXNrEkEKCHN1YnRpdGxlGAMgASgLMi8uYmlsaWJp", + "bGkuY29tbXVuaXR5LnNlcnZpY2UuZG0udjEuVmlkZW9TdWJ0aXRsZRITCgtz", + "cGVjaWFsX2RtcxgEIAMoCRJECgdhaV9mbGFnGAUgASgLMjMuYmlsaWJpbGku", + "Y29tbXVuaXR5LnNlcnZpY2UuZG0udjEuRGFubWFrdUZsYWdDb25maWcSTgoN", + "cGxheWVyX2NvbmZpZxgGIAEoCzI3LmJpbGliaWxpLmNvbW11bml0eS5zZXJ2", + "aWNlLmRtLnYxLkRhbm11UGxheWVyVmlld0NvbmZpZxIWCg5zZW5kX2JveF9z", + "dHlsZRgHIAEoBRINCgVhbGxvdxgIIAEoCBIRCgljaGVja19ib3gYCSABKAkS", + "GgoSY2hlY2tfYm94X3Nob3dfbXNnGAogASgJEhgKEHRleHRfcGxhY2Vob2xk", + "ZXIYCyABKAkSGQoRaW5wdXRfcGxhY2Vob2xkZXIYDCABKAkSHQoVcmVwb3J0", + "X2ZpbHRlcl9jb250ZW50GA0gAygJIqgDCg5EbVdlYlZpZXdSZXBseRINCgVz", + "dGF0ZRgBIAEoBRIMCgR0ZXh0GAIgASgJEhEKCXRleHRfc2lkZRgDIAEoCRI9", + "CgZkbV9zZ2UYBCABKAsyLS5iaWxpYmlsaS5jb21tdW5pdHkuc2VydmljZS5k", + "bS52MS5EbVNlZ0NvbmZpZxJBCgRmbGFnGAUgASgLMjMuYmlsaWJpbGkuY29t", + "bXVuaXR5LnNlcnZpY2UuZG0udjEuRGFubWFrdUZsYWdDb25maWcSEwoLc3Bl", + "Y2lhbF9kbXMYBiADKAkSEQoJY2hlY2tfYm94GAcgASgIEg0KBWNvdW50GAgg", + "ASgDEj8KCmNvbW1hbmREbXMYCSADKAsyKy5iaWxpYmlsaS5jb21tdW5pdHku", + "c2VydmljZS5kbS52MS5Db21tYW5kRG0STQoNcGxheWVyX2NvbmZpZxgKIAEo", + "CzI2LmJpbGliaWxpLmNvbW11bml0eS5zZXJ2aWNlLmRtLnYxLkRhbm11V2Vi", + "UGxheWVyQ29uZmlnEh0KFXJlcG9ydF9maWx0ZXJfY29udGVudBgLIAMoCSKh", + "AQoJQ29tbWFuZERtEgoKAmlkGAEgASgDEgsKA29pZBgCIAEoAxILCgNtaWQY", + "AyABKAkSDwoHY29tbWFuZBgEIAEoCRIPCgdjb250ZW50GAUgASgJEhAKCHBy", + "b2dyZXNzGAYgASgFEg0KBWN0aW1lGAcgASgJEg0KBW10aW1lGAggASgJEg0K", + "BWV4dHJhGAkgASgJEg0KBWlkU3RyGAogASgJIi8KC0RtU2VnQ29uZmlnEhEK", + "CXBhZ2Vfc2l6ZRgBIAEoAxINCgV0b3RhbBgCIAEoAyJTCglWaWRlb01hc2sS", + "CwoDY2lkGAEgASgDEgwKBHBsYXQYAiABKAUSCwoDZnBzGAMgASgFEgwKBHRp", + "bWUYBCABKAMSEAoIbWFza191cmwYBSABKAkibwoNVmlkZW9TdWJ0aXRsZRIL", + "CgNsYW4YASABKAkSDgoGbGFuRG9jGAIgASgJEkEKCXN1YnRpdGxlcxgDIAMo", + "CzIuLmJpbGliaWxpLmNvbW11bml0eS5zZXJ2aWNlLmRtLnYxLlN1YnRpdGxl", + "SXRlbSKPAwoURGFubXVXZWJQbGF5ZXJDb25maWcSEQoJZG1fc3dpdGNoGAEg", + "ASgIEhEKCWFpX3N3aXRjaBgCIAEoCBIQCghhaV9sZXZlbBgDIAEoBRIQCghi", + "bG9ja3RvcBgEIAEoCBITCgtibG9ja3Njcm9sbBgFIAEoCBITCgtibG9ja2Jv", + "dHRvbRgGIAEoCBISCgpibG9ja2NvbG9yGAcgASgIEhQKDGJsb2Nrc3BlY2lh", + "bBgIIAEoCBIUCgxwcmV2ZW50c2hhZGUYCSABKAgSDQoFZG1hc2sYCiABKAgS", + "DwoHb3BhY2l0eRgLIAEoAhIOCgZkbWFyZWEYDCABKAUSEQoJc3BlZWRwbHVz", + "GA0gASgCEhAKCGZvbnRzaXplGA4gASgCEhIKCnNjcmVlbnN5bmMYDyABKAgS", + "EQoJc3BlZWRzeW5jGBAgASgIEhIKCmZvbnRmYW1pbHkYESABKAkSDAoEYm9s", + "ZBgSIAEoCBISCgpmb250Ym9yZGVyGBMgASgFEhEKCWRyYXdfdHlwZRgUIAEo", + "CSKaAQoMU3VidGl0bGVJdGVtEgoKAmlkGAEgASgDEg4KBmlkX3N0chgCIAEo", + "CRILCgNsYW4YAyABKAkSDwoHbGFuX2RvYxgEIAEoCRIUCgxzdWJ0aXRsZV91", + "cmwYBSABKAkSOgoGYXV0aG9yGAYgASgLMiouYmlsaWJpbGkuY29tbXVuaXR5", + "LnNlcnZpY2UuZG0udjEuVXNlckluZm8iXAoIVXNlckluZm8SCwoDbWlkGAEg", + "ASgDEgwKBG5hbWUYAiABKAkSCwoDc2V4GAMgASgJEgwKBGZhY2UYBCABKAkS", + "DAoEc2lnbhgFIAEoCRIMCgRyYW5rGAYgASgFItYBCgtEYW5tYWt1RWxlbRIK", + "CgJpZBgBIAEoAxIQCghwcm9ncmVzcxgCIAEoBRIMCgRtb2RlGAMgASgFEhAK", + "CGZvbnRzaXplGAQgASgFEg0KBWNvbG9yGAUgASgNEg8KB21pZEhhc2gYBiAB", + "KAkSDwoHY29udGVudBgHIAEoCRINCgVjdGltZRgIIAEoAxIOCgZ3ZWlnaHQY", + "CSABKAUSDgoGYWN0aW9uGAogASgJEgwKBHBvb2wYCyABKAUSDQoFaWRTdHIY", + "DCABKAkSDAoEYXR0chgNIAEoBSKgCwoRRG1QbGF5ZXJDb25maWdSZXESCgoC", + "dHMYASABKAMSRQoGc3dpdGNoGAIgASgLMjUuYmlsaWJpbGkuY29tbXVuaXR5", + "LnNlcnZpY2UuZG0udjEuUGxheWVyRGFubWFrdVN3aXRjaBJOCgtzd2l0Y2hf", + "c2F2ZRgDIAEoCzI5LmJpbGliaWxpLmNvbW11bml0eS5zZXJ2aWNlLmRtLnYx", + "LlBsYXllckRhbm1ha3VTd2l0Y2hTYXZlElsKEnVzZV9kZWZhdWx0X2NvbmZp", + "ZxgEIAEoCzI/LmJpbGliaWxpLmNvbW11bml0eS5zZXJ2aWNlLmRtLnYxLlBs", + "YXllckRhbm1ha3VVc2VEZWZhdWx0Q29uZmlnEmEKFWFpX3JlY29tbWVuZGVk", + "X3N3aXRjaBgFIAEoCzJCLmJpbGliaWxpLmNvbW11bml0eS5zZXJ2aWNlLmRt", + "LnYxLlBsYXllckRhbm1ha3VBaVJlY29tbWVuZGVkU3dpdGNoEl8KFGFpX3Jl", + "Y29tbWVuZGVkX2xldmVsGAYgASgLMkEuYmlsaWJpbGkuY29tbXVuaXR5LnNl", + "cnZpY2UuZG0udjEuUGxheWVyRGFubWFrdUFpUmVjb21tZW5kZWRMZXZlbBJJ", + "CghibG9ja3RvcBgHIAEoCzI3LmJpbGliaWxpLmNvbW11bml0eS5zZXJ2aWNl", + "LmRtLnYxLlBsYXllckRhbm1ha3VCbG9ja3RvcBJPCgtibG9ja3Njcm9sbBgI", + "IAEoCzI6LmJpbGliaWxpLmNvbW11bml0eS5zZXJ2aWNlLmRtLnYxLlBsYXll", + "ckRhbm1ha3VCbG9ja3Njcm9sbBJPCgtibG9ja2JvdHRvbRgJIAEoCzI6LmJp", + "bGliaWxpLmNvbW11bml0eS5zZXJ2aWNlLmRtLnYxLlBsYXllckRhbm1ha3VC", + "bG9ja2JvdHRvbRJTCg1ibG9ja2NvbG9yZnVsGAogASgLMjwuYmlsaWJpbGku", + "Y29tbXVuaXR5LnNlcnZpY2UuZG0udjEuUGxheWVyRGFubWFrdUJsb2NrY29s", + "b3JmdWwSTwoLYmxvY2tyZXBlYXQYCyABKAsyOi5iaWxpYmlsaS5jb21tdW5p", + "dHkuc2VydmljZS5kbS52MS5QbGF5ZXJEYW5tYWt1QmxvY2tyZXBlYXQSUQoM", + "YmxvY2tzcGVjaWFsGAwgASgLMjsuYmlsaWJpbGkuY29tbXVuaXR5LnNlcnZp", + "Y2UuZG0udjEuUGxheWVyRGFubWFrdUJsb2Nrc3BlY2lhbBJHCgdvcGFjaXR5", + "GA0gASgLMjYuYmlsaWJpbGkuY29tbXVuaXR5LnNlcnZpY2UuZG0udjEuUGxh", + "eWVyRGFubWFrdU9wYWNpdHkSUwoNc2NhbGluZ2ZhY3RvchgOIAEoCzI8LmJp", + "bGliaWxpLmNvbW11bml0eS5zZXJ2aWNlLmRtLnYxLlBsYXllckRhbm1ha3VT", + "Y2FsaW5nZmFjdG9yEkUKBmRvbWFpbhgPIAEoCzI1LmJpbGliaWxpLmNvbW11", + "bml0eS5zZXJ2aWNlLmRtLnYxLlBsYXllckRhbm1ha3VEb21haW4SQwoFc3Bl", + "ZWQYECABKAsyNC5iaWxpYmlsaS5jb21tdW5pdHkuc2VydmljZS5kbS52MS5Q", + "bGF5ZXJEYW5tYWt1U3BlZWQSVwoPZW5hYmxlYmxvY2tsaXN0GBEgASgLMj4u", + "YmlsaWJpbGkuY29tbXVuaXR5LnNlcnZpY2UuZG0udjEuUGxheWVyRGFubWFr", + "dUVuYWJsZWJsb2NrbGlzdBJeChlpbmxpbmVQbGF5ZXJEYW5tYWt1U3dpdGNo", + "GBIgASgLMjsuYmlsaWJpbGkuY29tbXVuaXR5LnNlcnZpY2UuZG0udjEuSW5s", + "aW5lUGxheWVyRGFubWFrdVN3aXRjaCIpCghSZXNwb25zZRIMCgRjb2RlGAEg", + "ASgFEg8KB21lc3NhZ2UYAiABKAkiKQoLRGFubWFrdUZsYWcSDAoEZG1pZBgB", + "IAEoAxIMCgRmbGFnGAIgASgNIksKEURhbm1ha3VGbGFnQ29uZmlnEhAKCHJl", + "Y19mbGFnGAEgASgFEhAKCHJlY190ZXh0GAIgASgJEhIKCnJlY19zd2l0Y2gY", + "AyABKAUiUAoNRGFubWFrdUFJRmxhZxI/CghkbV9mbGFncxgBIAMoCzItLmJp", + "bGliaWxpLmNvbW11bml0eS5zZXJ2aWNlLmRtLnYxLkRhbm1ha3VGbGFnIrEC", + "ChVEYW5tdVBsYXllclZpZXdDb25maWcSYQodZGFubXVrdV9kZWZhdWx0X3Bs", + "YXllcl9jb25maWcYASABKAsyOi5iaWxpYmlsaS5jb21tdW5pdHkuc2Vydmlj", + "ZS5kbS52MS5EYW5tdURlZmF1bHRQbGF5ZXJDb25maWcSUgoVZGFubXVrdV9w", + "bGF5ZXJfY29uZmlnGAIgASgLMjMuYmlsaWJpbGkuY29tbXVuaXR5LnNlcnZp", + "Y2UuZG0udjEuRGFubXVQbGF5ZXJDb25maWcSYQodZGFubXVrdV9wbGF5ZXJf", + "ZHluYW1pY19jb25maWcYAyADKAsyOi5iaWxpYmlsaS5jb21tdW5pdHkuc2Vy", + "dmljZS5kbS52MS5EYW5tdVBsYXllckR5bmFtaWNDb25maWcioQQKGERhbm11", + "RGVmYXVsdFBsYXllckNvbmZpZxIpCiFwbGF5ZXJfZGFubWFrdV91c2VfZGVm", + "YXVsdF9jb25maWcYASABKAgSLAokcGxheWVyX2Rhbm1ha3VfYWlfcmVjb21t", + "ZW5kZWRfc3dpdGNoGAQgASgIEisKI3BsYXllcl9kYW5tYWt1X2FpX3JlY29t", + "bWVuZGVkX2xldmVsGAUgASgFEh8KF3BsYXllcl9kYW5tYWt1X2Jsb2NrdG9w", + "GAYgASgIEiIKGnBsYXllcl9kYW5tYWt1X2Jsb2Nrc2Nyb2xsGAcgASgIEiIK", + "GnBsYXllcl9kYW5tYWt1X2Jsb2NrYm90dG9tGAggASgIEiQKHHBsYXllcl9k", + "YW5tYWt1X2Jsb2NrY29sb3JmdWwYCSABKAgSIgoacGxheWVyX2Rhbm1ha3Vf", + "YmxvY2tyZXBlYXQYCiABKAgSIwobcGxheWVyX2Rhbm1ha3VfYmxvY2tzcGVj", + "aWFsGAsgASgIEh4KFnBsYXllcl9kYW5tYWt1X29wYWNpdHkYDCABKAISJAoc", + "cGxheWVyX2Rhbm1ha3Vfc2NhbGluZ2ZhY3RvchgNIAEoAhIdChVwbGF5ZXJf", + "ZGFubWFrdV9kb21haW4YDiABKAISHAoUcGxheWVyX2Rhbm1ha3Vfc3BlZWQY", + "DyABKAUSJAocaW5saW5lX3BsYXllcl9kYW5tYWt1X3N3aXRjaBgQIAEoCCKr", + "BQoRRGFubXVQbGF5ZXJDb25maWcSHQoVcGxheWVyX2Rhbm1ha3Vfc3dpdGNo", + "GAEgASgIEiIKGnBsYXllcl9kYW5tYWt1X3N3aXRjaF9zYXZlGAIgASgIEikK", + "IXBsYXllcl9kYW5tYWt1X3VzZV9kZWZhdWx0X2NvbmZpZxgDIAEoCBIsCiRw", + "bGF5ZXJfZGFubWFrdV9haV9yZWNvbW1lbmRlZF9zd2l0Y2gYBCABKAgSKwoj", + "cGxheWVyX2Rhbm1ha3VfYWlfcmVjb21tZW5kZWRfbGV2ZWwYBSABKAUSHwoX", + "cGxheWVyX2Rhbm1ha3VfYmxvY2t0b3AYBiABKAgSIgoacGxheWVyX2Rhbm1h", + "a3VfYmxvY2tzY3JvbGwYByABKAgSIgoacGxheWVyX2Rhbm1ha3VfYmxvY2ti", + "b3R0b20YCCABKAgSJAoccGxheWVyX2Rhbm1ha3VfYmxvY2tjb2xvcmZ1bBgJ", + "IAEoCBIiChpwbGF5ZXJfZGFubWFrdV9ibG9ja3JlcGVhdBgKIAEoCBIjChtw", + "bGF5ZXJfZGFubWFrdV9ibG9ja3NwZWNpYWwYCyABKAgSHgoWcGxheWVyX2Rh", + "bm1ha3Vfb3BhY2l0eRgMIAEoAhIkChxwbGF5ZXJfZGFubWFrdV9zY2FsaW5n", + "ZmFjdG9yGA0gASgCEh0KFXBsYXllcl9kYW5tYWt1X2RvbWFpbhgOIAEoAhIc", + "ChRwbGF5ZXJfZGFubWFrdV9zcGVlZBgPIAEoBRImCh5wbGF5ZXJfZGFubWFr", + "dV9lbmFibGVibG9ja2xpc3QYECABKAgSJAocaW5saW5lX3BsYXllcl9kYW5t", + "YWt1X3N3aXRjaBgRIAEoCBIkChxpbmxpbmVfcGxheWVyX2Rhbm1ha3VfY29u", + "ZmlnGBIgASgFIksKGERhbm11UGxheWVyRHluYW1pY0NvbmZpZxIQCghwcm9n", + "cmVzcxgBIAEoBRIdChVwbGF5ZXJfZGFubWFrdV9kb21haW4YAiABKAIiNwoT", + "UGxheWVyRGFubWFrdVN3aXRjaBINCgV2YWx1ZRgBIAEoCBIRCgljYW5JZ25v", + "cmUYAiABKAgiKAoXUGxheWVyRGFubWFrdVN3aXRjaFNhdmUSDQoFdmFsdWUY", + "ASABKAgiLgodUGxheWVyRGFubWFrdVVzZURlZmF1bHRDb25maWcSDQoFdmFs", + "dWUYASABKAgiMQogUGxheWVyRGFubWFrdUFpUmVjb21tZW5kZWRTd2l0Y2gS", + "DQoFdmFsdWUYASABKAgiMAofUGxheWVyRGFubWFrdUFpUmVjb21tZW5kZWRM", + "ZXZlbBINCgV2YWx1ZRgBIAEoCCImChVQbGF5ZXJEYW5tYWt1QmxvY2t0b3AS", + "DQoFdmFsdWUYASABKAgiKQoYUGxheWVyRGFubWFrdUJsb2Nrc2Nyb2xsEg0K", + "BXZhbHVlGAEgASgIIikKGFBsYXllckRhbm1ha3VCbG9ja2JvdHRvbRINCgV2", + "YWx1ZRgBIAEoCCIrChpQbGF5ZXJEYW5tYWt1QmxvY2tjb2xvcmZ1bBINCgV2", + "YWx1ZRgBIAEoCCIpChhQbGF5ZXJEYW5tYWt1QmxvY2tyZXBlYXQSDQoFdmFs", + "dWUYASABKAgiKgoZUGxheWVyRGFubWFrdUJsb2Nrc3BlY2lhbBINCgV2YWx1", + "ZRgBIAEoCCIlChRQbGF5ZXJEYW5tYWt1T3BhY2l0eRINCgV2YWx1ZRgBIAEo", + "AiIrChpQbGF5ZXJEYW5tYWt1U2NhbGluZ2ZhY3RvchINCgV2YWx1ZRgBIAEo", + "AiIkChNQbGF5ZXJEYW5tYWt1RG9tYWluEg0KBXZhbHVlGAEgASgCIiMKElBs", + "YXllckRhbm1ha3VTcGVlZBINCgV2YWx1ZRgBIAEoBSItChxQbGF5ZXJEYW5t", + "YWt1RW5hYmxlYmxvY2tsaXN0Eg0KBXZhbHVlGAEgASgIIioKGUlubGluZVBs", + "YXllckRhbm1ha3VTd2l0Y2gSDQoFdmFsdWUYASABKAgqTAoJRE1BdHRyQml0", + "EhQKEERNQXR0ckJpdFByb3RlY3QQABIVChFETUF0dHJCaXRGcm9tTGl2ZRAB", + "EhIKDkRNQXR0ckhpZ2hMaWtlEAIyqgQKAkRNEnMKC0RtU2VnTW9iaWxlEjAu", + "YmlsaWJpbGkuY29tbXVuaXR5LnNlcnZpY2UuZG0udjEuRG1TZWdNb2JpbGVS", + "ZXEaMi5iaWxpYmlsaS5jb21tdW5pdHkuc2VydmljZS5kbS52MS5EbVNlZ01v", + "YmlsZVJlcGx5EmQKBkRtVmlldxIrLmJpbGliaWxpLmNvbW11bml0eS5zZXJ2", + "aWNlLmRtLnYxLkRtVmlld1JlcRotLmJpbGliaWxpLmNvbW11bml0eS5zZXJ2", + "aWNlLmRtLnYxLkRtVmlld1JlcGx5EnEKDkRtUGxheWVyQ29uZmlnEjMuYmls", + "aWJpbGkuY29tbXVuaXR5LnNlcnZpY2UuZG0udjEuRG1QbGF5ZXJDb25maWdS", + "ZXEaKi5iaWxpYmlsaS5jb21tdW5pdHkuc2VydmljZS5kbS52MS5SZXNwb25z", + "ZRJqCghEbVNlZ090dBItLmJpbGliaWxpLmNvbW11bml0eS5zZXJ2aWNlLmRt", + "LnYxLkRtU2VnT3R0UmVxGi8uYmlsaWJpbGkuY29tbXVuaXR5LnNlcnZpY2Uu", + "ZG0udjEuRG1TZWdPdHRSZXBseRJqCghEbVNlZ1NESxItLmJpbGliaWxpLmNv", + "bW11bml0eS5zZXJ2aWNlLmRtLnYxLkRtU2VnU0RLUmVxGi8uYmlsaWJpbGku", + "Y29tbXVuaXR5LnNlcnZpY2UuZG0udjEuRG1TZWdTREtSZXBseWIGcHJvdG8z")); + descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, + new pbr::FileDescriptor[] { }, + new pbr::GeneratedClrTypeInfo(new[] {typeof(global::Bilibili.Community.Service.Dm.V1.DMAttrBit), }, null, new pbr::GeneratedClrTypeInfo[] { + new pbr::GeneratedClrTypeInfo(typeof(global::Bilibili.Community.Service.Dm.V1.DmSegSDKReq), global::Bilibili.Community.Service.Dm.V1.DmSegSDKReq.Parser, new[]{ "Pid", "Oid", "Type", "SegmentIndex" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Bilibili.Community.Service.Dm.V1.DmSegSDKReply), global::Bilibili.Community.Service.Dm.V1.DmSegSDKReply.Parser, new[]{ "Closed", "Elems" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Bilibili.Community.Service.Dm.V1.DmSegOttReq), global::Bilibili.Community.Service.Dm.V1.DmSegOttReq.Parser, new[]{ "Pid", "Oid", "Type", "SegmentIndex" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Bilibili.Community.Service.Dm.V1.DmSegOttReply), global::Bilibili.Community.Service.Dm.V1.DmSegOttReply.Parser, new[]{ "Closed", "Elems" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Bilibili.Community.Service.Dm.V1.DmSegMobileReq), global::Bilibili.Community.Service.Dm.V1.DmSegMobileReq.Parser, new[]{ "Pid", "Oid", "Type", "SegmentIndex", "TeenagersMode" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Bilibili.Community.Service.Dm.V1.DmSegMobileReply), global::Bilibili.Community.Service.Dm.V1.DmSegMobileReply.Parser, new[]{ "Elems", "State", "AiFlag" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Bilibili.Community.Service.Dm.V1.DmViewReq), global::Bilibili.Community.Service.Dm.V1.DmViewReq.Parser, new[]{ "Pid", "Oid", "Type", "Spmid", "IsHardBoot" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Bilibili.Community.Service.Dm.V1.DmViewReply), global::Bilibili.Community.Service.Dm.V1.DmViewReply.Parser, new[]{ "Closed", "Mask", "Subtitle", "SpecialDms", "AiFlag", "PlayerConfig", "SendBoxStyle", "Allow", "CheckBox", "CheckBoxShowMsg", "TextPlaceholder", "InputPlaceholder", "ReportFilterContent" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Bilibili.Community.Service.Dm.V1.DmWebViewReply), global::Bilibili.Community.Service.Dm.V1.DmWebViewReply.Parser, new[]{ "State", "Text", "TextSide", "DmSge", "Flag", "SpecialDms", "CheckBox", "Count", "CommandDms", "PlayerConfig", "ReportFilterContent" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Bilibili.Community.Service.Dm.V1.CommandDm), global::Bilibili.Community.Service.Dm.V1.CommandDm.Parser, new[]{ "Id", "Oid", "Mid", "Command", "Content", "Progress", "Ctime", "Mtime", "Extra", "IdStr" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Bilibili.Community.Service.Dm.V1.DmSegConfig), global::Bilibili.Community.Service.Dm.V1.DmSegConfig.Parser, new[]{ "PageSize", "Total" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Bilibili.Community.Service.Dm.V1.VideoMask), global::Bilibili.Community.Service.Dm.V1.VideoMask.Parser, new[]{ "Cid", "Plat", "Fps", "Time", "MaskUrl" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Bilibili.Community.Service.Dm.V1.VideoSubtitle), global::Bilibili.Community.Service.Dm.V1.VideoSubtitle.Parser, new[]{ "Lan", "LanDoc", "Subtitles" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Bilibili.Community.Service.Dm.V1.DanmuWebPlayerConfig), global::Bilibili.Community.Service.Dm.V1.DanmuWebPlayerConfig.Parser, new[]{ "DmSwitch", "AiSwitch", "AiLevel", "Blocktop", "Blockscroll", "Blockbottom", "Blockcolor", "Blockspecial", "Preventshade", "Dmask", "Opacity", "Dmarea", "Speedplus", "Fontsize", "Screensync", "Speedsync", "Fontfamily", "Bold", "Fontborder", "DrawType" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Bilibili.Community.Service.Dm.V1.SubtitleItem), global::Bilibili.Community.Service.Dm.V1.SubtitleItem.Parser, new[]{ "Id", "IdStr", "Lan", "LanDoc", "SubtitleUrl", "Author" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Bilibili.Community.Service.Dm.V1.UserInfo), global::Bilibili.Community.Service.Dm.V1.UserInfo.Parser, new[]{ "Mid", "Name", "Sex", "Face", "Sign", "Rank" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Bilibili.Community.Service.Dm.V1.DanmakuElem), global::Bilibili.Community.Service.Dm.V1.DanmakuElem.Parser, new[]{ "Id", "Progress", "Mode", "Fontsize", "Color", "MidHash", "Content", "Ctime", "Weight", "Action", "Pool", "IdStr", "Attr" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Bilibili.Community.Service.Dm.V1.DmPlayerConfigReq), global::Bilibili.Community.Service.Dm.V1.DmPlayerConfigReq.Parser, new[]{ "Ts", "Switch", "SwitchSave", "UseDefaultConfig", "AiRecommendedSwitch", "AiRecommendedLevel", "Blocktop", "Blockscroll", "Blockbottom", "Blockcolorful", "Blockrepeat", "Blockspecial", "Opacity", "Scalingfactor", "Domain", "Speed", "Enableblocklist", "InlinePlayerDanmakuSwitch" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Bilibili.Community.Service.Dm.V1.Response), global::Bilibili.Community.Service.Dm.V1.Response.Parser, new[]{ "Code", "Message" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Bilibili.Community.Service.Dm.V1.DanmakuFlag), global::Bilibili.Community.Service.Dm.V1.DanmakuFlag.Parser, new[]{ "Dmid", "Flag" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Bilibili.Community.Service.Dm.V1.DanmakuFlagConfig), global::Bilibili.Community.Service.Dm.V1.DanmakuFlagConfig.Parser, new[]{ "RecFlag", "RecText", "RecSwitch" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Bilibili.Community.Service.Dm.V1.DanmakuAIFlag), global::Bilibili.Community.Service.Dm.V1.DanmakuAIFlag.Parser, new[]{ "DmFlags" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Bilibili.Community.Service.Dm.V1.DanmuPlayerViewConfig), global::Bilibili.Community.Service.Dm.V1.DanmuPlayerViewConfig.Parser, new[]{ "DanmukuDefaultPlayerConfig", "DanmukuPlayerConfig", "DanmukuPlayerDynamicConfig" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Bilibili.Community.Service.Dm.V1.DanmuDefaultPlayerConfig), global::Bilibili.Community.Service.Dm.V1.DanmuDefaultPlayerConfig.Parser, new[]{ "PlayerDanmakuUseDefaultConfig", "PlayerDanmakuAiRecommendedSwitch", "PlayerDanmakuAiRecommendedLevel", "PlayerDanmakuBlocktop", "PlayerDanmakuBlockscroll", "PlayerDanmakuBlockbottom", "PlayerDanmakuBlockcolorful", "PlayerDanmakuBlockrepeat", "PlayerDanmakuBlockspecial", "PlayerDanmakuOpacity", "PlayerDanmakuScalingfactor", "PlayerDanmakuDomain", "PlayerDanmakuSpeed", "InlinePlayerDanmakuSwitch" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Bilibili.Community.Service.Dm.V1.DanmuPlayerConfig), global::Bilibili.Community.Service.Dm.V1.DanmuPlayerConfig.Parser, new[]{ "PlayerDanmakuSwitch", "PlayerDanmakuSwitchSave", "PlayerDanmakuUseDefaultConfig", "PlayerDanmakuAiRecommendedSwitch", "PlayerDanmakuAiRecommendedLevel", "PlayerDanmakuBlocktop", "PlayerDanmakuBlockscroll", "PlayerDanmakuBlockbottom", "PlayerDanmakuBlockcolorful", "PlayerDanmakuBlockrepeat", "PlayerDanmakuBlockspecial", "PlayerDanmakuOpacity", "PlayerDanmakuScalingfactor", "PlayerDanmakuDomain", "PlayerDanmakuSpeed", "PlayerDanmakuEnableblocklist", "InlinePlayerDanmakuSwitch", "InlinePlayerDanmakuConfig" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Bilibili.Community.Service.Dm.V1.DanmuPlayerDynamicConfig), global::Bilibili.Community.Service.Dm.V1.DanmuPlayerDynamicConfig.Parser, new[]{ "Progress", "PlayerDanmakuDomain" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuSwitch), global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuSwitch.Parser, new[]{ "Value", "CanIgnore" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuSwitchSave), global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuSwitchSave.Parser, new[]{ "Value" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuUseDefaultConfig), global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuUseDefaultConfig.Parser, new[]{ "Value" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuAiRecommendedSwitch), global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuAiRecommendedSwitch.Parser, new[]{ "Value" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuAiRecommendedLevel), global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuAiRecommendedLevel.Parser, new[]{ "Value" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuBlocktop), global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuBlocktop.Parser, new[]{ "Value" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuBlockscroll), global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuBlockscroll.Parser, new[]{ "Value" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuBlockbottom), global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuBlockbottom.Parser, new[]{ "Value" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuBlockcolorful), global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuBlockcolorful.Parser, new[]{ "Value" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuBlockrepeat), global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuBlockrepeat.Parser, new[]{ "Value" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuBlockspecial), global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuBlockspecial.Parser, new[]{ "Value" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuOpacity), global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuOpacity.Parser, new[]{ "Value" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuScalingfactor), global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuScalingfactor.Parser, new[]{ "Value" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuDomain), global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuDomain.Parser, new[]{ "Value" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuSpeed), global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuSpeed.Parser, new[]{ "Value" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuEnableblocklist), global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuEnableblocklist.Parser, new[]{ "Value" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Bilibili.Community.Service.Dm.V1.InlinePlayerDanmakuSwitch), global::Bilibili.Community.Service.Dm.V1.InlinePlayerDanmakuSwitch.Parser, new[]{ "Value" }, null, null, null, null) + })); + } + #endregion + + } + #region Enums + /// + /// 弹幕属性位值 + /// + public enum DMAttrBit { + /// + /// 保护弹幕 + /// + [pbr::OriginalName("DMAttrBitProtect")] Protect = 0, + /// + /// 直播弹幕 + /// + [pbr::OriginalName("DMAttrBitFromLive")] FromLive = 1, + /// + /// 高赞弹幕 + /// + [pbr::OriginalName("DMAttrHighLike")] DmattrHighLike = 2, + } + + #endregion + + #region Messages + /// + /// 弹幕SDK-请求 + /// + public sealed partial class DmSegSDKReq : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new DmSegSDKReq()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pbr::MessageDescriptor Descriptor { + get { return global::Bilibili.Community.Service.Dm.V1.DmReflection.Descriptor.MessageTypes[0]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public DmSegSDKReq() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public DmSegSDKReq(DmSegSDKReq other) : this() { + pid_ = other.pid_; + oid_ = other.oid_; + type_ = other.type_; + segmentIndex_ = other.segmentIndex_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public DmSegSDKReq Clone() { + return new DmSegSDKReq(this); + } + + /// Field number for the "pid" field. + public const int PidFieldNumber = 1; + private long pid_; + /// + /// 稿件avid/漫画epid + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public long Pid { + get { return pid_; } + set { + pid_ = value; + } + } + + /// Field number for the "oid" field. + public const int OidFieldNumber = 2; + private long oid_; + /// + /// 视频cid/漫画cid + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public long Oid { + get { return oid_; } + set { + oid_ = value; + } + } + + /// Field number for the "type" field. + public const int TypeFieldNumber = 3; + private int type_; + /// + /// 弹幕类型 + /// 1:视频 2:漫画 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int Type { + get { return type_; } + set { + type_ = value; + } + } + + /// Field number for the "segment_index" field. + public const int SegmentIndexFieldNumber = 4; + private long segmentIndex_; + /// + /// 分段(6min) + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public long SegmentIndex { + get { return segmentIndex_; } + set { + segmentIndex_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as DmSegSDKReq); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(DmSegSDKReq other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Pid != other.Pid) return false; + if (Oid != other.Oid) return false; + if (Type != other.Type) return false; + if (SegmentIndex != other.SegmentIndex) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override int GetHashCode() { + int hash = 1; + if (Pid != 0L) hash ^= Pid.GetHashCode(); + if (Oid != 0L) hash ^= Oid.GetHashCode(); + if (Type != 0) hash ^= Type.GetHashCode(); + if (SegmentIndex != 0L) hash ^= SegmentIndex.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void WriteTo(pb::CodedOutputStream output) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + output.WriteRawMessage(this); + #else + if (Pid != 0L) { + output.WriteRawTag(8); + output.WriteInt64(Pid); + } + if (Oid != 0L) { + output.WriteRawTag(16); + output.WriteInt64(Oid); + } + if (Type != 0) { + output.WriteRawTag(24); + output.WriteInt32(Type); + } + if (SegmentIndex != 0L) { + output.WriteRawTag(32); + output.WriteInt64(SegmentIndex); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + if (Pid != 0L) { + output.WriteRawTag(8); + output.WriteInt64(Pid); + } + if (Oid != 0L) { + output.WriteRawTag(16); + output.WriteInt64(Oid); + } + if (Type != 0) { + output.WriteRawTag(24); + output.WriteInt32(Type); + } + if (SegmentIndex != 0L) { + output.WriteRawTag(32); + output.WriteInt64(SegmentIndex); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(ref output); + } + } + #endif + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int CalculateSize() { + int size = 0; + if (Pid != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(Pid); + } + if (Oid != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(Oid); + } + if (Type != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Type); + } + if (SegmentIndex != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(SegmentIndex); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(DmSegSDKReq other) { + if (other == null) { + return; + } + if (other.Pid != 0L) { + Pid = other.Pid; + } + if (other.Oid != 0L) { + Oid = other.Oid; + } + if (other.Type != 0) { + Type = other.Type; + } + if (other.SegmentIndex != 0L) { + SegmentIndex = other.SegmentIndex; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(pb::CodedInputStream input) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + input.ReadRawMessage(this); + #else + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Pid = input.ReadInt64(); + break; + } + case 16: { + Oid = input.ReadInt64(); + break; + } + case 24: { + Type = input.ReadInt32(); + break; + } + case 32: { + SegmentIndex = input.ReadInt64(); + break; + } + } + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 8: { + Pid = input.ReadInt64(); + break; + } + case 16: { + Oid = input.ReadInt64(); + break; + } + case 24: { + Type = input.ReadInt32(); + break; + } + case 32: { + SegmentIndex = input.ReadInt64(); + break; + } + } + } + } + #endif + + } + + /// + /// 弹幕SDK-响应 + /// + public sealed partial class DmSegSDKReply : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new DmSegSDKReply()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pbr::MessageDescriptor Descriptor { + get { return global::Bilibili.Community.Service.Dm.V1.DmReflection.Descriptor.MessageTypes[1]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public DmSegSDKReply() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public DmSegSDKReply(DmSegSDKReply other) : this() { + closed_ = other.closed_; + elems_ = other.elems_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public DmSegSDKReply Clone() { + return new DmSegSDKReply(this); + } + + /// Field number for the "closed" field. + public const int ClosedFieldNumber = 1; + private bool closed_; + /// + /// 是否已关闭弹幕 + /// 0:未关闭 1:已关闭 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Closed { + get { return closed_; } + set { + closed_ = value; + } + } + + /// Field number for the "elems" field. + public const int ElemsFieldNumber = 2; + private static readonly pb::FieldCodec _repeated_elems_codec + = pb::FieldCodec.ForMessage(18, global::Bilibili.Community.Service.Dm.V1.DanmakuElem.Parser); + private readonly pbc::RepeatedField elems_ = new pbc::RepeatedField(); + /// + /// 弹幕列表 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public pbc::RepeatedField Elems { + get { return elems_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as DmSegSDKReply); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(DmSegSDKReply other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Closed != other.Closed) return false; + if(!elems_.Equals(other.elems_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override int GetHashCode() { + int hash = 1; + if (Closed != false) hash ^= Closed.GetHashCode(); + hash ^= elems_.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void WriteTo(pb::CodedOutputStream output) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + output.WriteRawMessage(this); + #else + if (Closed != false) { + output.WriteRawTag(8); + output.WriteBool(Closed); + } + elems_.WriteTo(output, _repeated_elems_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + if (Closed != false) { + output.WriteRawTag(8); + output.WriteBool(Closed); + } + elems_.WriteTo(ref output, _repeated_elems_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(ref output); + } + } + #endif + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int CalculateSize() { + int size = 0; + if (Closed != false) { + size += 1 + 1; + } + size += elems_.CalculateSize(_repeated_elems_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(DmSegSDKReply other) { + if (other == null) { + return; + } + if (other.Closed != false) { + Closed = other.Closed; + } + elems_.Add(other.elems_); + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(pb::CodedInputStream input) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + input.ReadRawMessage(this); + #else + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Closed = input.ReadBool(); + break; + } + case 18: { + elems_.AddEntriesFrom(input, _repeated_elems_codec); + break; + } + } + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 8: { + Closed = input.ReadBool(); + break; + } + case 18: { + elems_.AddEntriesFrom(ref input, _repeated_elems_codec); + break; + } + } + } + } + #endif + + } + + /// + /// ott弹幕列表-请求 + /// + public sealed partial class DmSegOttReq : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new DmSegOttReq()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pbr::MessageDescriptor Descriptor { + get { return global::Bilibili.Community.Service.Dm.V1.DmReflection.Descriptor.MessageTypes[2]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public DmSegOttReq() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public DmSegOttReq(DmSegOttReq other) : this() { + pid_ = other.pid_; + oid_ = other.oid_; + type_ = other.type_; + segmentIndex_ = other.segmentIndex_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public DmSegOttReq Clone() { + return new DmSegOttReq(this); + } + + /// Field number for the "pid" field. + public const int PidFieldNumber = 1; + private long pid_; + /// + /// 稿件avid/漫画epid + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public long Pid { + get { return pid_; } + set { + pid_ = value; + } + } + + /// Field number for the "oid" field. + public const int OidFieldNumber = 2; + private long oid_; + /// + /// 视频cid/漫画cid + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public long Oid { + get { return oid_; } + set { + oid_ = value; + } + } + + /// Field number for the "type" field. + public const int TypeFieldNumber = 3; + private int type_; + /// + /// 弹幕类型 + /// 1:视频 2:漫画 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int Type { + get { return type_; } + set { + type_ = value; + } + } + + /// Field number for the "segment_index" field. + public const int SegmentIndexFieldNumber = 4; + private long segmentIndex_; + /// + /// 分段(6min) + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public long SegmentIndex { + get { return segmentIndex_; } + set { + segmentIndex_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as DmSegOttReq); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(DmSegOttReq other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Pid != other.Pid) return false; + if (Oid != other.Oid) return false; + if (Type != other.Type) return false; + if (SegmentIndex != other.SegmentIndex) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override int GetHashCode() { + int hash = 1; + if (Pid != 0L) hash ^= Pid.GetHashCode(); + if (Oid != 0L) hash ^= Oid.GetHashCode(); + if (Type != 0) hash ^= Type.GetHashCode(); + if (SegmentIndex != 0L) hash ^= SegmentIndex.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void WriteTo(pb::CodedOutputStream output) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + output.WriteRawMessage(this); + #else + if (Pid != 0L) { + output.WriteRawTag(8); + output.WriteInt64(Pid); + } + if (Oid != 0L) { + output.WriteRawTag(16); + output.WriteInt64(Oid); + } + if (Type != 0) { + output.WriteRawTag(24); + output.WriteInt32(Type); + } + if (SegmentIndex != 0L) { + output.WriteRawTag(32); + output.WriteInt64(SegmentIndex); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + if (Pid != 0L) { + output.WriteRawTag(8); + output.WriteInt64(Pid); + } + if (Oid != 0L) { + output.WriteRawTag(16); + output.WriteInt64(Oid); + } + if (Type != 0) { + output.WriteRawTag(24); + output.WriteInt32(Type); + } + if (SegmentIndex != 0L) { + output.WriteRawTag(32); + output.WriteInt64(SegmentIndex); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(ref output); + } + } + #endif + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int CalculateSize() { + int size = 0; + if (Pid != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(Pid); + } + if (Oid != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(Oid); + } + if (Type != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Type); + } + if (SegmentIndex != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(SegmentIndex); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(DmSegOttReq other) { + if (other == null) { + return; + } + if (other.Pid != 0L) { + Pid = other.Pid; + } + if (other.Oid != 0L) { + Oid = other.Oid; + } + if (other.Type != 0) { + Type = other.Type; + } + if (other.SegmentIndex != 0L) { + SegmentIndex = other.SegmentIndex; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(pb::CodedInputStream input) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + input.ReadRawMessage(this); + #else + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Pid = input.ReadInt64(); + break; + } + case 16: { + Oid = input.ReadInt64(); + break; + } + case 24: { + Type = input.ReadInt32(); + break; + } + case 32: { + SegmentIndex = input.ReadInt64(); + break; + } + } + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 8: { + Pid = input.ReadInt64(); + break; + } + case 16: { + Oid = input.ReadInt64(); + break; + } + case 24: { + Type = input.ReadInt32(); + break; + } + case 32: { + SegmentIndex = input.ReadInt64(); + break; + } + } + } + } + #endif + + } + + /// + /// ott弹幕列表-响应 + /// + public sealed partial class DmSegOttReply : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new DmSegOttReply()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pbr::MessageDescriptor Descriptor { + get { return global::Bilibili.Community.Service.Dm.V1.DmReflection.Descriptor.MessageTypes[3]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public DmSegOttReply() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public DmSegOttReply(DmSegOttReply other) : this() { + closed_ = other.closed_; + elems_ = other.elems_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public DmSegOttReply Clone() { + return new DmSegOttReply(this); + } + + /// Field number for the "closed" field. + public const int ClosedFieldNumber = 1; + private bool closed_; + /// + /// 是否已关闭弹幕 + /// 0:未关闭 1:已关闭 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Closed { + get { return closed_; } + set { + closed_ = value; + } + } + + /// Field number for the "elems" field. + public const int ElemsFieldNumber = 2; + private static readonly pb::FieldCodec _repeated_elems_codec + = pb::FieldCodec.ForMessage(18, global::Bilibili.Community.Service.Dm.V1.DanmakuElem.Parser); + private readonly pbc::RepeatedField elems_ = new pbc::RepeatedField(); + /// + /// 弹幕列表 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public pbc::RepeatedField Elems { + get { return elems_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as DmSegOttReply); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(DmSegOttReply other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Closed != other.Closed) return false; + if(!elems_.Equals(other.elems_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override int GetHashCode() { + int hash = 1; + if (Closed != false) hash ^= Closed.GetHashCode(); + hash ^= elems_.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void WriteTo(pb::CodedOutputStream output) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + output.WriteRawMessage(this); + #else + if (Closed != false) { + output.WriteRawTag(8); + output.WriteBool(Closed); + } + elems_.WriteTo(output, _repeated_elems_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + if (Closed != false) { + output.WriteRawTag(8); + output.WriteBool(Closed); + } + elems_.WriteTo(ref output, _repeated_elems_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(ref output); + } + } + #endif + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int CalculateSize() { + int size = 0; + if (Closed != false) { + size += 1 + 1; + } + size += elems_.CalculateSize(_repeated_elems_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(DmSegOttReply other) { + if (other == null) { + return; + } + if (other.Closed != false) { + Closed = other.Closed; + } + elems_.Add(other.elems_); + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(pb::CodedInputStream input) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + input.ReadRawMessage(this); + #else + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Closed = input.ReadBool(); + break; + } + case 18: { + elems_.AddEntriesFrom(input, _repeated_elems_codec); + break; + } + } + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 8: { + Closed = input.ReadBool(); + break; + } + case 18: { + elems_.AddEntriesFrom(ref input, _repeated_elems_codec); + break; + } + } + } + } + #endif + + } + + /// + /// 获取弹幕-请求 + /// + public sealed partial class DmSegMobileReq : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new DmSegMobileReq()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pbr::MessageDescriptor Descriptor { + get { return global::Bilibili.Community.Service.Dm.V1.DmReflection.Descriptor.MessageTypes[4]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public DmSegMobileReq() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public DmSegMobileReq(DmSegMobileReq other) : this() { + pid_ = other.pid_; + oid_ = other.oid_; + type_ = other.type_; + segmentIndex_ = other.segmentIndex_; + teenagersMode_ = other.teenagersMode_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public DmSegMobileReq Clone() { + return new DmSegMobileReq(this); + } + + /// Field number for the "pid" field. + public const int PidFieldNumber = 1; + private long pid_; + /// + /// 稿件avid/漫画epid + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public long Pid { + get { return pid_; } + set { + pid_ = value; + } + } + + /// Field number for the "oid" field. + public const int OidFieldNumber = 2; + private long oid_; + /// + /// 视频cid/漫画cid + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public long Oid { + get { return oid_; } + set { + oid_ = value; + } + } + + /// Field number for the "type" field. + public const int TypeFieldNumber = 3; + private int type_; + /// + /// 弹幕类型 + /// 1:视频 2:漫画 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int Type { + get { return type_; } + set { + type_ = value; + } + } + + /// Field number for the "segment_index" field. + public const int SegmentIndexFieldNumber = 4; + private long segmentIndex_; + /// + /// 分段(6min) + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public long SegmentIndex { + get { return segmentIndex_; } + set { + segmentIndex_ = value; + } + } + + /// Field number for the "teenagers_mode" field. + public const int TeenagersModeFieldNumber = 5; + private int teenagersMode_; + /// + /// 是否青少年模式 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int TeenagersMode { + get { return teenagersMode_; } + set { + teenagersMode_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as DmSegMobileReq); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(DmSegMobileReq other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Pid != other.Pid) return false; + if (Oid != other.Oid) return false; + if (Type != other.Type) return false; + if (SegmentIndex != other.SegmentIndex) return false; + if (TeenagersMode != other.TeenagersMode) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override int GetHashCode() { + int hash = 1; + if (Pid != 0L) hash ^= Pid.GetHashCode(); + if (Oid != 0L) hash ^= Oid.GetHashCode(); + if (Type != 0) hash ^= Type.GetHashCode(); + if (SegmentIndex != 0L) hash ^= SegmentIndex.GetHashCode(); + if (TeenagersMode != 0) hash ^= TeenagersMode.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void WriteTo(pb::CodedOutputStream output) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + output.WriteRawMessage(this); + #else + if (Pid != 0L) { + output.WriteRawTag(8); + output.WriteInt64(Pid); + } + if (Oid != 0L) { + output.WriteRawTag(16); + output.WriteInt64(Oid); + } + if (Type != 0) { + output.WriteRawTag(24); + output.WriteInt32(Type); + } + if (SegmentIndex != 0L) { + output.WriteRawTag(32); + output.WriteInt64(SegmentIndex); + } + if (TeenagersMode != 0) { + output.WriteRawTag(40); + output.WriteInt32(TeenagersMode); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + if (Pid != 0L) { + output.WriteRawTag(8); + output.WriteInt64(Pid); + } + if (Oid != 0L) { + output.WriteRawTag(16); + output.WriteInt64(Oid); + } + if (Type != 0) { + output.WriteRawTag(24); + output.WriteInt32(Type); + } + if (SegmentIndex != 0L) { + output.WriteRawTag(32); + output.WriteInt64(SegmentIndex); + } + if (TeenagersMode != 0) { + output.WriteRawTag(40); + output.WriteInt32(TeenagersMode); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(ref output); + } + } + #endif + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int CalculateSize() { + int size = 0; + if (Pid != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(Pid); + } + if (Oid != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(Oid); + } + if (Type != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Type); + } + if (SegmentIndex != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(SegmentIndex); + } + if (TeenagersMode != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(TeenagersMode); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(DmSegMobileReq other) { + if (other == null) { + return; + } + if (other.Pid != 0L) { + Pid = other.Pid; + } + if (other.Oid != 0L) { + Oid = other.Oid; + } + if (other.Type != 0) { + Type = other.Type; + } + if (other.SegmentIndex != 0L) { + SegmentIndex = other.SegmentIndex; + } + if (other.TeenagersMode != 0) { + TeenagersMode = other.TeenagersMode; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(pb::CodedInputStream input) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + input.ReadRawMessage(this); + #else + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Pid = input.ReadInt64(); + break; + } + case 16: { + Oid = input.ReadInt64(); + break; + } + case 24: { + Type = input.ReadInt32(); + break; + } + case 32: { + SegmentIndex = input.ReadInt64(); + break; + } + case 40: { + TeenagersMode = input.ReadInt32(); + break; + } + } + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 8: { + Pid = input.ReadInt64(); + break; + } + case 16: { + Oid = input.ReadInt64(); + break; + } + case 24: { + Type = input.ReadInt32(); + break; + } + case 32: { + SegmentIndex = input.ReadInt64(); + break; + } + case 40: { + TeenagersMode = input.ReadInt32(); + break; + } + } + } + } + #endif + + } + + /// + /// 获取弹幕-响应 + /// + public sealed partial class DmSegMobileReply : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new DmSegMobileReply()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pbr::MessageDescriptor Descriptor { + get { return global::Bilibili.Community.Service.Dm.V1.DmReflection.Descriptor.MessageTypes[5]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public DmSegMobileReply() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public DmSegMobileReply(DmSegMobileReply other) : this() { + elems_ = other.elems_.Clone(); + state_ = other.state_; + aiFlag_ = other.aiFlag_ != null ? other.aiFlag_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public DmSegMobileReply Clone() { + return new DmSegMobileReply(this); + } + + /// Field number for the "elems" field. + public const int ElemsFieldNumber = 1; + private static readonly pb::FieldCodec _repeated_elems_codec + = pb::FieldCodec.ForMessage(10, global::Bilibili.Community.Service.Dm.V1.DanmakuElem.Parser); + private readonly pbc::RepeatedField elems_ = new pbc::RepeatedField(); + /// + /// 弹幕列表 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public pbc::RepeatedField Elems { + get { return elems_; } + } + + /// Field number for the "state" field. + public const int StateFieldNumber = 2; + private int state_; + /// + /// 是否已关闭弹幕 + /// 0:未关闭 1:已关闭 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int State { + get { return state_; } + set { + state_ = value; + } + } + + /// Field number for the "ai_flag" field. + public const int AiFlagFieldNumber = 3; + private global::Bilibili.Community.Service.Dm.V1.DanmakuAIFlag aiFlag_; + /// + /// 弹幕云屏蔽ai评分值 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public global::Bilibili.Community.Service.Dm.V1.DanmakuAIFlag AiFlag { + get { return aiFlag_; } + set { + aiFlag_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as DmSegMobileReply); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(DmSegMobileReply other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if(!elems_.Equals(other.elems_)) return false; + if (State != other.State) return false; + if (!object.Equals(AiFlag, other.AiFlag)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override int GetHashCode() { + int hash = 1; + hash ^= elems_.GetHashCode(); + if (State != 0) hash ^= State.GetHashCode(); + if (aiFlag_ != null) hash ^= AiFlag.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void WriteTo(pb::CodedOutputStream output) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + output.WriteRawMessage(this); + #else + elems_.WriteTo(output, _repeated_elems_codec); + if (State != 0) { + output.WriteRawTag(16); + output.WriteInt32(State); + } + if (aiFlag_ != null) { + output.WriteRawTag(26); + output.WriteMessage(AiFlag); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + elems_.WriteTo(ref output, _repeated_elems_codec); + if (State != 0) { + output.WriteRawTag(16); + output.WriteInt32(State); + } + if (aiFlag_ != null) { + output.WriteRawTag(26); + output.WriteMessage(AiFlag); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(ref output); + } + } + #endif + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int CalculateSize() { + int size = 0; + size += elems_.CalculateSize(_repeated_elems_codec); + if (State != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(State); + } + if (aiFlag_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(AiFlag); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(DmSegMobileReply other) { + if (other == null) { + return; + } + elems_.Add(other.elems_); + if (other.State != 0) { + State = other.State; + } + if (other.aiFlag_ != null) { + if (aiFlag_ == null) { + AiFlag = new global::Bilibili.Community.Service.Dm.V1.DanmakuAIFlag(); + } + AiFlag.MergeFrom(other.AiFlag); + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(pb::CodedInputStream input) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + input.ReadRawMessage(this); + #else + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + elems_.AddEntriesFrom(input, _repeated_elems_codec); + break; + } + case 16: { + State = input.ReadInt32(); + break; + } + case 26: { + if (aiFlag_ == null) { + AiFlag = new global::Bilibili.Community.Service.Dm.V1.DanmakuAIFlag(); + } + input.ReadMessage(AiFlag); + break; + } + } + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 10: { + elems_.AddEntriesFrom(ref input, _repeated_elems_codec); + break; + } + case 16: { + State = input.ReadInt32(); + break; + } + case 26: { + if (aiFlag_ == null) { + AiFlag = new global::Bilibili.Community.Service.Dm.V1.DanmakuAIFlag(); + } + input.ReadMessage(AiFlag); + break; + } + } + } + } + #endif + + } + + /// + /// 客户端弹幕元数据-请求 + /// + public sealed partial class DmViewReq : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new DmViewReq()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pbr::MessageDescriptor Descriptor { + get { return global::Bilibili.Community.Service.Dm.V1.DmReflection.Descriptor.MessageTypes[6]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public DmViewReq() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public DmViewReq(DmViewReq other) : this() { + pid_ = other.pid_; + oid_ = other.oid_; + type_ = other.type_; + spmid_ = other.spmid_; + isHardBoot_ = other.isHardBoot_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public DmViewReq Clone() { + return new DmViewReq(this); + } + + /// Field number for the "pid" field. + public const int PidFieldNumber = 1; + private long pid_; + /// + /// 稿件avid/漫画epid + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public long Pid { + get { return pid_; } + set { + pid_ = value; + } + } + + /// Field number for the "oid" field. + public const int OidFieldNumber = 2; + private long oid_; + /// + /// 视频cid/漫画cid + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public long Oid { + get { return oid_; } + set { + oid_ = value; + } + } + + /// Field number for the "type" field. + public const int TypeFieldNumber = 3; + private int type_; + /// + /// 弹幕类型 + /// 1:视频 2:漫画 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int Type { + get { return type_; } + set { + type_ = value; + } + } + + /// Field number for the "spmid" field. + public const int SpmidFieldNumber = 4; + private string spmid_ = ""; + /// + /// 页面spm + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public string Spmid { + get { return spmid_; } + set { + spmid_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "is_hard_boot" field. + public const int IsHardBootFieldNumber = 5; + private int isHardBoot_; + /// + /// 是否冷启 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int IsHardBoot { + get { return isHardBoot_; } + set { + isHardBoot_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as DmViewReq); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(DmViewReq other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Pid != other.Pid) return false; + if (Oid != other.Oid) return false; + if (Type != other.Type) return false; + if (Spmid != other.Spmid) return false; + if (IsHardBoot != other.IsHardBoot) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override int GetHashCode() { + int hash = 1; + if (Pid != 0L) hash ^= Pid.GetHashCode(); + if (Oid != 0L) hash ^= Oid.GetHashCode(); + if (Type != 0) hash ^= Type.GetHashCode(); + if (Spmid.Length != 0) hash ^= Spmid.GetHashCode(); + if (IsHardBoot != 0) hash ^= IsHardBoot.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void WriteTo(pb::CodedOutputStream output) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + output.WriteRawMessage(this); + #else + if (Pid != 0L) { + output.WriteRawTag(8); + output.WriteInt64(Pid); + } + if (Oid != 0L) { + output.WriteRawTag(16); + output.WriteInt64(Oid); + } + if (Type != 0) { + output.WriteRawTag(24); + output.WriteInt32(Type); + } + if (Spmid.Length != 0) { + output.WriteRawTag(34); + output.WriteString(Spmid); + } + if (IsHardBoot != 0) { + output.WriteRawTag(40); + output.WriteInt32(IsHardBoot); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + if (Pid != 0L) { + output.WriteRawTag(8); + output.WriteInt64(Pid); + } + if (Oid != 0L) { + output.WriteRawTag(16); + output.WriteInt64(Oid); + } + if (Type != 0) { + output.WriteRawTag(24); + output.WriteInt32(Type); + } + if (Spmid.Length != 0) { + output.WriteRawTag(34); + output.WriteString(Spmid); + } + if (IsHardBoot != 0) { + output.WriteRawTag(40); + output.WriteInt32(IsHardBoot); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(ref output); + } + } + #endif + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int CalculateSize() { + int size = 0; + if (Pid != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(Pid); + } + if (Oid != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(Oid); + } + if (Type != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Type); + } + if (Spmid.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Spmid); + } + if (IsHardBoot != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(IsHardBoot); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(DmViewReq other) { + if (other == null) { + return; + } + if (other.Pid != 0L) { + Pid = other.Pid; + } + if (other.Oid != 0L) { + Oid = other.Oid; + } + if (other.Type != 0) { + Type = other.Type; + } + if (other.Spmid.Length != 0) { + Spmid = other.Spmid; + } + if (other.IsHardBoot != 0) { + IsHardBoot = other.IsHardBoot; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(pb::CodedInputStream input) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + input.ReadRawMessage(this); + #else + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Pid = input.ReadInt64(); + break; + } + case 16: { + Oid = input.ReadInt64(); + break; + } + case 24: { + Type = input.ReadInt32(); + break; + } + case 34: { + Spmid = input.ReadString(); + break; + } + case 40: { + IsHardBoot = input.ReadInt32(); + break; + } + } + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 8: { + Pid = input.ReadInt64(); + break; + } + case 16: { + Oid = input.ReadInt64(); + break; + } + case 24: { + Type = input.ReadInt32(); + break; + } + case 34: { + Spmid = input.ReadString(); + break; + } + case 40: { + IsHardBoot = input.ReadInt32(); + break; + } + } + } + } + #endif + + } + + /// + /// 客户端弹幕元数据-响应 + /// + public sealed partial class DmViewReply : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new DmViewReply()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pbr::MessageDescriptor Descriptor { + get { return global::Bilibili.Community.Service.Dm.V1.DmReflection.Descriptor.MessageTypes[7]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public DmViewReply() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public DmViewReply(DmViewReply other) : this() { + closed_ = other.closed_; + mask_ = other.mask_ != null ? other.mask_.Clone() : null; + subtitle_ = other.subtitle_ != null ? other.subtitle_.Clone() : null; + specialDms_ = other.specialDms_.Clone(); + aiFlag_ = other.aiFlag_ != null ? other.aiFlag_.Clone() : null; + playerConfig_ = other.playerConfig_ != null ? other.playerConfig_.Clone() : null; + sendBoxStyle_ = other.sendBoxStyle_; + allow_ = other.allow_; + checkBox_ = other.checkBox_; + checkBoxShowMsg_ = other.checkBoxShowMsg_; + textPlaceholder_ = other.textPlaceholder_; + inputPlaceholder_ = other.inputPlaceholder_; + reportFilterContent_ = other.reportFilterContent_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public DmViewReply Clone() { + return new DmViewReply(this); + } + + /// Field number for the "closed" field. + public const int ClosedFieldNumber = 1; + private bool closed_; + /// + /// 是否已关闭弹幕 + /// 0:未关闭 1:已关闭 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Closed { + get { return closed_; } + set { + closed_ = value; + } + } + + /// Field number for the "mask" field. + public const int MaskFieldNumber = 2; + private global::Bilibili.Community.Service.Dm.V1.VideoMask mask_; + /// + /// 智能防挡弹幕蒙版信息 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public global::Bilibili.Community.Service.Dm.V1.VideoMask Mask { + get { return mask_; } + set { + mask_ = value; + } + } + + /// Field number for the "subtitle" field. + public const int SubtitleFieldNumber = 3; + private global::Bilibili.Community.Service.Dm.V1.VideoSubtitle subtitle_; + /// + /// 视频字幕 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public global::Bilibili.Community.Service.Dm.V1.VideoSubtitle Subtitle { + get { return subtitle_; } + set { + subtitle_ = value; + } + } + + /// Field number for the "special_dms" field. + public const int SpecialDmsFieldNumber = 4; + private static readonly pb::FieldCodec _repeated_specialDms_codec + = pb::FieldCodec.ForString(34); + private readonly pbc::RepeatedField specialDms_ = new pbc::RepeatedField(); + /// + /// 高级弹幕专包url(bfs) + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public pbc::RepeatedField SpecialDms { + get { return specialDms_; } + } + + /// Field number for the "ai_flag" field. + public const int AiFlagFieldNumber = 5; + private global::Bilibili.Community.Service.Dm.V1.DanmakuFlagConfig aiFlag_; + /// + /// 云屏蔽配置信息 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public global::Bilibili.Community.Service.Dm.V1.DanmakuFlagConfig AiFlag { + get { return aiFlag_; } + set { + aiFlag_ = value; + } + } + + /// Field number for the "player_config" field. + public const int PlayerConfigFieldNumber = 6; + private global::Bilibili.Community.Service.Dm.V1.DanmuPlayerViewConfig playerConfig_; + /// + /// 弹幕配置信息 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public global::Bilibili.Community.Service.Dm.V1.DanmuPlayerViewConfig PlayerConfig { + get { return playerConfig_; } + set { + playerConfig_ = value; + } + } + + /// Field number for the "send_box_style" field. + public const int SendBoxStyleFieldNumber = 7; + private int sendBoxStyle_; + /// + /// 弹幕发送框样式 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int SendBoxStyle { + get { return sendBoxStyle_; } + set { + sendBoxStyle_ = value; + } + } + + /// Field number for the "allow" field. + public const int AllowFieldNumber = 8; + private bool allow_; + /// + /// 是否允许 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Allow { + get { return allow_; } + set { + allow_ = value; + } + } + + /// Field number for the "check_box" field. + public const int CheckBoxFieldNumber = 9; + private string checkBox_ = ""; + /// + /// check box 是否展示 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public string CheckBox { + get { return checkBox_; } + set { + checkBox_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "check_box_show_msg" field. + public const int CheckBoxShowMsgFieldNumber = 10; + private string checkBoxShowMsg_ = ""; + /// + /// check box 展示文本 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public string CheckBoxShowMsg { + get { return checkBoxShowMsg_; } + set { + checkBoxShowMsg_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "text_placeholder" field. + public const int TextPlaceholderFieldNumber = 11; + private string textPlaceholder_ = ""; + /// + /// 展示文案 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public string TextPlaceholder { + get { return textPlaceholder_; } + set { + textPlaceholder_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "input_placeholder" field. + public const int InputPlaceholderFieldNumber = 12; + private string inputPlaceholder_ = ""; + /// + /// 弹幕输入框文案 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public string InputPlaceholder { + get { return inputPlaceholder_; } + set { + inputPlaceholder_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "report_filter_content" field. + public const int ReportFilterContentFieldNumber = 13; + private static readonly pb::FieldCodec _repeated_reportFilterContent_codec + = pb::FieldCodec.ForString(106); + private readonly pbc::RepeatedField reportFilterContent_ = new pbc::RepeatedField(); + /// + /// 用户举报弹幕 cid维度屏蔽的正则规则 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public pbc::RepeatedField ReportFilterContent { + get { return reportFilterContent_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as DmViewReply); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(DmViewReply other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Closed != other.Closed) return false; + if (!object.Equals(Mask, other.Mask)) return false; + if (!object.Equals(Subtitle, other.Subtitle)) return false; + if(!specialDms_.Equals(other.specialDms_)) return false; + if (!object.Equals(AiFlag, other.AiFlag)) return false; + if (!object.Equals(PlayerConfig, other.PlayerConfig)) return false; + if (SendBoxStyle != other.SendBoxStyle) return false; + if (Allow != other.Allow) return false; + if (CheckBox != other.CheckBox) return false; + if (CheckBoxShowMsg != other.CheckBoxShowMsg) return false; + if (TextPlaceholder != other.TextPlaceholder) return false; + if (InputPlaceholder != other.InputPlaceholder) return false; + if(!reportFilterContent_.Equals(other.reportFilterContent_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override int GetHashCode() { + int hash = 1; + if (Closed != false) hash ^= Closed.GetHashCode(); + if (mask_ != null) hash ^= Mask.GetHashCode(); + if (subtitle_ != null) hash ^= Subtitle.GetHashCode(); + hash ^= specialDms_.GetHashCode(); + if (aiFlag_ != null) hash ^= AiFlag.GetHashCode(); + if (playerConfig_ != null) hash ^= PlayerConfig.GetHashCode(); + if (SendBoxStyle != 0) hash ^= SendBoxStyle.GetHashCode(); + if (Allow != false) hash ^= Allow.GetHashCode(); + if (CheckBox.Length != 0) hash ^= CheckBox.GetHashCode(); + if (CheckBoxShowMsg.Length != 0) hash ^= CheckBoxShowMsg.GetHashCode(); + if (TextPlaceholder.Length != 0) hash ^= TextPlaceholder.GetHashCode(); + if (InputPlaceholder.Length != 0) hash ^= InputPlaceholder.GetHashCode(); + hash ^= reportFilterContent_.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void WriteTo(pb::CodedOutputStream output) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + output.WriteRawMessage(this); + #else + if (Closed != false) { + output.WriteRawTag(8); + output.WriteBool(Closed); + } + if (mask_ != null) { + output.WriteRawTag(18); + output.WriteMessage(Mask); + } + if (subtitle_ != null) { + output.WriteRawTag(26); + output.WriteMessage(Subtitle); + } + specialDms_.WriteTo(output, _repeated_specialDms_codec); + if (aiFlag_ != null) { + output.WriteRawTag(42); + output.WriteMessage(AiFlag); + } + if (playerConfig_ != null) { + output.WriteRawTag(50); + output.WriteMessage(PlayerConfig); + } + if (SendBoxStyle != 0) { + output.WriteRawTag(56); + output.WriteInt32(SendBoxStyle); + } + if (Allow != false) { + output.WriteRawTag(64); + output.WriteBool(Allow); + } + if (CheckBox.Length != 0) { + output.WriteRawTag(74); + output.WriteString(CheckBox); + } + if (CheckBoxShowMsg.Length != 0) { + output.WriteRawTag(82); + output.WriteString(CheckBoxShowMsg); + } + if (TextPlaceholder.Length != 0) { + output.WriteRawTag(90); + output.WriteString(TextPlaceholder); + } + if (InputPlaceholder.Length != 0) { + output.WriteRawTag(98); + output.WriteString(InputPlaceholder); + } + reportFilterContent_.WriteTo(output, _repeated_reportFilterContent_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + if (Closed != false) { + output.WriteRawTag(8); + output.WriteBool(Closed); + } + if (mask_ != null) { + output.WriteRawTag(18); + output.WriteMessage(Mask); + } + if (subtitle_ != null) { + output.WriteRawTag(26); + output.WriteMessage(Subtitle); + } + specialDms_.WriteTo(ref output, _repeated_specialDms_codec); + if (aiFlag_ != null) { + output.WriteRawTag(42); + output.WriteMessage(AiFlag); + } + if (playerConfig_ != null) { + output.WriteRawTag(50); + output.WriteMessage(PlayerConfig); + } + if (SendBoxStyle != 0) { + output.WriteRawTag(56); + output.WriteInt32(SendBoxStyle); + } + if (Allow != false) { + output.WriteRawTag(64); + output.WriteBool(Allow); + } + if (CheckBox.Length != 0) { + output.WriteRawTag(74); + output.WriteString(CheckBox); + } + if (CheckBoxShowMsg.Length != 0) { + output.WriteRawTag(82); + output.WriteString(CheckBoxShowMsg); + } + if (TextPlaceholder.Length != 0) { + output.WriteRawTag(90); + output.WriteString(TextPlaceholder); + } + if (InputPlaceholder.Length != 0) { + output.WriteRawTag(98); + output.WriteString(InputPlaceholder); + } + reportFilterContent_.WriteTo(ref output, _repeated_reportFilterContent_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(ref output); + } + } + #endif + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int CalculateSize() { + int size = 0; + if (Closed != false) { + size += 1 + 1; + } + if (mask_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Mask); + } + if (subtitle_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Subtitle); + } + size += specialDms_.CalculateSize(_repeated_specialDms_codec); + if (aiFlag_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(AiFlag); + } + if (playerConfig_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(PlayerConfig); + } + if (SendBoxStyle != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(SendBoxStyle); + } + if (Allow != false) { + size += 1 + 1; + } + if (CheckBox.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(CheckBox); + } + if (CheckBoxShowMsg.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(CheckBoxShowMsg); + } + if (TextPlaceholder.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(TextPlaceholder); + } + if (InputPlaceholder.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(InputPlaceholder); + } + size += reportFilterContent_.CalculateSize(_repeated_reportFilterContent_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(DmViewReply other) { + if (other == null) { + return; + } + if (other.Closed != false) { + Closed = other.Closed; + } + if (other.mask_ != null) { + if (mask_ == null) { + Mask = new global::Bilibili.Community.Service.Dm.V1.VideoMask(); + } + Mask.MergeFrom(other.Mask); + } + if (other.subtitle_ != null) { + if (subtitle_ == null) { + Subtitle = new global::Bilibili.Community.Service.Dm.V1.VideoSubtitle(); + } + Subtitle.MergeFrom(other.Subtitle); + } + specialDms_.Add(other.specialDms_); + if (other.aiFlag_ != null) { + if (aiFlag_ == null) { + AiFlag = new global::Bilibili.Community.Service.Dm.V1.DanmakuFlagConfig(); + } + AiFlag.MergeFrom(other.AiFlag); + } + if (other.playerConfig_ != null) { + if (playerConfig_ == null) { + PlayerConfig = new global::Bilibili.Community.Service.Dm.V1.DanmuPlayerViewConfig(); + } + PlayerConfig.MergeFrom(other.PlayerConfig); + } + if (other.SendBoxStyle != 0) { + SendBoxStyle = other.SendBoxStyle; + } + if (other.Allow != false) { + Allow = other.Allow; + } + if (other.CheckBox.Length != 0) { + CheckBox = other.CheckBox; + } + if (other.CheckBoxShowMsg.Length != 0) { + CheckBoxShowMsg = other.CheckBoxShowMsg; + } + if (other.TextPlaceholder.Length != 0) { + TextPlaceholder = other.TextPlaceholder; + } + if (other.InputPlaceholder.Length != 0) { + InputPlaceholder = other.InputPlaceholder; + } + reportFilterContent_.Add(other.reportFilterContent_); + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(pb::CodedInputStream input) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + input.ReadRawMessage(this); + #else + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Closed = input.ReadBool(); + break; + } + case 18: { + if (mask_ == null) { + Mask = new global::Bilibili.Community.Service.Dm.V1.VideoMask(); + } + input.ReadMessage(Mask); + break; + } + case 26: { + if (subtitle_ == null) { + Subtitle = new global::Bilibili.Community.Service.Dm.V1.VideoSubtitle(); + } + input.ReadMessage(Subtitle); + break; + } + case 34: { + specialDms_.AddEntriesFrom(input, _repeated_specialDms_codec); + break; + } + case 42: { + if (aiFlag_ == null) { + AiFlag = new global::Bilibili.Community.Service.Dm.V1.DanmakuFlagConfig(); + } + input.ReadMessage(AiFlag); + break; + } + case 50: { + if (playerConfig_ == null) { + PlayerConfig = new global::Bilibili.Community.Service.Dm.V1.DanmuPlayerViewConfig(); + } + input.ReadMessage(PlayerConfig); + break; + } + case 56: { + SendBoxStyle = input.ReadInt32(); + break; + } + case 64: { + Allow = input.ReadBool(); + break; + } + case 74: { + CheckBox = input.ReadString(); + break; + } + case 82: { + CheckBoxShowMsg = input.ReadString(); + break; + } + case 90: { + TextPlaceholder = input.ReadString(); + break; + } + case 98: { + InputPlaceholder = input.ReadString(); + break; + } + case 106: { + reportFilterContent_.AddEntriesFrom(input, _repeated_reportFilterContent_codec); + break; + } + } + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 8: { + Closed = input.ReadBool(); + break; + } + case 18: { + if (mask_ == null) { + Mask = new global::Bilibili.Community.Service.Dm.V1.VideoMask(); + } + input.ReadMessage(Mask); + break; + } + case 26: { + if (subtitle_ == null) { + Subtitle = new global::Bilibili.Community.Service.Dm.V1.VideoSubtitle(); + } + input.ReadMessage(Subtitle); + break; + } + case 34: { + specialDms_.AddEntriesFrom(ref input, _repeated_specialDms_codec); + break; + } + case 42: { + if (aiFlag_ == null) { + AiFlag = new global::Bilibili.Community.Service.Dm.V1.DanmakuFlagConfig(); + } + input.ReadMessage(AiFlag); + break; + } + case 50: { + if (playerConfig_ == null) { + PlayerConfig = new global::Bilibili.Community.Service.Dm.V1.DanmuPlayerViewConfig(); + } + input.ReadMessage(PlayerConfig); + break; + } + case 56: { + SendBoxStyle = input.ReadInt32(); + break; + } + case 64: { + Allow = input.ReadBool(); + break; + } + case 74: { + CheckBox = input.ReadString(); + break; + } + case 82: { + CheckBoxShowMsg = input.ReadString(); + break; + } + case 90: { + TextPlaceholder = input.ReadString(); + break; + } + case 98: { + InputPlaceholder = input.ReadString(); + break; + } + case 106: { + reportFilterContent_.AddEntriesFrom(ref input, _repeated_reportFilterContent_codec); + break; + } + } + } + } + #endif + + } + + /// + /// web端弹幕元数据-响应 + /// + public sealed partial class DmWebViewReply : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new DmWebViewReply()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pbr::MessageDescriptor Descriptor { + get { return global::Bilibili.Community.Service.Dm.V1.DmReflection.Descriptor.MessageTypes[8]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public DmWebViewReply() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public DmWebViewReply(DmWebViewReply other) : this() { + state_ = other.state_; + text_ = other.text_; + textSide_ = other.textSide_; + dmSge_ = other.dmSge_ != null ? other.dmSge_.Clone() : null; + flag_ = other.flag_ != null ? other.flag_.Clone() : null; + specialDms_ = other.specialDms_.Clone(); + checkBox_ = other.checkBox_; + count_ = other.count_; + commandDms_ = other.commandDms_.Clone(); + playerConfig_ = other.playerConfig_ != null ? other.playerConfig_.Clone() : null; + reportFilterContent_ = other.reportFilterContent_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public DmWebViewReply Clone() { + return new DmWebViewReply(this); + } + + /// Field number for the "state" field. + public const int StateFieldNumber = 1; + private int state_; + /// + /// 是否已关闭弹幕 + /// 0:未关闭 1:已关闭 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int State { + get { return state_; } + set { + state_ = value; + } + } + + /// Field number for the "text" field. + public const int TextFieldNumber = 2; + private string text_ = ""; + /// + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public string Text { + get { return text_; } + set { + text_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "text_side" field. + public const int TextSideFieldNumber = 3; + private string textSide_ = ""; + /// + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public string TextSide { + get { return textSide_; } + set { + textSide_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "dm_sge" field. + public const int DmSgeFieldNumber = 4; + private global::Bilibili.Community.Service.Dm.V1.DmSegConfig dmSge_; + /// + /// 分段弹幕配置 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public global::Bilibili.Community.Service.Dm.V1.DmSegConfig DmSge { + get { return dmSge_; } + set { + dmSge_ = value; + } + } + + /// Field number for the "flag" field. + public const int FlagFieldNumber = 5; + private global::Bilibili.Community.Service.Dm.V1.DanmakuFlagConfig flag_; + /// + /// 云屏蔽配置信息 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public global::Bilibili.Community.Service.Dm.V1.DanmakuFlagConfig Flag { + get { return flag_; } + set { + flag_ = value; + } + } + + /// Field number for the "special_dms" field. + public const int SpecialDmsFieldNumber = 6; + private static readonly pb::FieldCodec _repeated_specialDms_codec + = pb::FieldCodec.ForString(50); + private readonly pbc::RepeatedField specialDms_ = new pbc::RepeatedField(); + /// + /// 高级弹幕专包url(bfs) + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public pbc::RepeatedField SpecialDms { + get { return specialDms_; } + } + + /// Field number for the "check_box" field. + public const int CheckBoxFieldNumber = 7; + private bool checkBox_; + /// + /// check box 是否展示 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool CheckBox { + get { return checkBox_; } + set { + checkBox_ = value; + } + } + + /// Field number for the "count" field. + public const int CountFieldNumber = 8; + private long count_; + /// + /// 弹幕数 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public long Count { + get { return count_; } + set { + count_ = value; + } + } + + /// Field number for the "commandDms" field. + public const int CommandDmsFieldNumber = 9; + private static readonly pb::FieldCodec _repeated_commandDms_codec + = pb::FieldCodec.ForMessage(74, global::Bilibili.Community.Service.Dm.V1.CommandDm.Parser); + private readonly pbc::RepeatedField commandDms_ = new pbc::RepeatedField(); + /// + /// 互动弹幕 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public pbc::RepeatedField CommandDms { + get { return commandDms_; } + } + + /// Field number for the "player_config" field. + public const int PlayerConfigFieldNumber = 10; + private global::Bilibili.Community.Service.Dm.V1.DanmuWebPlayerConfig playerConfig_; + /// + /// 用户弹幕配置 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public global::Bilibili.Community.Service.Dm.V1.DanmuWebPlayerConfig PlayerConfig { + get { return playerConfig_; } + set { + playerConfig_ = value; + } + } + + /// Field number for the "report_filter_content" field. + public const int ReportFilterContentFieldNumber = 11; + private static readonly pb::FieldCodec _repeated_reportFilterContent_codec + = pb::FieldCodec.ForString(90); + private readonly pbc::RepeatedField reportFilterContent_ = new pbc::RepeatedField(); + /// + /// 用户举报弹幕 cid维度屏蔽 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public pbc::RepeatedField ReportFilterContent { + get { return reportFilterContent_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as DmWebViewReply); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(DmWebViewReply other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (State != other.State) return false; + if (Text != other.Text) return false; + if (TextSide != other.TextSide) return false; + if (!object.Equals(DmSge, other.DmSge)) return false; + if (!object.Equals(Flag, other.Flag)) return false; + if(!specialDms_.Equals(other.specialDms_)) return false; + if (CheckBox != other.CheckBox) return false; + if (Count != other.Count) return false; + if(!commandDms_.Equals(other.commandDms_)) return false; + if (!object.Equals(PlayerConfig, other.PlayerConfig)) return false; + if(!reportFilterContent_.Equals(other.reportFilterContent_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override int GetHashCode() { + int hash = 1; + if (State != 0) hash ^= State.GetHashCode(); + if (Text.Length != 0) hash ^= Text.GetHashCode(); + if (TextSide.Length != 0) hash ^= TextSide.GetHashCode(); + if (dmSge_ != null) hash ^= DmSge.GetHashCode(); + if (flag_ != null) hash ^= Flag.GetHashCode(); + hash ^= specialDms_.GetHashCode(); + if (CheckBox != false) hash ^= CheckBox.GetHashCode(); + if (Count != 0L) hash ^= Count.GetHashCode(); + hash ^= commandDms_.GetHashCode(); + if (playerConfig_ != null) hash ^= PlayerConfig.GetHashCode(); + hash ^= reportFilterContent_.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void WriteTo(pb::CodedOutputStream output) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + output.WriteRawMessage(this); + #else + if (State != 0) { + output.WriteRawTag(8); + output.WriteInt32(State); + } + if (Text.Length != 0) { + output.WriteRawTag(18); + output.WriteString(Text); + } + if (TextSide.Length != 0) { + output.WriteRawTag(26); + output.WriteString(TextSide); + } + if (dmSge_ != null) { + output.WriteRawTag(34); + output.WriteMessage(DmSge); + } + if (flag_ != null) { + output.WriteRawTag(42); + output.WriteMessage(Flag); + } + specialDms_.WriteTo(output, _repeated_specialDms_codec); + if (CheckBox != false) { + output.WriteRawTag(56); + output.WriteBool(CheckBox); + } + if (Count != 0L) { + output.WriteRawTag(64); + output.WriteInt64(Count); + } + commandDms_.WriteTo(output, _repeated_commandDms_codec); + if (playerConfig_ != null) { + output.WriteRawTag(82); + output.WriteMessage(PlayerConfig); + } + reportFilterContent_.WriteTo(output, _repeated_reportFilterContent_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + if (State != 0) { + output.WriteRawTag(8); + output.WriteInt32(State); + } + if (Text.Length != 0) { + output.WriteRawTag(18); + output.WriteString(Text); + } + if (TextSide.Length != 0) { + output.WriteRawTag(26); + output.WriteString(TextSide); + } + if (dmSge_ != null) { + output.WriteRawTag(34); + output.WriteMessage(DmSge); + } + if (flag_ != null) { + output.WriteRawTag(42); + output.WriteMessage(Flag); + } + specialDms_.WriteTo(ref output, _repeated_specialDms_codec); + if (CheckBox != false) { + output.WriteRawTag(56); + output.WriteBool(CheckBox); + } + if (Count != 0L) { + output.WriteRawTag(64); + output.WriteInt64(Count); + } + commandDms_.WriteTo(ref output, _repeated_commandDms_codec); + if (playerConfig_ != null) { + output.WriteRawTag(82); + output.WriteMessage(PlayerConfig); + } + reportFilterContent_.WriteTo(ref output, _repeated_reportFilterContent_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(ref output); + } + } + #endif + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int CalculateSize() { + int size = 0; + if (State != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(State); + } + if (Text.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Text); + } + if (TextSide.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(TextSide); + } + if (dmSge_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(DmSge); + } + if (flag_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Flag); + } + size += specialDms_.CalculateSize(_repeated_specialDms_codec); + if (CheckBox != false) { + size += 1 + 1; + } + if (Count != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(Count); + } + size += commandDms_.CalculateSize(_repeated_commandDms_codec); + if (playerConfig_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(PlayerConfig); + } + size += reportFilterContent_.CalculateSize(_repeated_reportFilterContent_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(DmWebViewReply other) { + if (other == null) { + return; + } + if (other.State != 0) { + State = other.State; + } + if (other.Text.Length != 0) { + Text = other.Text; + } + if (other.TextSide.Length != 0) { + TextSide = other.TextSide; + } + if (other.dmSge_ != null) { + if (dmSge_ == null) { + DmSge = new global::Bilibili.Community.Service.Dm.V1.DmSegConfig(); + } + DmSge.MergeFrom(other.DmSge); + } + if (other.flag_ != null) { + if (flag_ == null) { + Flag = new global::Bilibili.Community.Service.Dm.V1.DanmakuFlagConfig(); + } + Flag.MergeFrom(other.Flag); + } + specialDms_.Add(other.specialDms_); + if (other.CheckBox != false) { + CheckBox = other.CheckBox; + } + if (other.Count != 0L) { + Count = other.Count; + } + commandDms_.Add(other.commandDms_); + if (other.playerConfig_ != null) { + if (playerConfig_ == null) { + PlayerConfig = new global::Bilibili.Community.Service.Dm.V1.DanmuWebPlayerConfig(); + } + PlayerConfig.MergeFrom(other.PlayerConfig); + } + reportFilterContent_.Add(other.reportFilterContent_); + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(pb::CodedInputStream input) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + input.ReadRawMessage(this); + #else + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + State = input.ReadInt32(); + break; + } + case 18: { + Text = input.ReadString(); + break; + } + case 26: { + TextSide = input.ReadString(); + break; + } + case 34: { + if (dmSge_ == null) { + DmSge = new global::Bilibili.Community.Service.Dm.V1.DmSegConfig(); + } + input.ReadMessage(DmSge); + break; + } + case 42: { + if (flag_ == null) { + Flag = new global::Bilibili.Community.Service.Dm.V1.DanmakuFlagConfig(); + } + input.ReadMessage(Flag); + break; + } + case 50: { + specialDms_.AddEntriesFrom(input, _repeated_specialDms_codec); + break; + } + case 56: { + CheckBox = input.ReadBool(); + break; + } + case 64: { + Count = input.ReadInt64(); + break; + } + case 74: { + commandDms_.AddEntriesFrom(input, _repeated_commandDms_codec); + break; + } + case 82: { + if (playerConfig_ == null) { + PlayerConfig = new global::Bilibili.Community.Service.Dm.V1.DanmuWebPlayerConfig(); + } + input.ReadMessage(PlayerConfig); + break; + } + case 90: { + reportFilterContent_.AddEntriesFrom(input, _repeated_reportFilterContent_codec); + break; + } + } + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 8: { + State = input.ReadInt32(); + break; + } + case 18: { + Text = input.ReadString(); + break; + } + case 26: { + TextSide = input.ReadString(); + break; + } + case 34: { + if (dmSge_ == null) { + DmSge = new global::Bilibili.Community.Service.Dm.V1.DmSegConfig(); + } + input.ReadMessage(DmSge); + break; + } + case 42: { + if (flag_ == null) { + Flag = new global::Bilibili.Community.Service.Dm.V1.DanmakuFlagConfig(); + } + input.ReadMessage(Flag); + break; + } + case 50: { + specialDms_.AddEntriesFrom(ref input, _repeated_specialDms_codec); + break; + } + case 56: { + CheckBox = input.ReadBool(); + break; + } + case 64: { + Count = input.ReadInt64(); + break; + } + case 74: { + commandDms_.AddEntriesFrom(ref input, _repeated_commandDms_codec); + break; + } + case 82: { + if (playerConfig_ == null) { + PlayerConfig = new global::Bilibili.Community.Service.Dm.V1.DanmuWebPlayerConfig(); + } + input.ReadMessage(PlayerConfig); + break; + } + case 90: { + reportFilterContent_.AddEntriesFrom(ref input, _repeated_reportFilterContent_codec); + break; + } + } + } + } + #endif + + } + + /// + /// 互动弹幕条目信息 + /// + public sealed partial class CommandDm : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new CommandDm()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pbr::MessageDescriptor Descriptor { + get { return global::Bilibili.Community.Service.Dm.V1.DmReflection.Descriptor.MessageTypes[9]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public CommandDm() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public CommandDm(CommandDm other) : this() { + id_ = other.id_; + oid_ = other.oid_; + mid_ = other.mid_; + command_ = other.command_; + content_ = other.content_; + progress_ = other.progress_; + ctime_ = other.ctime_; + mtime_ = other.mtime_; + extra_ = other.extra_; + idStr_ = other.idStr_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public CommandDm Clone() { + return new CommandDm(this); + } + + /// Field number for the "id" field. + public const int IdFieldNumber = 1; + private long id_; + /// + /// 弹幕id + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public long Id { + get { return id_; } + set { + id_ = value; + } + } + + /// Field number for the "oid" field. + public const int OidFieldNumber = 2; + private long oid_; + /// + /// 对象视频cid + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public long Oid { + get { return oid_; } + set { + oid_ = value; + } + } + + /// Field number for the "mid" field. + public const int MidFieldNumber = 3; + private string mid_ = ""; + /// + /// 发送者mid + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public string Mid { + get { return mid_; } + set { + mid_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "command" field. + public const int CommandFieldNumber = 4; + private string command_ = ""; + /// + /// 互动弹幕指令 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public string Command { + get { return command_; } + set { + command_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "content" field. + public const int ContentFieldNumber = 5; + private string content_ = ""; + /// + /// 互动弹幕正文 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public string Content { + get { return content_; } + set { + content_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "progress" field. + public const int ProgressFieldNumber = 6; + private int progress_; + /// + /// 出现时间 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int Progress { + get { return progress_; } + set { + progress_ = value; + } + } + + /// Field number for the "ctime" field. + public const int CtimeFieldNumber = 7; + private string ctime_ = ""; + /// + /// 创建时间 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public string Ctime { + get { return ctime_; } + set { + ctime_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "mtime" field. + public const int MtimeFieldNumber = 8; + private string mtime_ = ""; + /// + /// 发布时间 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public string Mtime { + get { return mtime_; } + set { + mtime_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "extra" field. + public const int ExtraFieldNumber = 9; + private string extra_ = ""; + /// + /// 扩展json数据 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public string Extra { + get { return extra_; } + set { + extra_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "idStr" field. + public const int IdStrFieldNumber = 10; + private string idStr_ = ""; + /// + /// 弹幕id str类型 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public string IdStr { + get { return idStr_; } + set { + idStr_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as CommandDm); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(CommandDm other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Id != other.Id) return false; + if (Oid != other.Oid) return false; + if (Mid != other.Mid) return false; + if (Command != other.Command) return false; + if (Content != other.Content) return false; + if (Progress != other.Progress) return false; + if (Ctime != other.Ctime) return false; + if (Mtime != other.Mtime) return false; + if (Extra != other.Extra) return false; + if (IdStr != other.IdStr) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override int GetHashCode() { + int hash = 1; + if (Id != 0L) hash ^= Id.GetHashCode(); + if (Oid != 0L) hash ^= Oid.GetHashCode(); + if (Mid.Length != 0) hash ^= Mid.GetHashCode(); + if (Command.Length != 0) hash ^= Command.GetHashCode(); + if (Content.Length != 0) hash ^= Content.GetHashCode(); + if (Progress != 0) hash ^= Progress.GetHashCode(); + if (Ctime.Length != 0) hash ^= Ctime.GetHashCode(); + if (Mtime.Length != 0) hash ^= Mtime.GetHashCode(); + if (Extra.Length != 0) hash ^= Extra.GetHashCode(); + if (IdStr.Length != 0) hash ^= IdStr.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void WriteTo(pb::CodedOutputStream output) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + output.WriteRawMessage(this); + #else + if (Id != 0L) { + output.WriteRawTag(8); + output.WriteInt64(Id); + } + if (Oid != 0L) { + output.WriteRawTag(16); + output.WriteInt64(Oid); + } + if (Mid.Length != 0) { + output.WriteRawTag(26); + output.WriteString(Mid); + } + if (Command.Length != 0) { + output.WriteRawTag(34); + output.WriteString(Command); + } + if (Content.Length != 0) { + output.WriteRawTag(42); + output.WriteString(Content); + } + if (Progress != 0) { + output.WriteRawTag(48); + output.WriteInt32(Progress); + } + if (Ctime.Length != 0) { + output.WriteRawTag(58); + output.WriteString(Ctime); + } + if (Mtime.Length != 0) { + output.WriteRawTag(66); + output.WriteString(Mtime); + } + if (Extra.Length != 0) { + output.WriteRawTag(74); + output.WriteString(Extra); + } + if (IdStr.Length != 0) { + output.WriteRawTag(82); + output.WriteString(IdStr); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + if (Id != 0L) { + output.WriteRawTag(8); + output.WriteInt64(Id); + } + if (Oid != 0L) { + output.WriteRawTag(16); + output.WriteInt64(Oid); + } + if (Mid.Length != 0) { + output.WriteRawTag(26); + output.WriteString(Mid); + } + if (Command.Length != 0) { + output.WriteRawTag(34); + output.WriteString(Command); + } + if (Content.Length != 0) { + output.WriteRawTag(42); + output.WriteString(Content); + } + if (Progress != 0) { + output.WriteRawTag(48); + output.WriteInt32(Progress); + } + if (Ctime.Length != 0) { + output.WriteRawTag(58); + output.WriteString(Ctime); + } + if (Mtime.Length != 0) { + output.WriteRawTag(66); + output.WriteString(Mtime); + } + if (Extra.Length != 0) { + output.WriteRawTag(74); + output.WriteString(Extra); + } + if (IdStr.Length != 0) { + output.WriteRawTag(82); + output.WriteString(IdStr); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(ref output); + } + } + #endif + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int CalculateSize() { + int size = 0; + if (Id != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(Id); + } + if (Oid != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(Oid); + } + if (Mid.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Mid); + } + if (Command.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Command); + } + if (Content.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Content); + } + if (Progress != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Progress); + } + if (Ctime.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Ctime); + } + if (Mtime.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Mtime); + } + if (Extra.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Extra); + } + if (IdStr.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(IdStr); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(CommandDm other) { + if (other == null) { + return; + } + if (other.Id != 0L) { + Id = other.Id; + } + if (other.Oid != 0L) { + Oid = other.Oid; + } + if (other.Mid.Length != 0) { + Mid = other.Mid; + } + if (other.Command.Length != 0) { + Command = other.Command; + } + if (other.Content.Length != 0) { + Content = other.Content; + } + if (other.Progress != 0) { + Progress = other.Progress; + } + if (other.Ctime.Length != 0) { + Ctime = other.Ctime; + } + if (other.Mtime.Length != 0) { + Mtime = other.Mtime; + } + if (other.Extra.Length != 0) { + Extra = other.Extra; + } + if (other.IdStr.Length != 0) { + IdStr = other.IdStr; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(pb::CodedInputStream input) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + input.ReadRawMessage(this); + #else + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Id = input.ReadInt64(); + break; + } + case 16: { + Oid = input.ReadInt64(); + break; + } + case 26: { + Mid = input.ReadString(); + break; + } + case 34: { + Command = input.ReadString(); + break; + } + case 42: { + Content = input.ReadString(); + break; + } + case 48: { + Progress = input.ReadInt32(); + break; + } + case 58: { + Ctime = input.ReadString(); + break; + } + case 66: { + Mtime = input.ReadString(); + break; + } + case 74: { + Extra = input.ReadString(); + break; + } + case 82: { + IdStr = input.ReadString(); + break; + } + } + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 8: { + Id = input.ReadInt64(); + break; + } + case 16: { + Oid = input.ReadInt64(); + break; + } + case 26: { + Mid = input.ReadString(); + break; + } + case 34: { + Command = input.ReadString(); + break; + } + case 42: { + Content = input.ReadString(); + break; + } + case 48: { + Progress = input.ReadInt32(); + break; + } + case 58: { + Ctime = input.ReadString(); + break; + } + case 66: { + Mtime = input.ReadString(); + break; + } + case 74: { + Extra = input.ReadString(); + break; + } + case 82: { + IdStr = input.ReadString(); + break; + } + } + } + } + #endif + + } + + /// + /// + public sealed partial class DmSegConfig : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new DmSegConfig()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pbr::MessageDescriptor Descriptor { + get { return global::Bilibili.Community.Service.Dm.V1.DmReflection.Descriptor.MessageTypes[10]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public DmSegConfig() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public DmSegConfig(DmSegConfig other) : this() { + pageSize_ = other.pageSize_; + total_ = other.total_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public DmSegConfig Clone() { + return new DmSegConfig(this); + } + + /// Field number for the "page_size" field. + public const int PageSizeFieldNumber = 1; + private long pageSize_; + /// + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public long PageSize { + get { return pageSize_; } + set { + pageSize_ = value; + } + } + + /// Field number for the "total" field. + public const int TotalFieldNumber = 2; + private long total_; + /// + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public long Total { + get { return total_; } + set { + total_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as DmSegConfig); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(DmSegConfig other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (PageSize != other.PageSize) return false; + if (Total != other.Total) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override int GetHashCode() { + int hash = 1; + if (PageSize != 0L) hash ^= PageSize.GetHashCode(); + if (Total != 0L) hash ^= Total.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void WriteTo(pb::CodedOutputStream output) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + output.WriteRawMessage(this); + #else + if (PageSize != 0L) { + output.WriteRawTag(8); + output.WriteInt64(PageSize); + } + if (Total != 0L) { + output.WriteRawTag(16); + output.WriteInt64(Total); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + if (PageSize != 0L) { + output.WriteRawTag(8); + output.WriteInt64(PageSize); + } + if (Total != 0L) { + output.WriteRawTag(16); + output.WriteInt64(Total); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(ref output); + } + } + #endif + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int CalculateSize() { + int size = 0; + if (PageSize != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(PageSize); + } + if (Total != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(Total); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(DmSegConfig other) { + if (other == null) { + return; + } + if (other.PageSize != 0L) { + PageSize = other.PageSize; + } + if (other.Total != 0L) { + Total = other.Total; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(pb::CodedInputStream input) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + input.ReadRawMessage(this); + #else + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + PageSize = input.ReadInt64(); + break; + } + case 16: { + Total = input.ReadInt64(); + break; + } + } + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 8: { + PageSize = input.ReadInt64(); + break; + } + case 16: { + Total = input.ReadInt64(); + break; + } + } + } + } + #endif + + } + + /// + /// 智能防挡弹幕蒙版信息 + /// + public sealed partial class VideoMask : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new VideoMask()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pbr::MessageDescriptor Descriptor { + get { return global::Bilibili.Community.Service.Dm.V1.DmReflection.Descriptor.MessageTypes[11]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public VideoMask() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public VideoMask(VideoMask other) : this() { + cid_ = other.cid_; + plat_ = other.plat_; + fps_ = other.fps_; + time_ = other.time_; + maskUrl_ = other.maskUrl_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public VideoMask Clone() { + return new VideoMask(this); + } + + /// Field number for the "cid" field. + public const int CidFieldNumber = 1; + private long cid_; + /// + /// 视频cid + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public long Cid { + get { return cid_; } + set { + cid_ = value; + } + } + + /// Field number for the "plat" field. + public const int PlatFieldNumber = 2; + private int plat_; + /// + /// 平台 + /// 0:web端 1:客户端 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int Plat { + get { return plat_; } + set { + plat_ = value; + } + } + + /// Field number for the "fps" field. + public const int FpsFieldNumber = 3; + private int fps_; + /// + /// 帧率 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int Fps { + get { return fps_; } + set { + fps_ = value; + } + } + + /// Field number for the "time" field. + public const int TimeFieldNumber = 4; + private long time_; + /// + /// 间隔时间 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public long Time { + get { return time_; } + set { + time_ = value; + } + } + + /// Field number for the "mask_url" field. + public const int MaskUrlFieldNumber = 5; + private string maskUrl_ = ""; + /// + /// 蒙版url + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public string MaskUrl { + get { return maskUrl_; } + set { + maskUrl_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as VideoMask); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(VideoMask other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Cid != other.Cid) return false; + if (Plat != other.Plat) return false; + if (Fps != other.Fps) return false; + if (Time != other.Time) return false; + if (MaskUrl != other.MaskUrl) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override int GetHashCode() { + int hash = 1; + if (Cid != 0L) hash ^= Cid.GetHashCode(); + if (Plat != 0) hash ^= Plat.GetHashCode(); + if (Fps != 0) hash ^= Fps.GetHashCode(); + if (Time != 0L) hash ^= Time.GetHashCode(); + if (MaskUrl.Length != 0) hash ^= MaskUrl.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void WriteTo(pb::CodedOutputStream output) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + output.WriteRawMessage(this); + #else + if (Cid != 0L) { + output.WriteRawTag(8); + output.WriteInt64(Cid); + } + if (Plat != 0) { + output.WriteRawTag(16); + output.WriteInt32(Plat); + } + if (Fps != 0) { + output.WriteRawTag(24); + output.WriteInt32(Fps); + } + if (Time != 0L) { + output.WriteRawTag(32); + output.WriteInt64(Time); + } + if (MaskUrl.Length != 0) { + output.WriteRawTag(42); + output.WriteString(MaskUrl); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + if (Cid != 0L) { + output.WriteRawTag(8); + output.WriteInt64(Cid); + } + if (Plat != 0) { + output.WriteRawTag(16); + output.WriteInt32(Plat); + } + if (Fps != 0) { + output.WriteRawTag(24); + output.WriteInt32(Fps); + } + if (Time != 0L) { + output.WriteRawTag(32); + output.WriteInt64(Time); + } + if (MaskUrl.Length != 0) { + output.WriteRawTag(42); + output.WriteString(MaskUrl); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(ref output); + } + } + #endif + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int CalculateSize() { + int size = 0; + if (Cid != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(Cid); + } + if (Plat != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Plat); + } + if (Fps != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Fps); + } + if (Time != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(Time); + } + if (MaskUrl.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(MaskUrl); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(VideoMask other) { + if (other == null) { + return; + } + if (other.Cid != 0L) { + Cid = other.Cid; + } + if (other.Plat != 0) { + Plat = other.Plat; + } + if (other.Fps != 0) { + Fps = other.Fps; + } + if (other.Time != 0L) { + Time = other.Time; + } + if (other.MaskUrl.Length != 0) { + MaskUrl = other.MaskUrl; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(pb::CodedInputStream input) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + input.ReadRawMessage(this); + #else + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Cid = input.ReadInt64(); + break; + } + case 16: { + Plat = input.ReadInt32(); + break; + } + case 24: { + Fps = input.ReadInt32(); + break; + } + case 32: { + Time = input.ReadInt64(); + break; + } + case 42: { + MaskUrl = input.ReadString(); + break; + } + } + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 8: { + Cid = input.ReadInt64(); + break; + } + case 16: { + Plat = input.ReadInt32(); + break; + } + case 24: { + Fps = input.ReadInt32(); + break; + } + case 32: { + Time = input.ReadInt64(); + break; + } + case 42: { + MaskUrl = input.ReadString(); + break; + } + } + } + } + #endif + + } + + /// + /// 视频字幕信息 + /// + public sealed partial class VideoSubtitle : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new VideoSubtitle()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pbr::MessageDescriptor Descriptor { + get { return global::Bilibili.Community.Service.Dm.V1.DmReflection.Descriptor.MessageTypes[12]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public VideoSubtitle() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public VideoSubtitle(VideoSubtitle other) : this() { + lan_ = other.lan_; + lanDoc_ = other.lanDoc_; + subtitles_ = other.subtitles_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public VideoSubtitle Clone() { + return new VideoSubtitle(this); + } + + /// Field number for the "lan" field. + public const int LanFieldNumber = 1; + private string lan_ = ""; + /// + /// 视频原语言代码 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public string Lan { + get { return lan_; } + set { + lan_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "lanDoc" field. + public const int LanDocFieldNumber = 2; + private string lanDoc_ = ""; + /// + /// 视频原语言 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public string LanDoc { + get { return lanDoc_; } + set { + lanDoc_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "subtitles" field. + public const int SubtitlesFieldNumber = 3; + private static readonly pb::FieldCodec _repeated_subtitles_codec + = pb::FieldCodec.ForMessage(26, global::Bilibili.Community.Service.Dm.V1.SubtitleItem.Parser); + private readonly pbc::RepeatedField subtitles_ = new pbc::RepeatedField(); + /// + /// 视频字幕列表 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public pbc::RepeatedField Subtitles { + get { return subtitles_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as VideoSubtitle); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(VideoSubtitle other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Lan != other.Lan) return false; + if (LanDoc != other.LanDoc) return false; + if(!subtitles_.Equals(other.subtitles_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override int GetHashCode() { + int hash = 1; + if (Lan.Length != 0) hash ^= Lan.GetHashCode(); + if (LanDoc.Length != 0) hash ^= LanDoc.GetHashCode(); + hash ^= subtitles_.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void WriteTo(pb::CodedOutputStream output) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + output.WriteRawMessage(this); + #else + if (Lan.Length != 0) { + output.WriteRawTag(10); + output.WriteString(Lan); + } + if (LanDoc.Length != 0) { + output.WriteRawTag(18); + output.WriteString(LanDoc); + } + subtitles_.WriteTo(output, _repeated_subtitles_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + if (Lan.Length != 0) { + output.WriteRawTag(10); + output.WriteString(Lan); + } + if (LanDoc.Length != 0) { + output.WriteRawTag(18); + output.WriteString(LanDoc); + } + subtitles_.WriteTo(ref output, _repeated_subtitles_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(ref output); + } + } + #endif + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int CalculateSize() { + int size = 0; + if (Lan.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Lan); + } + if (LanDoc.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(LanDoc); + } + size += subtitles_.CalculateSize(_repeated_subtitles_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(VideoSubtitle other) { + if (other == null) { + return; + } + if (other.Lan.Length != 0) { + Lan = other.Lan; + } + if (other.LanDoc.Length != 0) { + LanDoc = other.LanDoc; + } + subtitles_.Add(other.subtitles_); + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(pb::CodedInputStream input) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + input.ReadRawMessage(this); + #else + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + Lan = input.ReadString(); + break; + } + case 18: { + LanDoc = input.ReadString(); + break; + } + case 26: { + subtitles_.AddEntriesFrom(input, _repeated_subtitles_codec); + break; + } + } + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 10: { + Lan = input.ReadString(); + break; + } + case 18: { + LanDoc = input.ReadString(); + break; + } + case 26: { + subtitles_.AddEntriesFrom(ref input, _repeated_subtitles_codec); + break; + } + } + } + } + #endif + + } + + /// + /// web端用户弹幕配置 + /// + public sealed partial class DanmuWebPlayerConfig : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new DanmuWebPlayerConfig()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pbr::MessageDescriptor Descriptor { + get { return global::Bilibili.Community.Service.Dm.V1.DmReflection.Descriptor.MessageTypes[13]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public DanmuWebPlayerConfig() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public DanmuWebPlayerConfig(DanmuWebPlayerConfig other) : this() { + dmSwitch_ = other.dmSwitch_; + aiSwitch_ = other.aiSwitch_; + aiLevel_ = other.aiLevel_; + blocktop_ = other.blocktop_; + blockscroll_ = other.blockscroll_; + blockbottom_ = other.blockbottom_; + blockcolor_ = other.blockcolor_; + blockspecial_ = other.blockspecial_; + preventshade_ = other.preventshade_; + dmask_ = other.dmask_; + opacity_ = other.opacity_; + dmarea_ = other.dmarea_; + speedplus_ = other.speedplus_; + fontsize_ = other.fontsize_; + screensync_ = other.screensync_; + speedsync_ = other.speedsync_; + fontfamily_ = other.fontfamily_; + bold_ = other.bold_; + fontborder_ = other.fontborder_; + drawType_ = other.drawType_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public DanmuWebPlayerConfig Clone() { + return new DanmuWebPlayerConfig(this); + } + + /// Field number for the "dm_switch" field. + public const int DmSwitchFieldNumber = 1; + private bool dmSwitch_; + /// + /// 是否开启弹幕 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool DmSwitch { + get { return dmSwitch_; } + set { + dmSwitch_ = value; + } + } + + /// Field number for the "ai_switch" field. + public const int AiSwitchFieldNumber = 2; + private bool aiSwitch_; + /// + /// 是否开启智能云屏蔽 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool AiSwitch { + get { return aiSwitch_; } + set { + aiSwitch_ = value; + } + } + + /// Field number for the "ai_level" field. + public const int AiLevelFieldNumber = 3; + private int aiLevel_; + /// + /// 智能云屏蔽等级 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int AiLevel { + get { return aiLevel_; } + set { + aiLevel_ = value; + } + } + + /// Field number for the "blocktop" field. + public const int BlocktopFieldNumber = 4; + private bool blocktop_; + /// + /// 是否屏蔽顶端弹幕 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Blocktop { + get { return blocktop_; } + set { + blocktop_ = value; + } + } + + /// Field number for the "blockscroll" field. + public const int BlockscrollFieldNumber = 5; + private bool blockscroll_; + /// + /// 是否屏蔽滚动弹幕 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Blockscroll { + get { return blockscroll_; } + set { + blockscroll_ = value; + } + } + + /// Field number for the "blockbottom" field. + public const int BlockbottomFieldNumber = 6; + private bool blockbottom_; + /// + /// 是否屏蔽底端弹幕 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Blockbottom { + get { return blockbottom_; } + set { + blockbottom_ = value; + } + } + + /// Field number for the "blockcolor" field. + public const int BlockcolorFieldNumber = 7; + private bool blockcolor_; + /// + /// 是否屏蔽彩色弹幕 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Blockcolor { + get { return blockcolor_; } + set { + blockcolor_ = value; + } + } + + /// Field number for the "blockspecial" field. + public const int BlockspecialFieldNumber = 8; + private bool blockspecial_; + /// + /// 是否屏蔽重复弹幕 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Blockspecial { + get { return blockspecial_; } + set { + blockspecial_ = value; + } + } + + /// Field number for the "preventshade" field. + public const int PreventshadeFieldNumber = 9; + private bool preventshade_; + /// + /// + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Preventshade { + get { return preventshade_; } + set { + preventshade_ = value; + } + } + + /// Field number for the "dmask" field. + public const int DmaskFieldNumber = 10; + private bool dmask_; + /// + /// + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Dmask { + get { return dmask_; } + set { + dmask_ = value; + } + } + + /// Field number for the "opacity" field. + public const int OpacityFieldNumber = 11; + private float opacity_; + /// + /// + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public float Opacity { + get { return opacity_; } + set { + opacity_ = value; + } + } + + /// Field number for the "dmarea" field. + public const int DmareaFieldNumber = 12; + private int dmarea_; + /// + /// + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int Dmarea { + get { return dmarea_; } + set { + dmarea_ = value; + } + } + + /// Field number for the "speedplus" field. + public const int SpeedplusFieldNumber = 13; + private float speedplus_; + /// + /// + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public float Speedplus { + get { return speedplus_; } + set { + speedplus_ = value; + } + } + + /// Field number for the "fontsize" field. + public const int FontsizeFieldNumber = 14; + private float fontsize_; + /// + /// 弹幕字号 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public float Fontsize { + get { return fontsize_; } + set { + fontsize_ = value; + } + } + + /// Field number for the "screensync" field. + public const int ScreensyncFieldNumber = 15; + private bool screensync_; + /// + /// + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Screensync { + get { return screensync_; } + set { + screensync_ = value; + } + } + + /// Field number for the "speedsync" field. + public const int SpeedsyncFieldNumber = 16; + private bool speedsync_; + /// + /// + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Speedsync { + get { return speedsync_; } + set { + speedsync_ = value; + } + } + + /// Field number for the "fontfamily" field. + public const int FontfamilyFieldNumber = 17; + private string fontfamily_ = ""; + /// + /// + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public string Fontfamily { + get { return fontfamily_; } + set { + fontfamily_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "bold" field. + public const int BoldFieldNumber = 18; + private bool bold_; + /// + /// 是否使用加粗 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Bold { + get { return bold_; } + set { + bold_ = value; + } + } + + /// Field number for the "fontborder" field. + public const int FontborderFieldNumber = 19; + private int fontborder_; + /// + /// + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int Fontborder { + get { return fontborder_; } + set { + fontborder_ = value; + } + } + + /// Field number for the "draw_type" field. + public const int DrawTypeFieldNumber = 20; + private string drawType_ = ""; + /// + /// 弹幕渲染类型 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public string DrawType { + get { return drawType_; } + set { + drawType_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as DanmuWebPlayerConfig); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(DanmuWebPlayerConfig other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (DmSwitch != other.DmSwitch) return false; + if (AiSwitch != other.AiSwitch) return false; + if (AiLevel != other.AiLevel) return false; + if (Blocktop != other.Blocktop) return false; + if (Blockscroll != other.Blockscroll) return false; + if (Blockbottom != other.Blockbottom) return false; + if (Blockcolor != other.Blockcolor) return false; + if (Blockspecial != other.Blockspecial) return false; + if (Preventshade != other.Preventshade) return false; + if (Dmask != other.Dmask) return false; + if (!pbc::ProtobufEqualityComparers.BitwiseSingleEqualityComparer.Equals(Opacity, other.Opacity)) return false; + if (Dmarea != other.Dmarea) return false; + if (!pbc::ProtobufEqualityComparers.BitwiseSingleEqualityComparer.Equals(Speedplus, other.Speedplus)) return false; + if (!pbc::ProtobufEqualityComparers.BitwiseSingleEqualityComparer.Equals(Fontsize, other.Fontsize)) return false; + if (Screensync != other.Screensync) return false; + if (Speedsync != other.Speedsync) return false; + if (Fontfamily != other.Fontfamily) return false; + if (Bold != other.Bold) return false; + if (Fontborder != other.Fontborder) return false; + if (DrawType != other.DrawType) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override int GetHashCode() { + int hash = 1; + if (DmSwitch != false) hash ^= DmSwitch.GetHashCode(); + if (AiSwitch != false) hash ^= AiSwitch.GetHashCode(); + if (AiLevel != 0) hash ^= AiLevel.GetHashCode(); + if (Blocktop != false) hash ^= Blocktop.GetHashCode(); + if (Blockscroll != false) hash ^= Blockscroll.GetHashCode(); + if (Blockbottom != false) hash ^= Blockbottom.GetHashCode(); + if (Blockcolor != false) hash ^= Blockcolor.GetHashCode(); + if (Blockspecial != false) hash ^= Blockspecial.GetHashCode(); + if (Preventshade != false) hash ^= Preventshade.GetHashCode(); + if (Dmask != false) hash ^= Dmask.GetHashCode(); + if (Opacity != 0F) hash ^= pbc::ProtobufEqualityComparers.BitwiseSingleEqualityComparer.GetHashCode(Opacity); + if (Dmarea != 0) hash ^= Dmarea.GetHashCode(); + if (Speedplus != 0F) hash ^= pbc::ProtobufEqualityComparers.BitwiseSingleEqualityComparer.GetHashCode(Speedplus); + if (Fontsize != 0F) hash ^= pbc::ProtobufEqualityComparers.BitwiseSingleEqualityComparer.GetHashCode(Fontsize); + if (Screensync != false) hash ^= Screensync.GetHashCode(); + if (Speedsync != false) hash ^= Speedsync.GetHashCode(); + if (Fontfamily.Length != 0) hash ^= Fontfamily.GetHashCode(); + if (Bold != false) hash ^= Bold.GetHashCode(); + if (Fontborder != 0) hash ^= Fontborder.GetHashCode(); + if (DrawType.Length != 0) hash ^= DrawType.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void WriteTo(pb::CodedOutputStream output) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + output.WriteRawMessage(this); + #else + if (DmSwitch != false) { + output.WriteRawTag(8); + output.WriteBool(DmSwitch); + } + if (AiSwitch != false) { + output.WriteRawTag(16); + output.WriteBool(AiSwitch); + } + if (AiLevel != 0) { + output.WriteRawTag(24); + output.WriteInt32(AiLevel); + } + if (Blocktop != false) { + output.WriteRawTag(32); + output.WriteBool(Blocktop); + } + if (Blockscroll != false) { + output.WriteRawTag(40); + output.WriteBool(Blockscroll); + } + if (Blockbottom != false) { + output.WriteRawTag(48); + output.WriteBool(Blockbottom); + } + if (Blockcolor != false) { + output.WriteRawTag(56); + output.WriteBool(Blockcolor); + } + if (Blockspecial != false) { + output.WriteRawTag(64); + output.WriteBool(Blockspecial); + } + if (Preventshade != false) { + output.WriteRawTag(72); + output.WriteBool(Preventshade); + } + if (Dmask != false) { + output.WriteRawTag(80); + output.WriteBool(Dmask); + } + if (Opacity != 0F) { + output.WriteRawTag(93); + output.WriteFloat(Opacity); + } + if (Dmarea != 0) { + output.WriteRawTag(96); + output.WriteInt32(Dmarea); + } + if (Speedplus != 0F) { + output.WriteRawTag(109); + output.WriteFloat(Speedplus); + } + if (Fontsize != 0F) { + output.WriteRawTag(117); + output.WriteFloat(Fontsize); + } + if (Screensync != false) { + output.WriteRawTag(120); + output.WriteBool(Screensync); + } + if (Speedsync != false) { + output.WriteRawTag(128, 1); + output.WriteBool(Speedsync); + } + if (Fontfamily.Length != 0) { + output.WriteRawTag(138, 1); + output.WriteString(Fontfamily); + } + if (Bold != false) { + output.WriteRawTag(144, 1); + output.WriteBool(Bold); + } + if (Fontborder != 0) { + output.WriteRawTag(152, 1); + output.WriteInt32(Fontborder); + } + if (DrawType.Length != 0) { + output.WriteRawTag(162, 1); + output.WriteString(DrawType); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + if (DmSwitch != false) { + output.WriteRawTag(8); + output.WriteBool(DmSwitch); + } + if (AiSwitch != false) { + output.WriteRawTag(16); + output.WriteBool(AiSwitch); + } + if (AiLevel != 0) { + output.WriteRawTag(24); + output.WriteInt32(AiLevel); + } + if (Blocktop != false) { + output.WriteRawTag(32); + output.WriteBool(Blocktop); + } + if (Blockscroll != false) { + output.WriteRawTag(40); + output.WriteBool(Blockscroll); + } + if (Blockbottom != false) { + output.WriteRawTag(48); + output.WriteBool(Blockbottom); + } + if (Blockcolor != false) { + output.WriteRawTag(56); + output.WriteBool(Blockcolor); + } + if (Blockspecial != false) { + output.WriteRawTag(64); + output.WriteBool(Blockspecial); + } + if (Preventshade != false) { + output.WriteRawTag(72); + output.WriteBool(Preventshade); + } + if (Dmask != false) { + output.WriteRawTag(80); + output.WriteBool(Dmask); + } + if (Opacity != 0F) { + output.WriteRawTag(93); + output.WriteFloat(Opacity); + } + if (Dmarea != 0) { + output.WriteRawTag(96); + output.WriteInt32(Dmarea); + } + if (Speedplus != 0F) { + output.WriteRawTag(109); + output.WriteFloat(Speedplus); + } + if (Fontsize != 0F) { + output.WriteRawTag(117); + output.WriteFloat(Fontsize); + } + if (Screensync != false) { + output.WriteRawTag(120); + output.WriteBool(Screensync); + } + if (Speedsync != false) { + output.WriteRawTag(128, 1); + output.WriteBool(Speedsync); + } + if (Fontfamily.Length != 0) { + output.WriteRawTag(138, 1); + output.WriteString(Fontfamily); + } + if (Bold != false) { + output.WriteRawTag(144, 1); + output.WriteBool(Bold); + } + if (Fontborder != 0) { + output.WriteRawTag(152, 1); + output.WriteInt32(Fontborder); + } + if (DrawType.Length != 0) { + output.WriteRawTag(162, 1); + output.WriteString(DrawType); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(ref output); + } + } + #endif + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int CalculateSize() { + int size = 0; + if (DmSwitch != false) { + size += 1 + 1; + } + if (AiSwitch != false) { + size += 1 + 1; + } + if (AiLevel != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(AiLevel); + } + if (Blocktop != false) { + size += 1 + 1; + } + if (Blockscroll != false) { + size += 1 + 1; + } + if (Blockbottom != false) { + size += 1 + 1; + } + if (Blockcolor != false) { + size += 1 + 1; + } + if (Blockspecial != false) { + size += 1 + 1; + } + if (Preventshade != false) { + size += 1 + 1; + } + if (Dmask != false) { + size += 1 + 1; + } + if (Opacity != 0F) { + size += 1 + 4; + } + if (Dmarea != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Dmarea); + } + if (Speedplus != 0F) { + size += 1 + 4; + } + if (Fontsize != 0F) { + size += 1 + 4; + } + if (Screensync != false) { + size += 1 + 1; + } + if (Speedsync != false) { + size += 2 + 1; + } + if (Fontfamily.Length != 0) { + size += 2 + pb::CodedOutputStream.ComputeStringSize(Fontfamily); + } + if (Bold != false) { + size += 2 + 1; + } + if (Fontborder != 0) { + size += 2 + pb::CodedOutputStream.ComputeInt32Size(Fontborder); + } + if (DrawType.Length != 0) { + size += 2 + pb::CodedOutputStream.ComputeStringSize(DrawType); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(DanmuWebPlayerConfig other) { + if (other == null) { + return; + } + if (other.DmSwitch != false) { + DmSwitch = other.DmSwitch; + } + if (other.AiSwitch != false) { + AiSwitch = other.AiSwitch; + } + if (other.AiLevel != 0) { + AiLevel = other.AiLevel; + } + if (other.Blocktop != false) { + Blocktop = other.Blocktop; + } + if (other.Blockscroll != false) { + Blockscroll = other.Blockscroll; + } + if (other.Blockbottom != false) { + Blockbottom = other.Blockbottom; + } + if (other.Blockcolor != false) { + Blockcolor = other.Blockcolor; + } + if (other.Blockspecial != false) { + Blockspecial = other.Blockspecial; + } + if (other.Preventshade != false) { + Preventshade = other.Preventshade; + } + if (other.Dmask != false) { + Dmask = other.Dmask; + } + if (other.Opacity != 0F) { + Opacity = other.Opacity; + } + if (other.Dmarea != 0) { + Dmarea = other.Dmarea; + } + if (other.Speedplus != 0F) { + Speedplus = other.Speedplus; + } + if (other.Fontsize != 0F) { + Fontsize = other.Fontsize; + } + if (other.Screensync != false) { + Screensync = other.Screensync; + } + if (other.Speedsync != false) { + Speedsync = other.Speedsync; + } + if (other.Fontfamily.Length != 0) { + Fontfamily = other.Fontfamily; + } + if (other.Bold != false) { + Bold = other.Bold; + } + if (other.Fontborder != 0) { + Fontborder = other.Fontborder; + } + if (other.DrawType.Length != 0) { + DrawType = other.DrawType; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(pb::CodedInputStream input) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + input.ReadRawMessage(this); + #else + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + DmSwitch = input.ReadBool(); + break; + } + case 16: { + AiSwitch = input.ReadBool(); + break; + } + case 24: { + AiLevel = input.ReadInt32(); + break; + } + case 32: { + Blocktop = input.ReadBool(); + break; + } + case 40: { + Blockscroll = input.ReadBool(); + break; + } + case 48: { + Blockbottom = input.ReadBool(); + break; + } + case 56: { + Blockcolor = input.ReadBool(); + break; + } + case 64: { + Blockspecial = input.ReadBool(); + break; + } + case 72: { + Preventshade = input.ReadBool(); + break; + } + case 80: { + Dmask = input.ReadBool(); + break; + } + case 93: { + Opacity = input.ReadFloat(); + break; + } + case 96: { + Dmarea = input.ReadInt32(); + break; + } + case 109: { + Speedplus = input.ReadFloat(); + break; + } + case 117: { + Fontsize = input.ReadFloat(); + break; + } + case 120: { + Screensync = input.ReadBool(); + break; + } + case 128: { + Speedsync = input.ReadBool(); + break; + } + case 138: { + Fontfamily = input.ReadString(); + break; + } + case 144: { + Bold = input.ReadBool(); + break; + } + case 152: { + Fontborder = input.ReadInt32(); + break; + } + case 162: { + DrawType = input.ReadString(); + break; + } + } + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 8: { + DmSwitch = input.ReadBool(); + break; + } + case 16: { + AiSwitch = input.ReadBool(); + break; + } + case 24: { + AiLevel = input.ReadInt32(); + break; + } + case 32: { + Blocktop = input.ReadBool(); + break; + } + case 40: { + Blockscroll = input.ReadBool(); + break; + } + case 48: { + Blockbottom = input.ReadBool(); + break; + } + case 56: { + Blockcolor = input.ReadBool(); + break; + } + case 64: { + Blockspecial = input.ReadBool(); + break; + } + case 72: { + Preventshade = input.ReadBool(); + break; + } + case 80: { + Dmask = input.ReadBool(); + break; + } + case 93: { + Opacity = input.ReadFloat(); + break; + } + case 96: { + Dmarea = input.ReadInt32(); + break; + } + case 109: { + Speedplus = input.ReadFloat(); + break; + } + case 117: { + Fontsize = input.ReadFloat(); + break; + } + case 120: { + Screensync = input.ReadBool(); + break; + } + case 128: { + Speedsync = input.ReadBool(); + break; + } + case 138: { + Fontfamily = input.ReadString(); + break; + } + case 144: { + Bold = input.ReadBool(); + break; + } + case 152: { + Fontborder = input.ReadInt32(); + break; + } + case 162: { + DrawType = input.ReadString(); + break; + } + } + } + } + #endif + + } + + /// + /// 单个字幕信息 + /// + public sealed partial class SubtitleItem : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new SubtitleItem()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pbr::MessageDescriptor Descriptor { + get { return global::Bilibili.Community.Service.Dm.V1.DmReflection.Descriptor.MessageTypes[14]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public SubtitleItem() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public SubtitleItem(SubtitleItem other) : this() { + id_ = other.id_; + idStr_ = other.idStr_; + lan_ = other.lan_; + lanDoc_ = other.lanDoc_; + subtitleUrl_ = other.subtitleUrl_; + author_ = other.author_ != null ? other.author_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public SubtitleItem Clone() { + return new SubtitleItem(this); + } + + /// Field number for the "id" field. + public const int IdFieldNumber = 1; + private long id_; + /// + /// 字幕id + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public long Id { + get { return id_; } + set { + id_ = value; + } + } + + /// Field number for the "id_str" field. + public const int IdStrFieldNumber = 2; + private string idStr_ = ""; + /// + /// 字幕id str + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public string IdStr { + get { return idStr_; } + set { + idStr_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "lan" field. + public const int LanFieldNumber = 3; + private string lan_ = ""; + /// + /// 字幕语言代码 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public string Lan { + get { return lan_; } + set { + lan_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "lan_doc" field. + public const int LanDocFieldNumber = 4; + private string lanDoc_ = ""; + /// + /// 字幕语言 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public string LanDoc { + get { return lanDoc_; } + set { + lanDoc_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "subtitle_url" field. + public const int SubtitleUrlFieldNumber = 5; + private string subtitleUrl_ = ""; + /// + /// 字幕文件url + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public string SubtitleUrl { + get { return subtitleUrl_; } + set { + subtitleUrl_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "author" field. + public const int AuthorFieldNumber = 6; + private global::Bilibili.Community.Service.Dm.V1.UserInfo author_; + /// + /// 字幕作者信息 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public global::Bilibili.Community.Service.Dm.V1.UserInfo Author { + get { return author_; } + set { + author_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as SubtitleItem); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(SubtitleItem other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Id != other.Id) return false; + if (IdStr != other.IdStr) return false; + if (Lan != other.Lan) return false; + if (LanDoc != other.LanDoc) return false; + if (SubtitleUrl != other.SubtitleUrl) return false; + if (!object.Equals(Author, other.Author)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override int GetHashCode() { + int hash = 1; + if (Id != 0L) hash ^= Id.GetHashCode(); + if (IdStr.Length != 0) hash ^= IdStr.GetHashCode(); + if (Lan.Length != 0) hash ^= Lan.GetHashCode(); + if (LanDoc.Length != 0) hash ^= LanDoc.GetHashCode(); + if (SubtitleUrl.Length != 0) hash ^= SubtitleUrl.GetHashCode(); + if (author_ != null) hash ^= Author.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void WriteTo(pb::CodedOutputStream output) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + output.WriteRawMessage(this); + #else + if (Id != 0L) { + output.WriteRawTag(8); + output.WriteInt64(Id); + } + if (IdStr.Length != 0) { + output.WriteRawTag(18); + output.WriteString(IdStr); + } + if (Lan.Length != 0) { + output.WriteRawTag(26); + output.WriteString(Lan); + } + if (LanDoc.Length != 0) { + output.WriteRawTag(34); + output.WriteString(LanDoc); + } + if (SubtitleUrl.Length != 0) { + output.WriteRawTag(42); + output.WriteString(SubtitleUrl); + } + if (author_ != null) { + output.WriteRawTag(50); + output.WriteMessage(Author); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + if (Id != 0L) { + output.WriteRawTag(8); + output.WriteInt64(Id); + } + if (IdStr.Length != 0) { + output.WriteRawTag(18); + output.WriteString(IdStr); + } + if (Lan.Length != 0) { + output.WriteRawTag(26); + output.WriteString(Lan); + } + if (LanDoc.Length != 0) { + output.WriteRawTag(34); + output.WriteString(LanDoc); + } + if (SubtitleUrl.Length != 0) { + output.WriteRawTag(42); + output.WriteString(SubtitleUrl); + } + if (author_ != null) { + output.WriteRawTag(50); + output.WriteMessage(Author); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(ref output); + } + } + #endif + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int CalculateSize() { + int size = 0; + if (Id != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(Id); + } + if (IdStr.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(IdStr); + } + if (Lan.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Lan); + } + if (LanDoc.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(LanDoc); + } + if (SubtitleUrl.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(SubtitleUrl); + } + if (author_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Author); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(SubtitleItem other) { + if (other == null) { + return; + } + if (other.Id != 0L) { + Id = other.Id; + } + if (other.IdStr.Length != 0) { + IdStr = other.IdStr; + } + if (other.Lan.Length != 0) { + Lan = other.Lan; + } + if (other.LanDoc.Length != 0) { + LanDoc = other.LanDoc; + } + if (other.SubtitleUrl.Length != 0) { + SubtitleUrl = other.SubtitleUrl; + } + if (other.author_ != null) { + if (author_ == null) { + Author = new global::Bilibili.Community.Service.Dm.V1.UserInfo(); + } + Author.MergeFrom(other.Author); + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(pb::CodedInputStream input) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + input.ReadRawMessage(this); + #else + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Id = input.ReadInt64(); + break; + } + case 18: { + IdStr = input.ReadString(); + break; + } + case 26: { + Lan = input.ReadString(); + break; + } + case 34: { + LanDoc = input.ReadString(); + break; + } + case 42: { + SubtitleUrl = input.ReadString(); + break; + } + case 50: { + if (author_ == null) { + Author = new global::Bilibili.Community.Service.Dm.V1.UserInfo(); + } + input.ReadMessage(Author); + break; + } + } + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 8: { + Id = input.ReadInt64(); + break; + } + case 18: { + IdStr = input.ReadString(); + break; + } + case 26: { + Lan = input.ReadString(); + break; + } + case 34: { + LanDoc = input.ReadString(); + break; + } + case 42: { + SubtitleUrl = input.ReadString(); + break; + } + case 50: { + if (author_ == null) { + Author = new global::Bilibili.Community.Service.Dm.V1.UserInfo(); + } + input.ReadMessage(Author); + break; + } + } + } + } + #endif + + } + + /// + /// 字幕作者信息 + /// + public sealed partial class UserInfo : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new UserInfo()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pbr::MessageDescriptor Descriptor { + get { return global::Bilibili.Community.Service.Dm.V1.DmReflection.Descriptor.MessageTypes[15]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public UserInfo() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public UserInfo(UserInfo other) : this() { + mid_ = other.mid_; + name_ = other.name_; + sex_ = other.sex_; + face_ = other.face_; + sign_ = other.sign_; + rank_ = other.rank_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public UserInfo Clone() { + return new UserInfo(this); + } + + /// Field number for the "mid" field. + public const int MidFieldNumber = 1; + private long mid_; + /// + /// 用户mid + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public long Mid { + get { return mid_; } + set { + mid_ = value; + } + } + + /// Field number for the "name" field. + public const int NameFieldNumber = 2; + private string name_ = ""; + /// + /// 用户昵称 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public string Name { + get { return name_; } + set { + name_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "sex" field. + public const int SexFieldNumber = 3; + private string sex_ = ""; + /// + /// 用户性别 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public string Sex { + get { return sex_; } + set { + sex_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "face" field. + public const int FaceFieldNumber = 4; + private string face_ = ""; + /// + /// 用户头像url + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public string Face { + get { return face_; } + set { + face_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "sign" field. + public const int SignFieldNumber = 5; + private string sign_ = ""; + /// + /// 用户签名 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public string Sign { + get { return sign_; } + set { + sign_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "rank" field. + public const int RankFieldNumber = 6; + private int rank_; + /// + /// 用户等级 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int Rank { + get { return rank_; } + set { + rank_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as UserInfo); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(UserInfo other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Mid != other.Mid) return false; + if (Name != other.Name) return false; + if (Sex != other.Sex) return false; + if (Face != other.Face) return false; + if (Sign != other.Sign) return false; + if (Rank != other.Rank) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override int GetHashCode() { + int hash = 1; + if (Mid != 0L) hash ^= Mid.GetHashCode(); + if (Name.Length != 0) hash ^= Name.GetHashCode(); + if (Sex.Length != 0) hash ^= Sex.GetHashCode(); + if (Face.Length != 0) hash ^= Face.GetHashCode(); + if (Sign.Length != 0) hash ^= Sign.GetHashCode(); + if (Rank != 0) hash ^= Rank.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void WriteTo(pb::CodedOutputStream output) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + output.WriteRawMessage(this); + #else + if (Mid != 0L) { + output.WriteRawTag(8); + output.WriteInt64(Mid); + } + if (Name.Length != 0) { + output.WriteRawTag(18); + output.WriteString(Name); + } + if (Sex.Length != 0) { + output.WriteRawTag(26); + output.WriteString(Sex); + } + if (Face.Length != 0) { + output.WriteRawTag(34); + output.WriteString(Face); + } + if (Sign.Length != 0) { + output.WriteRawTag(42); + output.WriteString(Sign); + } + if (Rank != 0) { + output.WriteRawTag(48); + output.WriteInt32(Rank); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + if (Mid != 0L) { + output.WriteRawTag(8); + output.WriteInt64(Mid); + } + if (Name.Length != 0) { + output.WriteRawTag(18); + output.WriteString(Name); + } + if (Sex.Length != 0) { + output.WriteRawTag(26); + output.WriteString(Sex); + } + if (Face.Length != 0) { + output.WriteRawTag(34); + output.WriteString(Face); + } + if (Sign.Length != 0) { + output.WriteRawTag(42); + output.WriteString(Sign); + } + if (Rank != 0) { + output.WriteRawTag(48); + output.WriteInt32(Rank); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(ref output); + } + } + #endif + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int CalculateSize() { + int size = 0; + if (Mid != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(Mid); + } + if (Name.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Name); + } + if (Sex.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Sex); + } + if (Face.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Face); + } + if (Sign.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Sign); + } + if (Rank != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Rank); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(UserInfo other) { + if (other == null) { + return; + } + if (other.Mid != 0L) { + Mid = other.Mid; + } + if (other.Name.Length != 0) { + Name = other.Name; + } + if (other.Sex.Length != 0) { + Sex = other.Sex; + } + if (other.Face.Length != 0) { + Face = other.Face; + } + if (other.Sign.Length != 0) { + Sign = other.Sign; + } + if (other.Rank != 0) { + Rank = other.Rank; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(pb::CodedInputStream input) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + input.ReadRawMessage(this); + #else + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Mid = input.ReadInt64(); + break; + } + case 18: { + Name = input.ReadString(); + break; + } + case 26: { + Sex = input.ReadString(); + break; + } + case 34: { + Face = input.ReadString(); + break; + } + case 42: { + Sign = input.ReadString(); + break; + } + case 48: { + Rank = input.ReadInt32(); + break; + } + } + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 8: { + Mid = input.ReadInt64(); + break; + } + case 18: { + Name = input.ReadString(); + break; + } + case 26: { + Sex = input.ReadString(); + break; + } + case 34: { + Face = input.ReadString(); + break; + } + case 42: { + Sign = input.ReadString(); + break; + } + case 48: { + Rank = input.ReadInt32(); + break; + } + } + } + } + #endif + + } + + /// + /// 弹幕条目 + /// + public sealed partial class DanmakuElem : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new DanmakuElem()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pbr::MessageDescriptor Descriptor { + get { return global::Bilibili.Community.Service.Dm.V1.DmReflection.Descriptor.MessageTypes[16]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public DanmakuElem() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public DanmakuElem(DanmakuElem other) : this() { + id_ = other.id_; + progress_ = other.progress_; + mode_ = other.mode_; + fontsize_ = other.fontsize_; + color_ = other.color_; + midHash_ = other.midHash_; + content_ = other.content_; + ctime_ = other.ctime_; + weight_ = other.weight_; + action_ = other.action_; + pool_ = other.pool_; + idStr_ = other.idStr_; + attr_ = other.attr_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public DanmakuElem Clone() { + return new DanmakuElem(this); + } + + /// Field number for the "id" field. + public const int IdFieldNumber = 1; + private long id_; + /// + /// 弹幕dmid + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public long Id { + get { return id_; } + set { + id_ = value; + } + } + + /// Field number for the "progress" field. + public const int ProgressFieldNumber = 2; + private int progress_; + /// + /// 弹幕出现位置(单位ms) + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int Progress { + get { return progress_; } + set { + progress_ = value; + } + } + + /// Field number for the "mode" field. + public const int ModeFieldNumber = 3; + private int mode_; + /// + /// 弹幕类型 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int Mode { + get { return mode_; } + set { + mode_ = value; + } + } + + /// Field number for the "fontsize" field. + public const int FontsizeFieldNumber = 4; + private int fontsize_; + /// + /// 弹幕字号 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int Fontsize { + get { return fontsize_; } + set { + fontsize_ = value; + } + } + + /// Field number for the "color" field. + public const int ColorFieldNumber = 5; + private uint color_; + /// + /// 弹幕颜色 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public uint Color { + get { return color_; } + set { + color_ = value; + } + } + + /// Field number for the "midHash" field. + public const int MidHashFieldNumber = 6; + private string midHash_ = ""; + /// + /// 发送着mid hash + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public string MidHash { + get { return midHash_; } + set { + midHash_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "content" field. + public const int ContentFieldNumber = 7; + private string content_ = ""; + /// + /// 弹幕正文 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public string Content { + get { return content_; } + set { + content_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "ctime" field. + public const int CtimeFieldNumber = 8; + private long ctime_; + /// + /// 发送时间 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public long Ctime { + get { return ctime_; } + set { + ctime_ = value; + } + } + + /// Field number for the "weight" field. + public const int WeightFieldNumber = 9; + private int weight_; + /// + /// 权重 区间:[1,10] + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int Weight { + get { return weight_; } + set { + weight_ = value; + } + } + + /// Field number for the "action" field. + public const int ActionFieldNumber = 10; + private string action_ = ""; + /// + /// 动作 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public string Action { + get { return action_; } + set { + action_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "pool" field. + public const int PoolFieldNumber = 11; + private int pool_; + /// + /// 弹幕池 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int Pool { + get { return pool_; } + set { + pool_ = value; + } + } + + /// Field number for the "idStr" field. + public const int IdStrFieldNumber = 12; + private string idStr_ = ""; + /// + /// 弹幕dmid str + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public string IdStr { + get { return idStr_; } + set { + idStr_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "attr" field. + public const int AttrFieldNumber = 13; + private int attr_; + /// + /// 弹幕属性位(bin求AND) + /// bit0:保护 bit1:直播 bit2:高赞 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int Attr { + get { return attr_; } + set { + attr_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as DanmakuElem); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(DanmakuElem other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Id != other.Id) return false; + if (Progress != other.Progress) return false; + if (Mode != other.Mode) return false; + if (Fontsize != other.Fontsize) return false; + if (Color != other.Color) return false; + if (MidHash != other.MidHash) return false; + if (Content != other.Content) return false; + if (Ctime != other.Ctime) return false; + if (Weight != other.Weight) return false; + if (Action != other.Action) return false; + if (Pool != other.Pool) return false; + if (IdStr != other.IdStr) return false; + if (Attr != other.Attr) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override int GetHashCode() { + int hash = 1; + if (Id != 0L) hash ^= Id.GetHashCode(); + if (Progress != 0) hash ^= Progress.GetHashCode(); + if (Mode != 0) hash ^= Mode.GetHashCode(); + if (Fontsize != 0) hash ^= Fontsize.GetHashCode(); + if (Color != 0) hash ^= Color.GetHashCode(); + if (MidHash.Length != 0) hash ^= MidHash.GetHashCode(); + if (Content.Length != 0) hash ^= Content.GetHashCode(); + if (Ctime != 0L) hash ^= Ctime.GetHashCode(); + if (Weight != 0) hash ^= Weight.GetHashCode(); + if (Action.Length != 0) hash ^= Action.GetHashCode(); + if (Pool != 0) hash ^= Pool.GetHashCode(); + if (IdStr.Length != 0) hash ^= IdStr.GetHashCode(); + if (Attr != 0) hash ^= Attr.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void WriteTo(pb::CodedOutputStream output) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + output.WriteRawMessage(this); + #else + if (Id != 0L) { + output.WriteRawTag(8); + output.WriteInt64(Id); + } + if (Progress != 0) { + output.WriteRawTag(16); + output.WriteInt32(Progress); + } + if (Mode != 0) { + output.WriteRawTag(24); + output.WriteInt32(Mode); + } + if (Fontsize != 0) { + output.WriteRawTag(32); + output.WriteInt32(Fontsize); + } + if (Color != 0) { + output.WriteRawTag(40); + output.WriteUInt32(Color); + } + if (MidHash.Length != 0) { + output.WriteRawTag(50); + output.WriteString(MidHash); + } + if (Content.Length != 0) { + output.WriteRawTag(58); + output.WriteString(Content); + } + if (Ctime != 0L) { + output.WriteRawTag(64); + output.WriteInt64(Ctime); + } + if (Weight != 0) { + output.WriteRawTag(72); + output.WriteInt32(Weight); + } + if (Action.Length != 0) { + output.WriteRawTag(82); + output.WriteString(Action); + } + if (Pool != 0) { + output.WriteRawTag(88); + output.WriteInt32(Pool); + } + if (IdStr.Length != 0) { + output.WriteRawTag(98); + output.WriteString(IdStr); + } + if (Attr != 0) { + output.WriteRawTag(104); + output.WriteInt32(Attr); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + if (Id != 0L) { + output.WriteRawTag(8); + output.WriteInt64(Id); + } + if (Progress != 0) { + output.WriteRawTag(16); + output.WriteInt32(Progress); + } + if (Mode != 0) { + output.WriteRawTag(24); + output.WriteInt32(Mode); + } + if (Fontsize != 0) { + output.WriteRawTag(32); + output.WriteInt32(Fontsize); + } + if (Color != 0) { + output.WriteRawTag(40); + output.WriteUInt32(Color); + } + if (MidHash.Length != 0) { + output.WriteRawTag(50); + output.WriteString(MidHash); + } + if (Content.Length != 0) { + output.WriteRawTag(58); + output.WriteString(Content); + } + if (Ctime != 0L) { + output.WriteRawTag(64); + output.WriteInt64(Ctime); + } + if (Weight != 0) { + output.WriteRawTag(72); + output.WriteInt32(Weight); + } + if (Action.Length != 0) { + output.WriteRawTag(82); + output.WriteString(Action); + } + if (Pool != 0) { + output.WriteRawTag(88); + output.WriteInt32(Pool); + } + if (IdStr.Length != 0) { + output.WriteRawTag(98); + output.WriteString(IdStr); + } + if (Attr != 0) { + output.WriteRawTag(104); + output.WriteInt32(Attr); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(ref output); + } + } + #endif + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int CalculateSize() { + int size = 0; + if (Id != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(Id); + } + if (Progress != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Progress); + } + if (Mode != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Mode); + } + if (Fontsize != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Fontsize); + } + if (Color != 0) { + size += 1 + pb::CodedOutputStream.ComputeUInt32Size(Color); + } + if (MidHash.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(MidHash); + } + if (Content.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Content); + } + if (Ctime != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(Ctime); + } + if (Weight != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Weight); + } + if (Action.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Action); + } + if (Pool != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Pool); + } + if (IdStr.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(IdStr); + } + if (Attr != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Attr); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(DanmakuElem other) { + if (other == null) { + return; + } + if (other.Id != 0L) { + Id = other.Id; + } + if (other.Progress != 0) { + Progress = other.Progress; + } + if (other.Mode != 0) { + Mode = other.Mode; + } + if (other.Fontsize != 0) { + Fontsize = other.Fontsize; + } + if (other.Color != 0) { + Color = other.Color; + } + if (other.MidHash.Length != 0) { + MidHash = other.MidHash; + } + if (other.Content.Length != 0) { + Content = other.Content; + } + if (other.Ctime != 0L) { + Ctime = other.Ctime; + } + if (other.Weight != 0) { + Weight = other.Weight; + } + if (other.Action.Length != 0) { + Action = other.Action; + } + if (other.Pool != 0) { + Pool = other.Pool; + } + if (other.IdStr.Length != 0) { + IdStr = other.IdStr; + } + if (other.Attr != 0) { + Attr = other.Attr; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(pb::CodedInputStream input) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + input.ReadRawMessage(this); + #else + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Id = input.ReadInt64(); + break; + } + case 16: { + Progress = input.ReadInt32(); + break; + } + case 24: { + Mode = input.ReadInt32(); + break; + } + case 32: { + Fontsize = input.ReadInt32(); + break; + } + case 40: { + Color = input.ReadUInt32(); + break; + } + case 50: { + MidHash = input.ReadString(); + break; + } + case 58: { + Content = input.ReadString(); + break; + } + case 64: { + Ctime = input.ReadInt64(); + break; + } + case 72: { + Weight = input.ReadInt32(); + break; + } + case 82: { + Action = input.ReadString(); + break; + } + case 88: { + Pool = input.ReadInt32(); + break; + } + case 98: { + IdStr = input.ReadString(); + break; + } + case 104: { + Attr = input.ReadInt32(); + break; + } + } + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 8: { + Id = input.ReadInt64(); + break; + } + case 16: { + Progress = input.ReadInt32(); + break; + } + case 24: { + Mode = input.ReadInt32(); + break; + } + case 32: { + Fontsize = input.ReadInt32(); + break; + } + case 40: { + Color = input.ReadUInt32(); + break; + } + case 50: { + MidHash = input.ReadString(); + break; + } + case 58: { + Content = input.ReadString(); + break; + } + case 64: { + Ctime = input.ReadInt64(); + break; + } + case 72: { + Weight = input.ReadInt32(); + break; + } + case 82: { + Action = input.ReadString(); + break; + } + case 88: { + Pool = input.ReadInt32(); + break; + } + case 98: { + IdStr = input.ReadString(); + break; + } + case 104: { + Attr = input.ReadInt32(); + break; + } + } + } + } + #endif + + } + + /// + /// 修改弹幕配置-请求 + /// + public sealed partial class DmPlayerConfigReq : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new DmPlayerConfigReq()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pbr::MessageDescriptor Descriptor { + get { return global::Bilibili.Community.Service.Dm.V1.DmReflection.Descriptor.MessageTypes[17]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public DmPlayerConfigReq() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public DmPlayerConfigReq(DmPlayerConfigReq other) : this() { + ts_ = other.ts_; + switch_ = other.switch_ != null ? other.switch_.Clone() : null; + switchSave_ = other.switchSave_ != null ? other.switchSave_.Clone() : null; + useDefaultConfig_ = other.useDefaultConfig_ != null ? other.useDefaultConfig_.Clone() : null; + aiRecommendedSwitch_ = other.aiRecommendedSwitch_ != null ? other.aiRecommendedSwitch_.Clone() : null; + aiRecommendedLevel_ = other.aiRecommendedLevel_ != null ? other.aiRecommendedLevel_.Clone() : null; + blocktop_ = other.blocktop_ != null ? other.blocktop_.Clone() : null; + blockscroll_ = other.blockscroll_ != null ? other.blockscroll_.Clone() : null; + blockbottom_ = other.blockbottom_ != null ? other.blockbottom_.Clone() : null; + blockcolorful_ = other.blockcolorful_ != null ? other.blockcolorful_.Clone() : null; + blockrepeat_ = other.blockrepeat_ != null ? other.blockrepeat_.Clone() : null; + blockspecial_ = other.blockspecial_ != null ? other.blockspecial_.Clone() : null; + opacity_ = other.opacity_ != null ? other.opacity_.Clone() : null; + scalingfactor_ = other.scalingfactor_ != null ? other.scalingfactor_.Clone() : null; + domain_ = other.domain_ != null ? other.domain_.Clone() : null; + speed_ = other.speed_ != null ? other.speed_.Clone() : null; + enableblocklist_ = other.enableblocklist_ != null ? other.enableblocklist_.Clone() : null; + inlinePlayerDanmakuSwitch_ = other.inlinePlayerDanmakuSwitch_ != null ? other.inlinePlayerDanmakuSwitch_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public DmPlayerConfigReq Clone() { + return new DmPlayerConfigReq(this); + } + + /// Field number for the "ts" field. + public const int TsFieldNumber = 1; + private long ts_; + /// + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public long Ts { + get { return ts_; } + set { + ts_ = value; + } + } + + /// Field number for the "switch" field. + public const int SwitchFieldNumber = 2; + private global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuSwitch switch_; + /// + /// 是否开启弹幕 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuSwitch Switch { + get { return switch_; } + set { + switch_ = value; + } + } + + /// Field number for the "switch_save" field. + public const int SwitchSaveFieldNumber = 3; + private global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuSwitchSave switchSave_; + /// + /// 是否记录弹幕开关设置 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuSwitchSave SwitchSave { + get { return switchSave_; } + set { + switchSave_ = value; + } + } + + /// Field number for the "use_default_config" field. + public const int UseDefaultConfigFieldNumber = 4; + private global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuUseDefaultConfig useDefaultConfig_; + /// + /// 是否使用推荐弹幕设置 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuUseDefaultConfig UseDefaultConfig { + get { return useDefaultConfig_; } + set { + useDefaultConfig_ = value; + } + } + + /// Field number for the "ai_recommended_switch" field. + public const int AiRecommendedSwitchFieldNumber = 5; + private global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuAiRecommendedSwitch aiRecommendedSwitch_; + /// + /// 是否开启智能云屏蔽 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuAiRecommendedSwitch AiRecommendedSwitch { + get { return aiRecommendedSwitch_; } + set { + aiRecommendedSwitch_ = value; + } + } + + /// Field number for the "ai_recommended_level" field. + public const int AiRecommendedLevelFieldNumber = 6; + private global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuAiRecommendedLevel aiRecommendedLevel_; + /// + /// 智能云屏蔽等级 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuAiRecommendedLevel AiRecommendedLevel { + get { return aiRecommendedLevel_; } + set { + aiRecommendedLevel_ = value; + } + } + + /// Field number for the "blocktop" field. + public const int BlocktopFieldNumber = 7; + private global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuBlocktop blocktop_; + /// + /// 是否屏蔽顶端弹幕 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuBlocktop Blocktop { + get { return blocktop_; } + set { + blocktop_ = value; + } + } + + /// Field number for the "blockscroll" field. + public const int BlockscrollFieldNumber = 8; + private global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuBlockscroll blockscroll_; + /// + /// 是否屏蔽滚动弹幕 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuBlockscroll Blockscroll { + get { return blockscroll_; } + set { + blockscroll_ = value; + } + } + + /// Field number for the "blockbottom" field. + public const int BlockbottomFieldNumber = 9; + private global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuBlockbottom blockbottom_; + /// + /// 是否屏蔽底端弹幕 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuBlockbottom Blockbottom { + get { return blockbottom_; } + set { + blockbottom_ = value; + } + } + + /// Field number for the "blockcolorful" field. + public const int BlockcolorfulFieldNumber = 10; + private global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuBlockcolorful blockcolorful_; + /// + /// 是否屏蔽彩色弹幕 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuBlockcolorful Blockcolorful { + get { return blockcolorful_; } + set { + blockcolorful_ = value; + } + } + + /// Field number for the "blockrepeat" field. + public const int BlockrepeatFieldNumber = 11; + private global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuBlockrepeat blockrepeat_; + /// + /// 是否屏蔽重复弹幕 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuBlockrepeat Blockrepeat { + get { return blockrepeat_; } + set { + blockrepeat_ = value; + } + } + + /// Field number for the "blockspecial" field. + public const int BlockspecialFieldNumber = 12; + private global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuBlockspecial blockspecial_; + /// + /// 是否屏蔽高级弹幕 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuBlockspecial Blockspecial { + get { return blockspecial_; } + set { + blockspecial_ = value; + } + } + + /// Field number for the "opacity" field. + public const int OpacityFieldNumber = 13; + private global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuOpacity opacity_; + /// + /// 弹幕不透明度 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuOpacity Opacity { + get { return opacity_; } + set { + opacity_ = value; + } + } + + /// Field number for the "scalingfactor" field. + public const int ScalingfactorFieldNumber = 14; + private global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuScalingfactor scalingfactor_; + /// + /// 弹幕缩放比例 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuScalingfactor Scalingfactor { + get { return scalingfactor_; } + set { + scalingfactor_ = value; + } + } + + /// Field number for the "domain" field. + public const int DomainFieldNumber = 15; + private global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuDomain domain_; + /// + /// 弹幕显示区域 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuDomain Domain { + get { return domain_; } + set { + domain_ = value; + } + } + + /// Field number for the "speed" field. + public const int SpeedFieldNumber = 16; + private global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuSpeed speed_; + /// + /// 弹幕速度 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuSpeed Speed { + get { return speed_; } + set { + speed_ = value; + } + } + + /// Field number for the "enableblocklist" field. + public const int EnableblocklistFieldNumber = 17; + private global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuEnableblocklist enableblocklist_; + /// + /// 是否开启屏蔽列表 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuEnableblocklist Enableblocklist { + get { return enableblocklist_; } + set { + enableblocklist_ = value; + } + } + + /// Field number for the "inlinePlayerDanmakuSwitch" field. + public const int InlinePlayerDanmakuSwitchFieldNumber = 18; + private global::Bilibili.Community.Service.Dm.V1.InlinePlayerDanmakuSwitch inlinePlayerDanmakuSwitch_; + /// + /// 是否开启弹幕 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public global::Bilibili.Community.Service.Dm.V1.InlinePlayerDanmakuSwitch InlinePlayerDanmakuSwitch { + get { return inlinePlayerDanmakuSwitch_; } + set { + inlinePlayerDanmakuSwitch_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as DmPlayerConfigReq); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(DmPlayerConfigReq other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Ts != other.Ts) return false; + if (!object.Equals(Switch, other.Switch)) return false; + if (!object.Equals(SwitchSave, other.SwitchSave)) return false; + if (!object.Equals(UseDefaultConfig, other.UseDefaultConfig)) return false; + if (!object.Equals(AiRecommendedSwitch, other.AiRecommendedSwitch)) return false; + if (!object.Equals(AiRecommendedLevel, other.AiRecommendedLevel)) return false; + if (!object.Equals(Blocktop, other.Blocktop)) return false; + if (!object.Equals(Blockscroll, other.Blockscroll)) return false; + if (!object.Equals(Blockbottom, other.Blockbottom)) return false; + if (!object.Equals(Blockcolorful, other.Blockcolorful)) return false; + if (!object.Equals(Blockrepeat, other.Blockrepeat)) return false; + if (!object.Equals(Blockspecial, other.Blockspecial)) return false; + if (!object.Equals(Opacity, other.Opacity)) return false; + if (!object.Equals(Scalingfactor, other.Scalingfactor)) return false; + if (!object.Equals(Domain, other.Domain)) return false; + if (!object.Equals(Speed, other.Speed)) return false; + if (!object.Equals(Enableblocklist, other.Enableblocklist)) return false; + if (!object.Equals(InlinePlayerDanmakuSwitch, other.InlinePlayerDanmakuSwitch)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override int GetHashCode() { + int hash = 1; + if (Ts != 0L) hash ^= Ts.GetHashCode(); + if (switch_ != null) hash ^= Switch.GetHashCode(); + if (switchSave_ != null) hash ^= SwitchSave.GetHashCode(); + if (useDefaultConfig_ != null) hash ^= UseDefaultConfig.GetHashCode(); + if (aiRecommendedSwitch_ != null) hash ^= AiRecommendedSwitch.GetHashCode(); + if (aiRecommendedLevel_ != null) hash ^= AiRecommendedLevel.GetHashCode(); + if (blocktop_ != null) hash ^= Blocktop.GetHashCode(); + if (blockscroll_ != null) hash ^= Blockscroll.GetHashCode(); + if (blockbottom_ != null) hash ^= Blockbottom.GetHashCode(); + if (blockcolorful_ != null) hash ^= Blockcolorful.GetHashCode(); + if (blockrepeat_ != null) hash ^= Blockrepeat.GetHashCode(); + if (blockspecial_ != null) hash ^= Blockspecial.GetHashCode(); + if (opacity_ != null) hash ^= Opacity.GetHashCode(); + if (scalingfactor_ != null) hash ^= Scalingfactor.GetHashCode(); + if (domain_ != null) hash ^= Domain.GetHashCode(); + if (speed_ != null) hash ^= Speed.GetHashCode(); + if (enableblocklist_ != null) hash ^= Enableblocklist.GetHashCode(); + if (inlinePlayerDanmakuSwitch_ != null) hash ^= InlinePlayerDanmakuSwitch.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void WriteTo(pb::CodedOutputStream output) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + output.WriteRawMessage(this); + #else + if (Ts != 0L) { + output.WriteRawTag(8); + output.WriteInt64(Ts); + } + if (switch_ != null) { + output.WriteRawTag(18); + output.WriteMessage(Switch); + } + if (switchSave_ != null) { + output.WriteRawTag(26); + output.WriteMessage(SwitchSave); + } + if (useDefaultConfig_ != null) { + output.WriteRawTag(34); + output.WriteMessage(UseDefaultConfig); + } + if (aiRecommendedSwitch_ != null) { + output.WriteRawTag(42); + output.WriteMessage(AiRecommendedSwitch); + } + if (aiRecommendedLevel_ != null) { + output.WriteRawTag(50); + output.WriteMessage(AiRecommendedLevel); + } + if (blocktop_ != null) { + output.WriteRawTag(58); + output.WriteMessage(Blocktop); + } + if (blockscroll_ != null) { + output.WriteRawTag(66); + output.WriteMessage(Blockscroll); + } + if (blockbottom_ != null) { + output.WriteRawTag(74); + output.WriteMessage(Blockbottom); + } + if (blockcolorful_ != null) { + output.WriteRawTag(82); + output.WriteMessage(Blockcolorful); + } + if (blockrepeat_ != null) { + output.WriteRawTag(90); + output.WriteMessage(Blockrepeat); + } + if (blockspecial_ != null) { + output.WriteRawTag(98); + output.WriteMessage(Blockspecial); + } + if (opacity_ != null) { + output.WriteRawTag(106); + output.WriteMessage(Opacity); + } + if (scalingfactor_ != null) { + output.WriteRawTag(114); + output.WriteMessage(Scalingfactor); + } + if (domain_ != null) { + output.WriteRawTag(122); + output.WriteMessage(Domain); + } + if (speed_ != null) { + output.WriteRawTag(130, 1); + output.WriteMessage(Speed); + } + if (enableblocklist_ != null) { + output.WriteRawTag(138, 1); + output.WriteMessage(Enableblocklist); + } + if (inlinePlayerDanmakuSwitch_ != null) { + output.WriteRawTag(146, 1); + output.WriteMessage(InlinePlayerDanmakuSwitch); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + if (Ts != 0L) { + output.WriteRawTag(8); + output.WriteInt64(Ts); + } + if (switch_ != null) { + output.WriteRawTag(18); + output.WriteMessage(Switch); + } + if (switchSave_ != null) { + output.WriteRawTag(26); + output.WriteMessage(SwitchSave); + } + if (useDefaultConfig_ != null) { + output.WriteRawTag(34); + output.WriteMessage(UseDefaultConfig); + } + if (aiRecommendedSwitch_ != null) { + output.WriteRawTag(42); + output.WriteMessage(AiRecommendedSwitch); + } + if (aiRecommendedLevel_ != null) { + output.WriteRawTag(50); + output.WriteMessage(AiRecommendedLevel); + } + if (blocktop_ != null) { + output.WriteRawTag(58); + output.WriteMessage(Blocktop); + } + if (blockscroll_ != null) { + output.WriteRawTag(66); + output.WriteMessage(Blockscroll); + } + if (blockbottom_ != null) { + output.WriteRawTag(74); + output.WriteMessage(Blockbottom); + } + if (blockcolorful_ != null) { + output.WriteRawTag(82); + output.WriteMessage(Blockcolorful); + } + if (blockrepeat_ != null) { + output.WriteRawTag(90); + output.WriteMessage(Blockrepeat); + } + if (blockspecial_ != null) { + output.WriteRawTag(98); + output.WriteMessage(Blockspecial); + } + if (opacity_ != null) { + output.WriteRawTag(106); + output.WriteMessage(Opacity); + } + if (scalingfactor_ != null) { + output.WriteRawTag(114); + output.WriteMessage(Scalingfactor); + } + if (domain_ != null) { + output.WriteRawTag(122); + output.WriteMessage(Domain); + } + if (speed_ != null) { + output.WriteRawTag(130, 1); + output.WriteMessage(Speed); + } + if (enableblocklist_ != null) { + output.WriteRawTag(138, 1); + output.WriteMessage(Enableblocklist); + } + if (inlinePlayerDanmakuSwitch_ != null) { + output.WriteRawTag(146, 1); + output.WriteMessage(InlinePlayerDanmakuSwitch); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(ref output); + } + } + #endif + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int CalculateSize() { + int size = 0; + if (Ts != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(Ts); + } + if (switch_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Switch); + } + if (switchSave_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(SwitchSave); + } + if (useDefaultConfig_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(UseDefaultConfig); + } + if (aiRecommendedSwitch_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(AiRecommendedSwitch); + } + if (aiRecommendedLevel_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(AiRecommendedLevel); + } + if (blocktop_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Blocktop); + } + if (blockscroll_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Blockscroll); + } + if (blockbottom_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Blockbottom); + } + if (blockcolorful_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Blockcolorful); + } + if (blockrepeat_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Blockrepeat); + } + if (blockspecial_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Blockspecial); + } + if (opacity_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Opacity); + } + if (scalingfactor_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Scalingfactor); + } + if (domain_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Domain); + } + if (speed_ != null) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(Speed); + } + if (enableblocklist_ != null) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(Enableblocklist); + } + if (inlinePlayerDanmakuSwitch_ != null) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(InlinePlayerDanmakuSwitch); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(DmPlayerConfigReq other) { + if (other == null) { + return; + } + if (other.Ts != 0L) { + Ts = other.Ts; + } + if (other.switch_ != null) { + if (switch_ == null) { + Switch = new global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuSwitch(); + } + Switch.MergeFrom(other.Switch); + } + if (other.switchSave_ != null) { + if (switchSave_ == null) { + SwitchSave = new global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuSwitchSave(); + } + SwitchSave.MergeFrom(other.SwitchSave); + } + if (other.useDefaultConfig_ != null) { + if (useDefaultConfig_ == null) { + UseDefaultConfig = new global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuUseDefaultConfig(); + } + UseDefaultConfig.MergeFrom(other.UseDefaultConfig); + } + if (other.aiRecommendedSwitch_ != null) { + if (aiRecommendedSwitch_ == null) { + AiRecommendedSwitch = new global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuAiRecommendedSwitch(); + } + AiRecommendedSwitch.MergeFrom(other.AiRecommendedSwitch); + } + if (other.aiRecommendedLevel_ != null) { + if (aiRecommendedLevel_ == null) { + AiRecommendedLevel = new global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuAiRecommendedLevel(); + } + AiRecommendedLevel.MergeFrom(other.AiRecommendedLevel); + } + if (other.blocktop_ != null) { + if (blocktop_ == null) { + Blocktop = new global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuBlocktop(); + } + Blocktop.MergeFrom(other.Blocktop); + } + if (other.blockscroll_ != null) { + if (blockscroll_ == null) { + Blockscroll = new global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuBlockscroll(); + } + Blockscroll.MergeFrom(other.Blockscroll); + } + if (other.blockbottom_ != null) { + if (blockbottom_ == null) { + Blockbottom = new global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuBlockbottom(); + } + Blockbottom.MergeFrom(other.Blockbottom); + } + if (other.blockcolorful_ != null) { + if (blockcolorful_ == null) { + Blockcolorful = new global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuBlockcolorful(); + } + Blockcolorful.MergeFrom(other.Blockcolorful); + } + if (other.blockrepeat_ != null) { + if (blockrepeat_ == null) { + Blockrepeat = new global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuBlockrepeat(); + } + Blockrepeat.MergeFrom(other.Blockrepeat); + } + if (other.blockspecial_ != null) { + if (blockspecial_ == null) { + Blockspecial = new global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuBlockspecial(); + } + Blockspecial.MergeFrom(other.Blockspecial); + } + if (other.opacity_ != null) { + if (opacity_ == null) { + Opacity = new global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuOpacity(); + } + Opacity.MergeFrom(other.Opacity); + } + if (other.scalingfactor_ != null) { + if (scalingfactor_ == null) { + Scalingfactor = new global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuScalingfactor(); + } + Scalingfactor.MergeFrom(other.Scalingfactor); + } + if (other.domain_ != null) { + if (domain_ == null) { + Domain = new global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuDomain(); + } + Domain.MergeFrom(other.Domain); + } + if (other.speed_ != null) { + if (speed_ == null) { + Speed = new global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuSpeed(); + } + Speed.MergeFrom(other.Speed); + } + if (other.enableblocklist_ != null) { + if (enableblocklist_ == null) { + Enableblocklist = new global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuEnableblocklist(); + } + Enableblocklist.MergeFrom(other.Enableblocklist); + } + if (other.inlinePlayerDanmakuSwitch_ != null) { + if (inlinePlayerDanmakuSwitch_ == null) { + InlinePlayerDanmakuSwitch = new global::Bilibili.Community.Service.Dm.V1.InlinePlayerDanmakuSwitch(); + } + InlinePlayerDanmakuSwitch.MergeFrom(other.InlinePlayerDanmakuSwitch); + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(pb::CodedInputStream input) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + input.ReadRawMessage(this); + #else + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Ts = input.ReadInt64(); + break; + } + case 18: { + if (switch_ == null) { + Switch = new global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuSwitch(); + } + input.ReadMessage(Switch); + break; + } + case 26: { + if (switchSave_ == null) { + SwitchSave = new global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuSwitchSave(); + } + input.ReadMessage(SwitchSave); + break; + } + case 34: { + if (useDefaultConfig_ == null) { + UseDefaultConfig = new global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuUseDefaultConfig(); + } + input.ReadMessage(UseDefaultConfig); + break; + } + case 42: { + if (aiRecommendedSwitch_ == null) { + AiRecommendedSwitch = new global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuAiRecommendedSwitch(); + } + input.ReadMessage(AiRecommendedSwitch); + break; + } + case 50: { + if (aiRecommendedLevel_ == null) { + AiRecommendedLevel = new global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuAiRecommendedLevel(); + } + input.ReadMessage(AiRecommendedLevel); + break; + } + case 58: { + if (blocktop_ == null) { + Blocktop = new global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuBlocktop(); + } + input.ReadMessage(Blocktop); + break; + } + case 66: { + if (blockscroll_ == null) { + Blockscroll = new global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuBlockscroll(); + } + input.ReadMessage(Blockscroll); + break; + } + case 74: { + if (blockbottom_ == null) { + Blockbottom = new global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuBlockbottom(); + } + input.ReadMessage(Blockbottom); + break; + } + case 82: { + if (blockcolorful_ == null) { + Blockcolorful = new global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuBlockcolorful(); + } + input.ReadMessage(Blockcolorful); + break; + } + case 90: { + if (blockrepeat_ == null) { + Blockrepeat = new global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuBlockrepeat(); + } + input.ReadMessage(Blockrepeat); + break; + } + case 98: { + if (blockspecial_ == null) { + Blockspecial = new global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuBlockspecial(); + } + input.ReadMessage(Blockspecial); + break; + } + case 106: { + if (opacity_ == null) { + Opacity = new global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuOpacity(); + } + input.ReadMessage(Opacity); + break; + } + case 114: { + if (scalingfactor_ == null) { + Scalingfactor = new global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuScalingfactor(); + } + input.ReadMessage(Scalingfactor); + break; + } + case 122: { + if (domain_ == null) { + Domain = new global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuDomain(); + } + input.ReadMessage(Domain); + break; + } + case 130: { + if (speed_ == null) { + Speed = new global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuSpeed(); + } + input.ReadMessage(Speed); + break; + } + case 138: { + if (enableblocklist_ == null) { + Enableblocklist = new global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuEnableblocklist(); + } + input.ReadMessage(Enableblocklist); + break; + } + case 146: { + if (inlinePlayerDanmakuSwitch_ == null) { + InlinePlayerDanmakuSwitch = new global::Bilibili.Community.Service.Dm.V1.InlinePlayerDanmakuSwitch(); + } + input.ReadMessage(InlinePlayerDanmakuSwitch); + break; + } + } + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 8: { + Ts = input.ReadInt64(); + break; + } + case 18: { + if (switch_ == null) { + Switch = new global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuSwitch(); + } + input.ReadMessage(Switch); + break; + } + case 26: { + if (switchSave_ == null) { + SwitchSave = new global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuSwitchSave(); + } + input.ReadMessage(SwitchSave); + break; + } + case 34: { + if (useDefaultConfig_ == null) { + UseDefaultConfig = new global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuUseDefaultConfig(); + } + input.ReadMessage(UseDefaultConfig); + break; + } + case 42: { + if (aiRecommendedSwitch_ == null) { + AiRecommendedSwitch = new global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuAiRecommendedSwitch(); + } + input.ReadMessage(AiRecommendedSwitch); + break; + } + case 50: { + if (aiRecommendedLevel_ == null) { + AiRecommendedLevel = new global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuAiRecommendedLevel(); + } + input.ReadMessage(AiRecommendedLevel); + break; + } + case 58: { + if (blocktop_ == null) { + Blocktop = new global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuBlocktop(); + } + input.ReadMessage(Blocktop); + break; + } + case 66: { + if (blockscroll_ == null) { + Blockscroll = new global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuBlockscroll(); + } + input.ReadMessage(Blockscroll); + break; + } + case 74: { + if (blockbottom_ == null) { + Blockbottom = new global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuBlockbottom(); + } + input.ReadMessage(Blockbottom); + break; + } + case 82: { + if (blockcolorful_ == null) { + Blockcolorful = new global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuBlockcolorful(); + } + input.ReadMessage(Blockcolorful); + break; + } + case 90: { + if (blockrepeat_ == null) { + Blockrepeat = new global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuBlockrepeat(); + } + input.ReadMessage(Blockrepeat); + break; + } + case 98: { + if (blockspecial_ == null) { + Blockspecial = new global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuBlockspecial(); + } + input.ReadMessage(Blockspecial); + break; + } + case 106: { + if (opacity_ == null) { + Opacity = new global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuOpacity(); + } + input.ReadMessage(Opacity); + break; + } + case 114: { + if (scalingfactor_ == null) { + Scalingfactor = new global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuScalingfactor(); + } + input.ReadMessage(Scalingfactor); + break; + } + case 122: { + if (domain_ == null) { + Domain = new global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuDomain(); + } + input.ReadMessage(Domain); + break; + } + case 130: { + if (speed_ == null) { + Speed = new global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuSpeed(); + } + input.ReadMessage(Speed); + break; + } + case 138: { + if (enableblocklist_ == null) { + Enableblocklist = new global::Bilibili.Community.Service.Dm.V1.PlayerDanmakuEnableblocklist(); + } + input.ReadMessage(Enableblocklist); + break; + } + case 146: { + if (inlinePlayerDanmakuSwitch_ == null) { + InlinePlayerDanmakuSwitch = new global::Bilibili.Community.Service.Dm.V1.InlinePlayerDanmakuSwitch(); + } + input.ReadMessage(InlinePlayerDanmakuSwitch); + break; + } + } + } + } + #endif + + } + + /// + /// 修改弹幕配置-响应 + /// + public sealed partial class Response : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Response()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pbr::MessageDescriptor Descriptor { + get { return global::Bilibili.Community.Service.Dm.V1.DmReflection.Descriptor.MessageTypes[18]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public Response() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public Response(Response other) : this() { + code_ = other.code_; + message_ = other.message_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public Response Clone() { + return new Response(this); + } + + /// Field number for the "code" field. + public const int CodeFieldNumber = 1; + private int code_; + /// + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int Code { + get { return code_; } + set { + code_ = value; + } + } + + /// Field number for the "message" field. + public const int MessageFieldNumber = 2; + private string message_ = ""; + /// + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public string Message { + get { return message_; } + set { + message_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as Response); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(Response other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Code != other.Code) return false; + if (Message != other.Message) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override int GetHashCode() { + int hash = 1; + if (Code != 0) hash ^= Code.GetHashCode(); + if (Message.Length != 0) hash ^= Message.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void WriteTo(pb::CodedOutputStream output) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + output.WriteRawMessage(this); + #else + if (Code != 0) { + output.WriteRawTag(8); + output.WriteInt32(Code); + } + if (Message.Length != 0) { + output.WriteRawTag(18); + output.WriteString(Message); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + if (Code != 0) { + output.WriteRawTag(8); + output.WriteInt32(Code); + } + if (Message.Length != 0) { + output.WriteRawTag(18); + output.WriteString(Message); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(ref output); + } + } + #endif + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int CalculateSize() { + int size = 0; + if (Code != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Code); + } + if (Message.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Message); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(Response other) { + if (other == null) { + return; + } + if (other.Code != 0) { + Code = other.Code; + } + if (other.Message.Length != 0) { + Message = other.Message; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(pb::CodedInputStream input) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + input.ReadRawMessage(this); + #else + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Code = input.ReadInt32(); + break; + } + case 18: { + Message = input.ReadString(); + break; + } + } + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 8: { + Code = input.ReadInt32(); + break; + } + case 18: { + Message = input.ReadString(); + break; + } + } + } + } + #endif + + } + + /// + /// 弹幕ai云屏蔽条目 + /// + public sealed partial class DanmakuFlag : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new DanmakuFlag()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pbr::MessageDescriptor Descriptor { + get { return global::Bilibili.Community.Service.Dm.V1.DmReflection.Descriptor.MessageTypes[19]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public DanmakuFlag() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public DanmakuFlag(DanmakuFlag other) : this() { + dmid_ = other.dmid_; + flag_ = other.flag_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public DanmakuFlag Clone() { + return new DanmakuFlag(this); + } + + /// Field number for the "dmid" field. + public const int DmidFieldNumber = 1; + private long dmid_; + /// + /// 弹幕dmid + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public long Dmid { + get { return dmid_; } + set { + dmid_ = value; + } + } + + /// Field number for the "flag" field. + public const int FlagFieldNumber = 2; + private uint flag_; + /// + /// 评分 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public uint Flag { + get { return flag_; } + set { + flag_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as DanmakuFlag); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(DanmakuFlag other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Dmid != other.Dmid) return false; + if (Flag != other.Flag) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override int GetHashCode() { + int hash = 1; + if (Dmid != 0L) hash ^= Dmid.GetHashCode(); + if (Flag != 0) hash ^= Flag.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void WriteTo(pb::CodedOutputStream output) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + output.WriteRawMessage(this); + #else + if (Dmid != 0L) { + output.WriteRawTag(8); + output.WriteInt64(Dmid); + } + if (Flag != 0) { + output.WriteRawTag(16); + output.WriteUInt32(Flag); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + if (Dmid != 0L) { + output.WriteRawTag(8); + output.WriteInt64(Dmid); + } + if (Flag != 0) { + output.WriteRawTag(16); + output.WriteUInt32(Flag); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(ref output); + } + } + #endif + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int CalculateSize() { + int size = 0; + if (Dmid != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(Dmid); + } + if (Flag != 0) { + size += 1 + pb::CodedOutputStream.ComputeUInt32Size(Flag); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(DanmakuFlag other) { + if (other == null) { + return; + } + if (other.Dmid != 0L) { + Dmid = other.Dmid; + } + if (other.Flag != 0) { + Flag = other.Flag; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(pb::CodedInputStream input) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + input.ReadRawMessage(this); + #else + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Dmid = input.ReadInt64(); + break; + } + case 16: { + Flag = input.ReadUInt32(); + break; + } + } + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 8: { + Dmid = input.ReadInt64(); + break; + } + case 16: { + Flag = input.ReadUInt32(); + break; + } + } + } + } + #endif + + } + + /// + /// 云屏蔽配置信息 + /// + public sealed partial class DanmakuFlagConfig : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new DanmakuFlagConfig()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pbr::MessageDescriptor Descriptor { + get { return global::Bilibili.Community.Service.Dm.V1.DmReflection.Descriptor.MessageTypes[20]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public DanmakuFlagConfig() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public DanmakuFlagConfig(DanmakuFlagConfig other) : this() { + recFlag_ = other.recFlag_; + recText_ = other.recText_; + recSwitch_ = other.recSwitch_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public DanmakuFlagConfig Clone() { + return new DanmakuFlagConfig(this); + } + + /// Field number for the "rec_flag" field. + public const int RecFlagFieldNumber = 1; + private int recFlag_; + /// + /// 云屏蔽等级 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int RecFlag { + get { return recFlag_; } + set { + recFlag_ = value; + } + } + + /// Field number for the "rec_text" field. + public const int RecTextFieldNumber = 2; + private string recText_ = ""; + /// + /// 云屏蔽文案 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public string RecText { + get { return recText_; } + set { + recText_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "rec_switch" field. + public const int RecSwitchFieldNumber = 3; + private int recSwitch_; + /// + /// 云屏蔽开关 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int RecSwitch { + get { return recSwitch_; } + set { + recSwitch_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as DanmakuFlagConfig); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(DanmakuFlagConfig other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (RecFlag != other.RecFlag) return false; + if (RecText != other.RecText) return false; + if (RecSwitch != other.RecSwitch) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override int GetHashCode() { + int hash = 1; + if (RecFlag != 0) hash ^= RecFlag.GetHashCode(); + if (RecText.Length != 0) hash ^= RecText.GetHashCode(); + if (RecSwitch != 0) hash ^= RecSwitch.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void WriteTo(pb::CodedOutputStream output) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + output.WriteRawMessage(this); + #else + if (RecFlag != 0) { + output.WriteRawTag(8); + output.WriteInt32(RecFlag); + } + if (RecText.Length != 0) { + output.WriteRawTag(18); + output.WriteString(RecText); + } + if (RecSwitch != 0) { + output.WriteRawTag(24); + output.WriteInt32(RecSwitch); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + if (RecFlag != 0) { + output.WriteRawTag(8); + output.WriteInt32(RecFlag); + } + if (RecText.Length != 0) { + output.WriteRawTag(18); + output.WriteString(RecText); + } + if (RecSwitch != 0) { + output.WriteRawTag(24); + output.WriteInt32(RecSwitch); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(ref output); + } + } + #endif + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int CalculateSize() { + int size = 0; + if (RecFlag != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(RecFlag); + } + if (RecText.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(RecText); + } + if (RecSwitch != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(RecSwitch); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(DanmakuFlagConfig other) { + if (other == null) { + return; + } + if (other.RecFlag != 0) { + RecFlag = other.RecFlag; + } + if (other.RecText.Length != 0) { + RecText = other.RecText; + } + if (other.RecSwitch != 0) { + RecSwitch = other.RecSwitch; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(pb::CodedInputStream input) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + input.ReadRawMessage(this); + #else + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + RecFlag = input.ReadInt32(); + break; + } + case 18: { + RecText = input.ReadString(); + break; + } + case 24: { + RecSwitch = input.ReadInt32(); + break; + } + } + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 8: { + RecFlag = input.ReadInt32(); + break; + } + case 18: { + RecText = input.ReadString(); + break; + } + case 24: { + RecSwitch = input.ReadInt32(); + break; + } + } + } + } + #endif + + } + + /// + /// 弹幕ai云屏蔽列表 + /// + public sealed partial class DanmakuAIFlag : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new DanmakuAIFlag()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pbr::MessageDescriptor Descriptor { + get { return global::Bilibili.Community.Service.Dm.V1.DmReflection.Descriptor.MessageTypes[21]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public DanmakuAIFlag() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public DanmakuAIFlag(DanmakuAIFlag other) : this() { + dmFlags_ = other.dmFlags_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public DanmakuAIFlag Clone() { + return new DanmakuAIFlag(this); + } + + /// Field number for the "dm_flags" field. + public const int DmFlagsFieldNumber = 1; + private static readonly pb::FieldCodec _repeated_dmFlags_codec + = pb::FieldCodec.ForMessage(10, global::Bilibili.Community.Service.Dm.V1.DanmakuFlag.Parser); + private readonly pbc::RepeatedField dmFlags_ = new pbc::RepeatedField(); + /// + /// 弹幕ai云屏蔽条目 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public pbc::RepeatedField DmFlags { + get { return dmFlags_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as DanmakuAIFlag); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(DanmakuAIFlag other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if(!dmFlags_.Equals(other.dmFlags_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override int GetHashCode() { + int hash = 1; + hash ^= dmFlags_.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void WriteTo(pb::CodedOutputStream output) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + output.WriteRawMessage(this); + #else + dmFlags_.WriteTo(output, _repeated_dmFlags_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + dmFlags_.WriteTo(ref output, _repeated_dmFlags_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(ref output); + } + } + #endif + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int CalculateSize() { + int size = 0; + size += dmFlags_.CalculateSize(_repeated_dmFlags_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(DanmakuAIFlag other) { + if (other == null) { + return; + } + dmFlags_.Add(other.dmFlags_); + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(pb::CodedInputStream input) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + input.ReadRawMessage(this); + #else + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + dmFlags_.AddEntriesFrom(input, _repeated_dmFlags_codec); + break; + } + } + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 10: { + dmFlags_.AddEntriesFrom(ref input, _repeated_dmFlags_codec); + break; + } + } + } + } + #endif + + } + + /// + /// 弹幕配置信息 + /// + public sealed partial class DanmuPlayerViewConfig : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new DanmuPlayerViewConfig()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pbr::MessageDescriptor Descriptor { + get { return global::Bilibili.Community.Service.Dm.V1.DmReflection.Descriptor.MessageTypes[22]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public DanmuPlayerViewConfig() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public DanmuPlayerViewConfig(DanmuPlayerViewConfig other) : this() { + danmukuDefaultPlayerConfig_ = other.danmukuDefaultPlayerConfig_ != null ? other.danmukuDefaultPlayerConfig_.Clone() : null; + danmukuPlayerConfig_ = other.danmukuPlayerConfig_ != null ? other.danmukuPlayerConfig_.Clone() : null; + danmukuPlayerDynamicConfig_ = other.danmukuPlayerDynamicConfig_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public DanmuPlayerViewConfig Clone() { + return new DanmuPlayerViewConfig(this); + } + + /// Field number for the "danmuku_default_player_config" field. + public const int DanmukuDefaultPlayerConfigFieldNumber = 1; + private global::Bilibili.Community.Service.Dm.V1.DanmuDefaultPlayerConfig danmukuDefaultPlayerConfig_; + /// + /// 弹幕默认配置 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public global::Bilibili.Community.Service.Dm.V1.DanmuDefaultPlayerConfig DanmukuDefaultPlayerConfig { + get { return danmukuDefaultPlayerConfig_; } + set { + danmukuDefaultPlayerConfig_ = value; + } + } + + /// Field number for the "danmuku_player_config" field. + public const int DanmukuPlayerConfigFieldNumber = 2; + private global::Bilibili.Community.Service.Dm.V1.DanmuPlayerConfig danmukuPlayerConfig_; + /// + /// 弹幕用户配置 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public global::Bilibili.Community.Service.Dm.V1.DanmuPlayerConfig DanmukuPlayerConfig { + get { return danmukuPlayerConfig_; } + set { + danmukuPlayerConfig_ = value; + } + } + + /// Field number for the "danmuku_player_dynamic_config" field. + public const int DanmukuPlayerDynamicConfigFieldNumber = 3; + private static readonly pb::FieldCodec _repeated_danmukuPlayerDynamicConfig_codec + = pb::FieldCodec.ForMessage(26, global::Bilibili.Community.Service.Dm.V1.DanmuPlayerDynamicConfig.Parser); + private readonly pbc::RepeatedField danmukuPlayerDynamicConfig_ = new pbc::RepeatedField(); + /// + /// 弹幕显示区域自动配置列表 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public pbc::RepeatedField DanmukuPlayerDynamicConfig { + get { return danmukuPlayerDynamicConfig_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as DanmuPlayerViewConfig); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(DanmuPlayerViewConfig other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(DanmukuDefaultPlayerConfig, other.DanmukuDefaultPlayerConfig)) return false; + if (!object.Equals(DanmukuPlayerConfig, other.DanmukuPlayerConfig)) return false; + if(!danmukuPlayerDynamicConfig_.Equals(other.danmukuPlayerDynamicConfig_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override int GetHashCode() { + int hash = 1; + if (danmukuDefaultPlayerConfig_ != null) hash ^= DanmukuDefaultPlayerConfig.GetHashCode(); + if (danmukuPlayerConfig_ != null) hash ^= DanmukuPlayerConfig.GetHashCode(); + hash ^= danmukuPlayerDynamicConfig_.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void WriteTo(pb::CodedOutputStream output) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + output.WriteRawMessage(this); + #else + if (danmukuDefaultPlayerConfig_ != null) { + output.WriteRawTag(10); + output.WriteMessage(DanmukuDefaultPlayerConfig); + } + if (danmukuPlayerConfig_ != null) { + output.WriteRawTag(18); + output.WriteMessage(DanmukuPlayerConfig); + } + danmukuPlayerDynamicConfig_.WriteTo(output, _repeated_danmukuPlayerDynamicConfig_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + if (danmukuDefaultPlayerConfig_ != null) { + output.WriteRawTag(10); + output.WriteMessage(DanmukuDefaultPlayerConfig); + } + if (danmukuPlayerConfig_ != null) { + output.WriteRawTag(18); + output.WriteMessage(DanmukuPlayerConfig); + } + danmukuPlayerDynamicConfig_.WriteTo(ref output, _repeated_danmukuPlayerDynamicConfig_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(ref output); + } + } + #endif + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int CalculateSize() { + int size = 0; + if (danmukuDefaultPlayerConfig_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(DanmukuDefaultPlayerConfig); + } + if (danmukuPlayerConfig_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(DanmukuPlayerConfig); + } + size += danmukuPlayerDynamicConfig_.CalculateSize(_repeated_danmukuPlayerDynamicConfig_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(DanmuPlayerViewConfig other) { + if (other == null) { + return; + } + if (other.danmukuDefaultPlayerConfig_ != null) { + if (danmukuDefaultPlayerConfig_ == null) { + DanmukuDefaultPlayerConfig = new global::Bilibili.Community.Service.Dm.V1.DanmuDefaultPlayerConfig(); + } + DanmukuDefaultPlayerConfig.MergeFrom(other.DanmukuDefaultPlayerConfig); + } + if (other.danmukuPlayerConfig_ != null) { + if (danmukuPlayerConfig_ == null) { + DanmukuPlayerConfig = new global::Bilibili.Community.Service.Dm.V1.DanmuPlayerConfig(); + } + DanmukuPlayerConfig.MergeFrom(other.DanmukuPlayerConfig); + } + danmukuPlayerDynamicConfig_.Add(other.danmukuPlayerDynamicConfig_); + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(pb::CodedInputStream input) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + input.ReadRawMessage(this); + #else + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + if (danmukuDefaultPlayerConfig_ == null) { + DanmukuDefaultPlayerConfig = new global::Bilibili.Community.Service.Dm.V1.DanmuDefaultPlayerConfig(); + } + input.ReadMessage(DanmukuDefaultPlayerConfig); + break; + } + case 18: { + if (danmukuPlayerConfig_ == null) { + DanmukuPlayerConfig = new global::Bilibili.Community.Service.Dm.V1.DanmuPlayerConfig(); + } + input.ReadMessage(DanmukuPlayerConfig); + break; + } + case 26: { + danmukuPlayerDynamicConfig_.AddEntriesFrom(input, _repeated_danmukuPlayerDynamicConfig_codec); + break; + } + } + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 10: { + if (danmukuDefaultPlayerConfig_ == null) { + DanmukuDefaultPlayerConfig = new global::Bilibili.Community.Service.Dm.V1.DanmuDefaultPlayerConfig(); + } + input.ReadMessage(DanmukuDefaultPlayerConfig); + break; + } + case 18: { + if (danmukuPlayerConfig_ == null) { + DanmukuPlayerConfig = new global::Bilibili.Community.Service.Dm.V1.DanmuPlayerConfig(); + } + input.ReadMessage(DanmukuPlayerConfig); + break; + } + case 26: { + danmukuPlayerDynamicConfig_.AddEntriesFrom(ref input, _repeated_danmukuPlayerDynamicConfig_codec); + break; + } + } + } + } + #endif + + } + + /// + /// 弹幕默认配置 + /// + public sealed partial class DanmuDefaultPlayerConfig : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new DanmuDefaultPlayerConfig()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pbr::MessageDescriptor Descriptor { + get { return global::Bilibili.Community.Service.Dm.V1.DmReflection.Descriptor.MessageTypes[23]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public DanmuDefaultPlayerConfig() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public DanmuDefaultPlayerConfig(DanmuDefaultPlayerConfig other) : this() { + playerDanmakuUseDefaultConfig_ = other.playerDanmakuUseDefaultConfig_; + playerDanmakuAiRecommendedSwitch_ = other.playerDanmakuAiRecommendedSwitch_; + playerDanmakuAiRecommendedLevel_ = other.playerDanmakuAiRecommendedLevel_; + playerDanmakuBlocktop_ = other.playerDanmakuBlocktop_; + playerDanmakuBlockscroll_ = other.playerDanmakuBlockscroll_; + playerDanmakuBlockbottom_ = other.playerDanmakuBlockbottom_; + playerDanmakuBlockcolorful_ = other.playerDanmakuBlockcolorful_; + playerDanmakuBlockrepeat_ = other.playerDanmakuBlockrepeat_; + playerDanmakuBlockspecial_ = other.playerDanmakuBlockspecial_; + playerDanmakuOpacity_ = other.playerDanmakuOpacity_; + playerDanmakuScalingfactor_ = other.playerDanmakuScalingfactor_; + playerDanmakuDomain_ = other.playerDanmakuDomain_; + playerDanmakuSpeed_ = other.playerDanmakuSpeed_; + inlinePlayerDanmakuSwitch_ = other.inlinePlayerDanmakuSwitch_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public DanmuDefaultPlayerConfig Clone() { + return new DanmuDefaultPlayerConfig(this); + } + + /// Field number for the "player_danmaku_use_default_config" field. + public const int PlayerDanmakuUseDefaultConfigFieldNumber = 1; + private bool playerDanmakuUseDefaultConfig_; + /// + /// 是否使用推荐弹幕设置 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool PlayerDanmakuUseDefaultConfig { + get { return playerDanmakuUseDefaultConfig_; } + set { + playerDanmakuUseDefaultConfig_ = value; + } + } + + /// Field number for the "player_danmaku_ai_recommended_switch" field. + public const int PlayerDanmakuAiRecommendedSwitchFieldNumber = 4; + private bool playerDanmakuAiRecommendedSwitch_; + /// + /// 是否开启智能云屏蔽 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool PlayerDanmakuAiRecommendedSwitch { + get { return playerDanmakuAiRecommendedSwitch_; } + set { + playerDanmakuAiRecommendedSwitch_ = value; + } + } + + /// Field number for the "player_danmaku_ai_recommended_level" field. + public const int PlayerDanmakuAiRecommendedLevelFieldNumber = 5; + private int playerDanmakuAiRecommendedLevel_; + /// + /// 智能云屏蔽等级 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int PlayerDanmakuAiRecommendedLevel { + get { return playerDanmakuAiRecommendedLevel_; } + set { + playerDanmakuAiRecommendedLevel_ = value; + } + } + + /// Field number for the "player_danmaku_blocktop" field. + public const int PlayerDanmakuBlocktopFieldNumber = 6; + private bool playerDanmakuBlocktop_; + /// + /// 是否屏蔽顶端弹幕 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool PlayerDanmakuBlocktop { + get { return playerDanmakuBlocktop_; } + set { + playerDanmakuBlocktop_ = value; + } + } + + /// Field number for the "player_danmaku_blockscroll" field. + public const int PlayerDanmakuBlockscrollFieldNumber = 7; + private bool playerDanmakuBlockscroll_; + /// + /// 是否屏蔽滚动弹幕 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool PlayerDanmakuBlockscroll { + get { return playerDanmakuBlockscroll_; } + set { + playerDanmakuBlockscroll_ = value; + } + } + + /// Field number for the "player_danmaku_blockbottom" field. + public const int PlayerDanmakuBlockbottomFieldNumber = 8; + private bool playerDanmakuBlockbottom_; + /// + /// 是否屏蔽底端弹幕 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool PlayerDanmakuBlockbottom { + get { return playerDanmakuBlockbottom_; } + set { + playerDanmakuBlockbottom_ = value; + } + } + + /// Field number for the "player_danmaku_blockcolorful" field. + public const int PlayerDanmakuBlockcolorfulFieldNumber = 9; + private bool playerDanmakuBlockcolorful_; + /// + /// 是否屏蔽彩色弹幕 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool PlayerDanmakuBlockcolorful { + get { return playerDanmakuBlockcolorful_; } + set { + playerDanmakuBlockcolorful_ = value; + } + } + + /// Field number for the "player_danmaku_blockrepeat" field. + public const int PlayerDanmakuBlockrepeatFieldNumber = 10; + private bool playerDanmakuBlockrepeat_; + /// + /// 是否屏蔽重复弹幕 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool PlayerDanmakuBlockrepeat { + get { return playerDanmakuBlockrepeat_; } + set { + playerDanmakuBlockrepeat_ = value; + } + } + + /// Field number for the "player_danmaku_blockspecial" field. + public const int PlayerDanmakuBlockspecialFieldNumber = 11; + private bool playerDanmakuBlockspecial_; + /// + /// 是否屏蔽高级弹幕 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool PlayerDanmakuBlockspecial { + get { return playerDanmakuBlockspecial_; } + set { + playerDanmakuBlockspecial_ = value; + } + } + + /// Field number for the "player_danmaku_opacity" field. + public const int PlayerDanmakuOpacityFieldNumber = 12; + private float playerDanmakuOpacity_; + /// + /// 弹幕不透明度 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public float PlayerDanmakuOpacity { + get { return playerDanmakuOpacity_; } + set { + playerDanmakuOpacity_ = value; + } + } + + /// Field number for the "player_danmaku_scalingfactor" field. + public const int PlayerDanmakuScalingfactorFieldNumber = 13; + private float playerDanmakuScalingfactor_; + /// + /// 弹幕缩放比例 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public float PlayerDanmakuScalingfactor { + get { return playerDanmakuScalingfactor_; } + set { + playerDanmakuScalingfactor_ = value; + } + } + + /// Field number for the "player_danmaku_domain" field. + public const int PlayerDanmakuDomainFieldNumber = 14; + private float playerDanmakuDomain_; + /// + /// 弹幕显示区域 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public float PlayerDanmakuDomain { + get { return playerDanmakuDomain_; } + set { + playerDanmakuDomain_ = value; + } + } + + /// Field number for the "player_danmaku_speed" field. + public const int PlayerDanmakuSpeedFieldNumber = 15; + private int playerDanmakuSpeed_; + /// + /// 弹幕速度 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int PlayerDanmakuSpeed { + get { return playerDanmakuSpeed_; } + set { + playerDanmakuSpeed_ = value; + } + } + + /// Field number for the "inline_player_danmaku_switch" field. + public const int InlinePlayerDanmakuSwitchFieldNumber = 16; + private bool inlinePlayerDanmakuSwitch_; + /// + /// 是否开启弹幕 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool InlinePlayerDanmakuSwitch { + get { return inlinePlayerDanmakuSwitch_; } + set { + inlinePlayerDanmakuSwitch_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as DanmuDefaultPlayerConfig); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(DanmuDefaultPlayerConfig other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (PlayerDanmakuUseDefaultConfig != other.PlayerDanmakuUseDefaultConfig) return false; + if (PlayerDanmakuAiRecommendedSwitch != other.PlayerDanmakuAiRecommendedSwitch) return false; + if (PlayerDanmakuAiRecommendedLevel != other.PlayerDanmakuAiRecommendedLevel) return false; + if (PlayerDanmakuBlocktop != other.PlayerDanmakuBlocktop) return false; + if (PlayerDanmakuBlockscroll != other.PlayerDanmakuBlockscroll) return false; + if (PlayerDanmakuBlockbottom != other.PlayerDanmakuBlockbottom) return false; + if (PlayerDanmakuBlockcolorful != other.PlayerDanmakuBlockcolorful) return false; + if (PlayerDanmakuBlockrepeat != other.PlayerDanmakuBlockrepeat) return false; + if (PlayerDanmakuBlockspecial != other.PlayerDanmakuBlockspecial) return false; + if (!pbc::ProtobufEqualityComparers.BitwiseSingleEqualityComparer.Equals(PlayerDanmakuOpacity, other.PlayerDanmakuOpacity)) return false; + if (!pbc::ProtobufEqualityComparers.BitwiseSingleEqualityComparer.Equals(PlayerDanmakuScalingfactor, other.PlayerDanmakuScalingfactor)) return false; + if (!pbc::ProtobufEqualityComparers.BitwiseSingleEqualityComparer.Equals(PlayerDanmakuDomain, other.PlayerDanmakuDomain)) return false; + if (PlayerDanmakuSpeed != other.PlayerDanmakuSpeed) return false; + if (InlinePlayerDanmakuSwitch != other.InlinePlayerDanmakuSwitch) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override int GetHashCode() { + int hash = 1; + if (PlayerDanmakuUseDefaultConfig != false) hash ^= PlayerDanmakuUseDefaultConfig.GetHashCode(); + if (PlayerDanmakuAiRecommendedSwitch != false) hash ^= PlayerDanmakuAiRecommendedSwitch.GetHashCode(); + if (PlayerDanmakuAiRecommendedLevel != 0) hash ^= PlayerDanmakuAiRecommendedLevel.GetHashCode(); + if (PlayerDanmakuBlocktop != false) hash ^= PlayerDanmakuBlocktop.GetHashCode(); + if (PlayerDanmakuBlockscroll != false) hash ^= PlayerDanmakuBlockscroll.GetHashCode(); + if (PlayerDanmakuBlockbottom != false) hash ^= PlayerDanmakuBlockbottom.GetHashCode(); + if (PlayerDanmakuBlockcolorful != false) hash ^= PlayerDanmakuBlockcolorful.GetHashCode(); + if (PlayerDanmakuBlockrepeat != false) hash ^= PlayerDanmakuBlockrepeat.GetHashCode(); + if (PlayerDanmakuBlockspecial != false) hash ^= PlayerDanmakuBlockspecial.GetHashCode(); + if (PlayerDanmakuOpacity != 0F) hash ^= pbc::ProtobufEqualityComparers.BitwiseSingleEqualityComparer.GetHashCode(PlayerDanmakuOpacity); + if (PlayerDanmakuScalingfactor != 0F) hash ^= pbc::ProtobufEqualityComparers.BitwiseSingleEqualityComparer.GetHashCode(PlayerDanmakuScalingfactor); + if (PlayerDanmakuDomain != 0F) hash ^= pbc::ProtobufEqualityComparers.BitwiseSingleEqualityComparer.GetHashCode(PlayerDanmakuDomain); + if (PlayerDanmakuSpeed != 0) hash ^= PlayerDanmakuSpeed.GetHashCode(); + if (InlinePlayerDanmakuSwitch != false) hash ^= InlinePlayerDanmakuSwitch.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void WriteTo(pb::CodedOutputStream output) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + output.WriteRawMessage(this); + #else + if (PlayerDanmakuUseDefaultConfig != false) { + output.WriteRawTag(8); + output.WriteBool(PlayerDanmakuUseDefaultConfig); + } + if (PlayerDanmakuAiRecommendedSwitch != false) { + output.WriteRawTag(32); + output.WriteBool(PlayerDanmakuAiRecommendedSwitch); + } + if (PlayerDanmakuAiRecommendedLevel != 0) { + output.WriteRawTag(40); + output.WriteInt32(PlayerDanmakuAiRecommendedLevel); + } + if (PlayerDanmakuBlocktop != false) { + output.WriteRawTag(48); + output.WriteBool(PlayerDanmakuBlocktop); + } + if (PlayerDanmakuBlockscroll != false) { + output.WriteRawTag(56); + output.WriteBool(PlayerDanmakuBlockscroll); + } + if (PlayerDanmakuBlockbottom != false) { + output.WriteRawTag(64); + output.WriteBool(PlayerDanmakuBlockbottom); + } + if (PlayerDanmakuBlockcolorful != false) { + output.WriteRawTag(72); + output.WriteBool(PlayerDanmakuBlockcolorful); + } + if (PlayerDanmakuBlockrepeat != false) { + output.WriteRawTag(80); + output.WriteBool(PlayerDanmakuBlockrepeat); + } + if (PlayerDanmakuBlockspecial != false) { + output.WriteRawTag(88); + output.WriteBool(PlayerDanmakuBlockspecial); + } + if (PlayerDanmakuOpacity != 0F) { + output.WriteRawTag(101); + output.WriteFloat(PlayerDanmakuOpacity); + } + if (PlayerDanmakuScalingfactor != 0F) { + output.WriteRawTag(109); + output.WriteFloat(PlayerDanmakuScalingfactor); + } + if (PlayerDanmakuDomain != 0F) { + output.WriteRawTag(117); + output.WriteFloat(PlayerDanmakuDomain); + } + if (PlayerDanmakuSpeed != 0) { + output.WriteRawTag(120); + output.WriteInt32(PlayerDanmakuSpeed); + } + if (InlinePlayerDanmakuSwitch != false) { + output.WriteRawTag(128, 1); + output.WriteBool(InlinePlayerDanmakuSwitch); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + if (PlayerDanmakuUseDefaultConfig != false) { + output.WriteRawTag(8); + output.WriteBool(PlayerDanmakuUseDefaultConfig); + } + if (PlayerDanmakuAiRecommendedSwitch != false) { + output.WriteRawTag(32); + output.WriteBool(PlayerDanmakuAiRecommendedSwitch); + } + if (PlayerDanmakuAiRecommendedLevel != 0) { + output.WriteRawTag(40); + output.WriteInt32(PlayerDanmakuAiRecommendedLevel); + } + if (PlayerDanmakuBlocktop != false) { + output.WriteRawTag(48); + output.WriteBool(PlayerDanmakuBlocktop); + } + if (PlayerDanmakuBlockscroll != false) { + output.WriteRawTag(56); + output.WriteBool(PlayerDanmakuBlockscroll); + } + if (PlayerDanmakuBlockbottom != false) { + output.WriteRawTag(64); + output.WriteBool(PlayerDanmakuBlockbottom); + } + if (PlayerDanmakuBlockcolorful != false) { + output.WriteRawTag(72); + output.WriteBool(PlayerDanmakuBlockcolorful); + } + if (PlayerDanmakuBlockrepeat != false) { + output.WriteRawTag(80); + output.WriteBool(PlayerDanmakuBlockrepeat); + } + if (PlayerDanmakuBlockspecial != false) { + output.WriteRawTag(88); + output.WriteBool(PlayerDanmakuBlockspecial); + } + if (PlayerDanmakuOpacity != 0F) { + output.WriteRawTag(101); + output.WriteFloat(PlayerDanmakuOpacity); + } + if (PlayerDanmakuScalingfactor != 0F) { + output.WriteRawTag(109); + output.WriteFloat(PlayerDanmakuScalingfactor); + } + if (PlayerDanmakuDomain != 0F) { + output.WriteRawTag(117); + output.WriteFloat(PlayerDanmakuDomain); + } + if (PlayerDanmakuSpeed != 0) { + output.WriteRawTag(120); + output.WriteInt32(PlayerDanmakuSpeed); + } + if (InlinePlayerDanmakuSwitch != false) { + output.WriteRawTag(128, 1); + output.WriteBool(InlinePlayerDanmakuSwitch); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(ref output); + } + } + #endif + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int CalculateSize() { + int size = 0; + if (PlayerDanmakuUseDefaultConfig != false) { + size += 1 + 1; + } + if (PlayerDanmakuAiRecommendedSwitch != false) { + size += 1 + 1; + } + if (PlayerDanmakuAiRecommendedLevel != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(PlayerDanmakuAiRecommendedLevel); + } + if (PlayerDanmakuBlocktop != false) { + size += 1 + 1; + } + if (PlayerDanmakuBlockscroll != false) { + size += 1 + 1; + } + if (PlayerDanmakuBlockbottom != false) { + size += 1 + 1; + } + if (PlayerDanmakuBlockcolorful != false) { + size += 1 + 1; + } + if (PlayerDanmakuBlockrepeat != false) { + size += 1 + 1; + } + if (PlayerDanmakuBlockspecial != false) { + size += 1 + 1; + } + if (PlayerDanmakuOpacity != 0F) { + size += 1 + 4; + } + if (PlayerDanmakuScalingfactor != 0F) { + size += 1 + 4; + } + if (PlayerDanmakuDomain != 0F) { + size += 1 + 4; + } + if (PlayerDanmakuSpeed != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(PlayerDanmakuSpeed); + } + if (InlinePlayerDanmakuSwitch != false) { + size += 2 + 1; + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(DanmuDefaultPlayerConfig other) { + if (other == null) { + return; + } + if (other.PlayerDanmakuUseDefaultConfig != false) { + PlayerDanmakuUseDefaultConfig = other.PlayerDanmakuUseDefaultConfig; + } + if (other.PlayerDanmakuAiRecommendedSwitch != false) { + PlayerDanmakuAiRecommendedSwitch = other.PlayerDanmakuAiRecommendedSwitch; + } + if (other.PlayerDanmakuAiRecommendedLevel != 0) { + PlayerDanmakuAiRecommendedLevel = other.PlayerDanmakuAiRecommendedLevel; + } + if (other.PlayerDanmakuBlocktop != false) { + PlayerDanmakuBlocktop = other.PlayerDanmakuBlocktop; + } + if (other.PlayerDanmakuBlockscroll != false) { + PlayerDanmakuBlockscroll = other.PlayerDanmakuBlockscroll; + } + if (other.PlayerDanmakuBlockbottom != false) { + PlayerDanmakuBlockbottom = other.PlayerDanmakuBlockbottom; + } + if (other.PlayerDanmakuBlockcolorful != false) { + PlayerDanmakuBlockcolorful = other.PlayerDanmakuBlockcolorful; + } + if (other.PlayerDanmakuBlockrepeat != false) { + PlayerDanmakuBlockrepeat = other.PlayerDanmakuBlockrepeat; + } + if (other.PlayerDanmakuBlockspecial != false) { + PlayerDanmakuBlockspecial = other.PlayerDanmakuBlockspecial; + } + if (other.PlayerDanmakuOpacity != 0F) { + PlayerDanmakuOpacity = other.PlayerDanmakuOpacity; + } + if (other.PlayerDanmakuScalingfactor != 0F) { + PlayerDanmakuScalingfactor = other.PlayerDanmakuScalingfactor; + } + if (other.PlayerDanmakuDomain != 0F) { + PlayerDanmakuDomain = other.PlayerDanmakuDomain; + } + if (other.PlayerDanmakuSpeed != 0) { + PlayerDanmakuSpeed = other.PlayerDanmakuSpeed; + } + if (other.InlinePlayerDanmakuSwitch != false) { + InlinePlayerDanmakuSwitch = other.InlinePlayerDanmakuSwitch; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(pb::CodedInputStream input) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + input.ReadRawMessage(this); + #else + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + PlayerDanmakuUseDefaultConfig = input.ReadBool(); + break; + } + case 32: { + PlayerDanmakuAiRecommendedSwitch = input.ReadBool(); + break; + } + case 40: { + PlayerDanmakuAiRecommendedLevel = input.ReadInt32(); + break; + } + case 48: { + PlayerDanmakuBlocktop = input.ReadBool(); + break; + } + case 56: { + PlayerDanmakuBlockscroll = input.ReadBool(); + break; + } + case 64: { + PlayerDanmakuBlockbottom = input.ReadBool(); + break; + } + case 72: { + PlayerDanmakuBlockcolorful = input.ReadBool(); + break; + } + case 80: { + PlayerDanmakuBlockrepeat = input.ReadBool(); + break; + } + case 88: { + PlayerDanmakuBlockspecial = input.ReadBool(); + break; + } + case 101: { + PlayerDanmakuOpacity = input.ReadFloat(); + break; + } + case 109: { + PlayerDanmakuScalingfactor = input.ReadFloat(); + break; + } + case 117: { + PlayerDanmakuDomain = input.ReadFloat(); + break; + } + case 120: { + PlayerDanmakuSpeed = input.ReadInt32(); + break; + } + case 128: { + InlinePlayerDanmakuSwitch = input.ReadBool(); + break; + } + } + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 8: { + PlayerDanmakuUseDefaultConfig = input.ReadBool(); + break; + } + case 32: { + PlayerDanmakuAiRecommendedSwitch = input.ReadBool(); + break; + } + case 40: { + PlayerDanmakuAiRecommendedLevel = input.ReadInt32(); + break; + } + case 48: { + PlayerDanmakuBlocktop = input.ReadBool(); + break; + } + case 56: { + PlayerDanmakuBlockscroll = input.ReadBool(); + break; + } + case 64: { + PlayerDanmakuBlockbottom = input.ReadBool(); + break; + } + case 72: { + PlayerDanmakuBlockcolorful = input.ReadBool(); + break; + } + case 80: { + PlayerDanmakuBlockrepeat = input.ReadBool(); + break; + } + case 88: { + PlayerDanmakuBlockspecial = input.ReadBool(); + break; + } + case 101: { + PlayerDanmakuOpacity = input.ReadFloat(); + break; + } + case 109: { + PlayerDanmakuScalingfactor = input.ReadFloat(); + break; + } + case 117: { + PlayerDanmakuDomain = input.ReadFloat(); + break; + } + case 120: { + PlayerDanmakuSpeed = input.ReadInt32(); + break; + } + case 128: { + InlinePlayerDanmakuSwitch = input.ReadBool(); + break; + } + } + } + } + #endif + + } + + /// + /// 弹幕配置 + /// + public sealed partial class DanmuPlayerConfig : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new DanmuPlayerConfig()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pbr::MessageDescriptor Descriptor { + get { return global::Bilibili.Community.Service.Dm.V1.DmReflection.Descriptor.MessageTypes[24]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public DanmuPlayerConfig() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public DanmuPlayerConfig(DanmuPlayerConfig other) : this() { + playerDanmakuSwitch_ = other.playerDanmakuSwitch_; + playerDanmakuSwitchSave_ = other.playerDanmakuSwitchSave_; + playerDanmakuUseDefaultConfig_ = other.playerDanmakuUseDefaultConfig_; + playerDanmakuAiRecommendedSwitch_ = other.playerDanmakuAiRecommendedSwitch_; + playerDanmakuAiRecommendedLevel_ = other.playerDanmakuAiRecommendedLevel_; + playerDanmakuBlocktop_ = other.playerDanmakuBlocktop_; + playerDanmakuBlockscroll_ = other.playerDanmakuBlockscroll_; + playerDanmakuBlockbottom_ = other.playerDanmakuBlockbottom_; + playerDanmakuBlockcolorful_ = other.playerDanmakuBlockcolorful_; + playerDanmakuBlockrepeat_ = other.playerDanmakuBlockrepeat_; + playerDanmakuBlockspecial_ = other.playerDanmakuBlockspecial_; + playerDanmakuOpacity_ = other.playerDanmakuOpacity_; + playerDanmakuScalingfactor_ = other.playerDanmakuScalingfactor_; + playerDanmakuDomain_ = other.playerDanmakuDomain_; + playerDanmakuSpeed_ = other.playerDanmakuSpeed_; + playerDanmakuEnableblocklist_ = other.playerDanmakuEnableblocklist_; + inlinePlayerDanmakuSwitch_ = other.inlinePlayerDanmakuSwitch_; + inlinePlayerDanmakuConfig_ = other.inlinePlayerDanmakuConfig_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public DanmuPlayerConfig Clone() { + return new DanmuPlayerConfig(this); + } + + /// Field number for the "player_danmaku_switch" field. + public const int PlayerDanmakuSwitchFieldNumber = 1; + private bool playerDanmakuSwitch_; + /// + /// 是否开启弹幕 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool PlayerDanmakuSwitch { + get { return playerDanmakuSwitch_; } + set { + playerDanmakuSwitch_ = value; + } + } + + /// Field number for the "player_danmaku_switch_save" field. + public const int PlayerDanmakuSwitchSaveFieldNumber = 2; + private bool playerDanmakuSwitchSave_; + /// + /// 是否记录弹幕开关设置 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool PlayerDanmakuSwitchSave { + get { return playerDanmakuSwitchSave_; } + set { + playerDanmakuSwitchSave_ = value; + } + } + + /// Field number for the "player_danmaku_use_default_config" field. + public const int PlayerDanmakuUseDefaultConfigFieldNumber = 3; + private bool playerDanmakuUseDefaultConfig_; + /// + /// 是否使用推荐弹幕设置 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool PlayerDanmakuUseDefaultConfig { + get { return playerDanmakuUseDefaultConfig_; } + set { + playerDanmakuUseDefaultConfig_ = value; + } + } + + /// Field number for the "player_danmaku_ai_recommended_switch" field. + public const int PlayerDanmakuAiRecommendedSwitchFieldNumber = 4; + private bool playerDanmakuAiRecommendedSwitch_; + /// + /// 是否开启智能云屏蔽 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool PlayerDanmakuAiRecommendedSwitch { + get { return playerDanmakuAiRecommendedSwitch_; } + set { + playerDanmakuAiRecommendedSwitch_ = value; + } + } + + /// Field number for the "player_danmaku_ai_recommended_level" field. + public const int PlayerDanmakuAiRecommendedLevelFieldNumber = 5; + private int playerDanmakuAiRecommendedLevel_; + /// + /// 智能云屏蔽等级 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int PlayerDanmakuAiRecommendedLevel { + get { return playerDanmakuAiRecommendedLevel_; } + set { + playerDanmakuAiRecommendedLevel_ = value; + } + } + + /// Field number for the "player_danmaku_blocktop" field. + public const int PlayerDanmakuBlocktopFieldNumber = 6; + private bool playerDanmakuBlocktop_; + /// + /// 是否屏蔽顶端弹幕 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool PlayerDanmakuBlocktop { + get { return playerDanmakuBlocktop_; } + set { + playerDanmakuBlocktop_ = value; + } + } + + /// Field number for the "player_danmaku_blockscroll" field. + public const int PlayerDanmakuBlockscrollFieldNumber = 7; + private bool playerDanmakuBlockscroll_; + /// + /// 是否屏蔽滚动弹幕 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool PlayerDanmakuBlockscroll { + get { return playerDanmakuBlockscroll_; } + set { + playerDanmakuBlockscroll_ = value; + } + } + + /// Field number for the "player_danmaku_blockbottom" field. + public const int PlayerDanmakuBlockbottomFieldNumber = 8; + private bool playerDanmakuBlockbottom_; + /// + /// 是否屏蔽底端弹幕 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool PlayerDanmakuBlockbottom { + get { return playerDanmakuBlockbottom_; } + set { + playerDanmakuBlockbottom_ = value; + } + } + + /// Field number for the "player_danmaku_blockcolorful" field. + public const int PlayerDanmakuBlockcolorfulFieldNumber = 9; + private bool playerDanmakuBlockcolorful_; + /// + /// 是否屏蔽彩色弹幕 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool PlayerDanmakuBlockcolorful { + get { return playerDanmakuBlockcolorful_; } + set { + playerDanmakuBlockcolorful_ = value; + } + } + + /// Field number for the "player_danmaku_blockrepeat" field. + public const int PlayerDanmakuBlockrepeatFieldNumber = 10; + private bool playerDanmakuBlockrepeat_; + /// + /// 是否屏蔽重复弹幕 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool PlayerDanmakuBlockrepeat { + get { return playerDanmakuBlockrepeat_; } + set { + playerDanmakuBlockrepeat_ = value; + } + } + + /// Field number for the "player_danmaku_blockspecial" field. + public const int PlayerDanmakuBlockspecialFieldNumber = 11; + private bool playerDanmakuBlockspecial_; + /// + /// 是否屏蔽高级弹幕 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool PlayerDanmakuBlockspecial { + get { return playerDanmakuBlockspecial_; } + set { + playerDanmakuBlockspecial_ = value; + } + } + + /// Field number for the "player_danmaku_opacity" field. + public const int PlayerDanmakuOpacityFieldNumber = 12; + private float playerDanmakuOpacity_; + /// + /// 弹幕不透明度 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public float PlayerDanmakuOpacity { + get { return playerDanmakuOpacity_; } + set { + playerDanmakuOpacity_ = value; + } + } + + /// Field number for the "player_danmaku_scalingfactor" field. + public const int PlayerDanmakuScalingfactorFieldNumber = 13; + private float playerDanmakuScalingfactor_; + /// + /// 弹幕缩放比例 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public float PlayerDanmakuScalingfactor { + get { return playerDanmakuScalingfactor_; } + set { + playerDanmakuScalingfactor_ = value; + } + } + + /// Field number for the "player_danmaku_domain" field. + public const int PlayerDanmakuDomainFieldNumber = 14; + private float playerDanmakuDomain_; + /// + /// 弹幕显示区域 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public float PlayerDanmakuDomain { + get { return playerDanmakuDomain_; } + set { + playerDanmakuDomain_ = value; + } + } + + /// Field number for the "player_danmaku_speed" field. + public const int PlayerDanmakuSpeedFieldNumber = 15; + private int playerDanmakuSpeed_; + /// + /// 弹幕速度 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int PlayerDanmakuSpeed { + get { return playerDanmakuSpeed_; } + set { + playerDanmakuSpeed_ = value; + } + } + + /// Field number for the "player_danmaku_enableblocklist" field. + public const int PlayerDanmakuEnableblocklistFieldNumber = 16; + private bool playerDanmakuEnableblocklist_; + /// + /// 是否开启屏蔽列表 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool PlayerDanmakuEnableblocklist { + get { return playerDanmakuEnableblocklist_; } + set { + playerDanmakuEnableblocklist_ = value; + } + } + + /// Field number for the "inline_player_danmaku_switch" field. + public const int InlinePlayerDanmakuSwitchFieldNumber = 17; + private bool inlinePlayerDanmakuSwitch_; + /// + /// 是否开启弹幕 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool InlinePlayerDanmakuSwitch { + get { return inlinePlayerDanmakuSwitch_; } + set { + inlinePlayerDanmakuSwitch_ = value; + } + } + + /// Field number for the "inline_player_danmaku_config" field. + public const int InlinePlayerDanmakuConfigFieldNumber = 18; + private int inlinePlayerDanmakuConfig_; + /// + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int InlinePlayerDanmakuConfig { + get { return inlinePlayerDanmakuConfig_; } + set { + inlinePlayerDanmakuConfig_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as DanmuPlayerConfig); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(DanmuPlayerConfig other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (PlayerDanmakuSwitch != other.PlayerDanmakuSwitch) return false; + if (PlayerDanmakuSwitchSave != other.PlayerDanmakuSwitchSave) return false; + if (PlayerDanmakuUseDefaultConfig != other.PlayerDanmakuUseDefaultConfig) return false; + if (PlayerDanmakuAiRecommendedSwitch != other.PlayerDanmakuAiRecommendedSwitch) return false; + if (PlayerDanmakuAiRecommendedLevel != other.PlayerDanmakuAiRecommendedLevel) return false; + if (PlayerDanmakuBlocktop != other.PlayerDanmakuBlocktop) return false; + if (PlayerDanmakuBlockscroll != other.PlayerDanmakuBlockscroll) return false; + if (PlayerDanmakuBlockbottom != other.PlayerDanmakuBlockbottom) return false; + if (PlayerDanmakuBlockcolorful != other.PlayerDanmakuBlockcolorful) return false; + if (PlayerDanmakuBlockrepeat != other.PlayerDanmakuBlockrepeat) return false; + if (PlayerDanmakuBlockspecial != other.PlayerDanmakuBlockspecial) return false; + if (!pbc::ProtobufEqualityComparers.BitwiseSingleEqualityComparer.Equals(PlayerDanmakuOpacity, other.PlayerDanmakuOpacity)) return false; + if (!pbc::ProtobufEqualityComparers.BitwiseSingleEqualityComparer.Equals(PlayerDanmakuScalingfactor, other.PlayerDanmakuScalingfactor)) return false; + if (!pbc::ProtobufEqualityComparers.BitwiseSingleEqualityComparer.Equals(PlayerDanmakuDomain, other.PlayerDanmakuDomain)) return false; + if (PlayerDanmakuSpeed != other.PlayerDanmakuSpeed) return false; + if (PlayerDanmakuEnableblocklist != other.PlayerDanmakuEnableblocklist) return false; + if (InlinePlayerDanmakuSwitch != other.InlinePlayerDanmakuSwitch) return false; + if (InlinePlayerDanmakuConfig != other.InlinePlayerDanmakuConfig) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override int GetHashCode() { + int hash = 1; + if (PlayerDanmakuSwitch != false) hash ^= PlayerDanmakuSwitch.GetHashCode(); + if (PlayerDanmakuSwitchSave != false) hash ^= PlayerDanmakuSwitchSave.GetHashCode(); + if (PlayerDanmakuUseDefaultConfig != false) hash ^= PlayerDanmakuUseDefaultConfig.GetHashCode(); + if (PlayerDanmakuAiRecommendedSwitch != false) hash ^= PlayerDanmakuAiRecommendedSwitch.GetHashCode(); + if (PlayerDanmakuAiRecommendedLevel != 0) hash ^= PlayerDanmakuAiRecommendedLevel.GetHashCode(); + if (PlayerDanmakuBlocktop != false) hash ^= PlayerDanmakuBlocktop.GetHashCode(); + if (PlayerDanmakuBlockscroll != false) hash ^= PlayerDanmakuBlockscroll.GetHashCode(); + if (PlayerDanmakuBlockbottom != false) hash ^= PlayerDanmakuBlockbottom.GetHashCode(); + if (PlayerDanmakuBlockcolorful != false) hash ^= PlayerDanmakuBlockcolorful.GetHashCode(); + if (PlayerDanmakuBlockrepeat != false) hash ^= PlayerDanmakuBlockrepeat.GetHashCode(); + if (PlayerDanmakuBlockspecial != false) hash ^= PlayerDanmakuBlockspecial.GetHashCode(); + if (PlayerDanmakuOpacity != 0F) hash ^= pbc::ProtobufEqualityComparers.BitwiseSingleEqualityComparer.GetHashCode(PlayerDanmakuOpacity); + if (PlayerDanmakuScalingfactor != 0F) hash ^= pbc::ProtobufEqualityComparers.BitwiseSingleEqualityComparer.GetHashCode(PlayerDanmakuScalingfactor); + if (PlayerDanmakuDomain != 0F) hash ^= pbc::ProtobufEqualityComparers.BitwiseSingleEqualityComparer.GetHashCode(PlayerDanmakuDomain); + if (PlayerDanmakuSpeed != 0) hash ^= PlayerDanmakuSpeed.GetHashCode(); + if (PlayerDanmakuEnableblocklist != false) hash ^= PlayerDanmakuEnableblocklist.GetHashCode(); + if (InlinePlayerDanmakuSwitch != false) hash ^= InlinePlayerDanmakuSwitch.GetHashCode(); + if (InlinePlayerDanmakuConfig != 0) hash ^= InlinePlayerDanmakuConfig.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void WriteTo(pb::CodedOutputStream output) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + output.WriteRawMessage(this); + #else + if (PlayerDanmakuSwitch != false) { + output.WriteRawTag(8); + output.WriteBool(PlayerDanmakuSwitch); + } + if (PlayerDanmakuSwitchSave != false) { + output.WriteRawTag(16); + output.WriteBool(PlayerDanmakuSwitchSave); + } + if (PlayerDanmakuUseDefaultConfig != false) { + output.WriteRawTag(24); + output.WriteBool(PlayerDanmakuUseDefaultConfig); + } + if (PlayerDanmakuAiRecommendedSwitch != false) { + output.WriteRawTag(32); + output.WriteBool(PlayerDanmakuAiRecommendedSwitch); + } + if (PlayerDanmakuAiRecommendedLevel != 0) { + output.WriteRawTag(40); + output.WriteInt32(PlayerDanmakuAiRecommendedLevel); + } + if (PlayerDanmakuBlocktop != false) { + output.WriteRawTag(48); + output.WriteBool(PlayerDanmakuBlocktop); + } + if (PlayerDanmakuBlockscroll != false) { + output.WriteRawTag(56); + output.WriteBool(PlayerDanmakuBlockscroll); + } + if (PlayerDanmakuBlockbottom != false) { + output.WriteRawTag(64); + output.WriteBool(PlayerDanmakuBlockbottom); + } + if (PlayerDanmakuBlockcolorful != false) { + output.WriteRawTag(72); + output.WriteBool(PlayerDanmakuBlockcolorful); + } + if (PlayerDanmakuBlockrepeat != false) { + output.WriteRawTag(80); + output.WriteBool(PlayerDanmakuBlockrepeat); + } + if (PlayerDanmakuBlockspecial != false) { + output.WriteRawTag(88); + output.WriteBool(PlayerDanmakuBlockspecial); + } + if (PlayerDanmakuOpacity != 0F) { + output.WriteRawTag(101); + output.WriteFloat(PlayerDanmakuOpacity); + } + if (PlayerDanmakuScalingfactor != 0F) { + output.WriteRawTag(109); + output.WriteFloat(PlayerDanmakuScalingfactor); + } + if (PlayerDanmakuDomain != 0F) { + output.WriteRawTag(117); + output.WriteFloat(PlayerDanmakuDomain); + } + if (PlayerDanmakuSpeed != 0) { + output.WriteRawTag(120); + output.WriteInt32(PlayerDanmakuSpeed); + } + if (PlayerDanmakuEnableblocklist != false) { + output.WriteRawTag(128, 1); + output.WriteBool(PlayerDanmakuEnableblocklist); + } + if (InlinePlayerDanmakuSwitch != false) { + output.WriteRawTag(136, 1); + output.WriteBool(InlinePlayerDanmakuSwitch); + } + if (InlinePlayerDanmakuConfig != 0) { + output.WriteRawTag(144, 1); + output.WriteInt32(InlinePlayerDanmakuConfig); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + if (PlayerDanmakuSwitch != false) { + output.WriteRawTag(8); + output.WriteBool(PlayerDanmakuSwitch); + } + if (PlayerDanmakuSwitchSave != false) { + output.WriteRawTag(16); + output.WriteBool(PlayerDanmakuSwitchSave); + } + if (PlayerDanmakuUseDefaultConfig != false) { + output.WriteRawTag(24); + output.WriteBool(PlayerDanmakuUseDefaultConfig); + } + if (PlayerDanmakuAiRecommendedSwitch != false) { + output.WriteRawTag(32); + output.WriteBool(PlayerDanmakuAiRecommendedSwitch); + } + if (PlayerDanmakuAiRecommendedLevel != 0) { + output.WriteRawTag(40); + output.WriteInt32(PlayerDanmakuAiRecommendedLevel); + } + if (PlayerDanmakuBlocktop != false) { + output.WriteRawTag(48); + output.WriteBool(PlayerDanmakuBlocktop); + } + if (PlayerDanmakuBlockscroll != false) { + output.WriteRawTag(56); + output.WriteBool(PlayerDanmakuBlockscroll); + } + if (PlayerDanmakuBlockbottom != false) { + output.WriteRawTag(64); + output.WriteBool(PlayerDanmakuBlockbottom); + } + if (PlayerDanmakuBlockcolorful != false) { + output.WriteRawTag(72); + output.WriteBool(PlayerDanmakuBlockcolorful); + } + if (PlayerDanmakuBlockrepeat != false) { + output.WriteRawTag(80); + output.WriteBool(PlayerDanmakuBlockrepeat); + } + if (PlayerDanmakuBlockspecial != false) { + output.WriteRawTag(88); + output.WriteBool(PlayerDanmakuBlockspecial); + } + if (PlayerDanmakuOpacity != 0F) { + output.WriteRawTag(101); + output.WriteFloat(PlayerDanmakuOpacity); + } + if (PlayerDanmakuScalingfactor != 0F) { + output.WriteRawTag(109); + output.WriteFloat(PlayerDanmakuScalingfactor); + } + if (PlayerDanmakuDomain != 0F) { + output.WriteRawTag(117); + output.WriteFloat(PlayerDanmakuDomain); + } + if (PlayerDanmakuSpeed != 0) { + output.WriteRawTag(120); + output.WriteInt32(PlayerDanmakuSpeed); + } + if (PlayerDanmakuEnableblocklist != false) { + output.WriteRawTag(128, 1); + output.WriteBool(PlayerDanmakuEnableblocklist); + } + if (InlinePlayerDanmakuSwitch != false) { + output.WriteRawTag(136, 1); + output.WriteBool(InlinePlayerDanmakuSwitch); + } + if (InlinePlayerDanmakuConfig != 0) { + output.WriteRawTag(144, 1); + output.WriteInt32(InlinePlayerDanmakuConfig); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(ref output); + } + } + #endif + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int CalculateSize() { + int size = 0; + if (PlayerDanmakuSwitch != false) { + size += 1 + 1; + } + if (PlayerDanmakuSwitchSave != false) { + size += 1 + 1; + } + if (PlayerDanmakuUseDefaultConfig != false) { + size += 1 + 1; + } + if (PlayerDanmakuAiRecommendedSwitch != false) { + size += 1 + 1; + } + if (PlayerDanmakuAiRecommendedLevel != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(PlayerDanmakuAiRecommendedLevel); + } + if (PlayerDanmakuBlocktop != false) { + size += 1 + 1; + } + if (PlayerDanmakuBlockscroll != false) { + size += 1 + 1; + } + if (PlayerDanmakuBlockbottom != false) { + size += 1 + 1; + } + if (PlayerDanmakuBlockcolorful != false) { + size += 1 + 1; + } + if (PlayerDanmakuBlockrepeat != false) { + size += 1 + 1; + } + if (PlayerDanmakuBlockspecial != false) { + size += 1 + 1; + } + if (PlayerDanmakuOpacity != 0F) { + size += 1 + 4; + } + if (PlayerDanmakuScalingfactor != 0F) { + size += 1 + 4; + } + if (PlayerDanmakuDomain != 0F) { + size += 1 + 4; + } + if (PlayerDanmakuSpeed != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(PlayerDanmakuSpeed); + } + if (PlayerDanmakuEnableblocklist != false) { + size += 2 + 1; + } + if (InlinePlayerDanmakuSwitch != false) { + size += 2 + 1; + } + if (InlinePlayerDanmakuConfig != 0) { + size += 2 + pb::CodedOutputStream.ComputeInt32Size(InlinePlayerDanmakuConfig); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(DanmuPlayerConfig other) { + if (other == null) { + return; + } + if (other.PlayerDanmakuSwitch != false) { + PlayerDanmakuSwitch = other.PlayerDanmakuSwitch; + } + if (other.PlayerDanmakuSwitchSave != false) { + PlayerDanmakuSwitchSave = other.PlayerDanmakuSwitchSave; + } + if (other.PlayerDanmakuUseDefaultConfig != false) { + PlayerDanmakuUseDefaultConfig = other.PlayerDanmakuUseDefaultConfig; + } + if (other.PlayerDanmakuAiRecommendedSwitch != false) { + PlayerDanmakuAiRecommendedSwitch = other.PlayerDanmakuAiRecommendedSwitch; + } + if (other.PlayerDanmakuAiRecommendedLevel != 0) { + PlayerDanmakuAiRecommendedLevel = other.PlayerDanmakuAiRecommendedLevel; + } + if (other.PlayerDanmakuBlocktop != false) { + PlayerDanmakuBlocktop = other.PlayerDanmakuBlocktop; + } + if (other.PlayerDanmakuBlockscroll != false) { + PlayerDanmakuBlockscroll = other.PlayerDanmakuBlockscroll; + } + if (other.PlayerDanmakuBlockbottom != false) { + PlayerDanmakuBlockbottom = other.PlayerDanmakuBlockbottom; + } + if (other.PlayerDanmakuBlockcolorful != false) { + PlayerDanmakuBlockcolorful = other.PlayerDanmakuBlockcolorful; + } + if (other.PlayerDanmakuBlockrepeat != false) { + PlayerDanmakuBlockrepeat = other.PlayerDanmakuBlockrepeat; + } + if (other.PlayerDanmakuBlockspecial != false) { + PlayerDanmakuBlockspecial = other.PlayerDanmakuBlockspecial; + } + if (other.PlayerDanmakuOpacity != 0F) { + PlayerDanmakuOpacity = other.PlayerDanmakuOpacity; + } + if (other.PlayerDanmakuScalingfactor != 0F) { + PlayerDanmakuScalingfactor = other.PlayerDanmakuScalingfactor; + } + if (other.PlayerDanmakuDomain != 0F) { + PlayerDanmakuDomain = other.PlayerDanmakuDomain; + } + if (other.PlayerDanmakuSpeed != 0) { + PlayerDanmakuSpeed = other.PlayerDanmakuSpeed; + } + if (other.PlayerDanmakuEnableblocklist != false) { + PlayerDanmakuEnableblocklist = other.PlayerDanmakuEnableblocklist; + } + if (other.InlinePlayerDanmakuSwitch != false) { + InlinePlayerDanmakuSwitch = other.InlinePlayerDanmakuSwitch; + } + if (other.InlinePlayerDanmakuConfig != 0) { + InlinePlayerDanmakuConfig = other.InlinePlayerDanmakuConfig; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(pb::CodedInputStream input) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + input.ReadRawMessage(this); + #else + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + PlayerDanmakuSwitch = input.ReadBool(); + break; + } + case 16: { + PlayerDanmakuSwitchSave = input.ReadBool(); + break; + } + case 24: { + PlayerDanmakuUseDefaultConfig = input.ReadBool(); + break; + } + case 32: { + PlayerDanmakuAiRecommendedSwitch = input.ReadBool(); + break; + } + case 40: { + PlayerDanmakuAiRecommendedLevel = input.ReadInt32(); + break; + } + case 48: { + PlayerDanmakuBlocktop = input.ReadBool(); + break; + } + case 56: { + PlayerDanmakuBlockscroll = input.ReadBool(); + break; + } + case 64: { + PlayerDanmakuBlockbottom = input.ReadBool(); + break; + } + case 72: { + PlayerDanmakuBlockcolorful = input.ReadBool(); + break; + } + case 80: { + PlayerDanmakuBlockrepeat = input.ReadBool(); + break; + } + case 88: { + PlayerDanmakuBlockspecial = input.ReadBool(); + break; + } + case 101: { + PlayerDanmakuOpacity = input.ReadFloat(); + break; + } + case 109: { + PlayerDanmakuScalingfactor = input.ReadFloat(); + break; + } + case 117: { + PlayerDanmakuDomain = input.ReadFloat(); + break; + } + case 120: { + PlayerDanmakuSpeed = input.ReadInt32(); + break; + } + case 128: { + PlayerDanmakuEnableblocklist = input.ReadBool(); + break; + } + case 136: { + InlinePlayerDanmakuSwitch = input.ReadBool(); + break; + } + case 144: { + InlinePlayerDanmakuConfig = input.ReadInt32(); + break; + } + } + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 8: { + PlayerDanmakuSwitch = input.ReadBool(); + break; + } + case 16: { + PlayerDanmakuSwitchSave = input.ReadBool(); + break; + } + case 24: { + PlayerDanmakuUseDefaultConfig = input.ReadBool(); + break; + } + case 32: { + PlayerDanmakuAiRecommendedSwitch = input.ReadBool(); + break; + } + case 40: { + PlayerDanmakuAiRecommendedLevel = input.ReadInt32(); + break; + } + case 48: { + PlayerDanmakuBlocktop = input.ReadBool(); + break; + } + case 56: { + PlayerDanmakuBlockscroll = input.ReadBool(); + break; + } + case 64: { + PlayerDanmakuBlockbottom = input.ReadBool(); + break; + } + case 72: { + PlayerDanmakuBlockcolorful = input.ReadBool(); + break; + } + case 80: { + PlayerDanmakuBlockrepeat = input.ReadBool(); + break; + } + case 88: { + PlayerDanmakuBlockspecial = input.ReadBool(); + break; + } + case 101: { + PlayerDanmakuOpacity = input.ReadFloat(); + break; + } + case 109: { + PlayerDanmakuScalingfactor = input.ReadFloat(); + break; + } + case 117: { + PlayerDanmakuDomain = input.ReadFloat(); + break; + } + case 120: { + PlayerDanmakuSpeed = input.ReadInt32(); + break; + } + case 128: { + PlayerDanmakuEnableblocklist = input.ReadBool(); + break; + } + case 136: { + InlinePlayerDanmakuSwitch = input.ReadBool(); + break; + } + case 144: { + InlinePlayerDanmakuConfig = input.ReadInt32(); + break; + } + } + } + } + #endif + + } + + /// + /// 弹幕显示区域自动配置 + /// + public sealed partial class DanmuPlayerDynamicConfig : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new DanmuPlayerDynamicConfig()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pbr::MessageDescriptor Descriptor { + get { return global::Bilibili.Community.Service.Dm.V1.DmReflection.Descriptor.MessageTypes[25]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public DanmuPlayerDynamicConfig() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public DanmuPlayerDynamicConfig(DanmuPlayerDynamicConfig other) : this() { + progress_ = other.progress_; + playerDanmakuDomain_ = other.playerDanmakuDomain_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public DanmuPlayerDynamicConfig Clone() { + return new DanmuPlayerDynamicConfig(this); + } + + /// Field number for the "progress" field. + public const int ProgressFieldNumber = 1; + private int progress_; + /// + /// 时间 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int Progress { + get { return progress_; } + set { + progress_ = value; + } + } + + /// Field number for the "player_danmaku_domain" field. + public const int PlayerDanmakuDomainFieldNumber = 2; + private float playerDanmakuDomain_; + /// + /// 弹幕显示区域 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public float PlayerDanmakuDomain { + get { return playerDanmakuDomain_; } + set { + playerDanmakuDomain_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as DanmuPlayerDynamicConfig); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(DanmuPlayerDynamicConfig other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Progress != other.Progress) return false; + if (!pbc::ProtobufEqualityComparers.BitwiseSingleEqualityComparer.Equals(PlayerDanmakuDomain, other.PlayerDanmakuDomain)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override int GetHashCode() { + int hash = 1; + if (Progress != 0) hash ^= Progress.GetHashCode(); + if (PlayerDanmakuDomain != 0F) hash ^= pbc::ProtobufEqualityComparers.BitwiseSingleEqualityComparer.GetHashCode(PlayerDanmakuDomain); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void WriteTo(pb::CodedOutputStream output) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + output.WriteRawMessage(this); + #else + if (Progress != 0) { + output.WriteRawTag(8); + output.WriteInt32(Progress); + } + if (PlayerDanmakuDomain != 0F) { + output.WriteRawTag(21); + output.WriteFloat(PlayerDanmakuDomain); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + if (Progress != 0) { + output.WriteRawTag(8); + output.WriteInt32(Progress); + } + if (PlayerDanmakuDomain != 0F) { + output.WriteRawTag(21); + output.WriteFloat(PlayerDanmakuDomain); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(ref output); + } + } + #endif + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int CalculateSize() { + int size = 0; + if (Progress != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Progress); + } + if (PlayerDanmakuDomain != 0F) { + size += 1 + 4; + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(DanmuPlayerDynamicConfig other) { + if (other == null) { + return; + } + if (other.Progress != 0) { + Progress = other.Progress; + } + if (other.PlayerDanmakuDomain != 0F) { + PlayerDanmakuDomain = other.PlayerDanmakuDomain; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(pb::CodedInputStream input) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + input.ReadRawMessage(this); + #else + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Progress = input.ReadInt32(); + break; + } + case 21: { + PlayerDanmakuDomain = input.ReadFloat(); + break; + } + } + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 8: { + Progress = input.ReadInt32(); + break; + } + case 21: { + PlayerDanmakuDomain = input.ReadFloat(); + break; + } + } + } + } + #endif + + } + + /// + /// 是否开启弹幕 + /// + public sealed partial class PlayerDanmakuSwitch : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new PlayerDanmakuSwitch()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pbr::MessageDescriptor Descriptor { + get { return global::Bilibili.Community.Service.Dm.V1.DmReflection.Descriptor.MessageTypes[26]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public PlayerDanmakuSwitch() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public PlayerDanmakuSwitch(PlayerDanmakuSwitch other) : this() { + value_ = other.value_; + canIgnore_ = other.canIgnore_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public PlayerDanmakuSwitch Clone() { + return new PlayerDanmakuSwitch(this); + } + + /// Field number for the "value" field. + public const int ValueFieldNumber = 1; + private bool value_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Value { + get { return value_; } + set { + value_ = value; + } + } + + /// Field number for the "canIgnore" field. + public const int CanIgnoreFieldNumber = 2; + private bool canIgnore_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool CanIgnore { + get { return canIgnore_; } + set { + canIgnore_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as PlayerDanmakuSwitch); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(PlayerDanmakuSwitch other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Value != other.Value) return false; + if (CanIgnore != other.CanIgnore) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override int GetHashCode() { + int hash = 1; + if (Value != false) hash ^= Value.GetHashCode(); + if (CanIgnore != false) hash ^= CanIgnore.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void WriteTo(pb::CodedOutputStream output) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + output.WriteRawMessage(this); + #else + if (Value != false) { + output.WriteRawTag(8); + output.WriteBool(Value); + } + if (CanIgnore != false) { + output.WriteRawTag(16); + output.WriteBool(CanIgnore); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + if (Value != false) { + output.WriteRawTag(8); + output.WriteBool(Value); + } + if (CanIgnore != false) { + output.WriteRawTag(16); + output.WriteBool(CanIgnore); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(ref output); + } + } + #endif + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int CalculateSize() { + int size = 0; + if (Value != false) { + size += 1 + 1; + } + if (CanIgnore != false) { + size += 1 + 1; + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(PlayerDanmakuSwitch other) { + if (other == null) { + return; + } + if (other.Value != false) { + Value = other.Value; + } + if (other.CanIgnore != false) { + CanIgnore = other.CanIgnore; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(pb::CodedInputStream input) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + input.ReadRawMessage(this); + #else + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Value = input.ReadBool(); + break; + } + case 16: { + CanIgnore = input.ReadBool(); + break; + } + } + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 8: { + Value = input.ReadBool(); + break; + } + case 16: { + CanIgnore = input.ReadBool(); + break; + } + } + } + } + #endif + + } + + /// + /// 是否记录弹幕开关设置 + /// + public sealed partial class PlayerDanmakuSwitchSave : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new PlayerDanmakuSwitchSave()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pbr::MessageDescriptor Descriptor { + get { return global::Bilibili.Community.Service.Dm.V1.DmReflection.Descriptor.MessageTypes[27]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public PlayerDanmakuSwitchSave() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public PlayerDanmakuSwitchSave(PlayerDanmakuSwitchSave other) : this() { + value_ = other.value_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public PlayerDanmakuSwitchSave Clone() { + return new PlayerDanmakuSwitchSave(this); + } + + /// Field number for the "value" field. + public const int ValueFieldNumber = 1; + private bool value_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Value { + get { return value_; } + set { + value_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as PlayerDanmakuSwitchSave); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(PlayerDanmakuSwitchSave other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Value != other.Value) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override int GetHashCode() { + int hash = 1; + if (Value != false) hash ^= Value.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void WriteTo(pb::CodedOutputStream output) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + output.WriteRawMessage(this); + #else + if (Value != false) { + output.WriteRawTag(8); + output.WriteBool(Value); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + if (Value != false) { + output.WriteRawTag(8); + output.WriteBool(Value); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(ref output); + } + } + #endif + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int CalculateSize() { + int size = 0; + if (Value != false) { + size += 1 + 1; + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(PlayerDanmakuSwitchSave other) { + if (other == null) { + return; + } + if (other.Value != false) { + Value = other.Value; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(pb::CodedInputStream input) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + input.ReadRawMessage(this); + #else + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Value = input.ReadBool(); + break; + } + } + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 8: { + Value = input.ReadBool(); + break; + } + } + } + } + #endif + + } + + /// + /// 是否使用推荐弹幕设置 + /// + public sealed partial class PlayerDanmakuUseDefaultConfig : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new PlayerDanmakuUseDefaultConfig()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pbr::MessageDescriptor Descriptor { + get { return global::Bilibili.Community.Service.Dm.V1.DmReflection.Descriptor.MessageTypes[28]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public PlayerDanmakuUseDefaultConfig() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public PlayerDanmakuUseDefaultConfig(PlayerDanmakuUseDefaultConfig other) : this() { + value_ = other.value_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public PlayerDanmakuUseDefaultConfig Clone() { + return new PlayerDanmakuUseDefaultConfig(this); + } + + /// Field number for the "value" field. + public const int ValueFieldNumber = 1; + private bool value_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Value { + get { return value_; } + set { + value_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as PlayerDanmakuUseDefaultConfig); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(PlayerDanmakuUseDefaultConfig other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Value != other.Value) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override int GetHashCode() { + int hash = 1; + if (Value != false) hash ^= Value.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void WriteTo(pb::CodedOutputStream output) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + output.WriteRawMessage(this); + #else + if (Value != false) { + output.WriteRawTag(8); + output.WriteBool(Value); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + if (Value != false) { + output.WriteRawTag(8); + output.WriteBool(Value); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(ref output); + } + } + #endif + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int CalculateSize() { + int size = 0; + if (Value != false) { + size += 1 + 1; + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(PlayerDanmakuUseDefaultConfig other) { + if (other == null) { + return; + } + if (other.Value != false) { + Value = other.Value; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(pb::CodedInputStream input) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + input.ReadRawMessage(this); + #else + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Value = input.ReadBool(); + break; + } + } + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 8: { + Value = input.ReadBool(); + break; + } + } + } + } + #endif + + } + + /// + /// 是否开启智能云屏蔽 + /// + public sealed partial class PlayerDanmakuAiRecommendedSwitch : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new PlayerDanmakuAiRecommendedSwitch()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pbr::MessageDescriptor Descriptor { + get { return global::Bilibili.Community.Service.Dm.V1.DmReflection.Descriptor.MessageTypes[29]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public PlayerDanmakuAiRecommendedSwitch() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public PlayerDanmakuAiRecommendedSwitch(PlayerDanmakuAiRecommendedSwitch other) : this() { + value_ = other.value_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public PlayerDanmakuAiRecommendedSwitch Clone() { + return new PlayerDanmakuAiRecommendedSwitch(this); + } + + /// Field number for the "value" field. + public const int ValueFieldNumber = 1; + private bool value_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Value { + get { return value_; } + set { + value_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as PlayerDanmakuAiRecommendedSwitch); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(PlayerDanmakuAiRecommendedSwitch other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Value != other.Value) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override int GetHashCode() { + int hash = 1; + if (Value != false) hash ^= Value.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void WriteTo(pb::CodedOutputStream output) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + output.WriteRawMessage(this); + #else + if (Value != false) { + output.WriteRawTag(8); + output.WriteBool(Value); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + if (Value != false) { + output.WriteRawTag(8); + output.WriteBool(Value); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(ref output); + } + } + #endif + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int CalculateSize() { + int size = 0; + if (Value != false) { + size += 1 + 1; + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(PlayerDanmakuAiRecommendedSwitch other) { + if (other == null) { + return; + } + if (other.Value != false) { + Value = other.Value; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(pb::CodedInputStream input) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + input.ReadRawMessage(this); + #else + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Value = input.ReadBool(); + break; + } + } + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 8: { + Value = input.ReadBool(); + break; + } + } + } + } + #endif + + } + + /// + /// 智能云屏蔽等级 + /// + public sealed partial class PlayerDanmakuAiRecommendedLevel : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new PlayerDanmakuAiRecommendedLevel()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pbr::MessageDescriptor Descriptor { + get { return global::Bilibili.Community.Service.Dm.V1.DmReflection.Descriptor.MessageTypes[30]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public PlayerDanmakuAiRecommendedLevel() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public PlayerDanmakuAiRecommendedLevel(PlayerDanmakuAiRecommendedLevel other) : this() { + value_ = other.value_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public PlayerDanmakuAiRecommendedLevel Clone() { + return new PlayerDanmakuAiRecommendedLevel(this); + } + + /// Field number for the "value" field. + public const int ValueFieldNumber = 1; + private bool value_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Value { + get { return value_; } + set { + value_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as PlayerDanmakuAiRecommendedLevel); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(PlayerDanmakuAiRecommendedLevel other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Value != other.Value) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override int GetHashCode() { + int hash = 1; + if (Value != false) hash ^= Value.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void WriteTo(pb::CodedOutputStream output) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + output.WriteRawMessage(this); + #else + if (Value != false) { + output.WriteRawTag(8); + output.WriteBool(Value); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + if (Value != false) { + output.WriteRawTag(8); + output.WriteBool(Value); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(ref output); + } + } + #endif + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int CalculateSize() { + int size = 0; + if (Value != false) { + size += 1 + 1; + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(PlayerDanmakuAiRecommendedLevel other) { + if (other == null) { + return; + } + if (other.Value != false) { + Value = other.Value; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(pb::CodedInputStream input) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + input.ReadRawMessage(this); + #else + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Value = input.ReadBool(); + break; + } + } + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 8: { + Value = input.ReadBool(); + break; + } + } + } + } + #endif + + } + + /// + /// 是否屏蔽顶端弹幕 + /// + public sealed partial class PlayerDanmakuBlocktop : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new PlayerDanmakuBlocktop()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pbr::MessageDescriptor Descriptor { + get { return global::Bilibili.Community.Service.Dm.V1.DmReflection.Descriptor.MessageTypes[31]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public PlayerDanmakuBlocktop() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public PlayerDanmakuBlocktop(PlayerDanmakuBlocktop other) : this() { + value_ = other.value_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public PlayerDanmakuBlocktop Clone() { + return new PlayerDanmakuBlocktop(this); + } + + /// Field number for the "value" field. + public const int ValueFieldNumber = 1; + private bool value_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Value { + get { return value_; } + set { + value_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as PlayerDanmakuBlocktop); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(PlayerDanmakuBlocktop other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Value != other.Value) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override int GetHashCode() { + int hash = 1; + if (Value != false) hash ^= Value.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void WriteTo(pb::CodedOutputStream output) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + output.WriteRawMessage(this); + #else + if (Value != false) { + output.WriteRawTag(8); + output.WriteBool(Value); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + if (Value != false) { + output.WriteRawTag(8); + output.WriteBool(Value); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(ref output); + } + } + #endif + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int CalculateSize() { + int size = 0; + if (Value != false) { + size += 1 + 1; + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(PlayerDanmakuBlocktop other) { + if (other == null) { + return; + } + if (other.Value != false) { + Value = other.Value; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(pb::CodedInputStream input) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + input.ReadRawMessage(this); + #else + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Value = input.ReadBool(); + break; + } + } + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 8: { + Value = input.ReadBool(); + break; + } + } + } + } + #endif + + } + + /// + /// 是否屏蔽滚动弹幕 + /// + public sealed partial class PlayerDanmakuBlockscroll : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new PlayerDanmakuBlockscroll()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pbr::MessageDescriptor Descriptor { + get { return global::Bilibili.Community.Service.Dm.V1.DmReflection.Descriptor.MessageTypes[32]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public PlayerDanmakuBlockscroll() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public PlayerDanmakuBlockscroll(PlayerDanmakuBlockscroll other) : this() { + value_ = other.value_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public PlayerDanmakuBlockscroll Clone() { + return new PlayerDanmakuBlockscroll(this); + } + + /// Field number for the "value" field. + public const int ValueFieldNumber = 1; + private bool value_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Value { + get { return value_; } + set { + value_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as PlayerDanmakuBlockscroll); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(PlayerDanmakuBlockscroll other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Value != other.Value) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override int GetHashCode() { + int hash = 1; + if (Value != false) hash ^= Value.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void WriteTo(pb::CodedOutputStream output) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + output.WriteRawMessage(this); + #else + if (Value != false) { + output.WriteRawTag(8); + output.WriteBool(Value); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + if (Value != false) { + output.WriteRawTag(8); + output.WriteBool(Value); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(ref output); + } + } + #endif + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int CalculateSize() { + int size = 0; + if (Value != false) { + size += 1 + 1; + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(PlayerDanmakuBlockscroll other) { + if (other == null) { + return; + } + if (other.Value != false) { + Value = other.Value; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(pb::CodedInputStream input) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + input.ReadRawMessage(this); + #else + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Value = input.ReadBool(); + break; + } + } + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 8: { + Value = input.ReadBool(); + break; + } + } + } + } + #endif + + } + + /// + /// 是否屏蔽底端弹幕 + /// + public sealed partial class PlayerDanmakuBlockbottom : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new PlayerDanmakuBlockbottom()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pbr::MessageDescriptor Descriptor { + get { return global::Bilibili.Community.Service.Dm.V1.DmReflection.Descriptor.MessageTypes[33]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public PlayerDanmakuBlockbottom() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public PlayerDanmakuBlockbottom(PlayerDanmakuBlockbottom other) : this() { + value_ = other.value_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public PlayerDanmakuBlockbottom Clone() { + return new PlayerDanmakuBlockbottom(this); + } + + /// Field number for the "value" field. + public const int ValueFieldNumber = 1; + private bool value_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Value { + get { return value_; } + set { + value_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as PlayerDanmakuBlockbottom); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(PlayerDanmakuBlockbottom other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Value != other.Value) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override int GetHashCode() { + int hash = 1; + if (Value != false) hash ^= Value.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void WriteTo(pb::CodedOutputStream output) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + output.WriteRawMessage(this); + #else + if (Value != false) { + output.WriteRawTag(8); + output.WriteBool(Value); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + if (Value != false) { + output.WriteRawTag(8); + output.WriteBool(Value); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(ref output); + } + } + #endif + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int CalculateSize() { + int size = 0; + if (Value != false) { + size += 1 + 1; + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(PlayerDanmakuBlockbottom other) { + if (other == null) { + return; + } + if (other.Value != false) { + Value = other.Value; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(pb::CodedInputStream input) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + input.ReadRawMessage(this); + #else + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Value = input.ReadBool(); + break; + } + } + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 8: { + Value = input.ReadBool(); + break; + } + } + } + } + #endif + + } + + /// + /// 是否屏蔽彩色弹幕 + /// + public sealed partial class PlayerDanmakuBlockcolorful : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new PlayerDanmakuBlockcolorful()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pbr::MessageDescriptor Descriptor { + get { return global::Bilibili.Community.Service.Dm.V1.DmReflection.Descriptor.MessageTypes[34]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public PlayerDanmakuBlockcolorful() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public PlayerDanmakuBlockcolorful(PlayerDanmakuBlockcolorful other) : this() { + value_ = other.value_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public PlayerDanmakuBlockcolorful Clone() { + return new PlayerDanmakuBlockcolorful(this); + } + + /// Field number for the "value" field. + public const int ValueFieldNumber = 1; + private bool value_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Value { + get { return value_; } + set { + value_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as PlayerDanmakuBlockcolorful); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(PlayerDanmakuBlockcolorful other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Value != other.Value) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override int GetHashCode() { + int hash = 1; + if (Value != false) hash ^= Value.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void WriteTo(pb::CodedOutputStream output) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + output.WriteRawMessage(this); + #else + if (Value != false) { + output.WriteRawTag(8); + output.WriteBool(Value); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + if (Value != false) { + output.WriteRawTag(8); + output.WriteBool(Value); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(ref output); + } + } + #endif + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int CalculateSize() { + int size = 0; + if (Value != false) { + size += 1 + 1; + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(PlayerDanmakuBlockcolorful other) { + if (other == null) { + return; + } + if (other.Value != false) { + Value = other.Value; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(pb::CodedInputStream input) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + input.ReadRawMessage(this); + #else + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Value = input.ReadBool(); + break; + } + } + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 8: { + Value = input.ReadBool(); + break; + } + } + } + } + #endif + + } + + /// + /// 是否屏蔽重复弹幕 + /// + public sealed partial class PlayerDanmakuBlockrepeat : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new PlayerDanmakuBlockrepeat()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pbr::MessageDescriptor Descriptor { + get { return global::Bilibili.Community.Service.Dm.V1.DmReflection.Descriptor.MessageTypes[35]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public PlayerDanmakuBlockrepeat() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public PlayerDanmakuBlockrepeat(PlayerDanmakuBlockrepeat other) : this() { + value_ = other.value_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public PlayerDanmakuBlockrepeat Clone() { + return new PlayerDanmakuBlockrepeat(this); + } + + /// Field number for the "value" field. + public const int ValueFieldNumber = 1; + private bool value_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Value { + get { return value_; } + set { + value_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as PlayerDanmakuBlockrepeat); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(PlayerDanmakuBlockrepeat other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Value != other.Value) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override int GetHashCode() { + int hash = 1; + if (Value != false) hash ^= Value.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void WriteTo(pb::CodedOutputStream output) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + output.WriteRawMessage(this); + #else + if (Value != false) { + output.WriteRawTag(8); + output.WriteBool(Value); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + if (Value != false) { + output.WriteRawTag(8); + output.WriteBool(Value); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(ref output); + } + } + #endif + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int CalculateSize() { + int size = 0; + if (Value != false) { + size += 1 + 1; + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(PlayerDanmakuBlockrepeat other) { + if (other == null) { + return; + } + if (other.Value != false) { + Value = other.Value; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(pb::CodedInputStream input) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + input.ReadRawMessage(this); + #else + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Value = input.ReadBool(); + break; + } + } + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 8: { + Value = input.ReadBool(); + break; + } + } + } + } + #endif + + } + + /// + /// 是否屏蔽高级弹幕 + /// + public sealed partial class PlayerDanmakuBlockspecial : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new PlayerDanmakuBlockspecial()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pbr::MessageDescriptor Descriptor { + get { return global::Bilibili.Community.Service.Dm.V1.DmReflection.Descriptor.MessageTypes[36]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public PlayerDanmakuBlockspecial() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public PlayerDanmakuBlockspecial(PlayerDanmakuBlockspecial other) : this() { + value_ = other.value_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public PlayerDanmakuBlockspecial Clone() { + return new PlayerDanmakuBlockspecial(this); + } + + /// Field number for the "value" field. + public const int ValueFieldNumber = 1; + private bool value_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Value { + get { return value_; } + set { + value_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as PlayerDanmakuBlockspecial); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(PlayerDanmakuBlockspecial other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Value != other.Value) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override int GetHashCode() { + int hash = 1; + if (Value != false) hash ^= Value.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void WriteTo(pb::CodedOutputStream output) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + output.WriteRawMessage(this); + #else + if (Value != false) { + output.WriteRawTag(8); + output.WriteBool(Value); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + if (Value != false) { + output.WriteRawTag(8); + output.WriteBool(Value); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(ref output); + } + } + #endif + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int CalculateSize() { + int size = 0; + if (Value != false) { + size += 1 + 1; + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(PlayerDanmakuBlockspecial other) { + if (other == null) { + return; + } + if (other.Value != false) { + Value = other.Value; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(pb::CodedInputStream input) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + input.ReadRawMessage(this); + #else + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Value = input.ReadBool(); + break; + } + } + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 8: { + Value = input.ReadBool(); + break; + } + } + } + } + #endif + + } + + /// + /// 弹幕不透明度 + /// + public sealed partial class PlayerDanmakuOpacity : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new PlayerDanmakuOpacity()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pbr::MessageDescriptor Descriptor { + get { return global::Bilibili.Community.Service.Dm.V1.DmReflection.Descriptor.MessageTypes[37]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public PlayerDanmakuOpacity() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public PlayerDanmakuOpacity(PlayerDanmakuOpacity other) : this() { + value_ = other.value_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public PlayerDanmakuOpacity Clone() { + return new PlayerDanmakuOpacity(this); + } + + /// Field number for the "value" field. + public const int ValueFieldNumber = 1; + private float value_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public float Value { + get { return value_; } + set { + value_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as PlayerDanmakuOpacity); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(PlayerDanmakuOpacity other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!pbc::ProtobufEqualityComparers.BitwiseSingleEqualityComparer.Equals(Value, other.Value)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override int GetHashCode() { + int hash = 1; + if (Value != 0F) hash ^= pbc::ProtobufEqualityComparers.BitwiseSingleEqualityComparer.GetHashCode(Value); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void WriteTo(pb::CodedOutputStream output) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + output.WriteRawMessage(this); + #else + if (Value != 0F) { + output.WriteRawTag(13); + output.WriteFloat(Value); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + if (Value != 0F) { + output.WriteRawTag(13); + output.WriteFloat(Value); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(ref output); + } + } + #endif + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int CalculateSize() { + int size = 0; + if (Value != 0F) { + size += 1 + 4; + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(PlayerDanmakuOpacity other) { + if (other == null) { + return; + } + if (other.Value != 0F) { + Value = other.Value; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(pb::CodedInputStream input) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + input.ReadRawMessage(this); + #else + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 13: { + Value = input.ReadFloat(); + break; + } + } + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 13: { + Value = input.ReadFloat(); + break; + } + } + } + } + #endif + + } + + /// + /// 弹幕缩放比例 + /// + public sealed partial class PlayerDanmakuScalingfactor : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new PlayerDanmakuScalingfactor()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pbr::MessageDescriptor Descriptor { + get { return global::Bilibili.Community.Service.Dm.V1.DmReflection.Descriptor.MessageTypes[38]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public PlayerDanmakuScalingfactor() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public PlayerDanmakuScalingfactor(PlayerDanmakuScalingfactor other) : this() { + value_ = other.value_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public PlayerDanmakuScalingfactor Clone() { + return new PlayerDanmakuScalingfactor(this); + } + + /// Field number for the "value" field. + public const int ValueFieldNumber = 1; + private float value_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public float Value { + get { return value_; } + set { + value_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as PlayerDanmakuScalingfactor); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(PlayerDanmakuScalingfactor other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!pbc::ProtobufEqualityComparers.BitwiseSingleEqualityComparer.Equals(Value, other.Value)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override int GetHashCode() { + int hash = 1; + if (Value != 0F) hash ^= pbc::ProtobufEqualityComparers.BitwiseSingleEqualityComparer.GetHashCode(Value); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void WriteTo(pb::CodedOutputStream output) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + output.WriteRawMessage(this); + #else + if (Value != 0F) { + output.WriteRawTag(13); + output.WriteFloat(Value); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + if (Value != 0F) { + output.WriteRawTag(13); + output.WriteFloat(Value); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(ref output); + } + } + #endif + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int CalculateSize() { + int size = 0; + if (Value != 0F) { + size += 1 + 4; + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(PlayerDanmakuScalingfactor other) { + if (other == null) { + return; + } + if (other.Value != 0F) { + Value = other.Value; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(pb::CodedInputStream input) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + input.ReadRawMessage(this); + #else + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 13: { + Value = input.ReadFloat(); + break; + } + } + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 13: { + Value = input.ReadFloat(); + break; + } + } + } + } + #endif + + } + + /// + /// 弹幕显示区域 + /// + public sealed partial class PlayerDanmakuDomain : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new PlayerDanmakuDomain()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pbr::MessageDescriptor Descriptor { + get { return global::Bilibili.Community.Service.Dm.V1.DmReflection.Descriptor.MessageTypes[39]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public PlayerDanmakuDomain() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public PlayerDanmakuDomain(PlayerDanmakuDomain other) : this() { + value_ = other.value_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public PlayerDanmakuDomain Clone() { + return new PlayerDanmakuDomain(this); + } + + /// Field number for the "value" field. + public const int ValueFieldNumber = 1; + private float value_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public float Value { + get { return value_; } + set { + value_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as PlayerDanmakuDomain); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(PlayerDanmakuDomain other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!pbc::ProtobufEqualityComparers.BitwiseSingleEqualityComparer.Equals(Value, other.Value)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override int GetHashCode() { + int hash = 1; + if (Value != 0F) hash ^= pbc::ProtobufEqualityComparers.BitwiseSingleEqualityComparer.GetHashCode(Value); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void WriteTo(pb::CodedOutputStream output) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + output.WriteRawMessage(this); + #else + if (Value != 0F) { + output.WriteRawTag(13); + output.WriteFloat(Value); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + if (Value != 0F) { + output.WriteRawTag(13); + output.WriteFloat(Value); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(ref output); + } + } + #endif + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int CalculateSize() { + int size = 0; + if (Value != 0F) { + size += 1 + 4; + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(PlayerDanmakuDomain other) { + if (other == null) { + return; + } + if (other.Value != 0F) { + Value = other.Value; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(pb::CodedInputStream input) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + input.ReadRawMessage(this); + #else + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 13: { + Value = input.ReadFloat(); + break; + } + } + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 13: { + Value = input.ReadFloat(); + break; + } + } + } + } + #endif + + } + + /// + /// 弹幕速度 + /// + public sealed partial class PlayerDanmakuSpeed : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new PlayerDanmakuSpeed()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pbr::MessageDescriptor Descriptor { + get { return global::Bilibili.Community.Service.Dm.V1.DmReflection.Descriptor.MessageTypes[40]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public PlayerDanmakuSpeed() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public PlayerDanmakuSpeed(PlayerDanmakuSpeed other) : this() { + value_ = other.value_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public PlayerDanmakuSpeed Clone() { + return new PlayerDanmakuSpeed(this); + } + + /// Field number for the "value" field. + public const int ValueFieldNumber = 1; + private int value_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int Value { + get { return value_; } + set { + value_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as PlayerDanmakuSpeed); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(PlayerDanmakuSpeed other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Value != other.Value) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override int GetHashCode() { + int hash = 1; + if (Value != 0) hash ^= Value.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void WriteTo(pb::CodedOutputStream output) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + output.WriteRawMessage(this); + #else + if (Value != 0) { + output.WriteRawTag(8); + output.WriteInt32(Value); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + if (Value != 0) { + output.WriteRawTag(8); + output.WriteInt32(Value); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(ref output); + } + } + #endif + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int CalculateSize() { + int size = 0; + if (Value != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Value); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(PlayerDanmakuSpeed other) { + if (other == null) { + return; + } + if (other.Value != 0) { + Value = other.Value; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(pb::CodedInputStream input) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + input.ReadRawMessage(this); + #else + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Value = input.ReadInt32(); + break; + } + } + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 8: { + Value = input.ReadInt32(); + break; + } + } + } + } + #endif + + } + + /// + /// 是否开启屏蔽列表 + /// + public sealed partial class PlayerDanmakuEnableblocklist : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new PlayerDanmakuEnableblocklist()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pbr::MessageDescriptor Descriptor { + get { return global::Bilibili.Community.Service.Dm.V1.DmReflection.Descriptor.MessageTypes[41]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public PlayerDanmakuEnableblocklist() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public PlayerDanmakuEnableblocklist(PlayerDanmakuEnableblocklist other) : this() { + value_ = other.value_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public PlayerDanmakuEnableblocklist Clone() { + return new PlayerDanmakuEnableblocklist(this); + } + + /// Field number for the "value" field. + public const int ValueFieldNumber = 1; + private bool value_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Value { + get { return value_; } + set { + value_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as PlayerDanmakuEnableblocklist); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(PlayerDanmakuEnableblocklist other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Value != other.Value) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override int GetHashCode() { + int hash = 1; + if (Value != false) hash ^= Value.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void WriteTo(pb::CodedOutputStream output) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + output.WriteRawMessage(this); + #else + if (Value != false) { + output.WriteRawTag(8); + output.WriteBool(Value); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + if (Value != false) { + output.WriteRawTag(8); + output.WriteBool(Value); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(ref output); + } + } + #endif + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int CalculateSize() { + int size = 0; + if (Value != false) { + size += 1 + 1; + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(PlayerDanmakuEnableblocklist other) { + if (other == null) { + return; + } + if (other.Value != false) { + Value = other.Value; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(pb::CodedInputStream input) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + input.ReadRawMessage(this); + #else + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Value = input.ReadBool(); + break; + } + } + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 8: { + Value = input.ReadBool(); + break; + } + } + } + } + #endif + + } + + /// + /// 是否开启弹幕 + /// + public sealed partial class InlinePlayerDanmakuSwitch : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new InlinePlayerDanmakuSwitch()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pbr::MessageDescriptor Descriptor { + get { return global::Bilibili.Community.Service.Dm.V1.DmReflection.Descriptor.MessageTypes[42]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public InlinePlayerDanmakuSwitch() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public InlinePlayerDanmakuSwitch(InlinePlayerDanmakuSwitch other) : this() { + value_ = other.value_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public InlinePlayerDanmakuSwitch Clone() { + return new InlinePlayerDanmakuSwitch(this); + } + + /// Field number for the "value" field. + public const int ValueFieldNumber = 1; + private bool value_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Value { + get { return value_; } + set { + value_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as InlinePlayerDanmakuSwitch); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(InlinePlayerDanmakuSwitch other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Value != other.Value) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override int GetHashCode() { + int hash = 1; + if (Value != false) hash ^= Value.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void WriteTo(pb::CodedOutputStream output) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + output.WriteRawMessage(this); + #else + if (Value != false) { + output.WriteRawTag(8); + output.WriteBool(Value); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + if (Value != false) { + output.WriteRawTag(8); + output.WriteBool(Value); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(ref output); + } + } + #endif + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int CalculateSize() { + int size = 0; + if (Value != false) { + size += 1 + 1; + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(InlinePlayerDanmakuSwitch other) { + if (other == null) { + return; + } + if (other.Value != false) { + Value = other.Value; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(pb::CodedInputStream input) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + input.ReadRawMessage(this); + #else + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Value = input.ReadBool(); + break; + } + } + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 8: { + Value = input.ReadBool(); + break; + } + } + } + } + #endif + + } + + #endregion + +} + +#endregion Designer generated code diff --git a/DownKyi.Core/Danmaku2Ass/Bilibili.cs b/DownKyi.Core/Danmaku2Ass/Bilibili.cs new file mode 100644 index 0000000..2f525d1 --- /dev/null +++ b/DownKyi.Core/Danmaku2Ass/Bilibili.cs @@ -0,0 +1,167 @@ +using DownKyi.Core.BiliApi.Danmaku; + +namespace DownKyi.Core.Danmaku2Ass; + +public class Bilibili +{ + private static Bilibili instance; + + private readonly Dictionary config = new Dictionary + { + { "top_filter", false }, + { "bottom_filter", false }, + { "scroll_filter", false } + }; + + private readonly Dictionary mapping = new Dictionary + { + { 0, "none" }, // 保留项 + { 1, "scroll" }, + { 2, "scroll" }, + { 3, "scroll" }, + { 4, "bottom" }, + { 5, "top" }, + { 6, "scroll" }, // 逆向滚动弹幕,还是当滚动处理 + { 7, "none" }, // 高级弹幕,暂时不要考虑 + { 8, "none" }, // 代码弹幕,暂时不要考虑 + { 9, "none" }, // BAS弹幕,暂时不要考虑 + { 10, "none" }, // 未知,暂时不要考虑 + { 11, "none" }, // 保留项 + { 12, "none" }, // 保留项 + { 13, "none" }, // 保留项 + { 14, "none" }, // 保留项 + { 15, "none" }, // 保留项 + }; + + // 弹幕标准字体大小 + private readonly int normalFontSize = 25; + + /// + /// 获取Bilibili实例 + /// + /// + public static Bilibili GetInstance() + { + if (instance == null) + { + instance = new Bilibili(); + } + + return instance; + } + + /// + /// 隐藏Bilibili()方法,必须使用单例模式 + /// + private Bilibili() { } + + /// + /// 是否屏蔽顶部弹幕 + /// + /// + /// + public Bilibili SetTopFilter(bool isFilter) + { + config["top_filter"] = isFilter; + return this; + } + + /// + /// 是否屏蔽底部弹幕 + /// + /// + /// + public Bilibili SetBottomFilter(bool isFilter) + { + config["bottom_filter"] = isFilter; + return this; + } + + /// + /// 是否屏蔽滚动弹幕 + /// + /// + /// + public Bilibili SetScrollFilter(bool isFilter) + { + config["scroll_filter"] = isFilter; + return this; + } + + public void Create(long avid, long cid, Config subtitleConfig, string assFile) + { + // 弹幕转换 + var biliDanmakus = DanmakuProtobuf.GetAllDanmakuProto(avid, cid); + + // 按弹幕出现顺序排序 + biliDanmakus.Sort((x, y) => { return x.Progress.CompareTo(y.Progress); }); + + var danmakus = new List(); + foreach (var biliDanmaku in biliDanmakus) + { + var danmaku = new Danmaku + { + // biliDanmaku.Progress单位是毫秒,所以除以1000,单位变为秒 + Start = biliDanmaku.Progress / 1000.0f, + Style = mapping[biliDanmaku.Mode], + Color = (int)biliDanmaku.Color, + Commenter = biliDanmaku.MidHash, + Content = biliDanmaku.Content, + SizeRatio = 1.0f * biliDanmaku.Fontsize / normalFontSize + }; + + danmakus.Add(danmaku); + } + + // 弹幕预处理 + Producer producer = new Producer(config, danmakus); + producer.StartHandle(); + + // 字幕生成 + var keepedDanmakus = producer.KeepedDanmakus; + var studio = new Studio(subtitleConfig, keepedDanmakus); + studio.StartHandle(); + studio.CreateAssFile(assFile); + } + + public Dictionary GetResolution(int quality) + { + var resolution = new Dictionary + { + { "width", 0 }, + { "height", 0 } + }; + + switch (quality) + { + // 240P 极速(仅mp4方式) + case 6: + break; + // 360P 流畅 + case 16: + break; + // 480P 清晰 + case 32: + break; + // 720P 高清(登录) + case 64: + break; + // 720P60 高清(大会员) + case 74: + break; + // 1080P 高清(登录) + case 80: + break; + // 1080P+ 高清(大会员) + case 112: + break; + // 1080P60 高清(大会员) + case 116: + break; + // 4K 超清(大会员)(需要fourk=1) + case 120: + break; + } + return resolution; + } +} \ No newline at end of file diff --git a/DownKyi.Core/Danmaku2Ass/Collision.cs b/DownKyi.Core/Danmaku2Ass/Collision.cs new file mode 100644 index 0000000..4e5c966 --- /dev/null +++ b/DownKyi.Core/Danmaku2Ass/Collision.cs @@ -0,0 +1,56 @@ +namespace DownKyi.Core.Danmaku2Ass; + +/// +/// 碰撞处理 +/// +public class Collision +{ + private readonly int lineCount; + private readonly List leaves; + + public Collision(int lineCount) + { + this.lineCount = lineCount; + leaves = Leaves(); + } + + private List Leaves() + { + var ret = new List(lineCount); + for (int i = 0; i < lineCount; i++) ret.Add(0); + return ret; + } + + /// + /// 碰撞检测 + /// 返回行号和时间偏移 + /// + /// + /// + public Tuple Detect(Display display) + { + List beyonds = new List(); + for (int i = 0; i < leaves.Count; i++) + { + float beyond = display.Danmaku.Start - leaves[i]; + // 某一行有足够空间,直接返回行号和 0 偏移 + if (beyond >= 0) + { + return Tuple.Create(i, 0f); + } + + beyonds.Add(beyond); + } + + // 所有行都没有空间了,那么找出哪一行能在最短时间内让出空间 + float soon = beyonds.Max(); + int lineIndex = beyonds.IndexOf(soon); + float offset = -soon; + return Tuple.Create(lineIndex, offset); + } + + public void Update(float leave, int lineIndex, float offset) + { + leaves[lineIndex] = Utils.IntCeiling(leave + offset); + } +} \ No newline at end of file diff --git a/DownKyi.Core/Danmaku2Ass/Config.cs b/DownKyi.Core/Danmaku2Ass/Config.cs new file mode 100644 index 0000000..3aeb050 --- /dev/null +++ b/DownKyi.Core/Danmaku2Ass/Config.cs @@ -0,0 +1,56 @@ +namespace DownKyi.Core.Danmaku2Ass; + +public class Config +{ + public string Title = "Downkyi"; + public int ScreenWidth = 1920; + public int ScreenHeight = 1080; + public string FontName = "黑体"; + public int BaseFontSize; // 字体大小,像素 + + // 限制行数 + private int lineCount; + + public int LineCount + { + get { return lineCount; } + set + { + if (value == 0) + { + lineCount = (int)Math.Floor(ScreenHeight / BaseFontSize * 1.0); + } + else + { + lineCount = value; + } + } + } + + public string LayoutAlgorithm; // 布局算法,async/sync + public int TuneDuration; // 微调时长 + public int DropOffset; // 丢弃偏移 + public int BottomMargin; // 底部边距 + public int CustomOffset; // 自定义偏移 + + public string HeaderTemplate = @"[Script Info] +; Script generated by Downkyi Danmaku Converter +; https://github.com/FlySelfLog/downkyi +Title: {title} +ScriptType: v4.00+ +Collisions: Normal +PlayResX: {width} +PlayResY: {height} +Timer: 10.0000 +WrapStyle: 2 +ScaledBorderAndShadow: no + +[V4+ Styles] +Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding +Style: Default,{fontname},54,&H00FFFFFF,&H00FFFFFF,&H00000000,&H00000000,0,0,0,0,100,100,0.00,0.00,1,2.00,0.00,2,30,30,120,0 +Style: Alternate,{fontname},36,&H00FFFFFF,&H00FFFFFF,&H00000000,&H00000000,0,0,0,0,100,100,0.00,0.00,1,2.00,0.00,2,30,30,84,0 +Style: Danmaku,{fontname},{fontsize},&H00FFFFFF,&H00FFFFFF,&H00000000,&H00000000,0,0,0,0,100,100,0.00,0.00,1,1.00,0.00,2,30,30,30,0 + +[Events] +Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text"; +} \ No newline at end of file diff --git a/DownKyi.Core/Danmaku2Ass/Creater.cs b/DownKyi.Core/Danmaku2Ass/Creater.cs new file mode 100644 index 0000000..fe739ef --- /dev/null +++ b/DownKyi.Core/Danmaku2Ass/Creater.cs @@ -0,0 +1,85 @@ +namespace DownKyi.Core.Danmaku2Ass; + +/// +/// 创建器 +/// +public class Creater +{ + public Config Config; + public List Danmakus; + public List Subtitles; + public string Text; + + public Creater(Config config, List danmakus) + { + Config = config; + Danmakus = danmakus; + Subtitles = SetSubtitles(); + Text = SetText(); + } + + protected List SetSubtitles() + { + var scroll = new Collision(Config.LineCount); + var stayed = new Collision(Config.LineCount); + Dictionary collisions = new Dictionary + { + { "scroll", scroll }, + { "top", stayed }, + { "bottom", stayed } + }; + + List subtitles = new List(); + foreach (var danmaku in Danmakus) + { + // 丢弃不支持的 + if (danmaku.Style == "none") + { + continue; + } + + // 创建显示方式对象 + var display = Display.Factory(Config, danmaku); + var collision = collisions[danmaku.Style]; + var detect = collision.Detect(display); + int lineIndex = detect.Item1; + float waitingOffset = detect.Item2; + + // 超过容忍的偏移量,丢弃掉此条弹幕 + if (waitingOffset > Config.DropOffset) + { + continue; + } + + // 接受偏移,更新碰撞信息 + display.Relayout(lineIndex); + collision.Update(display.Leave, lineIndex, waitingOffset); + + // 再加上自定义偏移 + float offset = waitingOffset + Config.CustomOffset; + Subtitle subtitle = new Subtitle(danmaku, display, offset); + + subtitles.Add(subtitle); + } + + return subtitles; + } + + protected string SetText() + { + string header = Config.HeaderTemplate + .Replace("{title}", Config.Title) + .Replace("{width}", Config.ScreenWidth.ToString()) + .Replace("{height}", Config.ScreenHeight.ToString()) + .Replace("{fontname}", Config.FontName) + .Replace("{fontsize}", Config.BaseFontSize.ToString()); + + string events = string.Empty; + foreach (var subtitle in Subtitles) + { + events += "\n" + subtitle.Text; + } + + return header + events; + } +} \ No newline at end of file diff --git a/DownKyi.Core/Danmaku2Ass/Danmaku.cs b/DownKyi.Core/Danmaku2Ass/Danmaku.cs new file mode 100644 index 0000000..024916a --- /dev/null +++ b/DownKyi.Core/Danmaku2Ass/Danmaku.cs @@ -0,0 +1,11 @@ +namespace DownKyi.Core.Danmaku2Ass; + +public class Danmaku +{ + public float Start { get; set; } + public string Style { get; set; } + public int Color { get; set; } + public string Commenter { get; set; } + public string Content { get; set; } + public float SizeRatio { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/Danmaku2Ass/Display.cs b/DownKyi.Core/Danmaku2Ass/Display.cs new file mode 100644 index 0000000..84440ea --- /dev/null +++ b/DownKyi.Core/Danmaku2Ass/Display.cs @@ -0,0 +1,411 @@ +using System.Reflection; + +namespace DownKyi.Core.Danmaku2Ass; + +/// +/// 显示方式 +/// +public class Display +{ + public Config Config; + public Danmaku Danmaku; + public int LineIndex; + + public int FontSize; + public bool IsScaled; + public int MaxLength; + public int Width; + public int Height; + + public Tuple Horizontal; + public Tuple Vertical; + + public int Duration; + public int Leave; + + protected Display() + { + } + + public Display(Config config, Danmaku danmaku) + { + Config = config; + Danmaku = danmaku; + LineIndex = 0; + + IsScaled = SetIsScaled(); + FontSize = SetFontSize(); + MaxLength = SetMaxLength(); + Width = SetWidth(); + Height = SetHeight(); + + Horizontal = SetHorizontal(); + Vertical = SetVertical(); + + Duration = SetDuration(); + Leave = SetLeave(); + } + + /// + /// 根据弹幕样式自动创建对应的 Display 类 + /// + /// + public static Display Factory(Config config, Danmaku danmaku) + { + Dictionary dict = new Dictionary + { + { "scroll", new ScrollDisplay(config, danmaku) }, + { "top", new TopDisplay(config, danmaku) }, + { "bottom", new BottomDisplay(config, danmaku) } + }; + return dict[danmaku.Style]; + } + + /// + /// 字体大小 + /// 按用户自定义的字体大小来缩放 + /// + /// + protected int SetFontSize() + { + if (IsScaled) + { + Console.WriteLine($"{Danmaku.SizeRatio}"); + } + + return Utils.IntCeiling(Config.BaseFontSize * Danmaku.SizeRatio); + } + + /// + /// 字体是否被缩放过 + /// + /// + protected bool SetIsScaled() + { + return !Math.Round(Danmaku.SizeRatio, 2).Equals(1.0); + //return Danmaku.SizeRatio.Equals(1.0f); + } + + /// + /// 最长的行字符数 + /// + /// + protected int SetMaxLength() + { + string[] lines = Danmaku.Content.Split('\n'); + int maxLength = 0; + foreach (string line in lines) + { + int length = Utils.DisplayLength(line); + if (maxLength < length) + { + maxLength = length; + } + } + + return maxLength; + } + + /// + /// 整条字幕宽度 + /// + /// + protected int SetWidth() + { + float charCount = MaxLength; // / 2; + return Utils.IntCeiling(FontSize * charCount); + } + + /// + /// 整条字幕高度 + /// + /// + protected int SetHeight() + { + int lineCount = Danmaku.Content.Split('\n').Length; + return lineCount * FontSize; + } + + /// + /// 出现和消失的水平坐标位置 + /// 默认在屏幕中间 + /// + /// + protected virtual Tuple SetHorizontal() + { + int x = (int)Math.Floor(Config.ScreenWidth / 2.0); + return Tuple.Create(x, x); + } + + /// + /// 出现和消失的垂直坐标位置 + /// 默认在屏幕中间 + /// + /// + protected virtual Tuple SetVertical() + { + int y = (int)Math.Floor(Config.ScreenHeight / 2.0); + return Tuple.Create(y, y); + } + + /// + /// 整条字幕的显示时间 + /// + /// + protected virtual int SetDuration() + { + int baseDuration = 3 + Config.TuneDuration; + if (baseDuration <= 0) + { + baseDuration = 0; + } + + float charCount = MaxLength / 2; + + int value; + if (charCount < 6) + { + value = baseDuration + 1; + } + else if (charCount < 12) + { + value = baseDuration + 2; + } + else + { + value = baseDuration + 3; + } + + return value; + } + + /// + /// 离开碰撞时间 + /// + /// + protected virtual int SetLeave() + { + return (int)(Danmaku.Start + Duration); + } + + /// + /// 按照新的行号重新布局 + /// + /// + public void Relayout(int lineIndex) + { + LineIndex = lineIndex; + Horizontal = SetHorizontal(); + Vertical = SetVertical(); + } +} + +/// +/// 顶部 +/// +public class TopDisplay : Display +{ + public TopDisplay(Config config, Danmaku danmaku) : base(config, danmaku) + { + //Console.WriteLine("TopDisplay constructor."); + } + + /// + /// + /// + /// + protected override Tuple SetVertical() + { + // 这里 y 坐标为 0 就是最顶行了 + int y = LineIndex * Config.BaseFontSize; + return Tuple.Create(y, y); + } +} + +/// +/// 底部 +/// +public class BottomDisplay : Display +{ + public BottomDisplay(Config config, Danmaku danmaku) : base(config, danmaku) + { + //Console.WriteLine("BottomDisplay constructor."); + } + + /// + /// + /// + /// + protected override Tuple SetVertical() + { + // 要让字幕不超出底部,减去高度 + int y = Config.ScreenHeight - (LineIndex * Config.BaseFontSize) - Height; + // 再减去自定义的底部边距 + y -= Config.BottomMargin; + return Tuple.Create(y, y); + } +} + +/// +/// 滚动 +/// +public class ScrollDisplay : Display +{ + public int Distance; + public int Speed; + + public ScrollDisplay(Config config, Danmaku danmaku) : base() + { + //Console.WriteLine("ScrollDisplay constructor."); + + Config = config; + Danmaku = danmaku; + LineIndex = 0; + + IsScaled = SetIsScaled(); + FontSize = SetFontSize(); + MaxLength = SetMaxLength(); + Width = SetWidth(); + Height = SetHeight(); + + Horizontal = SetHorizontal(); + Vertical = SetVertical(); + + Distance = SetDistance(); + Speed = SetSpeed(); + + Duration = SetDuration(); + Leave = SetLeave(); + } + + /// + /// ASS 的水平位置参考点是整条字幕文本的中点 + /// + /// + protected override Tuple SetHorizontal() + { + int x1 = Config.ScreenWidth + (int)Math.Floor(Width / 2.0); + int x2 = 0 - (int)Math.Floor(Width / 2.0); + return Tuple.Create(x1, x2); + } + + protected override Tuple SetVertical() + { + int baseFontSize = Config.BaseFontSize; + + // 垂直位置,按基准字体大小算每一行的高度 + int y = (LineIndex + 1) * baseFontSize; + + // 个别弹幕可能字体比基准要大,所以最上的一行还要避免挤出顶部屏幕 + // 坐标不能小于字体大小 + if (y < FontSize) + { + y = FontSize; + } + + return Tuple.Create(y, y); + } + + /// + /// 字幕坐标点的移动距离 + /// + /// + protected int SetDistance() + { + Tuple x = Horizontal; + return x.Item1 - x.Item2; + } + + /// + /// 字幕每个字的移动的速度 + /// + /// + protected int SetSpeed() + { + // 基准时间,就是每个字的移动时间 + // 12 秒加上用户自定义的微调 + int baseDuration = 12 + Config.TuneDuration; + if (baseDuration <= 0) + { + baseDuration = 1; + } + + return Utils.IntCeiling(Config.ScreenWidth / baseDuration); + } + + /// + /// 计算每条弹幕的显示时长,同步方式 + /// 每个弹幕的滚动速度都一样,辨认度好,适合观看剧集类视频。 + /// + /// + public int SyncDuration() + { + return Distance / Speed; + } + + /// + /// 计算每条弹幕的显示时长,异步方式 + /// 每个弹幕的滚动速度都不一样,动态调整,辨认度低,适合观看 MTV 类视频。 + /// + /// + public int AsyncDuration() + { + int baseDuration = 6 + Config.TuneDuration; + if (baseDuration <= 0) + { + baseDuration = 0; + } + + float charCount = MaxLength / 2; + + int value; + if (charCount < 6) + { + value = (int)(baseDuration + charCount); + } + else if (charCount < 12) + { + value = baseDuration + (int)(charCount / 2); + } + else if (charCount < 24) + { + value = baseDuration + (int)(charCount / 3); + } + else + { + value = baseDuration + 10; + } + + return value; + } + + /// + /// 整条字幕的移动时间 + /// + /// + protected override int SetDuration() + { + string methodName = Config.LayoutAlgorithm.Substring(0, 1).ToUpper() + Config.LayoutAlgorithm.Substring(1); + methodName += "Duration"; + MethodInfo method = typeof(ScrollDisplay).GetMethod(methodName); + if (method != null) + { + return (int)method.Invoke(this, null); + } + + return 0; + } + + /// + /// 离开碰撞时间 + /// + /// + protected override int SetLeave() + { + // 对于滚动样式弹幕来说,就是最后一个字符离开最右边缘的时间 + // 坐标是字幕中点,在屏幕外和内各有半个字幕宽度 + // 也就是跑过一个字幕宽度的路程 + float duration = Width / Speed; + return (int)(Danmaku.Start + duration); + } +} \ No newline at end of file diff --git a/DownKyi.Core/Danmaku2Ass/Filter.cs b/DownKyi.Core/Danmaku2Ass/Filter.cs new file mode 100644 index 0000000..06cd011 --- /dev/null +++ b/DownKyi.Core/Danmaku2Ass/Filter.cs @@ -0,0 +1,90 @@ +namespace DownKyi.Core.Danmaku2Ass; + +/// +/// 过滤器基类 +/// +public class Filter +{ + public virtual List DoFilter(List danmakus) + { + throw new NotImplementedException("使用了过滤器的未实现的方法。"); + } +} + +/// +/// 顶部样式过滤器 +/// +public class TopFilter : Filter +{ + public override List DoFilter(List danmakus) + { + List keep = new List(); + foreach (var danmaku in danmakus) + { + if (danmaku.Style == "top") + { + continue; + } + + keep.Add(danmaku); + } + + return keep; + } +} + +/// +/// 底部样式过滤器 +/// +public class BottomFilter : Filter +{ + public override List DoFilter(List danmakus) + { + List keep = new List(); + foreach (var danmaku in danmakus) + { + if (danmaku.Style == "bottom") + { + continue; + } + + keep.Add(danmaku); + } + + return keep; + } +} + +/// +/// 滚动样式过滤器 +/// +public class ScrollFilter : Filter +{ + public override List DoFilter(List danmakus) + { + List keep = new List(); + foreach (var danmaku in danmakus) + { + if (danmaku.Style == "scroll") + { + continue; + } + + keep.Add(danmaku); + } + + return keep; + } +} + +/// +/// 自定义过滤器 +/// +public class CustomFilter : Filter +{ + public override List DoFilter(List danmakus) + { + // TODO + return base.DoFilter(danmakus); + } +} \ No newline at end of file diff --git a/DownKyi.Core/Danmaku2Ass/Producer.cs b/DownKyi.Core/Danmaku2Ass/Producer.cs new file mode 100644 index 0000000..9d05017 --- /dev/null +++ b/DownKyi.Core/Danmaku2Ass/Producer.cs @@ -0,0 +1,101 @@ +namespace DownKyi.Core.Danmaku2Ass; + +public class Producer +{ + public Dictionary Config; + public Dictionary Filters; + public List Danmakus; + public List KeepedDanmakus; + public Dictionary FilterDetail; + + public Producer(Dictionary config, List danmakus) + { + Config = config; + Danmakus = danmakus; + } + + public void StartHandle() + { + LoadFilter(); + ApplyFilter(); + } + + public void LoadFilter() + { + Filters = new Dictionary(); + if (Config["top_filter"]) + { + Filters.Add("top_filter", new TopFilter()); + } + + if (Config["bottom_filter"]) + { + Filters.Add("bottom_filter", new BottomFilter()); + } + + if (Config["scroll_filter"]) + { + Filters.Add("scroll_filter", new ScrollFilter()); + } + //if (Config["custom_filter"]) + //{ + // Filters.Add("custom_filter", new CustomFilter()); + //} + } + + public void ApplyFilter() + { + Dictionary filterDetail = new Dictionary() + { + { "top_filter", 0 }, + { "bottom_filter", 0 }, + { "scroll_filter", 0 }, + //{ "custom_filter",0} + }; + + List danmakus = Danmakus; + //string[] orders = { "top_filter", "bottom_filter", "scroll_filter", "custom_filter" }; + string[] orders = { "top_filter", "bottom_filter", "scroll_filter" }; + foreach (string name in orders) + { + Filter filter; + try + { + filter = Filters[name]; + } + catch (Exception e) + { + Console.WriteLine("ApplyFilter()发生异常: {0}", e); + continue; + } + + int count = danmakus.Count; + danmakus = filter.DoFilter(danmakus); + filterDetail[name] = count - danmakus.Count; + } + + KeepedDanmakus = danmakus; + FilterDetail = filterDetail; + } + + public Dictionary Report() + { + int blockedCount = 0; + foreach (int count in FilterDetail.Values) + { + blockedCount += count; + } + + int passedCount = KeepedDanmakus.Count; + int totalCount = blockedCount + passedCount; + + Dictionary ret = new Dictionary + { + { "blocked", blockedCount }, + { "passed", passedCount }, + { "total", totalCount } + }; + + return (Dictionary)ret.Concat(FilterDetail); + } +} \ No newline at end of file diff --git a/DownKyi.Core/Danmaku2Ass/Studio.cs b/DownKyi.Core/Danmaku2Ass/Studio.cs new file mode 100644 index 0000000..b53c43f --- /dev/null +++ b/DownKyi.Core/Danmaku2Ass/Studio.cs @@ -0,0 +1,84 @@ +namespace DownKyi.Core.Danmaku2Ass; + +/// +/// 字幕工程类 +/// +public class Studio +{ + public Config Config; + public List Danmakus; + + public Creater Creater; + public int KeepedCount; + public int DropedCount; + + public Studio(Config config, List danmakus) + { + Config = config; + Danmakus = danmakus; + } + + public void StartHandle() + { + Creater = SetCreater(); + KeepedCount = SetKeepedCount(); + DropedCount = SetDropedCount(); + } + + /// + /// ass 创建器 + /// + /// + protected Creater SetCreater() + { + return new Creater(Config, Danmakus); + } + + /// + /// 保留条数 + /// + /// + protected int SetKeepedCount() + { + return Creater.Subtitles.Count(); + } + + /// + /// 丢弃条数 + /// + /// + protected int SetDropedCount() + { + return Danmakus.Count - KeepedCount; + } + + /// + /// 创建 ass 字幕 + /// + /// + public void CreateAssFile(string fileName) + { + CreateFile(fileName, Creater.Text); + } + + public void CreateFile(string fileName, string text) + { + try + { + File.WriteAllText(fileName, text); + } + catch (Exception) + { + } + } + + public Dictionary Report() + { + return new Dictionary() + { + { "total", Danmakus.Count }, + { "droped", DropedCount }, + { "keeped", KeepedCount }, + }; + } +} \ No newline at end of file diff --git a/DownKyi.Core/Danmaku2Ass/Subtitle.cs b/DownKyi.Core/Danmaku2Ass/Subtitle.cs new file mode 100644 index 0000000..bfd80f5 --- /dev/null +++ b/DownKyi.Core/Danmaku2Ass/Subtitle.cs @@ -0,0 +1,154 @@ +namespace DownKyi.Core.Danmaku2Ass; + +/// +/// 字幕 +/// +public class Subtitle +{ + public Danmaku Danmaku; + public Display Display; + public float Offset; + + public float Start; + public float End; + public string Color; + public Dictionary Position; + public string StartMarkup; + public string EndMarkup; + public string ColorMarkup; + public string BorderMarkup; + public string FontSizeMarkup; + public string StyleMarkup; + public string LayerMarkup; + public string ContentMarkup; + public string Text; + + public Subtitle(Danmaku danmaku, Display display, float offset = 0) + { + Danmaku = danmaku; + Display = display; + Offset = offset; + + Start = SetStart(); + End = SetEnd(); + Color = SetColor(); + Position = SetPosition(); + StartMarkup = SetStartMarkup(); + EndMarkup = SetEndMarkup(); + ColorMarkup = SetColorMarkup(); + BorderMarkup = SetBorderMarkup(); + FontSizeMarkup = SetFontSizeMarkup(); + StyleMarkup = SetStyleMarkup(); + LayerMarkup = SetLayerMarkup(); + ContentMarkup = SetContentMarkup(); + Text = SetText(); + } + + protected float SetStart() + { + return Danmaku.Start + Offset; + } + + protected float SetEnd() + { + return Start + Display.Duration; + } + + protected string SetColor() + { + return Utils.Int2bgr(Danmaku.Color); + } + + protected Dictionary SetPosition() + { + Tuple x = Display.Horizontal; + Tuple y = Display.Vertical; + + Dictionary value = new Dictionary + { + { "x1", x.Item1 }, + { "x2", x.Item2 }, + { "y1", y.Item1 }, + { "y2", y.Item2 } + }; + return value; + } + + protected string SetStartMarkup() + { + return Utils.Second2hms(Start); + } + + protected string SetEndMarkup() + { + return Utils.Second2hms(End); + } + + protected string SetColorMarkup() + { + // 白色不需要加特别标记 + if (Color == "FFFFFF") + { + return ""; + } + + return "\\c&H" + Color; + } + + protected string SetBorderMarkup() + { + // 暗色加个亮色边框,方便阅读 + if (Utils.IsDark(Danmaku.Color)) + { + //return "\\3c&HFFFFFF"; + return "\\3c&H000000"; + } + else + { + return "\\3c&H000000"; + } + //return ""; + } + + protected string SetFontSizeMarkup() + { + if (Display.IsScaled) + { + return $"\\fs{Display.FontSize}"; + } + + return ""; + } + + protected string SetStyleMarkup() + { + if (Danmaku.Style == "scroll") + { + return $"\\move({Position["x1"]}, {Position["y1"]}, {Position["x2"]}, {Position["y2"]})"; + } + + return $"\\a6\\pos({Position["x1"]}, {Position["y1"]})"; + } + + protected string SetLayerMarkup() + { + if (Danmaku.Style != "scroll") + { + return "-2"; + } + + return "-1"; + } + + protected string SetContentMarkup() + { + string markup = StyleMarkup + ColorMarkup + BorderMarkup + FontSizeMarkup; + string content = Utils.CorrectTypos(Danmaku.Content); + return $"{{{markup}}}{content}"; + } + + protected string SetText() + { + return $"Dialogue: {LayerMarkup},{StartMarkup},{EndMarkup},Danmaku,,0000,0000,0000,,{ContentMarkup}"; + } +} \ No newline at end of file diff --git a/DownKyi.Core/Danmaku2Ass/Utils.cs b/DownKyi.Core/Danmaku2Ass/Utils.cs new file mode 100644 index 0000000..df45a86 --- /dev/null +++ b/DownKyi.Core/Danmaku2Ass/Utils.cs @@ -0,0 +1,233 @@ +using System.Globalization; +using System.Text; + +namespace DownKyi.Core.Danmaku2Ass; + +internal static class Utils +{ + /// + /// 向上取整,返回int类型 + /// + /// + /// + public static int IntCeiling(float number) + { + return (int)Math.Ceiling(number); + } + + /// + /// 字符长度,1个汉字当2个英文 + /// + /// + /// + public static int DisplayLength(string text) + { + return Encoding.Default.GetBytes(text).Length; + } + + /// + /// 修正一些评论者的拼写错误 + /// + /// + /// + public static string CorrectTypos(string text) + { + text = text.Replace("/n", "\\N"); + text = text.Replace(">", ">"); + text = text.Replace("<", "<"); + return text; + } + + /// + /// 秒数转 时:分:秒 格式 + /// + /// + /// + public static string Second2hms(float seconds) + { + if (seconds < 0) + { + return "0:00:00.00"; + } + + int i = (int)Math.Floor(seconds / 1.0); + int dec = (int)(Math.Round(seconds % 1.0f, 2) * 100); + if (dec >= 100) + { + dec = 99; + } + + int min = (int)Math.Floor(i / 60.0); + int second = (int)(i % 60.0f); + + int hour = (int)Math.Floor(min / 60.0); + min = (int)Math.Floor(min % 60.0f); + + return $"{hour:D}:{min:D2}:{second:D2}.{dec:D2}"; + } + + /// + /// 时:分:秒 格式转 秒数 + /// + /// + /// + public static float Hms2second(string hms) + { + string[] numbers = hms.Split(':'); + float seconds = 0; + + for (int i = 0; i < numbers.Length; i++) + { + seconds += (float)(float.Parse(numbers[numbers.Length - i - 1]) * Math.Pow(60, i)); + } + + return seconds; + } + + /// + /// 同Hms2second(string hms),不过可以用 +/- 符号来连接多个 + /// 即 3:00-2:30 相当于 30 秒 + /// + /// + /// + public static float Xhms2second(string xhms) + { + string[] args = xhms.Replace("+", " +").Replace("-", " -").Split(' '); + float result = 0; + foreach (string hms in args) + { + result += Hms2second(hms); + } + + return result; + } + + /// + /// 颜色值,整型转 RGB + /// + /// + /// + public static string Int2rgb(int integer) + { + return integer.ToString("X").PadLeft(6, '0'); + ; + } + + /// + /// 颜色值,整型转 BGR + /// + /// + /// + public static string Int2bgr(int integer) + { + string rgb = Int2rgb(integer); + string bgr = rgb.Substring(4, 2) + rgb.Substring(2, 2) + rgb.Substring(0, 2); + return bgr; + } + + /// + /// 颜色值,整型转 HLS + /// + /// + /// + public static float[] Int2hls(int integer) + { + string rgb = Int2rgb(integer); + int[] rgb_decimals = { 0, 0, 0 }; + rgb_decimals[0] = int.Parse(rgb.Substring(0, 2), NumberStyles.HexNumber); + rgb_decimals[1] = int.Parse(rgb.Substring(2, 2), NumberStyles.HexNumber); + rgb_decimals[2] = int.Parse(rgb.Substring(4, 2), NumberStyles.HexNumber); + + int[] rgb_coordinates = { 0, 0, 0 }; + rgb_coordinates[0] = (int)Math.Floor(rgb_decimals[0] / 255.0); + rgb_coordinates[1] = (int)Math.Floor(rgb_decimals[1] / 255.0); + rgb_coordinates[2] = (int)Math.Floor(rgb_decimals[2] / 255.0); + float[] hls_corrdinates = Rgb2hls(rgb_coordinates); + + float[] hls = { 0, 0, 0 }; + hls[0] = hls_corrdinates[0] * 360; + hls[1] = hls_corrdinates[1] * 100; + hls[2] = hls_corrdinates[2] * 100; + return hls; + } + + /// + /// HLS: Hue, Luminance, Saturation + /// H: position in the spectrum + /// L: color lightness + /// S: color saturation + /// + /// + /// + private static float[] Rgb2hls(int[] rgb) + { + float[] hls = { 0, 0, 0 }; + int maxc = rgb.Max(); + int minc = rgb.Min(); + hls[1] = (minc + maxc) / 2.0f; + if (minc == maxc) + { + return hls; + } + + if (hls[1] <= 0.5) + { + hls[2] = (maxc - minc) / (maxc + minc); + } + else + { + hls[2] = (maxc - minc) / (2.0f - maxc - minc); + } + + float rc = (maxc - rgb[0]) / (maxc - minc); + float gc = (maxc - rgb[1]) / (maxc - minc); + float bc = (maxc - rgb[2]) / (maxc - minc); + if (rgb[0] == maxc) + { + hls[0] = bc - gc; + } + else if (rgb[1] == maxc) + { + hls[0] = 2.0f + rc - bc; + } + else + { + hls[0] = 4.0f + gc - rc; + } + + hls[0] = (hls[0] / 6.0f) % 1.0f; + return hls; + } + + /// + /// 是否属于暗色 + /// + /// + /// + public static bool IsDark(int integer) + { + if (integer == 0) + { + return true; + } + + float[] hls = Int2hls(integer); + float hue = hls[0]; + float lightness = hls[1]; + + // HSL 色轮见 + // http://zh.wikipedia.org/zh-cn/HSL和HSV色彩空间 + // 以下的数值都是我的主观判断认为是暗色 + if ((hue > 30 && hue < 210) && lightness < 33) + { + return true; + } + + if ((hue < 30 || hue > 210) && lightness < 66) + { + return true; + } + + return false; + } +} \ No newline at end of file diff --git a/DownKyi.Core/DownKyi.Core.csproj b/DownKyi.Core/DownKyi.Core.csproj new file mode 100644 index 0000000..e75063c --- /dev/null +++ b/DownKyi.Core/DownKyi.Core.csproj @@ -0,0 +1,25 @@ + + + + net6.0 + enable + enable + + + + + + + + + + + + + + + ..\DownKyi\bin\Debug\net6.0\Avalonia.Base.dll + + + + diff --git a/DownKyi.Core/Downloader/MultiThreadDownloader.cs b/DownKyi.Core/Downloader/MultiThreadDownloader.cs new file mode 100644 index 0000000..fa5ff25 --- /dev/null +++ b/DownKyi.Core/Downloader/MultiThreadDownloader.cs @@ -0,0 +1,448 @@ +using System.ComponentModel; +using System.Net; + +namespace DownKyi.Core.Downloader; + +/// +/// 文件合并改变事件 +/// +/// +/// +public delegate void FileMergeProgressChangedEventHandler(object sender, int e); + +/// +/// 多线程下载器 +/// +public class MultiThreadDownloader +{ + #region 属性 + + private string _url; + private bool _rangeAllowed; + private readonly HttpWebRequest _request; + + private Action _requestConfigure = req => + req.UserAgent = + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.122 Safari/537.36"; + + #endregion 属性 + + #region 公共属性 + + /// + /// RangeAllowed + /// + public bool RangeAllowed + { + get => _rangeAllowed; + set => _rangeAllowed = value; + } + + /// + /// 临时文件夹 + /// + public string TempFileDirectory { get; set; } + + /// + /// url地址 + /// + public string Url + { + get => _url; + set => _url = value; + } + + /// + /// 第几部分 + /// + public int NumberOfParts { get; set; } + + /// + /// 已接收字节数 + /// + public long TotalBytesReceived + { + get + { + try + { + lock (this) + { + return PartialDownloaderList.Where(t => t != null).Sum(t => t.TotalBytesRead); + } + } + catch + { + return 0; + } + } + } + + /// + /// 总进度 + /// + public float TotalProgress { get; private set; } + + /// + /// 文件大小 + /// + public long Size { get; private set; } + + /// + /// 下载速度 + /// + public float TotalSpeedInBytes + { + get + { + lock (this) + { + return PartialDownloaderList.Sum(t => t.SpeedInBytes); + } + } + } + + /// + /// 下载块 + /// + public List PartialDownloaderList { get; } + + /// + /// 文件路径 + /// + public string FilePath { get; set; } + + #endregion 公共属性 + + #region 变量 + + /// + /// 总下载进度更新事件 + /// + public event EventHandler TotalProgressChanged; + + /// + /// 文件合并完成事件 + /// + public event EventHandler FileMergedComplete; + + /// + /// 文件合并事件 + /// + public event FileMergeProgressChangedEventHandler FileMergeProgressChanged; + + private readonly AsyncOperation _aop; + + #endregion 变量 + + #region 下载管理器 + + /// + /// 多线程下载管理器 + /// + /// + /// + /// + /// + public MultiThreadDownloader(string sourceUrl, string tempDir, string savePath, int numOfParts) + { + _url = sourceUrl; + NumberOfParts = numOfParts; + TempFileDirectory = tempDir; + PartialDownloaderList = new List(); + _aop = AsyncOperationManager.CreateOperation(null); + FilePath = savePath; + _request = WebRequest.Create(sourceUrl) as HttpWebRequest; + } + + /// + /// 多线程下载管理器 + /// + /// + /// + /// + public MultiThreadDownloader(string sourceUrl, string savePath, int numOfParts) : this(sourceUrl, null, + savePath, numOfParts) + { + TempFileDirectory = Environment.GetFolderPath(Environment.SpecialFolder.InternetCache); + } + + /// + /// 多线程下载管理器 + /// + /// + /// + public MultiThreadDownloader(string sourceUrl, int numOfParts) : this(sourceUrl, null, numOfParts) + { + } + + #endregion 下载管理器 + + #region 事件 + + private void temp_DownloadPartCompleted(object sender, EventArgs e) + { + WaitOrResumeAll(PartialDownloaderList, true); + + if (TotalBytesReceived == Size) + { + UpdateProgress(); + MergeParts(); + return; + } + + PartialDownloaderList.Sort((x, y) => (int)(y.RemainingBytes - x.RemainingBytes)); + var rem = PartialDownloaderList[0].RemainingBytes; + if (rem < 50 * 1024) + { + WaitOrResumeAll(PartialDownloaderList, false); + return; + } + + var from = PartialDownloaderList[0].CurrentPosition + rem / 2; + var to = PartialDownloaderList[0].To; + if (from > to) + { + WaitOrResumeAll(PartialDownloaderList, false); + return; + } + + PartialDownloaderList[0].To = from - 1; + WaitOrResumeAll(PartialDownloaderList, false); + var temp = new PartialDownloader(_url, TempFileDirectory, Guid.NewGuid().ToString(), from, to, true); + temp.DownloadPartCompleted += temp_DownloadPartCompleted; + temp.DownloadPartProgressChanged += temp_DownloadPartProgressChanged; + lock (this) + { + PartialDownloaderList.Add(temp); + } + + temp.Start(_requestConfigure); + } + + private void temp_DownloadPartProgressChanged(object sender, EventArgs e) + { + UpdateProgress(); + } + + private void UpdateProgress() + { + int pr = (int)(TotalBytesReceived * 1d / Size * 100); + if (TotalProgress != pr) + { + TotalProgress = pr; + if (TotalProgressChanged != null) + { + _aop.Post(state => TotalProgressChanged(this, EventArgs.Empty), null); + } + } + } + + #endregion 事件 + + #region 方法 + + private void CreateFirstPartitions() + { + Size = GetContentLength(ref _rangeAllowed, ref _url); + int maximumPart = (int)(Size / (25 * 1024)); + maximumPart = maximumPart == 0 ? 1 : maximumPart; + if (!_rangeAllowed) + { + NumberOfParts = 1; + } + else if (NumberOfParts > maximumPart) + { + NumberOfParts = maximumPart; + } + + for (int i = 0; i < NumberOfParts; i++) + { + var temp = CreateNew(i, NumberOfParts, Size); + temp.DownloadPartProgressChanged += temp_DownloadPartProgressChanged; + temp.DownloadPartCompleted += temp_DownloadPartCompleted; + lock (this) + { + PartialDownloaderList.Add(temp); + } + + temp.Start(_requestConfigure); + } + } + + private void MergeParts() + { + var mergeOrderedList = PartialDownloaderList.OrderBy(x => x.From); + var dir = new FileInfo(FilePath).DirectoryName; + Directory.CreateDirectory(dir); + + + using (var fs = File.OpenWrite(FilePath)) + { + long totalBytesWrite = 0; + int mergeProgress = 0; + foreach (var item in mergeOrderedList) + { + using (var pdi = File.OpenRead(item.FullPath)) + { + byte[] buffer = new byte[4096]; + int read; + while ((read = pdi.Read(buffer, 0, buffer.Length)) > 0) + { + fs.Write(buffer, 0, read); + totalBytesWrite += read; + int temp = (int)(totalBytesWrite * 1d / Size * 100); + if (temp != mergeProgress && FileMergeProgressChanged != null) + { + mergeProgress = temp; + _aop.Post(state => FileMergeProgressChanged(this, temp), null); + } + } + } + + try + { + File.Delete(item.FullPath); + } + catch + { + // ignored + } + } + } + + if (FileMergedComplete != null) + { + _aop.Post(state => FileMergedComplete(state, EventArgs.Empty), this); + } + } + + private PartialDownloader CreateNew(int order, int parts, long contentLength) + { + var division = contentLength / parts; + var remaining = contentLength % parts; + var start = division * order; + var end = start + division - 1; + end += order == parts - 1 ? remaining : 0; + return new PartialDownloader(_url, TempFileDirectory, Guid.NewGuid().ToString("N"), start, end, true); + } + + /// + /// 暂停或继续 + /// + /// + /// + public static void WaitOrResumeAll(List list, bool wait) + { + for (var index = 0; index < list.Count; index++) + { + if (wait) + { + list[index].Wait(); + } + else + { + list[index].ResumeAfterWait(); + } + } + } + + /// + /// 配置请求头 + /// + /// + public void Configure(Action config) + { + _requestConfigure = config; + } + + /// + /// 获取内容长度 + /// + /// + /// + /// + public long GetContentLength(ref bool rangeAllowed, ref string redirectedUrl) + { + _request.UserAgent = + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.122 Safari/537.36"; + _request.ServicePoint.ConnectionLimit = 4; + _requestConfigure(_request); + + using (var resp = _request.GetResponse() as HttpWebResponse) + { + redirectedUrl = resp.ResponseUri.OriginalString; + var ctl = resp.ContentLength; + rangeAllowed = resp.Headers.AllKeys.Select((v, i) => new + { + HeaderName = v, + HeaderValue = resp.Headers[i] + }).Any(k => k.HeaderName.ToLower().Contains("range") && k.HeaderValue.ToLower().Contains("byte")); + _request.Abort(); + return ctl; + } + } + + #endregion 方法 + + #region 公共方法 + + /// + /// 暂停下载 + /// + public void Pause() + { + lock (this) + { + foreach (var t in PartialDownloaderList.Where(t => !t.Completed)) + { + t.Stop(); + } + } + + Thread.Sleep(200); + } + + /// + /// 开始下载 + /// + public void Start() + { + Task th = new Task(CreateFirstPartitions); + th.Start(); + } + + /// + /// 唤醒下载 + /// + public void Resume() + { + int count = PartialDownloaderList.Count; + for (int i = 0; i < count; i++) + { + if (PartialDownloaderList[i].Stopped) + { + var from = PartialDownloaderList[i].CurrentPosition + 1; + var to = PartialDownloaderList[i].To; + if (from > to) + { + continue; + } + + var temp = new PartialDownloader(_url, TempFileDirectory, Guid.NewGuid().ToString(), from, to, + _rangeAllowed); + temp.DownloadPartProgressChanged += temp_DownloadPartProgressChanged; + temp.DownloadPartCompleted += temp_DownloadPartCompleted; + lock (this) + { + PartialDownloaderList.Add(temp); + } + + PartialDownloaderList[i].To = PartialDownloaderList[i].CurrentPosition; + temp.Start(_requestConfigure); + } + } + } + + #endregion 公共方法 +} \ No newline at end of file diff --git a/DownKyi.Core/Downloader/PartialDownloader.cs b/DownKyi.Core/Downloader/PartialDownloader.cs new file mode 100644 index 0000000..284248d --- /dev/null +++ b/DownKyi.Core/Downloader/PartialDownloader.cs @@ -0,0 +1,263 @@ +using System.ComponentModel; +using System.Diagnostics; +using System.Net; + +namespace DownKyi.Core.Downloader; + +/// +/// 部分下载器 +/// +public class PartialDownloader +{ + /// + /// 这部分完成事件 + /// + public event EventHandler DownloadPartCompleted; + + /// + /// 部分下载进度改变事件 + /// + public event EventHandler DownloadPartProgressChanged; + + /// + /// 部分下载停止事件 + /// + public event EventHandler DownloadPartStopped; + + private readonly AsyncOperation _aop = AsyncOperationManager.CreateOperation(null); + private readonly int[] _lastSpeeds; + private long _counter; + private long _to; + private long _totalBytesRead; + private bool _wait; + + /// + /// 下载已停止 + /// + public bool Stopped { get; private set; } + + /// + /// 下载已完成 + /// + public bool Completed { get; private set; } + + /// + /// 下载进度 + /// + public int Progress { get; private set; } + + /// + /// 下载目录 + /// + public string Directory { get; } + + /// + /// 文件名 + /// + public string FileName { get; } + + /// + /// 已读字节数 + /// + public long TotalBytesRead => _totalBytesRead; + + /// + /// 内容长度 + /// + public long ContentLength { get; private set; } + + /// + /// RangeAllowed + /// + public bool RangeAllowed { get; } + + /// + /// url + /// + public string Url { get; } + + /// + /// to + /// + public long To + { + get => _to; + set + { + _to = value; + ContentLength = _to - From + 1; + } + } + + /// + /// from + /// + public long From { get; } + + /// + /// 当前位置 + /// + public long CurrentPosition => From + _totalBytesRead - 1; + + /// + /// 剩余字节数 + /// + public long RemainingBytes => ContentLength - _totalBytesRead; + + /// + /// 完整路径 + /// + public string FullPath => Path.Combine(Directory, FileName); + + /// + /// 下载速度 + /// + public int SpeedInBytes + { + get + { + if (Completed) + { + return 0; + } + + int totalSpeeds = _lastSpeeds.Sum(); + return totalSpeeds / 10; + } + } + + /// + /// 部分块下载 + /// + /// + /// + /// + /// + /// + /// + public PartialDownloader(string url, string dir, string fileGuid, long from, long to, bool rangeAllowed) + { + From = from; + _to = to; + Url = url; + RangeAllowed = rangeAllowed; + FileName = fileGuid; + Directory = dir; + _lastSpeeds = new int[10]; + } + + private void DownloadProcedure(Action config) + { + using (var file = new FileStream(FullPath, FileMode.Create, FileAccess.ReadWrite, FileShare.Delete)) + { + var sw = new Stopwatch(); + if (WebRequest.Create(Url) is HttpWebRequest req) + { + req.UserAgent = + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.122 Safari/537.36"; + req.AllowAutoRedirect = true; + req.MaximumAutomaticRedirections = 5; + req.ServicePoint.ConnectionLimit += 1; + req.ServicePoint.Expect100Continue = true; + req.ProtocolVersion = HttpVersion.Version11; + req.Proxy = WebRequest.GetSystemWebProxy(); + config(req); + if (RangeAllowed) + { + req.AddRange(From, _to); + } + + if (req.GetResponse() is HttpWebResponse resp) + { + ContentLength = resp.ContentLength; + if (ContentLength <= 0 || (RangeAllowed && ContentLength != _to - From + 1)) + { + throw new Exception("Invalid response content"); + } + + using (var tempStream = resp.GetResponseStream()) + { + int bytesRead; + byte[] buffer = new byte[4096]; + sw.Start(); + while ((bytesRead = tempStream.Read(buffer, 0, buffer.Length)) > 0) + { + if (_totalBytesRead + bytesRead > ContentLength) + { + bytesRead = (int)(ContentLength - _totalBytesRead); + } + + file.Write(buffer, 0, bytesRead); + _totalBytesRead += bytesRead; + _lastSpeeds[_counter] = (int)(_totalBytesRead / Math.Ceiling(sw.Elapsed.TotalSeconds)); + _counter = (_counter >= 9) ? 0 : _counter + 1; + int tempProgress = (int)(_totalBytesRead * 100 / ContentLength); + if (Progress != tempProgress) + { + Progress = tempProgress; + _aop.Post(state => { DownloadPartProgressChanged?.Invoke(this, EventArgs.Empty); }, + null); + } + + if (Stopped || (RangeAllowed && _totalBytesRead == ContentLength)) + { + break; + } + } + } + } + + req.Abort(); + } + + sw.Stop(); + if (!Stopped && DownloadPartCompleted != null) + { + _aop.Post(state => + { + Completed = true; + DownloadPartCompleted(this, EventArgs.Empty); + }, null); + } + + if (Stopped && DownloadPartStopped != null) + { + _aop.Post(state => DownloadPartStopped(this, EventArgs.Empty), null); + } + } + } + + /// + /// 启动下载 + /// + public void Start(Action config) + { + Stopped = false; + var procThread = new Thread(_ => DownloadProcedure(config)); + procThread.Start(); + } + + /// + /// 下载停止 + /// + public void Stop() + { + Stopped = true; + } + + /// + /// 暂停等待下载 + /// + public void Wait() + { + _wait = true; + } + + /// + /// 稍后唤醒 + /// + public void ResumeAfterWait() + { + _wait = false; + } +} \ No newline at end of file diff --git a/DownKyi.Core/FFmpeg/FFmpegHelper.cs b/DownKyi.Core/FFmpeg/FFmpegHelper.cs new file mode 100644 index 0000000..da3a3d7 --- /dev/null +++ b/DownKyi.Core/FFmpeg/FFmpegHelper.cs @@ -0,0 +1,116 @@ +using DownKyi.Core.Logging; +using FFMpegCore; +using FFMpegCore.Enums; + +namespace DownKyi.Core.FFmpeg; + +public static class FFmpegHelper +{ + private const string Tag = "FFmpegHelper"; + + /// + /// 合并音频和视频 + /// + /// 音频 + /// 视频 + /// + public static bool MergeVideo(string audio, string video, string destVideo) + { + if (!File.Exists(audio) && !File.Exists(video)) return false; + FFMpegArguments + .FromFileInput(audio) + .AddFileInput(video) + .OutputToFile(destVideo, true, options => options + .WithAudioCodec("copy") + .WithVideoCodec("copy") + .ForceFormat("mp4")) + .ProcessSynchronously(); + try + { + if (audio != null) + { + File.Delete(audio); + } + + if (video != null) + { + File.Delete(video); + } + } + catch (IOException e) + { + Console.WriteLine("MergeVideo()发生IO异常: {0}", e); + LogManager.Error(Tag, e); + } + + return true; + } + + /// + /// 去水印,非常消耗cpu资源 + /// + /// + /// + /// + /// + /// + /// + /// + public static void Delogo(string video, string destVideo, int x, int y, int width, int height, + Action action) + { + var arg = FFMpegArguments + .FromFileInput(video) + .OutputToFile( + destVideo, + true, + option => option + .WithCustomArgument($"-vf delogo=x={x}:y={y}:w={width}:h={height}:show=0 -hide_banner")) + .NotifyOnOutput(action.Invoke) + .NotifyOnError(action.Invoke) + .ProcessSynchronously(); + } + + /// + /// 从一个视频中仅提取音频 + /// + /// 源视频 + /// 目标音频 + /// 输出信息 + public static void ExtractAudio(string video, string audio, Action action) + { + FFMpegArguments + .FromFileInput(video) + .OutputToFile(audio, + true, + options => options + .WithCustomArgument("-hide_banner") + .WithAudioCodec("copy") + .DisableChannel(Channel.Video) + ) + .NotifyOnOutput(action.Invoke) + .NotifyOnError(action.Invoke) + .ProcessSynchronously(); + } + + /// + /// 从一个视频中仅提取视频 + /// + /// 源视频 + /// 目标视频 + /// 输出信息 + public static void ExtractVideo(string video, string destVideo, Action action) + { + FFMpegArguments.FromFileInput(video) + .OutputToFile( + destVideo, + true, + options => options + .WithCustomArgument("-hide_banner") + .WithVideoCodec("copy") + .DisableChannel(Channel.Audio)) + .NotifyOnOutput(action.Invoke) + .NotifyOnError(action.Invoke) + .ProcessSynchronously(); + } +} \ No newline at end of file diff --git a/DownKyi.Core/FileName/FileName.cs b/DownKyi.Core/FileName/FileName.cs new file mode 100644 index 0000000..2263afd --- /dev/null +++ b/DownKyi.Core/FileName/FileName.cs @@ -0,0 +1,191 @@ +using System.Text.RegularExpressions; + +namespace DownKyi.Core.FileName; + +public class FileName +{ + private readonly List nameParts; + private string order = "ORDER"; + private string section = "SECTION"; + private string mainTitle = "MAIN_TITLE"; + private string pageTitle = "PAGE_TITLE"; + private string videoZone = "VIDEO_ZONE"; + private string audioQuality = "AUDIO_QUALITY"; + private string videoQuality = "VIDEO_QUALITY"; + private string videoCodec = "VIDEO_CODEC"; + + private string videoPublishTime = "VIDEO_PUBLISH_TIME"; + + private long avid = -1; + private string bvid = "BVID"; + private long cid = -1; + + private long upMid = -1; + private string upName = "UP_NAME"; + + private FileName(List nameParts) + { + this.nameParts = nameParts; + } + + public static FileName Builder(List nameParts) + { + return new FileName(nameParts); + } + + public FileName SetOrder(int order) + { + this.order = order.ToString(); + return this; + } + + public FileName SetOrder(int order, int count) + { + int length = Math.Abs(count).ToString().Length; + this.order = order.ToString("D" + length); + + return this; + } + + public FileName SetSection(string section) + { + this.section = section; + return this; + } + + public FileName SetMainTitle(string mainTitle) + { + this.mainTitle = mainTitle; + return this; + } + + public FileName SetPageTitle(string pageTitle) + { + this.pageTitle = pageTitle; + return this; + } + + public FileName SetVideoZone(string videoZone) + { + this.videoZone = videoZone; + return this; + } + + public FileName SetAudioQuality(string audioQuality) + { + this.audioQuality = audioQuality; + return this; + } + + public FileName SetVideoQuality(string videoQuality) + { + this.videoQuality = videoQuality; + return this; + } + + public FileName SetVideoCodec(string videoCodec) + { + this.videoCodec = videoCodec; + return this; + } + + public FileName SetVideoPublishTime(string videoPublishTime) + { + this.videoPublishTime = videoPublishTime; + return this; + } + + public FileName SetAvid(long avid) + { + this.avid = avid; + return this; + } + + public FileName SetBvid(string bvid) + { + this.bvid = bvid; + return this; + } + + public FileName SetCid(long cid) + { + this.cid = cid; + return this; + } + + public FileName SetUpMid(long upMid) + { + this.upMid = upMid; + return this; + } + + public FileName SetUpName(string upName) + { + this.upName = upName; + return this; + } + + public string RelativePath() + { + string path = string.Empty; + + foreach (FileNamePart part in nameParts) + { + switch (part) + { + case FileNamePart.ORDER: + path += order; + break; + case FileNamePart.SECTION: + path += section; + break; + case FileNamePart.MAIN_TITLE: + path += mainTitle; + break; + case FileNamePart.PAGE_TITLE: + path += pageTitle; + break; + case FileNamePart.VIDEO_ZONE: + path += videoZone; + break; + case FileNamePart.AUDIO_QUALITY: + path += audioQuality; + break; + case FileNamePart.VIDEO_QUALITY: + path += videoQuality; + break; + case FileNamePart.VIDEO_CODEC: + path += videoCodec; + break; + case FileNamePart.VIDEO_PUBLISH_TIME: + path += videoPublishTime; + break; + case FileNamePart.AVID: + path += avid; + break; + case FileNamePart.BVID: + path += bvid; + break; + case FileNamePart.CID: + path += cid; + break; + case FileNamePart.UP_MID: + path += upMid; + break; + case FileNamePart.UP_NAME: + path += upName; + break; + } + + if (((int)part) >= 100) + { + path += HyphenSeparated.Hyphen[(int)part]; + } + } + + // 避免连续多个斜杠 + path = Regex.Replace(path, @"//+", "/"); + // 避免以斜杠开头和结尾的情况 + return path.TrimEnd('/').TrimStart('/'); + } +} \ No newline at end of file diff --git a/DownKyi.Core/FileName/FileNamePart.cs b/DownKyi.Core/FileName/FileNamePart.cs new file mode 100644 index 0000000..a0f152d --- /dev/null +++ b/DownKyi.Core/FileName/FileNamePart.cs @@ -0,0 +1,42 @@ +namespace DownKyi.Core.FileName; + +public enum FileNamePart +{ + // Video + ORDER = 1, + SECTION, + MAIN_TITLE, + PAGE_TITLE, + VIDEO_ZONE, + AUDIO_QUALITY, + VIDEO_QUALITY, + VIDEO_CODEC, + + VIDEO_PUBLISH_TIME, + + AVID, + BVID, + CID, + + UP_MID, + UP_NAME, + + // 斜杠 + SLASH = 100, + + // HyphenSeparated + UNDERSCORE = 101, // 下划线 + HYPHEN, // 连字符 + PLUS, // 加号 + COMMA, // 逗号 + PERIOD, // 句号 + AND, // and + NUMBER, // # + OPEN_PAREN, // 左圆括号 + CLOSE_PAREN, // 右圆括号 + OPEN_BRACKET, // 左方括号 + CLOSE_BRACKET, // 右方括号 + OPEN_BRACE, // 左花括号 + CLOSE_brace, // 右花括号 + BLANK, // 空白符 +} \ No newline at end of file diff --git a/DownKyi.Core/FileName/HyphenSeparated.cs b/DownKyi.Core/FileName/HyphenSeparated.cs new file mode 100644 index 0000000..aad9b2f --- /dev/null +++ b/DownKyi.Core/FileName/HyphenSeparated.cs @@ -0,0 +1,27 @@ +namespace DownKyi.Core.FileName; + +/// +/// 文件名字段 +/// +public static class HyphenSeparated +{ + // 文件名的分隔符 + public static Dictionary Hyphen = new Dictionary() + { + { 100, "/" }, + { 101, "_" }, + { 102, "-" }, + { 103, "+" }, + { 104, "," }, + { 105, "." }, + { 106, "&" }, + { 107, "#" }, + { 108, "(" }, + { 109, ")" }, + { 110, "[" }, + { 111, "]" }, + { 112, "{" }, + { 113, "}" }, + { 114, " " }, + }; +} \ No newline at end of file diff --git a/DownKyi.Core/Logging/LogInfo.cs b/DownKyi.Core/Logging/LogInfo.cs new file mode 100644 index 0000000..28fce50 --- /dev/null +++ b/DownKyi.Core/Logging/LogInfo.cs @@ -0,0 +1,52 @@ +namespace DownKyi.Core.Logging; + +/// +/// 日志信息 +/// +public class LogInfo +{ + /// + /// 时间 + /// + public DateTime Time { get; set; } + + /// + /// 线程id + /// + public int ThreadId { get; set; } + + /// + /// 日志级别 + /// + public LogLevel LogLevel { get; set; } + + /// + /// 异常源 + /// + public string Source { get; set; } + + /// + /// 异常信息 + /// + public string Message { get; set; } + + /// + /// 异常对象 + /// + public Exception Exception { get; set; } + + /// + /// 日志类型 + /// + public string ExceptionType { get; set; } + + /// + /// 请求路径 + /// + public string RequestUrl { get; set; } + + /// + /// 客户端代理 + /// + public string UserAgent { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/Logging/LogLevel.cs b/DownKyi.Core/Logging/LogLevel.cs new file mode 100644 index 0000000..8746a58 --- /dev/null +++ b/DownKyi.Core/Logging/LogLevel.cs @@ -0,0 +1,27 @@ +namespace DownKyi.Core.Logging; + +/// +/// 日志级别 +/// +public enum LogLevel +{ + /// + /// 信息级别 + /// + Info, + + /// + /// debug级别 + /// + Debug, + + /// + /// 错误级别 + /// + Error, + + /// + /// 致命级别 + /// + Fatal +} \ No newline at end of file diff --git a/DownKyi.Core/Logging/LogManager.cs b/DownKyi.Core/Logging/LogManager.cs new file mode 100644 index 0000000..77b4e5c --- /dev/null +++ b/DownKyi.Core/Logging/LogManager.cs @@ -0,0 +1,477 @@ +using System.Collections.Concurrent; +using System.Text.RegularExpressions; +using static System.DateTime; + +namespace DownKyi.Core.Logging; + +/// +/// 日志组件 +/// +public class LogManager +{ + private static readonly ConcurrentQueue> LogQueue = + new ConcurrentQueue>(); + + /// + /// 自定义事件 + /// + public static event Action Event; + + static LogManager() + { + var writeTask = new Task(obj => + { + while (true) + { + Pause.WaitOne(1000, true); + List temp = new List(); + foreach (var logItem in LogQueue) + { + string logPath = logItem.Item1; + string logMergeContent = string.Concat(logItem.Item2, Environment.NewLine, + "----------------------------------------------------------------------------------------------------------------------", + Environment.NewLine); + string[] logArr = temp.FirstOrDefault(d => d[0].Equals(logPath)); + if (logArr != null) + { + logArr[1] = string.Concat(logArr[1], logMergeContent); + } + else + { + logArr = new[] + { + logPath, + logMergeContent + }; + temp.Add(logArr); + } + + LogQueue.TryDequeue(out Tuple _); + } + + foreach (var item in temp) + { + WriteText(item[0], item[1]); + } + } + }, null, TaskCreationOptions.LongRunning); + writeTask.Start(); + } + + private static AutoResetEvent Pause => new AutoResetEvent(false); + + private static string logDirectory; + + /// + /// 日志存放目录,默认日志放在当前应用程序运行目录下的logs文件夹中 + /// + public static string LogDirectory + { + get => logDirectory ?? + (Directory.GetFiles(AppDomain.CurrentDomain.BaseDirectory).Any(s => s.Contains("Web.config")) + ? AppDomain.CurrentDomain.BaseDirectory + @"App_Data\Logs\" + : Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "logs")); + set + { + //自定义目录 + if (!Directory.Exists(value)) + { + Directory.CreateDirectory(value); + } + + logDirectory = value; + } + } + + /// + /// 写入Info级别的日志 + /// + /// + public static void Info(string info) + { + LogQueue.Enqueue(new Tuple(GetLogPath(), + $"{Now} [{Thread.CurrentThread.ManagedThreadId}] {nameof(info).ToUpper()} {info}")); + var log = new LogInfo() + { + LogLevel = LogLevel.Info, + Message = info, + Time = Now, + ThreadId = Thread.CurrentThread.ManagedThreadId + }; + Event?.Invoke(log); + } + + /// + /// 写入Info级别的日志 + /// + /// + /// + public static void Info(string source, string info) + { + LogQueue.Enqueue(new Tuple(GetLogPath(), + $"{Now} [{Thread.CurrentThread.ManagedThreadId}] {nameof(info).ToUpper()} {source} {info}")); + LogInfo log = new LogInfo() + { + LogLevel = LogLevel.Info, + Message = info, + Time = Now, + ThreadId = Thread.CurrentThread.ManagedThreadId, + Source = source + }; + Event?.Invoke(log); + } + + /// + /// 写入Info级别的日志 + /// + /// + /// + public static void Info(Type source, string info) + { + LogQueue.Enqueue(new Tuple(GetLogPath(), + $"{Now} [{Thread.CurrentThread.ManagedThreadId}] {nameof(info).ToUpper()} {source.FullName} {info}")); + LogInfo log = new LogInfo() + { + LogLevel = LogLevel.Info, + Message = info, + Time = Now, + ThreadId = Thread.CurrentThread.ManagedThreadId, + Source = source.FullName + }; + Event?.Invoke(log); + } + + /// + /// 写入debug级别日志 + /// + /// 异常对象 + public static void Debug(string debug) + { + LogQueue.Enqueue(new Tuple(GetLogPath(), + $"{Now} [{Thread.CurrentThread.ManagedThreadId}] {nameof(debug).ToUpper()} {debug}")); + LogInfo log = new LogInfo() + { + LogLevel = LogLevel.Debug, + Message = debug, + Time = Now, + ThreadId = Thread.CurrentThread.ManagedThreadId + }; + Event?.Invoke(log); + } + + /// + /// 写入debug级别日志 + /// + /// 异常源的类型 + /// 异常对象 + public static void Debug(string source, string debug) + { + LogQueue.Enqueue(new Tuple(GetLogPath(), + $"{Now} [{Thread.CurrentThread.ManagedThreadId}] {nameof(debug).ToUpper()} {source} {debug}")); + LogInfo log = new LogInfo() + { + LogLevel = LogLevel.Debug, + Message = debug, + Time = Now, + ThreadId = Thread.CurrentThread.ManagedThreadId, + Source = source + }; + Event?.Invoke(log); + } + + /// + /// 写入debug级别日志 + /// + /// 异常源的类型 + /// 异常对象 + public static void Debug(Type source, string debug) + { + LogQueue.Enqueue(new Tuple(GetLogPath(), + $"{Now} [{Thread.CurrentThread.ManagedThreadId}] {nameof(debug).ToUpper()} {source.FullName} {debug}")); + LogInfo log = new LogInfo() + { + LogLevel = LogLevel.Debug, + Message = debug, + Time = Now, + ThreadId = Thread.CurrentThread.ManagedThreadId, + Source = source.FullName + }; + Event?.Invoke(log); + } + + /// + /// 写入error级别日志 + /// + /// 异常对象 + public static void Error(Exception error) + { + LogQueue.Enqueue(new Tuple(GetLogPath(), + $"{Now} [{Thread.CurrentThread.ManagedThreadId}] {nameof(error).ToUpper()} {error.Source} {error.Message}{Environment.NewLine}{error.StackTrace}")); + LogInfo log = new LogInfo() + { + LogLevel = LogLevel.Error, + Message = error.Message, + Time = Now, + ThreadId = Thread.CurrentThread.ManagedThreadId, + Source = error.Source, + Exception = error, + ExceptionType = error.GetType().Name + }; + Event?.Invoke(log); + } + + /// + /// 写入error级别日志 + /// + /// 异常源的类型 + /// 异常对象 + public static void Error(Type source, Exception error) + { + LogQueue.Enqueue(new Tuple(GetLogPath(), + $"{Now} [{Thread.CurrentThread.ManagedThreadId}] {nameof(error).ToUpper()} {source.FullName} {error.Message}{Environment.NewLine}{error.StackTrace}")); + LogInfo log = new LogInfo() + { + LogLevel = LogLevel.Error, + Message = error.Message, + Time = Now, + ThreadId = Thread.CurrentThread.ManagedThreadId, + Source = source.FullName, + Exception = error, + ExceptionType = error.GetType().Name + }; + Event?.Invoke(log); + } + + /// + /// 写入error级别日志 + /// + /// 异常源的类型 + /// 异常信息 + public static void Error(Type source, string error) + { + LogQueue.Enqueue(new Tuple(GetLogPath(), + $"{Now} [{Thread.CurrentThread.ManagedThreadId}] {nameof(error).ToUpper()} {source.FullName} {error}")); + LogInfo log = new LogInfo() + { + LogLevel = LogLevel.Error, + Message = error, + Time = Now, + ThreadId = Thread.CurrentThread.ManagedThreadId, + Source = source.FullName, + //Exception = error, + ExceptionType = error.GetType().Name + }; + Event?.Invoke(log); + } + + /// + /// 写入error级别日志 + /// + /// 异常源的类型 + /// 异常对象 + public static void Error(string source, Exception error) + { + LogQueue.Enqueue(new Tuple(GetLogPath(), + $"{Now} [{Thread.CurrentThread.ManagedThreadId}] {nameof(error).ToUpper()} {source} {error.Message}{Environment.NewLine}{error.StackTrace}")); + LogInfo log = new LogInfo() + { + LogLevel = LogLevel.Error, + Message = error.Message, + Time = Now, + ThreadId = Thread.CurrentThread.ManagedThreadId, + Source = source, + Exception = error, + ExceptionType = error.GetType().Name + }; + Event?.Invoke(log); + } + + /// + /// 写入error级别日志 + /// + /// 异常源的类型 + /// 异常信息 + public static void Error(string source, string error) + { + LogQueue.Enqueue(new Tuple(GetLogPath(), + $"{Now} [{Thread.CurrentThread.ManagedThreadId}] {nameof(error).ToUpper()} {source} {error}")); + LogInfo log = new LogInfo() + { + LogLevel = LogLevel.Error, + Message = error, + Time = Now, + ThreadId = Thread.CurrentThread.ManagedThreadId, + Source = source, + //Exception = error, + ExceptionType = error.GetType().Name + }; + Event?.Invoke(log); + } + + /// + /// 写入fatal级别日志 + /// + /// 异常对象 + public static void Fatal(Exception fatal) + { + LogQueue.Enqueue(new Tuple(GetLogPath(), + $"{Now} [{Thread.CurrentThread.ManagedThreadId}] {nameof(fatal).ToUpper()} {fatal.Source} {fatal.Message}{Environment.NewLine}{fatal.StackTrace}")); + LogInfo log = new LogInfo() + { + LogLevel = LogLevel.Fatal, + Message = fatal.Message, + Time = Now, + ThreadId = Thread.CurrentThread.ManagedThreadId, + Source = fatal.Source, + Exception = fatal, + ExceptionType = fatal.GetType().Name + }; + Event?.Invoke(log); + } + + /// + /// 写入fatal级别日志 + /// + /// 异常源的类型 + /// 异常对象 + public static void Fatal(Type source, Exception fatal) + { + LogQueue.Enqueue(new Tuple(GetLogPath(), + $"{Now} [{Thread.CurrentThread.ManagedThreadId}] {nameof(fatal).ToUpper()} {source.FullName} {fatal.Message}{Environment.NewLine}{fatal.StackTrace}")); + LogInfo log = new LogInfo() + { + LogLevel = LogLevel.Fatal, + Message = fatal.Message, + Time = Now, + ThreadId = Thread.CurrentThread.ManagedThreadId, + Source = source.FullName, + Exception = fatal, + ExceptionType = fatal.GetType().Name + }; + Event?.Invoke(log); + } + + /// + /// 写入fatal级别日志 + /// + /// 异常源的类型 + /// 异常对象 + public static void Fatal(Type source, string fatal) + { + LogQueue.Enqueue(new Tuple(GetLogPath(), + $"{Now} [{Thread.CurrentThread.ManagedThreadId}] {nameof(fatal).ToUpper()} {source.FullName} {fatal}")); + LogInfo log = new LogInfo() + { + LogLevel = LogLevel.Fatal, + Message = fatal, + Time = Now, + ThreadId = Thread.CurrentThread.ManagedThreadId, + Source = source.FullName, + //Exception = fatal, + ExceptionType = fatal.GetType().Name + }; + Event?.Invoke(log); + } + + /// + /// 写入fatal级别日志 + /// + /// 异常源的类型 + /// 异常对象 + public static void Fatal(string source, Exception fatal) + { + LogQueue.Enqueue(new Tuple(GetLogPath(), + $"{Now} [{Thread.CurrentThread.ManagedThreadId}] {nameof(fatal).ToUpper()} {source} {fatal.Message}{Environment.NewLine}{fatal.StackTrace}")); + LogInfo log = new LogInfo() + { + LogLevel = LogLevel.Fatal, + Message = fatal.Message, + Time = Now, + ThreadId = Thread.CurrentThread.ManagedThreadId, + Source = source, + Exception = fatal, + ExceptionType = fatal.GetType().Name + }; + Event?.Invoke(log); + } + + /// + /// 写入fatal级别日志 + /// + /// 异常源的类型 + /// 异常对象 + public static void Fatal(string source, string fatal) + { + LogQueue.Enqueue(new Tuple(GetLogPath(), + $"{Now} [{Thread.CurrentThread.ManagedThreadId}] {nameof(fatal).ToUpper()} {source} {fatal}")); + LogInfo log = new LogInfo() + { + LogLevel = LogLevel.Fatal, + Message = fatal, + Time = Now, + ThreadId = Thread.CurrentThread.ManagedThreadId, + Source = source, + ExceptionType = fatal.GetType().Name + }; + Event?.Invoke(log); + } + + private static string GetLogPath() + { + string newFilePath; + var logDir = string.IsNullOrEmpty(LogDirectory) + ? Path.Combine(Environment.CurrentDirectory, "logs") + : LogDirectory; + Directory.CreateDirectory(logDir); + string extension = ".log"; + string fileNameNotExt = Now.ToString("yyyyMMdd"); + string fileNamePattern = string.Concat(fileNameNotExt, "(*)", extension); + List filePaths = Directory.GetFiles(logDir, fileNamePattern, SearchOption.TopDirectoryOnly).ToList(); + + if (filePaths.Count > 0) + { + int fileMaxLen = filePaths.Max(d => d.Length); + string lastFilePath = + filePaths.Where(d => d.Length == fileMaxLen).OrderByDescending(d => d).FirstOrDefault(); + if (new FileInfo(lastFilePath).Length > 1 * 1024 * 1024) + { + var no = new Regex(@"(?is)(?<=\()(.*)(?=\))").Match(Path.GetFileName(lastFilePath)).Value; + var parse = int.TryParse(no, out int tempno); + var formatno = $"({(parse ? (tempno + 1) : tempno)})"; + var newFileName = String.Concat(fileNameNotExt, formatno, extension); + newFilePath = Path.Combine(logDir, newFileName); + } + else + { + newFilePath = lastFilePath; + } + } + else + { + var newFileName = string.Concat(fileNameNotExt, $"({0})", extension); + newFilePath = Path.Combine(logDir, newFileName); + } + + return newFilePath; + } + + private static void WriteText(string logPath, string logContent) + { + try + { + if (!File.Exists(logPath)) + { + File.CreateText(logPath).Close(); + } + + using (var sw = File.AppendText(logPath)) + { + sw.Write(logContent); + } + } + catch (Exception) + { + // ignored + } + } +} \ No newline at end of file diff --git a/DownKyi.Core/Settings/AfterDownloadOperation.cs b/DownKyi.Core/Settings/AfterDownloadOperation.cs new file mode 100644 index 0000000..3f56728 --- /dev/null +++ b/DownKyi.Core/Settings/AfterDownloadOperation.cs @@ -0,0 +1,10 @@ +namespace DownKyi.Core.Settings; + +public enum AfterDownloadOperation +{ + NOT_SET = 0, + NONE = 1, + OPEN_FOLDER, + CLOSE_APP, + CLOSE_SYSTEM +} \ No newline at end of file diff --git a/DownKyi.Core/Settings/AllowStatus.cs b/DownKyi.Core/Settings/AllowStatus.cs new file mode 100644 index 0000000..d39f642 --- /dev/null +++ b/DownKyi.Core/Settings/AllowStatus.cs @@ -0,0 +1,8 @@ +namespace DownKyi.Core.Settings; + +public enum AllowStatus +{ + NONE = 0, + NO, + YES +} \ No newline at end of file diff --git a/DownKyi.Core/Settings/DanmakuLayoutAlgorithm.cs b/DownKyi.Core/Settings/DanmakuLayoutAlgorithm.cs new file mode 100644 index 0000000..d06f005 --- /dev/null +++ b/DownKyi.Core/Settings/DanmakuLayoutAlgorithm.cs @@ -0,0 +1,8 @@ +namespace DownKyi.Core.Settings; + +public enum DanmakuLayoutAlgorithm +{ + NONE = 0, + ASYNC, + SYNC +} \ No newline at end of file diff --git a/DownKyi.Core/Settings/DownloadFinishedSort.cs b/DownKyi.Core/Settings/DownloadFinishedSort.cs new file mode 100644 index 0000000..03ac700 --- /dev/null +++ b/DownKyi.Core/Settings/DownloadFinishedSort.cs @@ -0,0 +1,8 @@ +namespace DownKyi.Core.Settings; + +public enum DownloadFinishedSort +{ + NOT_SET = 0, + DOWNLOAD, + NUMBER +} \ No newline at end of file diff --git a/DownKyi.Core/Settings/Downloader.cs b/DownKyi.Core/Settings/Downloader.cs new file mode 100644 index 0000000..809b962 --- /dev/null +++ b/DownKyi.Core/Settings/Downloader.cs @@ -0,0 +1,9 @@ +namespace DownKyi.Core.Settings; + +public enum Downloader +{ + NOT_SET = 0, + BUILT_IN, + ARIA, + CUSTOM_ARIA, +} \ No newline at end of file diff --git a/DownKyi.Core/Settings/Models/AboutSettings.cs b/DownKyi.Core/Settings/Models/AboutSettings.cs new file mode 100644 index 0000000..817ded0 --- /dev/null +++ b/DownKyi.Core/Settings/Models/AboutSettings.cs @@ -0,0 +1,10 @@ +namespace DownKyi.Core.Settings.Models; + +/// +/// 关于 +/// +public class AboutSettings +{ + public AllowStatus IsReceiveBetaVersion { get; set; } = AllowStatus.NONE; + public AllowStatus AutoUpdateWhenLaunch { get; set; } = AllowStatus.NONE; +} \ No newline at end of file diff --git a/DownKyi.Core/Settings/Models/AppSettings.cs b/DownKyi.Core/Settings/Models/AppSettings.cs new file mode 100644 index 0000000..68e4c16 --- /dev/null +++ b/DownKyi.Core/Settings/Models/AppSettings.cs @@ -0,0 +1,11 @@ +namespace DownKyi.Core.Settings.Models; + +public class AppSettings +{ + public BasicSettings Basic { get; set; } = new(); + public NetworkSettings Network { get; set; } = new(); + public VideoSettings Video { get; set; } = new(); + public DanmakuSettings Danmaku { get; set; } = new(); + public AboutSettings About { get; set; } = new(); + public UserInfoSettings UserInfo { get; set; } = new(); +} \ No newline at end of file diff --git a/DownKyi.Core/Settings/Models/BasicSettings.cs b/DownKyi.Core/Settings/Models/BasicSettings.cs new file mode 100644 index 0000000..673561c --- /dev/null +++ b/DownKyi.Core/Settings/Models/BasicSettings.cs @@ -0,0 +1,14 @@ +namespace DownKyi.Core.Settings.Models; + +/// +/// 基本 +/// +public class BasicSettings +{ + public AfterDownloadOperation AfterDownload { get; set; } = AfterDownloadOperation.NOT_SET; + public AllowStatus IsListenClipboard { get; set; } = AllowStatus.NONE; + public AllowStatus IsAutoParseVideo { get; set; } = AllowStatus.NONE; + public ParseScope ParseScope { get; set; } = ParseScope.NOT_SET; + public AllowStatus IsAutoDownloadAll { get; set; } = AllowStatus.NONE; + public DownloadFinishedSort DownloadFinishedSort { get; set; } = DownloadFinishedSort.NOT_SET; +} \ No newline at end of file diff --git a/DownKyi.Core/Settings/Models/DanmakuSettings.cs b/DownKyi.Core/Settings/Models/DanmakuSettings.cs new file mode 100644 index 0000000..f145761 --- /dev/null +++ b/DownKyi.Core/Settings/Models/DanmakuSettings.cs @@ -0,0 +1,18 @@ +namespace DownKyi.Core.Settings.Models; + +/// +/// 弹幕 +/// +public class DanmakuSettings +{ + public AllowStatus DanmakuTopFilter { get; set; } = AllowStatus.NONE; + public AllowStatus DanmakuBottomFilter { get; set; } = AllowStatus.NONE; + public AllowStatus DanmakuScrollFilter { get; set; } = AllowStatus.NONE; + public AllowStatus IsCustomDanmakuResolution { get; set; } = AllowStatus.NONE; + public int DanmakuScreenWidth { get; set; } = -1; + public int DanmakuScreenHeight { get; set; } = -1; + public string DanmakuFontName { get; set; } = null; + public int DanmakuFontSize { get; set; } = -1; + public int DanmakuLineCount { get; set; } = -1; + public DanmakuLayoutAlgorithm DanmakuLayoutAlgorithm { get; set; } = DanmakuLayoutAlgorithm.NONE; +} \ No newline at end of file diff --git a/DownKyi.Core/Settings/Models/NetworkSettings.cs b/DownKyi.Core/Settings/Models/NetworkSettings.cs new file mode 100644 index 0000000..99436d3 --- /dev/null +++ b/DownKyi.Core/Settings/Models/NetworkSettings.cs @@ -0,0 +1,43 @@ +namespace DownKyi.Core.Settings.Models; + +/// +/// 网络 +/// +public class NetworkSettings +{ + public AllowStatus IsLiftingOfRegion { get; set; } = AllowStatus.NONE; + + public AllowStatus UseSSL { get; set; } = AllowStatus.NONE; + public string UserAgent { get; set; } = string.Empty; + + public Downloader Downloader { get; set; } = Downloader.NOT_SET; + public int MaxCurrentDownloads { get; set; } = -1; + + #region built-in + + public int Split { get; set; } = -1; + public AllowStatus IsHttpProxy { get; set; } = AllowStatus.NONE; + public string HttpProxy { get; set; } = null; + public int HttpProxyListenPort { get; set; } = -1; + + #endregion + + #region Aria + + public string AriaToken { get; set; } = null; + public string AriaHost { get; set; } = null; + + public int AriaListenPort { get; set; } = -1; + + // public AriaConfigLogLevel AriaLogLevel { get; set; } = AriaConfigLogLevel.NOT_SET; + public int AriaSplit { get; set; } = -1; + public int AriaMaxOverallDownloadLimit { get; set; } = -1; + public int AriaMaxDownloadLimit { get; set; } = -1; + // public AriaConfigFileAllocation AriaFileAllocation { get; set; } = AriaConfigFileAllocation.NOT_SET; + + public AllowStatus IsAriaHttpProxy { get; set; } = AllowStatus.NONE; + public string AriaHttpProxy { get; set; } = null; + public int AriaHttpProxyListenPort { get; set; } = -1; + + #endregion +} \ No newline at end of file diff --git a/DownKyi.Core/Settings/Models/UserInfoSettings.cs b/DownKyi.Core/Settings/Models/UserInfoSettings.cs new file mode 100644 index 0000000..f57736b --- /dev/null +++ b/DownKyi.Core/Settings/Models/UserInfoSettings.cs @@ -0,0 +1,12 @@ +namespace DownKyi.Core.Settings.Models; + +public class UserInfoSettings +{ + public long Mid { get; set; } + public string Name { get; set; } + public bool IsLogin { get; set; } // 是否登录 + public bool IsVip { get; set; } // 是否为大会员,未登录时为false + + public string ImgKey { get; set; } + public string SubKey { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/Settings/Models/VideoContentSettings.cs b/DownKyi.Core/Settings/Models/VideoContentSettings.cs new file mode 100644 index 0000000..b421e48 --- /dev/null +++ b/DownKyi.Core/Settings/Models/VideoContentSettings.cs @@ -0,0 +1,10 @@ +namespace DownKyi.Core.Settings.Models; + +public class VideoContentSettings +{ + public bool DownloadAudio { get; set; } = true; + public bool DownloadVideo { get; set; } = true; + public bool DownloadDanmaku { get; set; } = true; + public bool DownloadSubtitle { get; set; } = true; + public bool DownloadCover { get; set; } = true; +} \ No newline at end of file diff --git a/DownKyi.Core/Settings/Models/VideoSettings.cs b/DownKyi.Core/Settings/Models/VideoSettings.cs new file mode 100644 index 0000000..fd0c046 --- /dev/null +++ b/DownKyi.Core/Settings/Models/VideoSettings.cs @@ -0,0 +1,21 @@ +using DownKyi.Core.FileName; + +namespace DownKyi.Core.Settings.Models; + +/// +/// 视频 +/// +public class VideoSettings +{ + public int VideoCodecs { get; set; } = -1; // AVC or HEVC + public int Quality { get; set; } = -1; // 画质 + public int AudioQuality { get; set; } = -1; // 音质 + public AllowStatus IsTranscodingFlvToMp4 { get; set; } = AllowStatus.NONE; // 是否将flv转为mp4 + public string SaveVideoRootPath { get; set; } = null; // 视频保存路径 + public List HistoryVideoRootPaths { get; set; } = null; // 历史视频保存路径 + public AllowStatus IsUseSaveVideoRootPath { get; set; } = AllowStatus.NONE; // 是否使用默认视频保存路径 + public VideoContentSettings VideoContent { get; set; } = null; // 下载内容 + public List FileNameParts { get; set; } = null; // 文件命名格式 + public string FileNamePartTimeFormat { get; set; } = null; // 文件命名中的时间格式 + public OrderFormat OrderFormat { get; set; } = OrderFormat.NOT_SET; // 文件命名中的序号格式 +} \ No newline at end of file diff --git a/DownKyi.Core/Settings/OrderFormat.cs b/DownKyi.Core/Settings/OrderFormat.cs new file mode 100644 index 0000000..102cad8 --- /dev/null +++ b/DownKyi.Core/Settings/OrderFormat.cs @@ -0,0 +1,8 @@ +namespace DownKyi.Core.Settings; + +public enum OrderFormat +{ + NOT_SET = 0, + NATURAL, // 自然数 + LEADING_ZEROS, // 前导零填充 +} \ No newline at end of file diff --git a/DownKyi.Core/Settings/ParseScope.cs b/DownKyi.Core/Settings/ParseScope.cs new file mode 100644 index 0000000..837a7ea --- /dev/null +++ b/DownKyi.Core/Settings/ParseScope.cs @@ -0,0 +1,10 @@ +namespace DownKyi.Core.Settings; + +public enum ParseScope +{ + NOT_SET = 0, + NONE = 1, + SELECTED_ITEM, + CURRENT_SECTION, + ALL +} \ No newline at end of file diff --git a/DownKyi.Core/Settings/SettingsManager.About.cs b/DownKyi.Core/Settings/SettingsManager.About.cs new file mode 100644 index 0000000..f795387 --- /dev/null +++ b/DownKyi.Core/Settings/SettingsManager.About.cs @@ -0,0 +1,66 @@ +namespace DownKyi.Core.Settings; + +public partial class SettingsManager +{ + // 是否接收测试版更新 + private readonly AllowStatus isReceiveBetaVersion = AllowStatus.NO; + + // 是否在启动时自动检查更新 + private readonly AllowStatus autoUpdateWhenLaunch = AllowStatus.YES; + + /// + /// 获取是否接收测试版更新 + /// + /// + public AllowStatus IsReceiveBetaVersion() + { + appSettings = GetSettings(); + if (appSettings.About.IsReceiveBetaVersion == AllowStatus.NONE) + { + // 第一次获取,先设置默认值 + IsReceiveBetaVersion(isReceiveBetaVersion); + return isReceiveBetaVersion; + } + + return appSettings.About.IsReceiveBetaVersion; + } + + /// + /// 设置是否接收测试版更新 + /// + /// + /// + public bool IsReceiveBetaVersion(AllowStatus isReceiveBetaVersion) + { + appSettings.About.IsReceiveBetaVersion = isReceiveBetaVersion; + return SetSettings(); + } + + /// + /// 获取是否允许启动时检查更新 + /// + /// + public AllowStatus GetAutoUpdateWhenLaunch() + { + appSettings = GetSettings(); + if (appSettings.About.AutoUpdateWhenLaunch == AllowStatus.NONE) + { + // 第一次获取,先设置默认值 + SetAutoUpdateWhenLaunch(autoUpdateWhenLaunch); + return autoUpdateWhenLaunch; + } + + return appSettings.About.AutoUpdateWhenLaunch; + } + + /// + /// 设置是否允许启动时检查更新 + /// + /// + /// + public bool SetAutoUpdateWhenLaunch(AllowStatus autoUpdateWhenLaunch) + { + appSettings.About.AutoUpdateWhenLaunch = autoUpdateWhenLaunch; + return SetSettings(); + } +} \ No newline at end of file diff --git a/DownKyi.Core/Settings/SettingsManager.Basic.cs b/DownKyi.Core/Settings/SettingsManager.Basic.cs new file mode 100644 index 0000000..352b378 --- /dev/null +++ b/DownKyi.Core/Settings/SettingsManager.Basic.cs @@ -0,0 +1,190 @@ +namespace DownKyi.Core.Settings; + +public partial class SettingsManager +{ + // 默认下载完成后的操作 + private readonly AfterDownloadOperation afterDownload = AfterDownloadOperation.NONE; + + // 是否监听剪贴板 + private readonly AllowStatus isListenClipboard = AllowStatus.YES; + + // 视频详情页面是否自动解析 + private readonly AllowStatus isAutoParseVideo = AllowStatus.NO; + + // 默认的视频解析项 + private readonly ParseScope parseScope = ParseScope.NONE; + + // 解析后自动下载解析视频 + private readonly AllowStatus isAutoDownloadAll = AllowStatus.NO; + + // 下载完成列表排序 + private readonly DownloadFinishedSort finishedSort = DownloadFinishedSort.DOWNLOAD; + + /// + /// 获取下载完成后的操作 + /// + /// + public AfterDownloadOperation GetAfterDownloadOperation() + { + appSettings = GetSettings(); + if (appSettings.Basic.AfterDownload == AfterDownloadOperation.NOT_SET) + { + // 第一次获取,先设置默认值 + SetAfterDownloadOperation(afterDownload); + return afterDownload; + } + + return appSettings.Basic.AfterDownload; + } + + /// + /// 设置下载完成后的操作 + /// + /// + /// + public bool SetAfterDownloadOperation(AfterDownloadOperation afterDownload) + { + appSettings.Basic.AfterDownload = afterDownload; + return SetSettings(); + } + + /// + /// 是否监听剪贴板 + /// + /// + public AllowStatus IsListenClipboard() + { + appSettings = GetSettings(); + if (appSettings.Basic.IsListenClipboard == AllowStatus.NONE) + { + // 第一次获取,先设置默认值 + IsListenClipboard(isListenClipboard); + return isListenClipboard; + } + + return appSettings.Basic.IsListenClipboard; + } + + /// + /// 是否监听剪贴板 + /// + /// + /// + public bool IsListenClipboard(AllowStatus isListen) + { + appSettings.Basic.IsListenClipboard = isListen; + return SetSettings(); + } + + /// + /// 视频详情页面是否自动解析 + /// + /// + public AllowStatus IsAutoParseVideo() + { + appSettings = GetSettings(); + if (appSettings.Basic.IsAutoParseVideo == AllowStatus.NONE) + { + // 第一次获取,先设置默认值 + IsAutoParseVideo(isAutoParseVideo); + return isAutoParseVideo; + } + + return appSettings.Basic.IsAutoParseVideo; + } + + /// + /// 视频详情页面是否自动解析 + /// + /// + /// + public bool IsAutoParseVideo(AllowStatus IsAuto) + { + appSettings.Basic.IsAutoParseVideo = IsAuto; + return SetSettings(); + } + + /// + /// 获取视频解析项 + /// + /// + public ParseScope GetParseScope() + { + appSettings = GetSettings(); + if (appSettings.Basic.ParseScope == ParseScope.NOT_SET) + { + // 第一次获取,先设置默认值 + SetParseScope(parseScope); + return parseScope; + } + + return appSettings.Basic.ParseScope; + } + + /// + /// 设置视频解析项 + /// + /// + /// + public bool SetParseScope(ParseScope parseScope) + { + appSettings.Basic.ParseScope = parseScope; + return SetSettings(); + } + + /// + /// 解析后是否自动下载解析视频 + /// + /// + public AllowStatus IsAutoDownloadAll() + { + appSettings = GetSettings(); + if (appSettings.Basic.IsAutoDownloadAll == AllowStatus.NONE) + { + // 第一次获取,先设置默认值 + IsAutoDownloadAll(isAutoDownloadAll); + return isAutoDownloadAll; + } + + return appSettings.Basic.IsAutoDownloadAll; + } + + /// + /// 解析后是否自动下载解析视频 + /// + /// + /// + public bool IsAutoDownloadAll(AllowStatus isAutoDownloadAll) + { + appSettings.Basic.IsAutoDownloadAll = isAutoDownloadAll; + return SetSettings(); + } + + /// + /// 获取下载完成列表排序 + /// + /// + public DownloadFinishedSort GetDownloadFinishedSort() + { + appSettings = GetSettings(); + if (appSettings.Basic.DownloadFinishedSort == DownloadFinishedSort.NOT_SET) + { + // 第一次获取,先设置默认值 + SetDownloadFinishedSort(finishedSort); + return finishedSort; + } + + return appSettings.Basic.DownloadFinishedSort; + } + + /// + /// 设置下载完成列表排序 + /// + /// + /// + public bool SetDownloadFinishedSort(DownloadFinishedSort finishedSort) + { + appSettings.Basic.DownloadFinishedSort = finishedSort; + return SetSettings(); + } +} \ No newline at end of file diff --git a/DownKyi.Core/Settings/SettingsManager.Danmaku.cs b/DownKyi.Core/Settings/SettingsManager.Danmaku.cs new file mode 100644 index 0000000..cf5cebb --- /dev/null +++ b/DownKyi.Core/Settings/SettingsManager.Danmaku.cs @@ -0,0 +1,315 @@ +namespace DownKyi.Core.Settings; + +public partial class SettingsManager +{ + // 是否屏蔽顶部弹幕 + private readonly AllowStatus danmakuTopFilter = AllowStatus.NO; + + // 是否屏蔽底部弹幕 + private readonly AllowStatus danmakuBottomFilter = AllowStatus.NO; + + // 是否屏蔽滚动弹幕 + private readonly AllowStatus danmakuScrollFilter = AllowStatus.NO; + + // 是否自定义分辨率 + private readonly AllowStatus isCustomDanmakuResolution = AllowStatus.NO; + + // 分辨率-宽 + private readonly int danmakuScreenWidth = 1920; + + // 分辨率-高 + private readonly int danmakuScreenHeight = 1080; + + // 弹幕字体 + private readonly string danmakuFontName = "黑体"; + + // 弹幕字体大小 + private readonly int danmakuFontSize = 50; + + // 弹幕限制行数 + private readonly int danmakuLineCount = 0; + + // 弹幕布局算法 + private readonly DanmakuLayoutAlgorithm danmakuLayoutAlgorithm = DanmakuLayoutAlgorithm.SYNC; + + + /// + /// 获取是否屏蔽顶部弹幕 + /// + /// + public AllowStatus GetDanmakuTopFilter() + { + appSettings = GetSettings(); + if (appSettings.Danmaku.DanmakuTopFilter == AllowStatus.NONE) + { + // 第一次获取,先设置默认值 + SetDanmakuTopFilter(danmakuTopFilter); + return danmakuTopFilter; + } + + return appSettings.Danmaku.DanmakuTopFilter; + } + + /// + /// 设置是否屏蔽顶部弹幕 + /// + /// + /// + public bool SetDanmakuTopFilter(AllowStatus danmakuFilter) + { + appSettings.Danmaku.DanmakuTopFilter = danmakuFilter; + return SetSettings(); + } + + /// + /// 获取是否屏蔽底部弹幕 + /// + /// + public AllowStatus GetDanmakuBottomFilter() + { + appSettings = GetSettings(); + if (appSettings.Danmaku.DanmakuBottomFilter == AllowStatus.NONE) + { + // 第一次获取,先设置默认值 + SetDanmakuBottomFilter(danmakuBottomFilter); + return danmakuBottomFilter; + } + + return appSettings.Danmaku.DanmakuBottomFilter; + } + + /// + /// 设置是否屏蔽底部弹幕 + /// + /// + /// + public bool SetDanmakuBottomFilter(AllowStatus danmakuFilter) + { + appSettings.Danmaku.DanmakuBottomFilter = danmakuFilter; + return SetSettings(); + } + + /// + /// 获取是否屏蔽滚动弹幕 + /// + /// + public AllowStatus GetDanmakuScrollFilter() + { + appSettings = GetSettings(); + if (appSettings.Danmaku.DanmakuScrollFilter == AllowStatus.NONE) + { + // 第一次获取,先设置默认值 + SetDanmakuScrollFilter(danmakuScrollFilter); + return danmakuScrollFilter; + } + + return appSettings.Danmaku.DanmakuScrollFilter; + } + + /// + /// 设置是否屏蔽滚动弹幕 + /// + /// + /// + public bool SetDanmakuScrollFilter(AllowStatus danmakuFilter) + { + appSettings.Danmaku.DanmakuScrollFilter = danmakuFilter; + return SetSettings(); + } + + /// + /// 获取是否自定义分辨率 + /// + /// + public AllowStatus IsCustomDanmakuResolution() + { + appSettings = GetSettings(); + if (appSettings.Danmaku.IsCustomDanmakuResolution == AllowStatus.NONE) + { + // 第一次获取,先设置默认值 + IsCustomDanmakuResolution(isCustomDanmakuResolution); + return isCustomDanmakuResolution; + } + + return appSettings.Danmaku.IsCustomDanmakuResolution; + } + + /// + /// 设置是否自定义分辨率 + /// + /// + /// + public bool IsCustomDanmakuResolution(AllowStatus isCustomResolution) + { + appSettings.Danmaku.IsCustomDanmakuResolution = isCustomResolution; + return SetSettings(); + } + + /// + /// 获取分辨率-宽 + /// + /// + public int GetDanmakuScreenWidth() + { + appSettings = GetSettings(); + if (appSettings.Danmaku.DanmakuScreenWidth == -1) + { + // 第一次获取,先设置默认值 + SetDanmakuScreenWidth(danmakuScreenWidth); + return danmakuScreenWidth; + } + + return appSettings.Danmaku.DanmakuScreenWidth; + } + + /// + /// 设置分辨率-宽 + /// + /// + /// + public bool SetDanmakuScreenWidth(int screenWidth) + { + appSettings.Danmaku.DanmakuScreenWidth = screenWidth; + return SetSettings(); + } + + /// + /// 获取分辨率-高 + /// + /// + public int GetDanmakuScreenHeight() + { + appSettings = GetSettings(); + if (appSettings.Danmaku.DanmakuScreenHeight == -1) + { + // 第一次获取,先设置默认值 + SetDanmakuScreenHeight(danmakuScreenHeight); + return danmakuScreenHeight; + } + + return appSettings.Danmaku.DanmakuScreenHeight; + } + + /// + /// 设置分辨率-高 + /// + /// + /// + public bool SetDanmakuScreenHeight(int screenHeight) + { + appSettings.Danmaku.DanmakuScreenHeight = screenHeight; + return SetSettings(); + } + + /// + /// 获取弹幕字体 + /// + /// + public string GetDanmakuFontName() + { + appSettings = GetSettings(); + if (appSettings.Danmaku.DanmakuFontName == null) + { + // 第一次获取,先设置默认值 + SetDanmakuFontName(danmakuFontName); + return danmakuFontName; + } + + return appSettings.Danmaku.DanmakuFontName; + } + + /// + /// 设置弹幕字体 + /// + /// + /// + public bool SetDanmakuFontName(string danmakuFontName) + { + appSettings.Danmaku.DanmakuFontName = danmakuFontName; + return SetSettings(); + } + + /// + /// 获取弹幕字体大小 + /// + /// + public int GetDanmakuFontSize() + { + appSettings = GetSettings(); + if (appSettings.Danmaku.DanmakuFontSize == -1) + { + // 第一次获取,先设置默认值 + SetDanmakuFontSize(danmakuFontSize); + return danmakuFontSize; + } + + return appSettings.Danmaku.DanmakuFontSize; + } + + /// + /// 设置弹幕字体大小 + /// + /// + /// + public bool SetDanmakuFontSize(int danmakuFontSize) + { + appSettings.Danmaku.DanmakuFontSize = danmakuFontSize; + return SetSettings(); + } + + /// + /// 获取弹幕限制行数 + /// + /// + public int GetDanmakuLineCount() + { + appSettings = GetSettings(); + if (appSettings.Danmaku.DanmakuLineCount == -1) + { + // 第一次获取,先设置默认值 + SetDanmakuLineCount(danmakuLineCount); + return danmakuLineCount; + } + + return appSettings.Danmaku.DanmakuLineCount; + } + + /// + /// 设置弹幕限制行数 + /// + /// + /// + public bool SetDanmakuLineCount(int danmakuLineCount) + { + appSettings.Danmaku.DanmakuLineCount = danmakuLineCount; + return SetSettings(); + } + + /// + /// 获取弹幕布局算法 + /// + /// + public DanmakuLayoutAlgorithm GetDanmakuLayoutAlgorithm() + { + appSettings = GetSettings(); + if (appSettings.Danmaku.DanmakuLayoutAlgorithm == DanmakuLayoutAlgorithm.NONE) + { + // 第一次获取,先设置默认值 + SetDanmakuLayoutAlgorithm(danmakuLayoutAlgorithm); + return danmakuLayoutAlgorithm; + } + + return appSettings.Danmaku.DanmakuLayoutAlgorithm; + } + + /// + /// 设置弹幕布局算法 + /// + /// + /// + public bool SetDanmakuLayoutAlgorithm(DanmakuLayoutAlgorithm danmakuLayoutAlgorithm) + { + appSettings.Danmaku.DanmakuLayoutAlgorithm = danmakuLayoutAlgorithm; + return SetSettings(); + } +} \ No newline at end of file diff --git a/DownKyi.Core/Settings/SettingsManager.Network.cs b/DownKyi.Core/Settings/SettingsManager.Network.cs new file mode 100644 index 0000000..1cfc30b --- /dev/null +++ b/DownKyi.Core/Settings/SettingsManager.Network.cs @@ -0,0 +1,595 @@ +// using DownKyi.Core.Aria2cNet.Server; + +namespace DownKyi.Core.Settings +{ + public partial class SettingsManager + { + // 是否开启解除地区限制 + private readonly AllowStatus isLiftingOfRegion = AllowStatus.YES; + + // 启用https + private readonly AllowStatus useSSL = AllowStatus.YES; + + // UserAgent + private readonly string userAgent = + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36"; + + // 下载器 + private readonly Downloader downloader = Downloader.BUILT_IN; + + // 最大同时下载数(任务数) + private readonly int maxCurrentDownloads = 3; + + // 单文件最大线程数 + private readonly int split = 8; + + // HttpProxy代理 + private readonly AllowStatus isHttpProxy = AllowStatus.NO; + private readonly string httpProxy = string.Empty; + private readonly int httpProxyListenPort = 0; + + // Aria服务器token + private readonly string ariaToken = "downkyi"; + + // Aria服务器host + private readonly string ariaHost = "http://localhost"; + + // Aria服务器端口号 + private readonly int ariaListenPort = 6800; + + // Aria日志等级 + // private readonly AriaConfigLogLevel ariaLogLevel = AriaConfigLogLevel.INFO; + + // Aria单文件最大线程数 + private readonly int ariaSplit = 5; + + // Aria下载速度限制 + private readonly int ariaMaxOverallDownloadLimit = 0; + + // Aria下载单文件速度限制 + private readonly int ariaMaxDownloadLimit = 0; + + // Aria文件预分配 + // private readonly AriaConfigFileAllocation ariaFileAllocation = AriaConfigFileAllocation.NONE; + + // Aria HttpProxy代理 + private readonly AllowStatus isAriaHttpProxy = AllowStatus.NO; + private readonly string ariaHttpProxy = string.Empty; + private readonly int ariaHttpProxyListenPort = 0; + + /// + /// 获取是否解除地区限制 + /// + /// + public AllowStatus IsLiftingOfRegion() + { + appSettings = GetSettings(); + if (appSettings.Network.IsLiftingOfRegion == AllowStatus.NONE) + { + // 第一次获取,先设置默认值 + IsLiftingOfRegion(isLiftingOfRegion); + return isLiftingOfRegion; + } + + return appSettings.Network.IsLiftingOfRegion; + } + + /// + /// 设置是否解除地区限制 + /// + /// + /// + public bool IsLiftingOfRegion(AllowStatus isLiftingOfRegion) + { + appSettings.Network.IsLiftingOfRegion = isLiftingOfRegion; + return SetSettings(); + } + + /// + /// 获取是否启用https + /// + /// + public AllowStatus UseSSL() + { + appSettings = GetSettings(); + if (appSettings.Network.UseSSL == AllowStatus.NONE) + { + // 第一次获取,先设置默认值 + UseSSL(useSSL); + return useSSL; + } + + return appSettings.Network.UseSSL; + } + + /// + /// 设置是否启用https + /// + /// + /// + public bool UseSSL(AllowStatus useSSL) + { + appSettings.Network.UseSSL = useSSL; + return SetSettings(); + } + + /// + /// 获取UserAgent + /// + /// + public string GetUserAgent() + { + appSettings = GetSettings(); + if (appSettings.Network.UserAgent == string.Empty) + { + // 第一次获取,先设置默认值 + SetUserAgent(userAgent); + return userAgent; + } + + return appSettings.Network.UserAgent; + } + + /// + /// 设置UserAgent + /// + /// + /// + public bool SetUserAgent(string userAgent) + { + appSettings.Network.UserAgent = userAgent; + return SetSettings(); + } + + /// + /// 获取下载器 + /// + /// + public Downloader GetDownloader() + { + appSettings = GetSettings(); + if (appSettings.Network.Downloader != Downloader.NOT_SET) return appSettings.Network.Downloader; + // 第一次获取,先设置默认值 + SetDownloader(downloader); + return downloader; + } + + /// + /// 设置下载器 + /// + /// + /// + public bool SetDownloader(Downloader downloader) + { + appSettings.Network.Downloader = downloader; + return SetSettings(); + } + + /// + /// 获取最大同时下载数(任务数) + /// + /// + public int GetMaxCurrentDownloads() + { + appSettings = GetSettings(); + if (appSettings.Network.MaxCurrentDownloads != -1) return appSettings.Network.MaxCurrentDownloads; + // 第一次获取,先设置默认值 + SetMaxCurrentDownloads(maxCurrentDownloads); + return maxCurrentDownloads; + } + + /// + /// 设置最大同时下载数(任务数) + /// + /// + /// + public bool SetMaxCurrentDownloads(int maxCurrentDownloads) + { + appSettings.Network.MaxCurrentDownloads = maxCurrentDownloads; + return SetSettings(); + } + + /// + /// 获取单文件最大线程数 + /// + /// + public int GetSplit() + { + appSettings = GetSettings(); + if (appSettings.Network.Split != -1) return appSettings.Network.Split; + // 第一次获取,先设置默认值 + SetSplit(split); + return split; + } + + /// + /// 设置单文件最大线程数 + /// + /// + /// + public bool SetSplit(int split) + { + appSettings.Network.Split = split; + return SetSettings(); + } + + /// + /// 获取是否开启Http代理 + /// + /// + public AllowStatus IsHttpProxy() + { + appSettings = GetSettings(); + if (appSettings.Network.IsHttpProxy != AllowStatus.NONE) return appSettings.Network.IsHttpProxy; + // 第一次获取,先设置默认值 + IsHttpProxy(isHttpProxy); + return isHttpProxy; + } + + /// + /// 设置是否开启Http代理 + /// + /// + /// + public bool IsHttpProxy(AllowStatus isHttpProxy) + { + appSettings.Network.IsHttpProxy = isHttpProxy; + return SetSettings(); + } + + /// + /// 获取Http代理的地址 + /// + /// + public string GetHttpProxy() + { + appSettings = GetSettings(); + if (appSettings.Network.HttpProxy != null) return appSettings.Network.HttpProxy; + // 第一次获取,先设置默认值 + SetHttpProxy(httpProxy); + return httpProxy; + } + + /// + /// 设置Aria的http代理的地址 + /// + /// + /// + public bool SetHttpProxy(string httpProxy) + { + appSettings.Network.HttpProxy = httpProxy; + return SetSettings(); + } + + /// + /// 获取Http代理的端口 + /// + /// + public int GetHttpProxyListenPort() + { + appSettings = GetSettings(); + if (appSettings.Network.HttpProxyListenPort != -1) return appSettings.Network.HttpProxyListenPort; + // 第一次获取,先设置默认值 + SetHttpProxyListenPort(httpProxyListenPort); + return httpProxyListenPort; + + } + + /// + /// 设置Http代理的端口 + /// + /// + /// + public bool SetHttpProxyListenPort(int httpProxyListenPort) + { + appSettings.Network.HttpProxyListenPort = httpProxyListenPort; + return SetSettings(); + } + + /// + /// 获取Aria服务器的token + /// + /// + public string GetAriaToken() + { + appSettings = GetSettings(); + if (appSettings.Network.AriaToken == null) + { + // 第一次获取,先设置默认值 + SetHttpProxy(ariaToken); + return ariaToken; + } + + return appSettings.Network.AriaToken; + } + + /// + /// 设置Aria服务器的token + /// + /// + /// + public bool SetAriaToken(string token) + { + appSettings.Network.AriaToken = token; + return SetSettings(); + } + + /// + /// 获取Aria服务器的host + /// + /// + public string GetAriaHost() + { + appSettings = GetSettings(); + if (appSettings.Network.AriaHost == null) + { + // 第一次获取,先设置默认值 + SetHttpProxy(ariaHost); + return ariaHost; + } + + return appSettings.Network.AriaHost; + } + + /// + /// 设置Aria服务器的host + /// + /// + /// + public bool SetAriaHost(string host) + { + appSettings.Network.AriaHost = host; + return SetSettings(); + } + + /// + /// 获取Aria服务器的端口号 + /// + /// + public int GetAriaListenPort() + { + appSettings = GetSettings(); + if (appSettings.Network.AriaListenPort == -1) + { + // 第一次获取,先设置默认值 + SetAriaListenPort(ariaListenPort); + return ariaListenPort; + } + + return appSettings.Network.AriaListenPort; + } + + /// + /// 设置Aria服务器的端口号 + /// + /// + /// + public bool SetAriaListenPort(int ariaListenPort) + { + appSettings.Network.AriaListenPort = ariaListenPort; + return SetSettings(); + } + + /// + /// 获取Aria日志等级 + /// + /// + // public AriaConfigLogLevel GetAriaLogLevel() + // { + // appSettings = GetSettings(); + // if (appSettings.Network.AriaLogLevel == AriaConfigLogLevel.NOT_SET) + // { + // // 第一次获取,先设置默认值 + // SetAriaLogLevel(ariaLogLevel); + // return ariaLogLevel; + // } + // return appSettings.Network.AriaLogLevel; + // } + + /// + /// 设置Aria日志等级 + /// + /// + /// + // public bool SetAriaLogLevel(AriaConfigLogLevel ariaLogLevel) + // { + // appSettings.Network.AriaLogLevel = ariaLogLevel; + // return SetSettings(); + // } + + /// + /// 获取Aria单文件最大线程数 + /// + /// + public int GetAriaSplit() + { + appSettings = GetSettings(); + if (appSettings.Network.AriaSplit == -1) + { + // 第一次获取,先设置默认值 + SetAriaSplit(ariaSplit); + return ariaSplit; + } + + return appSettings.Network.AriaSplit; + } + + /// + /// 设置Aria单文件最大线程数 + /// + /// + /// + public bool SetAriaSplit(int ariaSplit) + { + appSettings.Network.AriaSplit = ariaSplit; + return SetSettings(); + } + + /// + /// 获取Aria下载速度限制 + /// + /// + public int GetAriaMaxOverallDownloadLimit() + { + appSettings = GetSettings(); + if (appSettings.Network.AriaMaxOverallDownloadLimit == -1) + { + // 第一次获取,先设置默认值 + SetAriaMaxOverallDownloadLimit(ariaMaxOverallDownloadLimit); + return ariaMaxOverallDownloadLimit; + } + + return appSettings.Network.AriaMaxOverallDownloadLimit; + } + + /// + /// 设置Aria下载速度限制 + /// + /// + /// + public bool SetAriaMaxOverallDownloadLimit(int ariaMaxOverallDownloadLimit) + { + appSettings.Network.AriaMaxOverallDownloadLimit = ariaMaxOverallDownloadLimit; + return SetSettings(); + } + + /// + /// 获取Aria下载单文件速度限制 + /// + /// + public int GetAriaMaxDownloadLimit() + { + appSettings = GetSettings(); + if (appSettings.Network.AriaMaxDownloadLimit == -1) + { + // 第一次获取,先设置默认值 + SetAriaMaxDownloadLimit(ariaMaxDownloadLimit); + return ariaMaxDownloadLimit; + } + + return appSettings.Network.AriaMaxDownloadLimit; + } + + /// + /// 设置Aria下载单文件速度限制 + /// + /// + /// + public bool SetAriaMaxDownloadLimit(int ariaMaxDownloadLimit) + { + appSettings.Network.AriaMaxDownloadLimit = ariaMaxDownloadLimit; + return SetSettings(); + } + + /// + /// 获取Aria文件预分配 + /// + /// + // public AriaConfigFileAllocation GetAriaFileAllocation() + // { + // appSettings = GetSettings(); + // if (appSettings.Network.AriaFileAllocation == AriaConfigFileAllocation.NOT_SET) + // { + // // 第一次获取,先设置默认值 + // SetAriaFileAllocation(ariaFileAllocation); + // return ariaFileAllocation; + // } + // return appSettings.Network.AriaFileAllocation; + // } + + /// + /// 设置Aria文件预分配 + /// + /// + /// + // public bool SetAriaFileAllocation(AriaConfigFileAllocation ariaFileAllocation) + // { + // appSettings.Network.AriaFileAllocation = ariaFileAllocation; + // return SetSettings(); + // } + + /// + /// 获取是否开启Aria http代理 + /// + /// + public AllowStatus IsAriaHttpProxy() + { + appSettings = GetSettings(); + if (appSettings.Network.IsAriaHttpProxy == AllowStatus.NONE) + { + // 第一次获取,先设置默认值 + IsAriaHttpProxy(isAriaHttpProxy); + return isAriaHttpProxy; + } + + return appSettings.Network.IsAriaHttpProxy; + } + + /// + /// 设置是否开启Aria http代理 + /// + /// + /// + public bool IsAriaHttpProxy(AllowStatus isAriaHttpProxy) + { + appSettings.Network.IsAriaHttpProxy = isAriaHttpProxy; + return SetSettings(); + } + + /// + /// 获取Aria的http代理的地址 + /// + /// + public string GetAriaHttpProxy() + { + appSettings = GetSettings(); + if (appSettings.Network.AriaHttpProxy == null) + { + // 第一次获取,先设置默认值 + SetAriaHttpProxy(ariaHttpProxy); + return ariaHttpProxy; + } + + return appSettings.Network.AriaHttpProxy; + } + + /// + /// 设置Aria的http代理的地址 + /// + /// + /// + public bool SetAriaHttpProxy(string ariaHttpProxy) + { + appSettings.Network.AriaHttpProxy = ariaHttpProxy; + return SetSettings(); + } + + /// + /// 获取Aria的http代理的端口 + /// + /// + public int GetAriaHttpProxyListenPort() + { + appSettings = GetSettings(); + if (appSettings.Network.AriaHttpProxyListenPort == -1) + { + // 第一次获取,先设置默认值 + SetAriaHttpProxyListenPort(ariaHttpProxyListenPort); + return ariaHttpProxyListenPort; + } + + return appSettings.Network.AriaHttpProxyListenPort; + } + + /// + /// 设置Aria的http代理的端口 + /// + /// + /// + public bool SetAriaHttpProxyListenPort(int ariaHttpProxyListenPort) + { + appSettings.Network.AriaHttpProxyListenPort = ariaHttpProxyListenPort; + return SetSettings(); + } + } +} \ No newline at end of file diff --git a/DownKyi.Core/Settings/SettingsManager.UserInfo.cs b/DownKyi.Core/Settings/SettingsManager.UserInfo.cs new file mode 100644 index 0000000..50649c1 --- /dev/null +++ b/DownKyi.Core/Settings/SettingsManager.UserInfo.cs @@ -0,0 +1,43 @@ +using DownKyi.Core.Settings.Models; + +namespace DownKyi.Core.Settings; + +public partial class SettingsManager +{ + // 登录用户的mid + private readonly UserInfoSettings userInfo = new UserInfoSettings + { + Mid = -1, + Name = "", + IsLogin = false, + IsVip = false + }; + + /// + /// 获取登录用户信息 + /// + /// + public UserInfoSettings GetUserInfo() + { + appSettings = GetSettings(); + if (appSettings.UserInfo == null) + { + // 第一次获取,先设置默认值 + SetUserInfo(userInfo); + return userInfo; + } + + return appSettings.UserInfo; + } + + /// + /// 设置中保存登录用户的信息,在index刷新用户状态时使用 + /// + /// + /// + public bool SetUserInfo(UserInfoSettings userInfo) + { + appSettings.UserInfo = userInfo; + return SetSettings(); + } +} \ No newline at end of file diff --git a/DownKyi.Core/Settings/SettingsManager.Video.cs b/DownKyi.Core/Settings/SettingsManager.Video.cs new file mode 100644 index 0000000..299acbb --- /dev/null +++ b/DownKyi.Core/Settings/SettingsManager.Video.cs @@ -0,0 +1,351 @@ +using DownKyi.Core.FileName; +using DownKyi.Core.Settings.Models; + +namespace DownKyi.Core.Settings; + +public partial class SettingsManager +{ + // 设置优先下载的视频编码 + private readonly int videoCodecs = 7; + + // 设置优先下载画质 + private readonly int quality = 120; + + // 设置优先下载音质 + private readonly int audioQuality = 30280; + + // 是否下载flv视频后转码为mp4 + private readonly AllowStatus isTranscodingFlvToMp4 = AllowStatus.YES; + + // 默认下载目录 + private readonly string saveVideoRootPath = Path.Combine(Environment.CurrentDirectory, "Media"); + + // 历史下载目录 + private readonly List historyVideoRootPaths = new(); + + // 是否使用默认下载目录,如果是,则每次点击下载选中项时不再询问下载目录 + private readonly AllowStatus isUseSaveVideoRootPath = AllowStatus.NO; + + // 下载内容 + private readonly VideoContentSettings videoContent = new(); + + // 文件命名格式 + private readonly List fileNameParts = new() + { + FileNamePart.MAIN_TITLE, + FileNamePart.SLASH, + FileNamePart.SECTION, + FileNamePart.SLASH, + FileNamePart.ORDER, + FileNamePart.HYPHEN, + FileNamePart.PAGE_TITLE, + FileNamePart.HYPHEN, + FileNamePart.VIDEO_QUALITY, + FileNamePart.HYPHEN, + FileNamePart.VIDEO_CODEC, + }; + + // 文件命名中的时间格式 + private readonly string fileNamePartTimeFormat = "yyyy-MM-dd"; + + // 文件命名中的序号格式 + private readonly OrderFormat orderFormat = OrderFormat.NATURAL; + + /// + /// 获取优先下载的视频编码 + /// + /// + public int GetVideoCodecs() + { + appSettings = GetSettings(); + if (appSettings.Video.VideoCodecs == -1) + { + // 第一次获取,先设置默认值 + SetVideoCodecs(videoCodecs); + return videoCodecs; + } + return appSettings.Video.VideoCodecs; + } + + /// + /// 设置优先下载的视频编码 + /// + /// + /// + public bool SetVideoCodecs(int videoCodecs) + { + appSettings.Video.VideoCodecs = videoCodecs; + return SetSettings(); + } + + /// + /// 获取优先下载画质 + /// + /// + public int GetQuality() + { + appSettings = GetSettings(); + if (appSettings.Video.Quality == -1) + { + // 第一次获取,先设置默认值 + SetQuality(quality); + return quality; + } + return appSettings.Video.Quality; + } + + /// + /// 设置优先下载画质 + /// + /// + /// + public bool SetQuality(int quality) + { + appSettings.Video.Quality = quality; + return SetSettings(); + } + + /// + /// 获取优先下载音质 + /// + /// + public int GetAudioQuality() + { + appSettings = GetSettings(); + if (appSettings.Video.AudioQuality == -1) + { + // 第一次获取,先设置默认值 + SetAudioQuality(audioQuality); + return audioQuality; + } + return appSettings.Video.AudioQuality; + } + + /// + /// 设置优先下载音质 + /// + /// + /// + public bool SetAudioQuality(int quality) + { + appSettings.Video.AudioQuality = quality; + return SetSettings(); + } + + /// + /// 获取是否下载flv视频后转码为mp4 + /// + /// + public AllowStatus IsTranscodingFlvToMp4() + { + appSettings = GetSettings(); + if (appSettings.Video.IsTranscodingFlvToMp4 == AllowStatus.NONE) + { + // 第一次获取,先设置默认值 + IsTranscodingFlvToMp4(isTranscodingFlvToMp4); + return isTranscodingFlvToMp4; + } + return appSettings.Video.IsTranscodingFlvToMp4; + } + + /// + /// 设置是否下载flv视频后转码为mp4 + /// + /// + /// + public bool IsTranscodingFlvToMp4(AllowStatus isTranscodingFlvToMp4) + { + appSettings.Video.IsTranscodingFlvToMp4 = isTranscodingFlvToMp4; + return SetSettings(); + } + + /// + /// 获取下载目录 + /// + /// + public string GetSaveVideoRootPath() + { + appSettings = GetSettings(); + if (appSettings.Video.SaveVideoRootPath == null) + { + // 第一次获取,先设置默认值 + SetSaveVideoRootPath(saveVideoRootPath); + return saveVideoRootPath; + } + return appSettings.Video.SaveVideoRootPath; + } + + /// + /// 设置下载目录 + /// + /// + /// + public bool SetSaveVideoRootPath(string path) + { + appSettings.Video.SaveVideoRootPath = path; + return SetSettings(); + } + + /// + /// 获取历史下载目录 + /// + /// + public List GetHistoryVideoRootPaths() + { + appSettings = GetSettings(); + if (appSettings.Video.HistoryVideoRootPaths == null) + { + // 第一次获取,先设置默认值 + SetHistoryVideoRootPaths(historyVideoRootPaths); + return historyVideoRootPaths; + } + return appSettings.Video.HistoryVideoRootPaths; + } + + /// + /// 设置历史下载目录 + /// + /// + /// + public bool SetHistoryVideoRootPaths(List historyPaths) + { + appSettings.Video.HistoryVideoRootPaths = historyPaths; + return SetSettings(); + } + + /// + /// 获取是否使用默认下载目录 + /// + /// + public AllowStatus IsUseSaveVideoRootPath() + { + appSettings = GetSettings(); + if (appSettings.Video.IsUseSaveVideoRootPath == AllowStatus.NONE) + { + // 第一次获取,先设置默认值 + IsUseSaveVideoRootPath(isUseSaveVideoRootPath); + return isUseSaveVideoRootPath; + } + return appSettings.Video.IsUseSaveVideoRootPath; + } + + /// + /// 设置是否使用默认下载目录 + /// + /// + /// + public bool IsUseSaveVideoRootPath(AllowStatus isUseSaveVideoRootPath) + { + appSettings.Video.IsUseSaveVideoRootPath = isUseSaveVideoRootPath; + return SetSettings(); + } + + /// + /// 获取下载内容 + /// + /// + public VideoContentSettings GetVideoContent() + { + appSettings = GetSettings(); + if (appSettings.Video.VideoContent == null) + { + // 第一次获取,先设置默认值 + SetVideoContent(videoContent); + return videoContent; + } + return appSettings.Video.VideoContent; + } + + /// + /// 设置下载内容 + /// + /// + /// + public bool SetVideoContent(VideoContentSettings videoContent) + { + appSettings.Video.VideoContent = videoContent; + return SetSettings(); + } + + /// + /// 获取文件命名格式 + /// + /// + public List GetFileNameParts() + { + appSettings = GetSettings(); + if (appSettings.Video.FileNameParts == null || appSettings.Video.FileNameParts.Count == 0) + { + // 第一次获取,先设置默认值 + SetFileNameParts(fileNameParts); + return fileNameParts; + } + return appSettings.Video.FileNameParts; + } + + /// + /// 设置文件命名格式 + /// + /// + /// + public bool SetFileNameParts(List fileNameParts) + { + appSettings.Video.FileNameParts = fileNameParts; + return SetSettings(); + } + + /// + /// 获取文件命名中的时间格式 + /// + /// + public string GetFileNamePartTimeFormat() + { + appSettings = GetSettings(); + if (appSettings.Video.FileNamePartTimeFormat == null || appSettings.Video.FileNamePartTimeFormat == string.Empty) + { + // 第一次获取,先设置默认值 + SetFileNamePartTimeFormat(fileNamePartTimeFormat); + return fileNamePartTimeFormat; + } + return appSettings.Video.FileNamePartTimeFormat; + } + + /// + /// 设置文件命名中的时间格式 + /// + /// + /// + public bool SetFileNamePartTimeFormat(string fileNamePartTimeFormat) + { + appSettings.Video.FileNamePartTimeFormat = fileNamePartTimeFormat; + return SetSettings(); + } + + /// + /// 获取文件命名中的序号格式 + /// + /// + public OrderFormat GetOrderFormat() + { + appSettings = GetSettings(); + if (appSettings.Video.OrderFormat == OrderFormat.NOT_SET) + { + // 第一次获取,先设置默认值 + SetOrderFormat(orderFormat); + return orderFormat; + } + return appSettings.Video.OrderFormat; + } + + /// + /// 设置文件命名中的序号格式 + /// + /// + /// + public bool SetOrderFormat(OrderFormat orderFormat) + { + appSettings.Video.OrderFormat = orderFormat; + return SetSettings(); + } + +} \ No newline at end of file diff --git a/DownKyi.Core/Settings/SettingsManager.cs b/DownKyi.Core/Settings/SettingsManager.cs new file mode 100644 index 0000000..e2183e8 --- /dev/null +++ b/DownKyi.Core/Settings/SettingsManager.cs @@ -0,0 +1,125 @@ +using System.Text; +using DownKyi.Core.Logging; +using DownKyi.Core.Settings.Models; +using DownKyi.Core.Storage; +using Newtonsoft.Json; +using Console = DownKyi.Core.Utils.Debugging.Console; + +#if DEBUG +#else +using DownKyi.Core.Utils.Encryptor; +#endif + +namespace DownKyi.Core.Settings; + +public partial class SettingsManager +{ + private static SettingsManager instance; + + // 内存中保存一份配置 + private AppSettings appSettings; + +#if DEBUG + // 设置的配置文件 + private readonly string settingsName = StorageManager.GetSettings() + "_debug.json"; +#else + // 设置的配置文件 + private readonly string settingsName = Storage.StorageManager.GetSettings(); + + // 密钥 + private readonly string password = "YO1J$4#p"; +#endif + + /// + /// 获取SettingsManager实例 + /// + /// + public static SettingsManager GetInstance() + { + if (instance == null) + { + instance = new SettingsManager(); + } + + return instance; + } + + /// + /// 隐藏Settings()方法,必须使用单例模式 + /// + private SettingsManager() + { + appSettings = GetSettings(); + } + + /// + /// 获取AppSettingsModel + /// + /// + private AppSettings GetSettings() + { + if (appSettings != null) + { + return appSettings; + } + + try + { + //FileStream fileStream = new FileStream(settingsName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); + //StreamReader streamReader = new StreamReader(fileStream, System.Text.Encoding.UTF8); + //string jsonWordTemplate = streamReader.ReadToEnd(); + //streamReader.Close(); + //fileStream.Close(); + string jsonWordTemplate = string.Empty; + using (var stream = new FileStream(settingsName, FileMode.Open, FileAccess.Read, + FileShare.ReadWrite | FileShare.Delete)) + { + using (var reader = new StreamReader(stream, Encoding.UTF8)) + { + jsonWordTemplate = reader.ReadToEnd(); + } + } + +#if DEBUG +#else + // 解密字符串 + jsonWordTemplate = Encryptor.DecryptString(jsonWordTemplate, password); +#endif + + return JsonConvert.DeserializeObject(jsonWordTemplate); + } + catch (Exception e) + { + Console.PrintLine("GetSettings()发生异常: {0}", e); + LogManager.Error("SettingsManager", e); + return new AppSettings(); + } + } + + /// + /// 设置AppSettingsModel + /// + /// + private bool SetSettings() + { + try + { + string json = JsonConvert.SerializeObject(appSettings); + +#if DEBUG +#else + // 加密字符串 + json = Encryptor.EncryptString(json, password); +#endif + + File.WriteAllText(settingsName, json); + return true; + } + catch (Exception e) + { + Console.PrintLine("SetSettings()发生异常: {0}", e); + LogManager.Error("SettingsManager", e); + return false; + } + } +} \ No newline at end of file diff --git a/DownKyi.Core/Settings/VideoCodecs.cs b/DownKyi.Core/Settings/VideoCodecs.cs new file mode 100644 index 0000000..10da355 --- /dev/null +++ b/DownKyi.Core/Settings/VideoCodecs.cs @@ -0,0 +1,8 @@ +namespace DownKyi.Core.Settings; + +public enum VideoCodecs +{ + NONE = 0, + AVC, + HEVC +} \ No newline at end of file diff --git a/DownKyi.Core/Storage/Constant.cs b/DownKyi.Core/Storage/Constant.cs new file mode 100644 index 0000000..6ca4265 --- /dev/null +++ b/DownKyi.Core/Storage/Constant.cs @@ -0,0 +1,66 @@ +namespace DownKyi.Core.Storage; + +/// +/// 存储到本地时使用的一些常量 +/// +internal static class Constant +{ + // 根目录 + //private static string Root { get; } = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "/Downkyi"; + private static string Root { get; } = Environment.CurrentDirectory; + + // Aria + public static string Aria { get; } = $"{Root}/Aria"; + + // 日志 + public static string Logs { get; } = $"{Root}/Logs"; + + // 数据库 + public static string Database { get; } = $"{Root}/Storage"; + + // 历史(搜索、下载) (加密) + public static string Download { get; } = $"{Database}/Download.db"; + public static string History { get; } = $"{Database}/History.db"; + + // 配置 + public static string Config { get; } = $"{Root}/Config"; + + // 设置 + public static string Settings { get; } = $"{Config}/Settings"; + + // 登录cookies + public static string Login { get; } = $"{Config}/Login"; + + // Bilibili + private static string Bilibili { get; } = $"{Root}/Bilibili"; + + // 弹幕 + public static string Danmaku { get; } = $"{Bilibili}/Danmakus"; + + // 字幕 + public static string Subtitle { get; } = $"{Bilibili}/Subtitle"; + + // 评论 + // TODO + + // 头图 + public static string Toutu { get; } = $"{Bilibili}/Toutu"; + + // 封面 + public static string Cover { get; } = $"{Bilibili}/Cover"; + + // 封面文件索引 + public static string CoverIndex { get; } = $"{Cover}/Index.db"; + + // 视频快照 + public static string Snapshot { get; } = $"{Bilibili}/Snapshot"; + + // 视频快照文件索引 + public static string SnapshotIndex { get; } = $"{Cover}/Index.db"; + + // 用户头像 + public static string Header { get; } = $"{Bilibili}/Header"; + + // 用户头像文件索引 + public static string HeaderIndex { get; } = $"{Header}/Index.db"; +} \ No newline at end of file diff --git a/DownKyi.Core/Storage/Database/Cover.cs b/DownKyi.Core/Storage/Database/Cover.cs new file mode 100644 index 0000000..037c246 --- /dev/null +++ b/DownKyi.Core/Storage/Database/Cover.cs @@ -0,0 +1,10 @@ +namespace DownKyi.Core.Storage.Database; + +public class Cover +{ + public long Avid { get; set; } + public string Bvid { get; set; } + public long Cid { get; set; } + public string Url { get; set; } + public string Md5 { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/Storage/Database/CoverDb.cs b/DownKyi.Core/Storage/Database/CoverDb.cs new file mode 100644 index 0000000..50de6ea --- /dev/null +++ b/DownKyi.Core/Storage/Database/CoverDb.cs @@ -0,0 +1,147 @@ +using DownKyi.Core.Logging; +using Console = DownKyi.Core.Utils.Debugging.Console; + +namespace DownKyi.Core.Storage.Database; + +public class CoverDb +{ + private const string key = "b5018ecc-09d1-4da2-aa49-4625e41e623e"; + private readonly string tableName = "cover"; + +#if DEBUG + private readonly DbHelper dbHelper = new DbHelper(StorageManager.GetCoverIndex().Replace(".db", "_debug.db")); +#else + private readonly DbHelper dbHelper = new DbHelper(StorageManager.GetCoverIndex(), key); +#endif + + public CoverDb() + { + CreateTable(); + } + + /// + /// 关闭数据库连接 + /// + public void Close() + { + dbHelper.Close(); + } + + /// + /// 插入新的数据 + /// + /// + public void Insert(Cover cover) + { + try + { + string sql = + $"insert into {tableName} values ({cover.Avid}, '{cover.Bvid}', {cover.Cid}, '{cover.Url}', '{cover.Md5}')"; + dbHelper.ExecuteNonQuery(sql); + } + catch (Exception e) + { + Console.PrintLine("Insert()发生异常: {0}", e); + LogManager.Error("CoverDb", e); + } + } + + /// + /// 更新数据,以url检索 + /// + /// + public void Update(Cover cover) + { + try + { + string sql = + $"update {tableName} set avid={cover.Avid}, bvid='{cover.Bvid}', cid={cover.Cid}, md5='{cover.Md5}' where url glob '{cover.Url}'"; + dbHelper.ExecuteNonQuery(sql); + } + catch (Exception e) + { + Console.PrintLine("Update()发生异常: {0}", e); + LogManager.Error("CoverDb", e); + } + } + + /// + /// 查询所有数据 + /// + /// + public List QueryAll() + { + string sql = $"select * from {tableName}"; + return Query(sql); + } + + /// + /// 查询url对应的数据 + /// + /// + /// + public Cover QueryByUrl(string url) + { + string sql = $"select * from {tableName} where url glob '{url}'"; + List query = Query(sql); + return query.Count > 0 ? query[0] : null; + } + + /// + /// 查询md5对应的数据 + /// + /// + /// + public Cover QueryByMd5(string md5) + { + string sql = $"select * from {tableName} where md5 glob '{md5}'"; + List query = Query(sql); + return query.Count > 0 ? query[0] : null; + } + + /// + /// 查询数据 + /// + /// + /// + private List Query(string sql) + { + List covers = new List(); + + try + { + dbHelper.ExecuteQuery(sql, reader => + { + while (reader.Read()) + { + Cover cover = new Cover + { + Avid = (long)reader["avid"], + Bvid = (string)reader["bvid"], + Cid = (long)reader["cid"], + Url = (string)reader["url"], + Md5 = (string)reader["md5"] + }; + covers.Add(cover); + } + }); + } + catch (Exception e) + { + Console.PrintLine("Query()发生异常: {0}", e); + LogManager.Error($"{tableName}", e); + } + + return covers; + } + + /// + /// 如果表不存在则创建表 + /// + private void CreateTable() + { + string sql = + $"create table if not exists {tableName} (avid unsigned big int, bvid varchar(20), cid unsigned big int, url varchar(255) unique, md5 varchar(32) unique)"; + dbHelper.ExecuteNonQuery(sql); + } +} \ No newline at end of file diff --git a/DownKyi.Core/Storage/Database/DbHelper.cs b/DownKyi.Core/Storage/Database/DbHelper.cs new file mode 100644 index 0000000..ceefac1 --- /dev/null +++ b/DownKyi.Core/Storage/Database/DbHelper.cs @@ -0,0 +1,179 @@ +using System.Data; +using DownKyi.Core.Logging; +using Microsoft.Data.Sqlite; +using Console = DownKyi.Core.Utils.Debugging.Console; + +namespace DownKyi.Core.Storage.Database; + +public class DbHelper +{ + private readonly string connStr; + private readonly SqliteConnection conn; + + private static readonly Dictionary database = new(); + + /// + /// 创建一个数据库 + /// + /// + public DbHelper(string dbPath) + { + connStr = new SqliteConnectionStringBuilder + { + Mode = SqliteOpenMode.ReadWriteCreate, + DataSource = dbPath + }.ToString(); + if (database.ContainsKey(connStr)) + { + conn = database[connStr]; + + if (conn != null) + { + return; + } + } + + conn = new SqliteConnection(connStr); + database.Add(connStr, conn); + } + + /// + /// 创建一个带密码的数据库 + /// + /// + /// + public DbHelper(string dbPath, string secretKey) + { + connStr = new SqliteConnectionStringBuilder + { + Mode = SqliteOpenMode.ReadWriteCreate, + Password = secretKey, + DataSource = dbPath + }.ToString(); + if (database.ContainsKey(connStr)) + { + conn = database[connStr]; + + if (conn != null) + { + return; + } + } + + conn = new SqliteConnection(connStr); + // conn.SetPassword(secretKey); + database.Add(connStr, conn); + } + + /// + /// 连接是否开启 + /// + /// + public bool IsOpen() + { + return conn.State == ConnectionState.Open; + } + + /// + /// 开启连接 + /// + public void Open() + { + if (conn == null) + { + return; + } + + if (!IsOpen()) + { + conn.Open(); + } + } + + /// + /// 关闭数据库 + /// + public void Close() + { + if (conn == null) + { + return; + } + + if (IsOpen()) + { + conn.Close(); + + database.Remove(connStr); + } + } + + /// + /// 执行一条SQL语句 + /// + /// + public void ExecuteNonQuery(string sql, Action action = null) + { + if (conn == null) + { + return; + } + + try + { + lock (conn) + { + Open(); + using (var tr = conn.BeginTransaction()) + { + using (var command = conn.CreateCommand()) + { + command.CommandText = sql; + // 添加参数 + action?.Invoke(command.Parameters); + command.ExecuteNonQuery(); + } + + tr.Commit(); + } + } + } + catch (SqliteException e) + { + Console.PrintLine("DbHelper ExecuteNonQuery()发生异常: {0}", e); + LogManager.Error("DbHelper ExecuteNonQuery()", e); + } + } + + /// + /// 执行一条SQL语句,并执行提供的操作,一般用于查询 + /// + /// + /// + public void ExecuteQuery(string sql, Action action) + { + if (conn == null) + { + return; + } + + try + { + lock (conn) + { + Open(); + using (var command = conn.CreateCommand()) + { + command.CommandText = sql; + var reader = command.ExecuteReader(); + action(reader); + } + } + } + catch (SqliteException e) + { + Console.PrintLine("DbHelper ExecuteQuery()发生异常: {0}", e); + LogManager.Error("DbHelper ExecuteQuery()", e); + } + } +} \ No newline at end of file diff --git a/DownKyi.Core/Storage/Database/Download/DownloadBaseDb.cs b/DownKyi.Core/Storage/Database/Download/DownloadBaseDb.cs new file mode 100644 index 0000000..83a4973 --- /dev/null +++ b/DownKyi.Core/Storage/Database/Download/DownloadBaseDb.cs @@ -0,0 +1,10 @@ +namespace DownKyi.Core.Storage.Database.Download; + +public class DownloadBaseDb : DownloadDb +{ + public DownloadBaseDb() + { + tableName = "download_base"; + CreateTable(); + } +} \ No newline at end of file diff --git a/DownKyi.Core/Storage/Database/Download/DownloadDb.cs b/DownKyi.Core/Storage/Database/Download/DownloadDb.cs new file mode 100644 index 0000000..8c5eeac --- /dev/null +++ b/DownKyi.Core/Storage/Database/Download/DownloadDb.cs @@ -0,0 +1,196 @@ +using System.Runtime.Serialization.Formatters.Binary; +using DownKyi.Core.Logging; +using Microsoft.Data.Sqlite; +using Console = DownKyi.Core.Utils.Debugging.Console; + +namespace DownKyi.Core.Storage.Database.Download; + +public class DownloadDb +{ + private const string key = "bdb8eb69-3698-4af9-b722-9312d0fba623"; + protected string tableName = "download"; + +#if DEBUG + private readonly DbHelper dbHelper = new DbHelper(StorageManager.GetDownload().Replace(".db", "_debug.db")); +#else + private readonly DbHelper dbHelper = new DbHelper(StorageManager.GetDownload(), key); +#endif + + /// + /// 关闭数据库连接 + /// + public void Close() + { + dbHelper.Close(); + } + + /// + /// 插入新的数据 + /// + /// + public void Insert(string uuid, object obj) + { + try + { + // 定义一个流 + Stream stream = new MemoryStream(); + // 定义一个格式化器 + BinaryFormatter formatter = new BinaryFormatter(); + // 序列化 + formatter.Serialize(stream, obj); + + byte[] array = null; + array = new byte[stream.Length]; + + //将二进制流写入数组 + stream.Position = 0; + stream.Read(array, 0, (int)stream.Length); + + //关闭流 + stream.Close(); + + string sql = $"insert into {tableName}(id, data) values (@id, @data)"; + dbHelper.ExecuteNonQuery(sql, new Action((para) => + { + para.Add("@id", SqliteType.Text).Value = uuid; + para.Add("@data", SqliteType.Blob).Value = array; + })); + } + catch (Exception e) + { + Console.PrintLine("Insert()发生异常: {0}", e); + LogManager.Error($"{tableName}", e); + } + } + + /// + /// 删除uuid对应的数据 + /// + /// + public void Delete(string uuid) + { + try + { + string sql = $"delete from {tableName} where id glob '{uuid}'"; + dbHelper.ExecuteNonQuery(sql); + } + catch (Exception e) + { + Console.PrintLine("Delete()发生异常: {0}", e); + LogManager.Error($"{tableName}", e); + } + } + + public void Update(string uuid, object obj) + { + try + { + // 定义一个流 + Stream stream = new MemoryStream(); + // 定义一个格式化器 + BinaryFormatter formatter = new BinaryFormatter(); + // 序列化 + formatter.Serialize(stream, obj); + + byte[] array = null; + array = new byte[stream.Length]; + + //将二进制流写入数组 + stream.Position = 0; + stream.Read(array, 0, (int)stream.Length); + + //关闭流 + stream.Close(); + + string sql = $"update {tableName} set data=@data where id glob @id"; + dbHelper.ExecuteNonQuery(sql, new Action((para) => + { + para.Add("@id", SqliteType.Text).Value = uuid; + para.Add("@data", SqliteType.Blob).Value = array; + })); + } + catch (Exception e) + { + Console.PrintLine("Insert()发生异常: {0}", e); + LogManager.Error($"{tableName}", e); + } + } + + /// + /// 查询所有数据 + /// + /// + /// + public Dictionary QueryAll() + { + string sql = $"select * from {tableName}"; + return Query(sql); + } + + /// + /// 查询uuid对应的数据 + /// + /// + /// + public object QueryById(string uuid) + { + string sql = $"select * from {tableName} where id glob '{uuid}'"; + Dictionary query = Query(sql); + + if (query.ContainsKey(uuid)) + { + query.TryGetValue(uuid, out object obj); + return obj; + } + else + { + return null; + } + } + + /// + /// 查询数据 + /// + /// + /// + private Dictionary Query(string sql) + { + Dictionary objects = new Dictionary(); + + dbHelper.ExecuteQuery(sql, reader => + { + while (reader.Read()) + { + try + { + // 读取字节数组 + byte[] array = (byte[])reader["data"]; + // 定义一个流 + MemoryStream stream = new MemoryStream(array); + //定义一个格式化器 + BinaryFormatter formatter = new BinaryFormatter(); + // 反序列化 + object obj = formatter.Deserialize(stream); + + objects.Add((string)reader["id"], obj); + } + catch (Exception e) + { + Console.PrintLine("Query()发生异常: {0}", e); + LogManager.Error($"{tableName}", e); + } + } + }); + + return objects; + } + + /// + /// 如果表不存在则创建表 + /// + protected void CreateTable() + { + string sql = $"create table if not exists {tableName} (id varchar(255) unique, data blob)"; + dbHelper.ExecuteNonQuery(sql); + } +} \ No newline at end of file diff --git a/DownKyi.Core/Storage/Database/Download/DownloadedDb.cs b/DownKyi.Core/Storage/Database/Download/DownloadedDb.cs new file mode 100644 index 0000000..0ad9627 --- /dev/null +++ b/DownKyi.Core/Storage/Database/Download/DownloadedDb.cs @@ -0,0 +1,10 @@ +namespace DownKyi.Core.Storage.Database.Download; + +public class DownloadedDb : DownloadDb +{ + public DownloadedDb() + { + tableName = "downloaded"; + CreateTable(); + } +} \ No newline at end of file diff --git a/DownKyi.Core/Storage/Database/Download/DownloadingDb.cs b/DownKyi.Core/Storage/Database/Download/DownloadingDb.cs new file mode 100644 index 0000000..1888a34 --- /dev/null +++ b/DownKyi.Core/Storage/Database/Download/DownloadingDb.cs @@ -0,0 +1,10 @@ +namespace DownKyi.Core.Storage.Database.Download; + +public class DownloadingDb : DownloadDb +{ + public DownloadingDb() + { + tableName = "downloading"; + CreateTable(); + } +} \ No newline at end of file diff --git a/DownKyi.Core/Storage/Database/Header.cs b/DownKyi.Core/Storage/Database/Header.cs new file mode 100644 index 0000000..cda3e11 --- /dev/null +++ b/DownKyi.Core/Storage/Database/Header.cs @@ -0,0 +1,9 @@ +namespace DownKyi.Core.Storage.Database; + +public class Header +{ + public long Mid { get; set; } + public string Name { get; set; } + public string Url { get; set; } + public string Md5 { get; set; } +} \ No newline at end of file diff --git a/DownKyi.Core/Storage/Database/HeaderDb.cs b/DownKyi.Core/Storage/Database/HeaderDb.cs new file mode 100644 index 0000000..9229b0f --- /dev/null +++ b/DownKyi.Core/Storage/Database/HeaderDb.cs @@ -0,0 +1,134 @@ +using DownKyi.Core.Logging; +using Console = DownKyi.Core.Utils.Debugging.Console; + +namespace DownKyi.Core.Storage.Database; + +public class HeaderDb +{ + private const string key = "7c1f1f40-7cdf-4d11-ad28-f0137a3c5308"; + private readonly string tableName = "header"; + +#if DEBUG + private readonly DbHelper dbHelper = new DbHelper(StorageManager.GetHeaderIndex().Replace(".db", "_debug.db")); +#else + private readonly DbHelper dbHelper = new DbHelper(StorageManager.GetHeaderIndex(), key); +#endif + + public HeaderDb() + { + CreateTable(); + } + + /// + /// 关闭数据库连接 + /// + public void Close() + { + dbHelper.Close(); + } + + /// + /// 插入新的数据 + /// + /// + public void Insert(Header header) + { + try + { + string sql = + $"insert into {tableName} values ({header.Mid}, '{header.Name}', '{header.Url}', '{header.Md5}')"; + dbHelper.ExecuteNonQuery(sql); + } + catch (Exception e) + { + Console.PrintLine("Insert()发生异常: {0}", e); + LogManager.Error("HeaderDb", e); + } + } + + /// + /// 更新数据 + /// + /// + public void Update(Header header) + { + try + { + string sql = + $"update {tableName} set name='{header.Name}', url='{header.Url}', md5='{header.Md5}' where mid={header.Mid}"; + dbHelper.ExecuteNonQuery(sql); + } + catch (Exception e) + { + Console.PrintLine("Update()发生异常: {0}", e); + LogManager.Error("HeaderDb", e); + } + } + + /// + /// 查询所有数据 + /// + /// + public List
QueryAll() + { + string sql = $"select * from {tableName}"; + return Query(sql); + } + + /// + /// 查询mid对应的数据 + /// + /// + /// + public Header QueryByMid(long mid) + { + string sql = $"select * from {tableName} where mid={mid}"; + List
query = Query(sql); + return query.Count > 0 ? query[0] : null; + } + + /// + /// 查询数据 + /// + /// + /// + private List
Query(string sql) + { + List
headers = new List
(); + + try + { + dbHelper.ExecuteQuery(sql, reader => + { + while (reader.Read()) + { + Header header = new Header + { + Mid = (long)reader["mid"], + Name = (string)reader["name"], + Url = (string)reader["url"], + Md5 = (string)reader["md5"] + }; + headers.Add(header); + } + }); + } + catch (Exception e) + { + Console.PrintLine("Query()发生异常: {0}", e); + LogManager.Error($"{tableName}", e); + } + + return headers; + } + + /// + /// 如果表不存在则创建表 + /// + private void CreateTable() + { + string sql = + $"create table if not exists {tableName} (mid unsigned big int unique, name varchar(255), url varchar(255), md5 varchar(32))"; + dbHelper.ExecuteNonQuery(sql); + } +} \ No newline at end of file diff --git a/DownKyi.Core/Storage/StorageCover.cs b/DownKyi.Core/Storage/StorageCover.cs new file mode 100644 index 0000000..9593d6b --- /dev/null +++ b/DownKyi.Core/Storage/StorageCover.cs @@ -0,0 +1,250 @@ +using Avalonia; +using Avalonia.Media.Imaging; +using DownKyi.Core.Logging; +using DownKyi.Core.Storage.Database; +using DownKyi.Core.Utils.Encryptor; +using Console = DownKyi.Core.Utils.Debugging.Console; + +namespace DownKyi.Core.Storage; + +public class StorageCover +{ + // 先判断本地有没有 + // 如果有 + // 则返回本地的图片路径 + // 如果没有 + // 则下载图片并返回本地的图片路径 + + /// + /// 获取封面缩略图 + /// + /// + /// + /// + /// + /// + /// + /// + public Bitmap GetCoverThumbnail(long avid, string bvid, long cid, string url, int width, int height) + { + string header = GetCover(avid, bvid, cid, url); + + return GetCoverThumbnail(header, width, height); + } + + /// + /// 获取封面缩略图 + /// + /// + /// + /// + /// + public Bitmap GetCoverThumbnail(string cover, int width, int height) + { + if (cover == null) + { + return null; + } + + try + { + Bitmap bitmap = new Bitmap(cover); + return bitmap.CreateScaledBitmap(new PixelSize(width, height)); + + // return StorageUtils.BitmapToBitmapImage(new Bitmap(thumbnail)); + } + catch (ArgumentException) + { + try + { + // SimpleDecoder simpleDecoder = new SimpleDecoder(cover); + // Bitmap bitmap = simpleDecoder.WebPtoBitmap(); + // Image thumbnail = bitmap.GetThumbnailImage(width, height, null, IntPtr.Zero); + // + // return StorageUtils.BitmapToBitmapImage(new Bitmap(thumbnail)); + return null; + } + catch (Exception ex) + { + Console.PrintLine("GetCoverThumbnail()发生异常: {0}", ex); + LogManager.Error("StorageCover.GetCoverThumbnail()", ex); + + return null; + } + } + catch (Exception e) + { + Console.PrintLine("GetCoverThumbnail()发生异常: {0}", e); + LogManager.Error("StorageCover.GetCoverThumbnail()", e); + + return null; + } + } + + /// + /// 获取封面 + /// + /// + /// + public string GetCover(string url) + { + return GetCover(0, "", 0, url); + } + + /// + /// 获取封面 + /// + /// + /// + /// + /// + /// + public string GetCover(long avid, string bvid, long cid, string url) + { + CoverDb coverDb = new CoverDb(); + Cover cover = coverDb.QueryByUrl(url); + + // 如果存在,直接返回 + // 如果不存在,则先下载 + if (cover != null) + { + string coverPath = $"{StorageManager.GetCover()}/{cover.Md5}"; + if (File.Exists(coverPath)) + { + Cover newCover = new Cover + { + Avid = avid, + Bvid = bvid, + Cid = cid, + Url = url, + Md5 = cover.Md5 + }; + coverDb.Update(newCover); + + //coverDb.Close(); + return $"{StorageManager.GetCover()}/{cover.Md5}"; + } + else + { + string md5 = DownloadImage(url); + if (md5 != null) + { + Cover newCover = new Cover + { + Avid = avid, + Bvid = bvid, + Cid = cid, + Url = url, + Md5 = md5 + }; + coverDb.Update(newCover); + + //coverDb.Close(); + return $"{StorageManager.GetCover()}/{md5}"; + } + else + { + //coverDb.Close(); + return null; + } + } + } + else + { + string md5 = DownloadImage(url); + if (md5 != null) + { + Cover newCover = new Cover + { + Avid = avid, + Bvid = bvid, + Cid = cid, + Url = url, + Md5 = md5 + }; + coverDb.Insert(newCover); + + //coverDb.Close(); + return $"{StorageManager.GetCover()}/{md5}"; + } + else + { + //coverDb.Close(); + return null; + } + } + } + + /// + /// 下载图片 + /// + /// + /// + private string DownloadImage(string url) + { + string localFile = Path.GetTempPath() + Guid.NewGuid().ToString("N"); + + // 下载 + bool isSuccessed = StorageUtils.DownloadImage(url, localFile); + if (isSuccessed) + { + try + { + string md5 = Hash.GetMD5HashFromFile(localFile); + + if (File.Exists(localFile)) + { + string destFile = $"{StorageManager.GetCover()}/{md5}"; + + try + { + File.Delete(destFile); + } + catch + { + } + + // 移动到指定位置 + File.Move(localFile, destFile); + + return md5; + } + else + { + return null; + } + } + catch (Exception e) + { + Console.PrintLine("DownloadImage()发生异常: {0}", e); + LogManager.Error("StorageCover", e); + return null; + } + } + + return null; + } + + /// + /// 本地是否存在 + /// + /// + /// + public bool IsLocal(CoverDb coverDb, string url) + { + Cover cover = coverDb.QueryByUrl(url); + return cover != null; + } + + /// + /// 返回图片md5值 + /// + /// + /// + /// + public string LocalCover(CoverDb coverDb, string url) + { + Cover cover = coverDb.QueryByUrl(url); + return cover.Md5; + } +} \ No newline at end of file diff --git a/DownKyi.Core/Storage/StorageHeader.cs b/DownKyi.Core/Storage/StorageHeader.cs new file mode 100644 index 0000000..b77b66f --- /dev/null +++ b/DownKyi.Core/Storage/StorageHeader.cs @@ -0,0 +1,210 @@ +using Avalonia; +using Avalonia.Media.Imaging; +using DownKyi.Core.Logging; +using DownKyi.Core.Storage.Database; +using DownKyi.Core.Utils.Encryptor; +using Console = DownKyi.Core.Utils.Debugging.Console; + +namespace DownKyi.Core.Storage; + +public class StorageHeader +{ + // 先判断本地有没有 + // 如果有 + // 则返回本地的图片路径 + // 如果没有 + // 则下载图片并返回本地的图片路径 + + /// + /// 获取用户头像缩略图 + /// + /// + /// + /// + /// + /// + /// + public Bitmap GetHeaderThumbnail(long mid, string name, string url, int width, int height) + { + string header = GetHeader(mid, name, url); + if (header == null) + { + return null; + } + + return GetHeaderThumbnail(header, width, height); + } + + /// + /// 获取用户头像缩略图 + /// + /// + /// + /// + /// + public Bitmap GetHeaderThumbnail(string header, int width, int height) + { + if (header == null) + { + return null; + } + + try + { + Bitmap bitmap = new Bitmap(header); + var thumbnail = bitmap.CreateScaledBitmap(new PixelSize(width, height)); + + return thumbnail; + } + catch (ArgumentException) + { + try + { + /*SimpleDecoder simpleDecoder = new SimpleDecoder(header); + Bitmap bitmap = simpleDecoder.WebPtoBitmap(); + Image thumbnail = bitmap.GetThumbnailImage(width, height, null, IntPtr.Zero); + + return StorageUtils.BitmapToBitmapImage(new Bitmap(thumbnail));*/ + return null; + } + catch (Exception ex) + { + Console.PrintLine("GetHeaderThumbnail()发生异常: {0}", ex); + LogManager.Error("StorageHeader.GetHeaderThumbnail()", ex); + + return null; + } + } + catch (Exception e) + { + Console.PrintLine("GetHeaderThumbnail()发生异常: {0}", e); + LogManager.Error("StorageHeader.GetHeaderThumbnail()", e); + + return null; + } + } + + /// + /// 获取用户头像 + /// + /// + /// + public string GetHeader(long mid, string name, string url) + { + HeaderDb headerDb = new HeaderDb(); + Header header = headerDb.QueryByMid(mid); + + if (header != null) + { + string headerPath = $"{StorageManager.GetHeader()}/{header.Md5}"; + if (File.Exists(headerPath)) + { + Header newHeader = new Header + { + Mid = mid, + Name = name, + Url = url, + Md5 = header.Md5 + }; + headerDb.Update(newHeader); + //headerDb.Close(); + return $"{StorageManager.GetHeader()}/{header.Md5}"; + } + else + { + string md5 = DownloadImage(url); + if (md5 != null) + { + Header newHeader = new Header + { + Mid = mid, + Name = name, + Url = url, + Md5 = md5 + }; + headerDb.Insert(newHeader); + //headerDb.Close(); + return $"{StorageManager.GetHeader()}/{md5}"; + } + else + { + //headerDb.Close(); + return null; + } + } + } + else + { + string md5 = DownloadImage(url); + if (md5 != null) + { + Header newHeader = new Header + { + Mid = mid, + Name = name, + Url = url, + Md5 = md5 + }; + headerDb.Insert(newHeader); + //headerDb.Close(); + return $"{StorageManager.GetHeader()}/{md5}"; + } + else + { + //headerDb.Close(); + return null; + } + } + } + + + /// + /// 下载图片 + /// + /// + /// + private string DownloadImage(string url) + { + string localFile = Path.GetTempPath() + Guid.NewGuid().ToString("N"); + + // 下载 + bool isSuccessed = StorageUtils.DownloadImage(url, localFile); + if (isSuccessed) + { + try + { + string md5 = Hash.GetMD5HashFromFile(localFile); + + if (File.Exists(localFile)) + { + string destFile = $"{StorageManager.GetHeader()}/{md5}"; + + try + { + File.Delete(destFile); + } + catch + { + } + + // 移动到指定位置 + File.Move(localFile, destFile); + + return md5; + } + else + { + return null; + } + } + catch (Exception e) + { + Console.PrintLine("DownloadImage()发生异常: {0}", e); + LogManager.Error("StorageHeader", e); + return null; + } + } + + return null; + } +} \ No newline at end of file diff --git a/DownKyi.Core/Storage/StorageManager.cs b/DownKyi.Core/Storage/StorageManager.cs new file mode 100644 index 0000000..03b2ad3 --- /dev/null +++ b/DownKyi.Core/Storage/StorageManager.cs @@ -0,0 +1,154 @@ +namespace DownKyi.Core.Storage; + +public static class StorageManager +{ + /// + /// 获取历史记录的文件路径 + /// + /// + public static string GetAriaDir() + { + CreateDirectory(Constant.Aria); + return Constant.Aria; + } + + /// + /// 获取历史记录的文件路径 + /// + /// + public static string GetDownload() + { + CreateDirectory(Constant.Database); + return Constant.Download; + } + + /// + /// 获取历史记录的文件路径 + /// + /// + public static string GetHistory() + { + CreateDirectory(Constant.Database); + return Constant.History; + } + + /// + /// 获取设置的文件路径 + /// + /// + public static string GetSettings() + { + CreateDirectory(Constant.Config); + return Constant.Settings; + } + + /// + /// 获取登录cookies的文件路径 + /// + /// + public static string GetLogin() + { + CreateDirectory(Constant.Config); + return Constant.Login; + } + + /// + /// 获取弹幕的文件夹路径 + /// + /// + public static string GetDanmaku() + { + return CreateDirectory(Constant.Danmaku); + } + + /// + /// 获取字幕的文件夹路径 + /// + /// + public static string GetSubtitle() + { + return CreateDirectory(Constant.Subtitle); + } + + /// + /// 获取头图的文件夹路径 + /// + /// + public static string GetToutu() + { + return CreateDirectory(Constant.Toutu); + } + + /// + /// 获取封面的文件夹路径 + /// + /// + public static string GetCover() + { + return CreateDirectory(Constant.Cover); + } + + /// + /// 获取封面索引的文件路径 + /// + /// + public static string GetCoverIndex() + { + CreateDirectory(Constant.Cover); + return Constant.CoverIndex; + } + + /// + /// 获取视频快照的文件夹路径 + /// + /// + public static string GetSnapshot() + { + return CreateDirectory(Constant.Snapshot); + } + + /// + /// 获取视频快照索引的文件路径 + /// + /// + public static string GetSnapshotIndex() + { + CreateDirectory(Constant.Snapshot); + return Constant.SnapshotIndex; + } + + /// + /// 获取用户头像的文件夹路径 + /// + /// + public static string GetHeader() + { + return CreateDirectory(Constant.Header); + } + + /// + /// 获取用户头像索引的文件路径 + /// + /// + public static string GetHeaderIndex() + { + CreateDirectory(Constant.Header); + return Constant.HeaderIndex; + } + + + /// + /// 若文件夹不存在,则创建文件夹 + /// + /// + /// + private static string CreateDirectory(string directory) + { + if (!Directory.Exists(directory)) + { + Directory.CreateDirectory(directory); + } + + return directory; + } +} \ No newline at end of file diff --git a/DownKyi.Core/Storage/StorageUtils.cs b/DownKyi.Core/Storage/StorageUtils.cs new file mode 100644 index 0000000..8f67e05 --- /dev/null +++ b/DownKyi.Core/Storage/StorageUtils.cs @@ -0,0 +1,52 @@ +using System.Net; +using DownKyi.Core.Logging; +using Console = DownKyi.Core.Utils.Debugging.Console; + +namespace DownKyi.Core.Storage; + +internal static class StorageUtils +{ + /// + /// 下载图片 + /// + /// + /// + /// + public static bool DownloadImage(string url, string localFile) + { + try + { + WebClient mywebclient = new WebClient(); + mywebclient.DownloadFile(url, localFile); + } + catch (Exception e) + { + Console.PrintLine("DownloadImage()发生异常: {0}", e); + LogManager.Error("StorageUtils", e); + return false; + } + + return true; + } + + /// + /// Bitmap转BitmapImage + /// + /// + /// + /*public static BitmapImage BitmapToBitmapImage(Bitmap bitmap) + { + BitmapImage result = new BitmapImage(); + using (MemoryStream stream = new MemoryStream()) + { + bitmap.Save(stream, ImageFormat.Bmp); + stream.Position = 0; + result.BeginInit(); + result.CacheOption = BitmapCacheOption.OnLoad; + result.StreamSource = stream; + result.EndInit(); + result.Freeze(); + } + return result; + }*/ +} \ No newline at end of file diff --git a/DownKyi.Core/Utils/Debugging/Console.cs b/DownKyi.Core/Utils/Debugging/Console.cs new file mode 100644 index 0000000..fe6bd43 --- /dev/null +++ b/DownKyi.Core/Utils/Debugging/Console.cs @@ -0,0 +1,137 @@ +namespace DownKyi.Core.Utils.Debugging; + +public static class Console +{ + public static void PrintLine() + { +#if DEBUG + System.Console.WriteLine(); +#endif + } + + public static void PrintLine(float value) + { +#if DEBUG + System.Console.WriteLine(value); +#endif + } + + public static void PrintLine(int value) + { +#if DEBUG + System.Console.WriteLine(value); +#endif + } + + public static void PrintLine(uint value) + { +#if DEBUG + System.Console.WriteLine(value); +#endif + } + + public static void PrintLine(long value) + { +#if DEBUG + System.Console.WriteLine(value); +#endif + } + + public static void PrintLine(ulong value) + { +#if DEBUG + System.Console.WriteLine(value); +#endif + } + + public static void PrintLine(object value) + { +#if DEBUG + System.Console.WriteLine(value); +#endif + } + + public static void PrintLine(string value) + { +#if DEBUG + System.Console.WriteLine(value); +#endif + } + + public static void PrintLine(string format, object arg0) + { +#if DEBUG + System.Console.WriteLine(format, arg0); +#endif + } + + public static void PrintLine(string format, object arg0, object arg1) + { +#if DEBUG + System.Console.WriteLine(format, arg0, arg1); +#endif + } + + public static void PrintLine(string format, object arg0, object arg1, object arg2) + { +#if DEBUG + System.Console.WriteLine(format, arg0, arg1, arg2); +#endif + } + + public static void PrintLine(string format, object arg0, object arg1, object arg2, object arg3) + { +#if DEBUG + System.Console.WriteLine(format, arg0, arg1, arg2); +#endif + } + + public static void PrintLine(string format, params object[] arg) + { +#if DEBUG + System.Console.WriteLine(format, arg); +#endif + } + + public static void PrintLine(char[] buffer, int index, int count) + { +#if DEBUG + System.Console.WriteLine(buffer, index, count); +#endif + } + + public static void PrintLine(decimal value) + { +#if DEBUG + System.Console.WriteLine(value); +#endif + } + + public static void PrintLine(char[] buffer) + { +#if DEBUG + System.Console.WriteLine(buffer); +#endif + } + + public static void PrintLine(char value) + { +#if DEBUG + System.Console.WriteLine(value); +#endif + } + + public static void PrintLine(bool value) + { +#if DEBUG + System.Console.WriteLine(value); +#endif + } + + public static void PrintLine(double value) + { +#if DEBUG + System.Console.WriteLine(value); +#endif + } +} \ No newline at end of file diff --git a/DownKyi.Core/Utils/Encryptor/Encryptor.File.cs b/DownKyi.Core/Utils/Encryptor/Encryptor.File.cs new file mode 100644 index 0000000..e329d89 --- /dev/null +++ b/DownKyi.Core/Utils/Encryptor/Encryptor.File.cs @@ -0,0 +1,240 @@ +using System; +using System.IO; +using System.Security.Cryptography; + +namespace DownKyi.Core.Utils.Encryptor; + +public static partial class Encryptor +{ + private const ulong FC_TAG = 0xFC010203040506CF; + private const int BUFFER_SIZE = 128 * 1024; + + /// + /// 加密文件 + /// + /// 待加密文件 + /// 加密后输入文件 + /// 加密密码 + public static void EncryptFile(string inFile, string outFile, string password) + { + using (FileStream fin = File.OpenRead(inFile), fout = File.OpenWrite(outFile)) + { + long lSize = fin.Length; // 输入文件长度 + int size = (int)lSize; + byte[] bytes = new byte[BUFFER_SIZE]; // 缓存 + int read = -1; // 输入文件读取数量 + int value = 0; + + // 获取IV和salt + byte[] IV = GenerateRandomBytes(16); + byte[] salt = GenerateRandomBytes(16); + + // 创建加密对象 + SymmetricAlgorithm sma = CreateRijndael(password, salt); + sma.IV = IV; + + // 在输出文件开始部分写入IV和salt + fout.Write(IV, 0, IV.Length); + fout.Write(salt, 0, salt.Length); + + // 创建散列加密 + HashAlgorithm hasher = SHA256.Create(); + using (CryptoStream cout = new(fout, sma.CreateEncryptor(), CryptoStreamMode.Write), + chash = new(Stream.Null, hasher, CryptoStreamMode.Write)) + { + BinaryWriter bw = new BinaryWriter(cout); + bw.Write(lSize); + + bw.Write(FC_TAG); + + // 读写字节块到加密流缓冲区 + while ((read = fin.Read(bytes, 0, bytes.Length)) != 0) + { + cout.Write(bytes, 0, read); + chash.Write(bytes, 0, read); + value += read; + } + + // 关闭加密流 + chash.Flush(); + chash.Close(); + + // 读取散列 + byte[] hash = hasher.Hash; + + // 输入文件写入散列 + cout.Write(hash, 0, hash.Length); + + // 关闭文件流 + cout.Flush(); + cout.Close(); + } + } + } + + /// + /// 解密文件 + /// + /// 待解密文件 + /// 解密后输出文件 + /// 解密密码 + public static void DecryptFile(string inFile, string outFile, string password) + { + // 创建打开文件流 + using (FileStream fin = File.OpenRead(inFile), fout = File.OpenWrite(outFile)) + { + int size = (int)fin.Length; + byte[] bytes = new byte[BUFFER_SIZE]; + int read = -1; + int value = 0; + int outValue = 0; + + byte[] IV = new byte[16]; + fin.Read(IV, 0, 16); + byte[] salt = new byte[16]; + fin.Read(salt, 0, 16); + + SymmetricAlgorithm sma = CreateRijndael(password, salt); + sma.IV = IV; + + value = 32; + long lSize = -1; + + // 创建散列对象, 校验文件 + HashAlgorithm hasher = SHA256.Create(); + + try + { + using (CryptoStream cin = new(fin, sma.CreateDecryptor(), CryptoStreamMode.Read), + chash = new(Stream.Null, hasher, CryptoStreamMode.Write)) + { + // 读取文件长度 + BinaryReader br = new BinaryReader(cin); + lSize = br.ReadInt64(); + ulong tag = br.ReadUInt64(); + + if (FC_TAG != tag) + throw new CryptoHelpException("文件被破坏"); + + long numReads = lSize / BUFFER_SIZE; + + long slack = lSize % BUFFER_SIZE; + + for (int i = 0; i < numReads; ++i) + { + read = cin.Read(bytes, 0, bytes.Length); + fout.Write(bytes, 0, read); + chash.Write(bytes, 0, read); + value += read; + outValue += read; + } + + if (slack > 0) + { + // .net6引入变更,使用旧方法无法读取完毕 + // int totalRead = 0; + // while (totalRead < slack) + // { + // read = cin.Read(bytes, 0, (int)slack-totalRead); + // fout.Write(bytes, 0, read); + // chash.Write(bytes, 0, read); + // value += read; + // outValue += read; + // totalRead += read; + // } + read = cin.Read(bytes, 0, (int)slack); + fout.Write(bytes, 0, read); + chash.Write(bytes, 0, read); + value += read; + outValue += read; + } + + chash.Flush(); + chash.Close(); + + fout.Flush(); + fout.Close(); + + byte[] curHash = hasher.Hash; + + // 获取比较和旧的散列对象 + byte[] oldHash = new byte[hasher.HashSize / 8]; + read = cin.Read(oldHash, 0, oldHash.Length); + if ((oldHash.Length != read) || (!CheckByteArrays(oldHash, curHash))) + throw new CryptoHelpException("文件被破坏"); + } + } + catch (Exception e) + { + Console.WriteLine("DecryptFile()发生异常: {0}", e); + } + + if (outValue != lSize) + throw new CryptoHelpException("文件大小不匹配"); + } + } + + /// + /// 检验两个Byte数组是否相同 + /// + /// Byte数组 + /// Byte数组 + /// true-相等 + private static bool CheckByteArrays(byte[] b1, byte[] b2) + { + if (b1.Length == b2.Length) + { + for (int i = 0; i < b1.Length; ++i) + { + if (b1[i] != b2[i]) + return false; + } + + return true; + } + + return false; + } + + /// + /// 创建DebugLZQ ,http://www.cnblogs.com/DebugLZQ + /// + /// 密码 + /// + /// 加密对象 + private static SymmetricAlgorithm CreateRijndael(string password, byte[] salt) + { + PasswordDeriveBytes pdb = new PasswordDeriveBytes(password, salt, "SHA256", 1000); + + SymmetricAlgorithm sma = Rijndael.Create(); + sma.KeySize = 256; + sma.Key = pdb.GetBytes(32); + sma.Padding = PaddingMode.PKCS7; + return sma; + } + + /// + /// 生成指定长度的随机Byte数组 + /// + /// Byte数组长度 + /// 随机Byte数组 + private static byte[] GenerateRandomBytes(int count) + { + // 加密文件随机数生成 + RandomNumberGenerator rand = new RNGCryptoServiceProvider(); + + byte[] bytes = new byte[count]; + rand.GetBytes(bytes); + return bytes; + } +} + +/// +/// 异常处理类 +/// +public class CryptoHelpException : ApplicationException +{ + public CryptoHelpException(string msg) : base(msg) + { + } +} \ No newline at end of file diff --git a/DownKyi.Core/Utils/Encryptor/Encryptor.String.cs b/DownKyi.Core/Utils/Encryptor/Encryptor.String.cs new file mode 100644 index 0000000..51c7421 --- /dev/null +++ b/DownKyi.Core/Utils/Encryptor/Encryptor.String.cs @@ -0,0 +1,69 @@ +using System.Security.Cryptography; +using System.Text; +using DownKyi.Core.Logging; +using Console = DownKyi.Core.Utils.Debugging.Console; + +namespace DownKyi.Core.Utils.Encryptor; + +public static partial class Encryptor +{ + /// + /// DES加密字符串 + /// + /// 待加密的字符串 + /// 加密密钥,要求为8位 + /// 加密成功返回加密后的字符串,失败返回源串 + public static string EncryptString(string encryptString, string encryptKey) + { + try + { + byte[] rgbKey = Encoding.UTF8.GetBytes(encryptKey.Substring(0, 8)); //转换为字节 + byte[] rgbIV = Encoding.UTF8.GetBytes(encryptKey.Substring(0, 8)); + byte[] inputByteArray = Encoding.UTF8.GetBytes(encryptString); + DESCryptoServiceProvider dCSP = new DESCryptoServiceProvider(); //实例化数据加密标准 + MemoryStream mStream = new MemoryStream(); //实例化内存流 + //将数据流链接到加密转换的流 + CryptoStream cStream = + new CryptoStream(mStream, dCSP.CreateEncryptor(rgbKey, rgbIV), CryptoStreamMode.Write); + cStream.Write(inputByteArray, 0, inputByteArray.Length); + cStream.FlushFinalBlock(); + // 转base64 + return Convert.ToBase64String(mStream.ToArray()); + } + catch (Exception e) + { + Console.PrintLine("EncryptString()发生异常: {0}", e); + LogManager.Error("Encryptor", e); + return encryptString; + } + } + + /// + /// DES解密字符串 + /// + /// 待解密的字符串 + /// 解密密钥,要求为8位,和加密密钥相同 + /// 解密成功返回解密后的字符串,失败返源串 + public static string DecryptString(string decryptString, string decryptKey) + { + try + { + byte[] rgbKey = Encoding.UTF8.GetBytes(decryptKey); + byte[] rgbIV = Encoding.UTF8.GetBytes(decryptKey); + byte[] inputByteArray = Convert.FromBase64String(decryptString); + DESCryptoServiceProvider DCSP = new DESCryptoServiceProvider(); + MemoryStream mStream = new MemoryStream(); + CryptoStream cStream = + new CryptoStream(mStream, DCSP.CreateDecryptor(rgbKey, rgbIV), CryptoStreamMode.Write); + cStream.Write(inputByteArray, 0, inputByteArray.Length); + cStream.FlushFinalBlock(); + return Encoding.UTF8.GetString(mStream.ToArray()); + } + catch (Exception e) + { + Console.PrintLine("DecryptString()发生异常: {0}", e); + LogManager.Error("Encryptor", e); + return decryptString; + } + } +} \ No newline at end of file diff --git a/DownKyi.Core/Utils/Encryptor/Hash.cs b/DownKyi.Core/Utils/Encryptor/Hash.cs new file mode 100644 index 0000000..cf9f122 --- /dev/null +++ b/DownKyi.Core/Utils/Encryptor/Hash.cs @@ -0,0 +1,65 @@ +using System.Security.Cryptography; +using System.Text; + +namespace DownKyi.Core.Utils.Encryptor; + +public static class Hash +{ + /// + /// 计算字符串MD5值 + /// + /// + /// + public static string GetMd5Hash(string input) + { + if (input == null) + { + return null; + } + + MD5 md5Hash = MD5.Create(); + + // 将输入字符串转换为字节数组并计算哈希数据 + byte[] data = md5Hash.ComputeHash(Encoding.UTF8.GetBytes(input)); + + // 创建一个 Stringbuilder 来收集字节并创建字符串 + StringBuilder sBuilder = new StringBuilder(); + + // 循环遍历哈希数据的每一个字节并格式化为十六进制字符串 + for (int i = 0; i < data.Length; i++) + { + sBuilder.Append(data[i].ToString("x2")); + } + + // 返回十六进制字符串 + return sBuilder.ToString(); + } + + /// + /// 计算文件MD5值 + /// + /// + /// + public static string GetMD5HashFromFile(string fileName) + { + try + { + FileStream file = new FileStream(fileName, FileMode.Open); + MD5 md5 = new MD5CryptoServiceProvider(); + byte[] retVal = md5.ComputeHash(file); + file.Close(); + + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < retVal.Length; i++) + { + sb.Append(retVal[i].ToString("x2")); + } + + return sb.ToString(); + } + catch (Exception e) + { + throw new Exception("GetMD5HashFromFile()发生异常: {0}" + e.Message); + } + } +} \ No newline at end of file diff --git a/DownKyi.Core/Utils/Format.cs b/DownKyi.Core/Utils/Format.cs new file mode 100644 index 0000000..4f00425 --- /dev/null +++ b/DownKyi.Core/Utils/Format.cs @@ -0,0 +1,234 @@ +using System.Text.RegularExpressions; + +namespace DownKyi.Core.Utils; + +public static class Format +{ + /// + /// 格式化Duration时间 + /// + /// + /// + public static string FormatDuration(long duration) + { + string formatDuration; + if (duration / 60 > 0) + { + long dur = duration / 60; + if (dur / 60 > 0) + { + formatDuration = $"{dur / 60}h{dur % 60}m{duration % 60}s"; + } + else + { + formatDuration = $"{duration / 60}m{duration % 60}s"; + } + } + else + { + formatDuration = $"{duration}s"; + } + + return formatDuration; + } + + /// + /// 格式化Duration时间,格式为00:00:00 + /// + /// + /// + public static string FormatDuration2(long duration) + { + string formatDuration; + if (duration / 60 > 0) + { + long dur = duration / 60; + if (dur / 60 > 0) + { + formatDuration = string.Format("{0:D2}", dur / 60) + ":" + string.Format("{0:D2}", dur % 60) + ":" + + string.Format("{0:D2}", duration % 60); + } + else + { + formatDuration = "00:" + string.Format("{0:D2}", duration / 60) + ":" + + string.Format("{0:D2}", duration % 60); + } + } + else + { + formatDuration = "00:00:" + string.Format("{0:D2}", duration); + } + + return formatDuration; + } + + /// + /// 格式化Duration时间,格式为00:00 + /// + /// + /// + public static string FormatDuration3(long duration) + { + string formatDuration; + if (duration / 60 > 0) + { + long dur = duration / 60; + if (dur / 60 > 0) + { + formatDuration = string.Format("{0:D2}", dur / 60) + ":" + string.Format("{0:D2}", dur % 60) + ":" + + string.Format("{0:D2}", duration % 60); + } + else + { + formatDuration = string.Format("{0:D2}", duration / 60) + ":" + string.Format("{0:D2}", duration % 60); + } + } + else + { + formatDuration = "00:" + string.Format("{0:D2}", duration); + } + + return formatDuration; + } + + /// + /// 格式化数字,超过10000的数字将单位改为万,超过100000000的数字将单位改为亿,并保留1位小数 + /// + /// + /// + public static string FormatNumber(long number) + { + if (number > 99999999) + { + return (number / 100000000.0f).ToString("F1") + "亿"; + } + + if (number > 9999) + { + return (number / 10000.0f).ToString("F1") + "万"; + } + else + { + return number.ToString(); + } + } + + /// + /// 格式化网速 + /// + /// + /// + public static string FormatSpeed(float speed) + { + string formatSpeed; + if (speed <= 0) + { + formatSpeed = "0B/s"; + } + else if (speed < 1024) + { + formatSpeed = string.Format("{0:F2}", speed) + "B/s"; + } + else if (speed < 1024 * 1024) + { + formatSpeed = string.Format("{0:F2}", speed / 1024) + "KB/s"; + } + else + { + formatSpeed = string.Format("{0:F2}", speed / 1024 / 1024) + "MB/s"; + } + + return formatSpeed; + } + + /// + /// 格式化字节大小,可用于文件大小的显示 + /// + /// + /// + public static string FormatFileSize(long fileSize) + { + string formatFileSize; + if (fileSize <= 0) + { + formatFileSize = "0B"; + } + else if (fileSize < 1024) + { + formatFileSize = fileSize.ToString() + "B"; + } + else if (fileSize < 1024 * 1024) + { + formatFileSize = (fileSize / 1024.0).ToString("#.##") + "KB"; + } + else if (fileSize < 1024 * 1024 * 1024) + { + formatFileSize = (fileSize / 1024.0 / 1024.0).ToString("#.##") + "MB"; + } + else + { + formatFileSize = (fileSize / 1024.0 / 1024.0 / 1024.0).ToString("#.##") + "GB"; + } + + return formatFileSize; + } + + /// + /// 去除非法字符 + /// + /// + /// + public static string FormatFileName(string originName) + { + string destName = originName; + + // Windows中不能作为文件名的字符 + destName = destName.Replace("\\", " "); + destName = destName.Replace("/", " "); + destName = destName.Replace(":", " "); + destName = destName.Replace("*", " "); + destName = destName.Replace("?", " "); + destName = destName.Replace("\"", " "); + destName = destName.Replace("<", " "); + destName = destName.Replace(">", " "); + destName = destName.Replace("|", " "); + + // 转义字符 + destName = destName.Replace("\a", ""); + destName = destName.Replace("\b", ""); + destName = destName.Replace("\f", ""); + destName = destName.Replace("\n", ""); + destName = destName.Replace("\r", ""); + destName = destName.Replace("\t", ""); + destName = destName.Replace("\v", ""); + + // 控制字符 + destName = Regex.Replace(destName, @"\p{C}+", string.Empty); + + // 如果只有空白字符、dot符 + if (destName == " " || destName == ".") + { + return "[empty title]"; + } + + // 移除前导和尾部的空白字符、dot符 + int i, j; + for (i = 0; i < destName.Length; i++) + { + if (destName[i] != ' ' && destName[i] != '.') + { + break; + } + } + + for (j = destName.Length - 1; j >= 0; j--) + { + if (destName[j] != ' ' && destName[j] != '.') + { + break; + } + } + + return destName.Substring(i, j - i + 1); + } +} \ No newline at end of file diff --git a/DownKyi.Core/Utils/HardDisk.cs b/DownKyi.Core/Utils/HardDisk.cs new file mode 100644 index 0000000..cd4f449 --- /dev/null +++ b/DownKyi.Core/Utils/HardDisk.cs @@ -0,0 +1,68 @@ +using DownKyi.Core.Logging; +using Console = DownKyi.Core.Utils.Debugging.Console; + +namespace DownKyi.Core.Utils; + +public static class HardDisk +{ + /// + /// 获取指定驱动器的空间总大小 + /// + /// 只需输入代表驱动器的字母即可 + /// + public static long GetHardDiskSpace(string hardDiskName) + { + long totalSize = 0; + + try + { + hardDiskName = $"{hardDiskName}:\\"; + DriveInfo[] drives = DriveInfo.GetDrives(); + + foreach (DriveInfo drive in drives) + { + if (drive.Name == hardDiskName) + { + totalSize = drive.TotalSize; + } + } + } + catch (Exception e) + { + Console.PrintLine("GetHardDiskSpace()发生异常: {0}", e); + LogManager.Error("HardDisk", e); + } + + return totalSize; + } + + /// + /// 获取指定驱动器的剩余空间总大小 + /// + /// 只需输入代表驱动器的字母即可 + /// + public static long GetHardDiskFreeSpace(string hardDiskName) + { + long freeSpace = 0; + try + { + hardDiskName = $"{hardDiskName}:\\"; + DriveInfo[] drives = DriveInfo.GetDrives(); + + foreach (DriveInfo drive in drives) + { + if (drive.Name == hardDiskName) + { + freeSpace = drive.TotalFreeSpace; + } + } + } + catch (Exception e) + { + Console.PrintLine("GetHardDiskFreeSpace()发生异常: {0}", e); + LogManager.Error("HardDisk", e); + } + + return freeSpace; + } +} \ No newline at end of file diff --git a/DownKyi.Core/Utils/ListHelper.cs b/DownKyi.Core/Utils/ListHelper.cs new file mode 100644 index 0000000..7e4b42c --- /dev/null +++ b/DownKyi.Core/Utils/ListHelper.cs @@ -0,0 +1,54 @@ +using System.Collections.ObjectModel; + +namespace DownKyi.Core.Utils; + +public static class ListHelper +{ + /// + /// 判断ObservableCollection中是否存在,不存在则添加 + /// + /// + /// + /// + public static void AddUnique(ObservableCollection list, T item) + { + if (!list.Contains(item)) + { + list.Add(item); + } + } + + /// + /// 判断List中是否存在,不存在则添加 + /// + /// + /// + /// + public static void AddUnique(List list, T item) + { + if (!list.Exists(t => t.Equals(item))) + { + list.Add(item); + } + } + + /// + /// 判断List中是否存在,不存在则添加 + /// + /// + /// + /// + /// + public static void InsertUnique(List list, T item, int index) + { + if (!list.Exists(t => t.Equals(item))) + { + list.Insert(index, item); + } + else + { + list.Remove(item); + list.Insert(index, item); + } + } +} \ No newline at end of file diff --git a/DownKyi.Core/Utils/MachineCode.cs b/DownKyi.Core/Utils/MachineCode.cs new file mode 100644 index 0000000..564f0f7 --- /dev/null +++ b/DownKyi.Core/Utils/MachineCode.cs @@ -0,0 +1,141 @@ +namespace DownKyi.Core.Utils; + +public class MachineCode +{ + private static MachineCode machineCode; + + // /// + // /// 获取机器码 + // /// + // /// + // public static string GetMachineCodeString() + // { + // if (machineCode == null) + // { + // machineCode = new MachineCode(); + // } + // + // string machineCodeString = "PC." + + // machineCode.GetMainBordId() + "." + + // machineCode.GetCpuInfo();// + "." + + // //machineCode.GetDiskID();// + "." + + // //machineCode.GetMoAddress(); + // return machineCodeString.Replace(" ", ""); + // } + // + // /// + // /// 获取主板ID + // /// + // /// + // public string GetMainBordId() + // { + // string strId = ""; + // try + // { + // using (ManagementClass mc = new ManagementClass("Win32_BaseBoard")) + // { + // ManagementObjectCollection moc = mc.GetInstances(); + // foreach (ManagementObject mo in moc) + // { + // strId = mo.Properties["SerialNumber"].Value.ToString(); + // mo.Dispose(); + // break; + // } + // } + // } + // catch (Exception) + // { + // return "unknown"; + // //throw; + // } + // return strId; + // } + // + // /// + // /// 获取cpu序列号 + // /// + // /// + // public string GetCpuInfo() + // { + // string cpuInfo = ""; + // try + // { + // using (ManagementClass cimobject = new ManagementClass("Win32_Processor")) + // { + // ManagementObjectCollection moc = cimobject.GetInstances(); + // + // foreach (ManagementObject mo in moc) + // { + // cpuInfo = mo.Properties["ProcessorId"].Value.ToString(); + // mo.Dispose(); + // } + // } + // } + // catch (Exception) + // { + // return "unknown"; + // //throw; + // } + // return cpuInfo; + // } + // + // /// + // /// 获取硬盘ID + // /// + // /// + // public string GetDiskID() + // { + // string diskName = ""; + // string diskID = ""; + // try + // { + // using (ManagementClass cimobject1 = new ManagementClass("Win32_DiskDrive")) + // { + // ManagementObjectCollection moc1 = cimobject1.GetInstances(); + // foreach (ManagementObject mo in moc1) + // { + // diskName = mo.Properties["Model"].Value.ToString(); + // diskID = mo.Properties["SerialNumber"].Value.ToString(); + // mo.Dispose(); + // } + // } + // } + // catch (Exception) + // { + // return "unknown"; + // //throw; + // } + // return diskName + diskID; + // } + // + // /// + // /// 获取网卡硬件地址 + // /// + // /// + // public string GetMoAddress() + // { + // string MoAddress = ""; + // try + // { + // using (ManagementClass mc = new ManagementClass("Win32_NetworkAdapterConfiguration")) + // { + // ManagementObjectCollection moc2 = mc.GetInstances(); + // foreach (ManagementObject mo in moc2) + // { + // if ((bool)mo["IPEnabled"]) + // { + // MoAddress = mo["MacAddress"].ToString(); + // } + // + // mo.Dispose(); + // } + // } + // } + // catch (Exception) + // { + // return "unknown"; + // //throw; + // } + // return MoAddress; + // } +} \ No newline at end of file diff --git a/DownKyi.Core/Utils/ObjectHelper.cs b/DownKyi.Core/Utils/ObjectHelper.cs new file mode 100644 index 0000000..98763b4 --- /dev/null +++ b/DownKyi.Core/Utils/ObjectHelper.cs @@ -0,0 +1,186 @@ +using System.Collections; +using System.Net; +using System.Reflection; +using System.Runtime.Serialization.Formatters.Binary; +using DownKyi.Core.Logging; +using Console = DownKyi.Core.Utils.Debugging.Console; + +namespace DownKyi.Core.Utils; + +public static class ObjectHelper +{ + /// + /// 解析二维码登录返回的url,用于设置cookie + /// + /// + /// + public static CookieContainer ParseCookie(string url) + { + CookieContainer cookieContainer = new CookieContainer(); + + if (url == null || url == "") + { + return cookieContainer; + } + + string[] strList = url.Split('?'); + if (strList.Count() < 2) + { + return cookieContainer; + } + + string[] strList2 = strList[1].Split('&'); + if (strList2.Count() == 0) + { + return cookieContainer; + } + + // 获取expires + string expires = strList2.FirstOrDefault(it => it.Contains("Expires")).Split('=')[1]; + DateTime dateTime = DateTime.Now; + dateTime = dateTime.AddSeconds(int.Parse(expires)); + + foreach (var item in strList2) + { + string[] strList3 = item.Split('='); + if (strList3.Count() < 2) + { + continue; + } + + string name = strList3[0]; + string value = strList3[1]; + + // 不需要 + if (name == "Expires" || name == "gourl") + { + continue; + } + + // 添加cookie + cookieContainer.Add( + new Cookie(name, value.Replace(",", "%2c"), "/", ".bilibili.com") { Expires = dateTime }); + Console.PrintLine(name + ": " + value + "\t" + cookieContainer.Count); + } + + return cookieContainer; + } + + /// + /// 将CookieContainer中的所有的Cookie读出来 + /// + /// + /// + public static List GetAllCookies(CookieContainer cc) + { + List lstCookies = new List(); + + Hashtable table = (Hashtable)cc.GetType().InvokeMember("m_domainTable", + BindingFlags.NonPublic | BindingFlags.GetField | + BindingFlags.Instance, null, cc, new object[] { }); + + foreach (object pathList in table.Values) + { + SortedList lstCookieCol = (SortedList)pathList.GetType().InvokeMember("m_list", + BindingFlags.NonPublic | BindingFlags.GetField + | BindingFlags.Instance, null, pathList, + new object[] { }); + foreach (CookieCollection colCookies in lstCookieCol.Values) + { + foreach (Cookie c in colCookies) + { + lstCookies.Add(c); + } + } + } + + return lstCookies; + } + + /// + /// 写入cookies到磁盘 + /// + /// + /// + /// + public static bool WriteCookiesToDisk(string file, CookieContainer cookieJar) + { + return WriteObjectToDisk(file, cookieJar); + } + + /// + /// 从磁盘读取cookie + /// + /// + /// + public static CookieContainer ReadCookiesFromDisk(string file) + { + return (CookieContainer)ReadObjectFromDisk(file); + } + + /// + /// 写入序列化对象到磁盘 + /// + /// + /// + /// + public static bool WriteObjectToDisk(string file, object obj) + { + try + { + using (Stream stream = File.Create(file)) + { + Console.PrintLine("Writing object to disk... "); + + BinaryFormatter formatter = new BinaryFormatter(); + formatter.Serialize(stream, obj); + + Console.PrintLine("Done."); + return true; + } + } + catch (IOException e) + { + Console.PrintLine("WriteObjectToDisk()发生IO异常: {0}", e); + LogManager.Error(e); + return false; + } + catch (Exception e) + { + Console.PrintLine("WriteObjectToDisk()发生异常: {0}", e); + LogManager.Error(e); + return false; + } + } + + /// + /// 从磁盘读取序列化对象 + /// + /// + /// + public static object ReadObjectFromDisk(string file) + { + try + { + using (Stream stream = File.Open(file, FileMode.Open)) + { + Console.PrintLine("Reading object from disk... "); + BinaryFormatter formatter = new BinaryFormatter(); + Console.PrintLine("Done."); + return formatter.Deserialize(stream); + } + } + catch (IOException e) + { + Console.PrintLine("ReadObjectFromDisk()发生IO异常: {0}", e); + LogManager.Error(e); + return null; + } + catch (Exception e) + { + Console.PrintLine("ReadObjectFromDisk()发生异常: {0}", e); + LogManager.Error(e); + return null; + } + } +} \ No newline at end of file diff --git a/DownKyi.Core/Utils/QRCode.cs b/DownKyi.Core/Utils/QRCode.cs new file mode 100644 index 0000000..594b659 --- /dev/null +++ b/DownKyi.Core/Utils/QRCode.cs @@ -0,0 +1,50 @@ +using Avalonia.Media.Imaging; +using QRCoder; + +namespace DownKyi.Core.Utils; + +public static class QRCode +{ + /// + /// 生成二维码 + /// + /// 信息 + /// 版本 1 ~ 40 + /// 像素点大小 + /// 图标路径 + /// 图标尺寸 + /// 图标边框厚度 + /// 二维码白边 + /// 位图 + public static Bitmap EncodeQRCode(string msg, int version, int pixel, string icon_path, int icon_size, + int icon_border, bool white_edge) + { + QRCodeGenerator code_generator = new QRCodeGenerator(); + + QRCodeData code_data = code_generator.CreateQrCode(msg, QRCodeGenerator.ECCLevel.H /* 这里设置容错率的一个级别 */, true, + false, QRCodeGenerator.EciMode.Utf8, version); + + BitmapByteQRCode qrCode = new BitmapByteQRCode(code_data); + byte[] qrCodeAsBitmapByteArr = qrCode.GetGraphic(20); + + Bitmap icon; + if (icon_path == null || icon_path == "") + { + icon = null; + } + else + { + icon = new Bitmap(icon_path); + } + + Bitmap bmp; + using (var ms = new MemoryStream(qrCodeAsBitmapByteArr)) + { + bmp = new Bitmap(ms); + } + + // Bitmap bmp = qrCode.GetGraphic(pixel, Color.FromRgb(0,0,0), Color.FromRgb(255,255,255), icon, icon_size, icon_border, white_edge); + + return bmp; + } +} \ No newline at end of file diff --git a/DownKyi.Core/Utils/StringLogicalComparer.cs b/DownKyi.Core/Utils/StringLogicalComparer.cs new file mode 100644 index 0000000..c59290e --- /dev/null +++ b/DownKyi.Core/Utils/StringLogicalComparer.cs @@ -0,0 +1,76 @@ +namespace DownKyi.Core.Utils; + +public class StringLogicalComparer : IComparer +{ + /// + /// 比较两个字符串,如果含用数字,则数字按数字的大小来比较。 + /// + /// + /// + /// + public int Compare(T x, T y) + { + if (x == null || y == null) + { + throw new ArgumentException("Parameters can't be null"); + } + + string fileA = x as string; + string fileB = y as string; + char[] arr1 = fileA.ToCharArray(); + char[] arr2 = fileB.ToCharArray(); + int i = 0, j = 0; + while (i < arr1.Length && j < arr2.Length) + { + if (char.IsDigit(arr1[i]) && char.IsDigit(arr2[j])) + { + string s1 = "", s2 = ""; + while (i < arr1.Length && char.IsDigit(arr1[i])) + { + s1 += arr1[i]; + i++; + } + + while (j < arr2.Length && char.IsDigit(arr2[j])) + { + s2 += arr2[j]; + j++; + } + + if (int.Parse(s1) > int.Parse(s2)) + { + return 1; + } + + if (int.Parse(s1) < int.Parse(s2)) + { + return -1; + } + } + else + { + if (arr1[i] > arr2[j]) + { + return 1; + } + + if (arr1[i] < arr2[j]) + { + return -1; + } + + i++; + j++; + } + } + + if (arr1.Length == arr2.Length) + { + return 0; + } + else + { + return arr1.Length > arr2.Length ? 1 : -1; + } + } +} \ No newline at end of file diff --git a/DownKyi.Core/Utils/Validator/Number.cs b/DownKyi.Core/Utils/Validator/Number.cs new file mode 100644 index 0000000..22c030e --- /dev/null +++ b/DownKyi.Core/Utils/Validator/Number.cs @@ -0,0 +1,26 @@ +using System.Text.RegularExpressions; + +namespace DownKyi.Core.Utils.Validator; + +public static class Number +{ + /// + /// 字符串转数字(长整型) + /// + /// + /// + public static long GetInt(string value) + { + return IsInt(value) ? long.Parse(value) : -1; + } + + /// + /// 是否为数字 + /// + /// + /// + public static bool IsInt(string value) + { + return Regex.IsMatch(value, @"^\d+$"); + } +} \ No newline at end of file diff --git a/DownKyi.sln b/DownKyi.sln new file mode 100644 index 0000000..e967986 --- /dev/null +++ b/DownKyi.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DownKyi", "DownKyi\DownKyi.csproj", "{545334D8-F429-47C1-99A7-A25EAC17D76A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DownKyi.Core", "DownKyi.Core\DownKyi.Core.csproj", "{153A9B2C-7494-411C-BA0A-121A1024C08E}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {545334D8-F429-47C1-99A7-A25EAC17D76A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {545334D8-F429-47C1-99A7-A25EAC17D76A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {545334D8-F429-47C1-99A7-A25EAC17D76A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {545334D8-F429-47C1-99A7-A25EAC17D76A}.Release|Any CPU.Build.0 = Release|Any CPU + {153A9B2C-7494-411C-BA0A-121A1024C08E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {153A9B2C-7494-411C-BA0A-121A1024C08E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {153A9B2C-7494-411C-BA0A-121A1024C08E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {153A9B2C-7494-411C-BA0A-121A1024C08E}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/DownKyi/App.axaml b/DownKyi/App.axaml new file mode 100644 index 0000000..082f8ce --- /dev/null +++ b/DownKyi/App.axaml @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/DownKyi/App.axaml.cs b/DownKyi/App.axaml.cs new file mode 100644 index 0000000..097c4ab --- /dev/null +++ b/DownKyi/App.axaml.cs @@ -0,0 +1,268 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Collections.Specialized; +using System.Linq; +using System.Threading.Tasks; +using Avalonia; +using Avalonia.Controls.ApplicationLifetimes; +using Avalonia.Markup.Xaml; +using Avalonia.Threading; +using DownKyi.Core.Settings; +using DownKyi.Services.Download; +using DownKyi.ViewModels; +using DownKyi.ViewModels.Dialogs; +using DownKyi.ViewModels.DownloadManager; +using DownKyi.ViewModels.Friends; +using DownKyi.ViewModels.Settings; +using DownKyi.ViewModels.Toolbox; +using DownKyi.ViewModels.UserSpace; +using DownKyi.Views; +using DownKyi.Views.Dialogs; +using DownKyi.Views.DownloadManager; +using DownKyi.Views.Friends; +using DownKyi.Views.Settings; +using DownKyi.Views.Toolbox; +using DownKyi.Views.UserSpace; +using Prism.DryIoc; +using Prism.Ioc; +using Prism.Services.Dialogs; +using ViewSeasonsSeries = DownKyi.Views.ViewSeasonsSeries; +using ViewSeasonsSeriesViewModel = DownKyi.ViewModels.ViewSeasonsSeriesViewModel; + +namespace DownKyi; + +public partial class App : PrismApplication +{ + public static ObservableCollection DownloadingList { get; set; } + public static ObservableCollection DownloadedList { get; set; } + + // 下载服务 + private IDownloadService? _downloadService; + + public static AppBuilder BuildAvaloniaApp() => + AppBuilder + .Configure() + .UsePlatformDetect(); + + public override void Initialize() + { + AvaloniaXamlLoader.Load(this); + if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) + { + // desktop.Startup += OnStartup; + desktop.Exit += OnExit!; + } + + base.Initialize(); + } + + protected override void RegisterTypes(IContainerRegistry containerRegistry) + { + // pages + containerRegistry.RegisterForNavigation(ViewIndexViewModel.Tag); + containerRegistry.RegisterForNavigation(ViewLoginViewModel.Tag); + containerRegistry.RegisterForNavigation(ViewVideoDetailViewModel.Tag); + containerRegistry.RegisterForNavigation(ViewSettingsViewModel.Tag); + containerRegistry.RegisterForNavigation(ViewToolboxViewModel.Tag); + containerRegistry.RegisterForNavigation(ViewDownloadManagerViewModel.Tag); + containerRegistry.RegisterForNavigation(ViewPublicFavoritesViewModel.Tag); + + containerRegistry.RegisterForNavigation(ViewUserSpaceViewModel.Tag); + containerRegistry.RegisterForNavigation(ViewPublicationViewModel.Tag); + // containerRegistry.RegisterForNavigation(ViewModels.ViewChannelViewModel.Tag); + containerRegistry.RegisterForNavigation(ViewSeasonsSeriesViewModel.Tag); + containerRegistry.RegisterForNavigation(ViewFriendsViewModel.Tag); + + containerRegistry.RegisterForNavigation(ViewMySpaceViewModel.Tag); + containerRegistry.RegisterForNavigation(ViewMyFavoritesViewModel.Tag); + containerRegistry.RegisterForNavigation(ViewMyBangumiFollowViewModel.Tag); + containerRegistry.RegisterForNavigation(ViewMyToViewVideoViewModel.Tag); + containerRegistry.RegisterForNavigation(ViewMyHistoryViewModel.Tag); + + // downloadManager pages + containerRegistry.RegisterForNavigation(ViewDownloadingViewModel.Tag); + containerRegistry.RegisterForNavigation(ViewDownloadFinishedViewModel.Tag); + + // Friend + containerRegistry.RegisterForNavigation(ViewFollowingViewModel.Tag); + containerRegistry.RegisterForNavigation(ViewFollowerViewModel.Tag); + + // settings pages + containerRegistry.RegisterForNavigation(ViewBasicViewModel.Tag); + containerRegistry.RegisterForNavigation(ViewNetworkViewModel.Tag); + containerRegistry.RegisterForNavigation(ViewVideoViewModel.Tag); + containerRegistry.RegisterForNavigation(ViewDanmakuViewModel.Tag); + containerRegistry.RegisterForNavigation(ViewAboutViewModel.Tag); + + // tools pages + containerRegistry.RegisterForNavigation(ViewBiliHelperViewModel.Tag); + containerRegistry.RegisterForNavigation(ViewDelogoViewModel.Tag); + containerRegistry.RegisterForNavigation(ViewExtractMediaViewModel.Tag); + + // UserSpace + containerRegistry.RegisterForNavigation(ViewArchiveViewModel.Tag); + // containerRegistry.RegisterForNavigation(ViewModels.UserSpace.ViewChannelViewModel.Tag); + containerRegistry.RegisterForNavigation(ViewModels.UserSpace + .ViewSeasonsSeriesViewModel.Tag); + + // dialogs + containerRegistry.RegisterDialog(ViewAlertDialogViewModel.Tag); + containerRegistry.RegisterDialog(ViewDownloadSetterViewModel.Tag); + containerRegistry.RegisterDialog(ViewParsingSelectorViewModel.Tag); + } + + + protected override AvaloniaObject CreateShell() + { + // 初始化数据 + DownloadingList = new ObservableCollection(); + DownloadedList = new ObservableCollection(); + + // 下载数据存储服务 + DownloadStorageService downloadStorageService = new DownloadStorageService(); + + // 从数据库读取 + List downloadingItems = downloadStorageService.GetDownloading(); + List downloadedItems = downloadStorageService.GetDownloaded(); + DownloadingList.AddRange(downloadingItems); + DownloadedList.AddRange(downloadedItems); + + // 下载列表发生变化时执行的任务 + DownloadingList.CollectionChanged += async (sender, e) => + { + await Task.Run(() => + { + if (e.Action == NotifyCollectionChangedAction.Add) + { + foreach (object item in e.NewItems) + { + if (item is DownloadingItem downloading) + { + //Console.WriteLine("DownloadingList添加"); + downloadStorageService.AddDownloading(downloading); + } + } + } + + if (e.Action == NotifyCollectionChangedAction.Remove) + { + foreach (object item in e.OldItems) + { + if (item is DownloadingItem downloading) + { + //Console.WriteLine("DownloadingList移除"); + downloadStorageService.RemoveDownloading(downloading); + } + } + } + }); + }; + + // 下载完成列表发生变化时执行的任务 + DownloadedList.CollectionChanged += async (sender, e) => + { + await Task.Run(() => + { + if (e.Action == NotifyCollectionChangedAction.Add) + { + foreach (object item in e.NewItems) + { + if (item is DownloadedItem downloaded) + { + //Console.WriteLine("DownloadedList添加"); + downloadStorageService.AddDownloaded(downloaded); + } + } + } + + if (e.Action == NotifyCollectionChangedAction.Remove) + { + foreach (object item in e.OldItems) + { + if (item is DownloadedItem downloaded) + { + //Console.WriteLine("DownloadedList移除"); + downloadStorageService.RemoveDownloaded(downloaded); + } + } + } + }); + }; + + // 启动下载服务 + var download = SettingsManager.GetInstance().GetDownloader(); + switch (download) + { + case Downloader.NOT_SET: + break; + case Downloader.BUILT_IN: + _downloadService = new BuiltinDownloadService(DownloadingList, DownloadedList, + (IDialogService)Container.GetContainer().GetService(typeof(IDialogService))); + break; + case Downloader.ARIA: + // downloadService = new AriaDownloadService(DownloadingList, DownloadedList, (IDialogService)Container.GetContainer().GetService(typeof(IDialogService))); + break; + case Downloader.CUSTOM_ARIA: + // downloadService = new CustomAriaDownloadService(DownloadingList, DownloadedList, (IDialogService)Container.GetContainer().GetService(typeof(IDialogService))); + break; + } + + _downloadService?.Start(); + + return Container.Resolve(); + } + + protected override void OnInitialized() + { + // var regionManager = Container.Resolve(); + // regionManager.RegisterViewWithRegion("ContentRegion", typeof(ViewIndex)); + // regionManager.RegisterViewWithRegion("DownloadManagerContentRegion", typeof(ViewDownloading)); + // regionManager.RegisterViewWithRegion("SettingsContentRegion", typeof(ViewBasic)); + } + + public static void PropertyChangeAsync(Action callback) + { + Dispatcher.UIThread.Invoke(callback); + } + + /// + /// 下载完成列表排序 + /// + /// + public static void SortDownloadedList(DownloadFinishedSort finishedSort) + { + var list = DownloadedList.ToList(); + switch (finishedSort) + { + case DownloadFinishedSort.DOWNLOAD: + // 按下载先后排序 + list.Sort((x, y) => x.Downloaded.FinishedTimestamp.CompareTo(y.Downloaded.FinishedTimestamp)); + break; + case DownloadFinishedSort.NUMBER: + // 按序号排序 + list.Sort((x, y) => + { + int compare = x.MainTitle.CompareTo(y.MainTitle); + return compare == 0 ? x.Order.CompareTo(y.Order) : compare; + }); + break; + default: + break; + } + + // 更新下载完成列表 + // 如果有更好的方法再重写 + DownloadedList.Clear(); + foreach (DownloadedItem item in list) + { + DownloadedList.Add(item); + } + } + + private void OnExit(object sender, ControlledApplicationLifetimeExitEventArgs e) + { + // 关闭下载服务 + _downloadService?.End(); + } +} \ No newline at end of file diff --git a/DownKyi/AppConstant.cs b/DownKyi/AppConstant.cs new file mode 100644 index 0000000..cad527c --- /dev/null +++ b/DownKyi/AppConstant.cs @@ -0,0 +1,7 @@ +namespace DownKyi +{ + public class AppConstant + { + public const string ClipboardId = "32ff00b1-1a09-4b25-9ca7-dcb6914b141c"; + } +} diff --git a/DownKyi/Converter/CountConverter.cs b/DownKyi/Converter/CountConverter.cs new file mode 100644 index 0000000..115a3f5 --- /dev/null +++ b/DownKyi/Converter/CountConverter.cs @@ -0,0 +1,21 @@ +using System; +using System.Globalization; +using Avalonia.Data.Converters; + +namespace DownKyi.Converter +{ + public class CountConverter : IValueConverter + { + public int Count { get; set; } + + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + return ((int)value) > Count; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/DownKyi/CustomAction/KeyUpBehavior.cs b/DownKyi/CustomAction/KeyUpBehavior.cs new file mode 100644 index 0000000..a50b7ff --- /dev/null +++ b/DownKyi/CustomAction/KeyUpBehavior.cs @@ -0,0 +1,57 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Input; +using Avalonia.Interactivity; +using Avalonia.Xaml.Interactivity; + +namespace DownKyi.CustomAction; + +public class KeyUpBehavior : Trigger +{ + private Key _key = Key.None; + + public static readonly StyledProperty KeyProperty = + AvaloniaProperty.Register(nameof(Key)); + + public Key Key + { + get => GetValue(KeyProperty); + set => SetValue(KeyProperty, value); + } + + /// + protected override void OnAttachedToVisualTree() + { + if (AssociatedObject is { }) + { + AssociatedObject.KeyUp += AssociatedObject_OnClick; + AssociatedObject.AddHandler(InputElement.KeyDownEvent, Button_OnKeyDown, RoutingStrategies.Tunnel); + // AssociatedObject.AddHandler(InputElement.KeyUpEvent, Button_OnKeyUp, RoutingStrategies.Tunnel); + } + } + + /// + protected override void OnDetachedFromVisualTree() + { + if (AssociatedObject is { }) + { + AssociatedObject.KeyUp -= AssociatedObject_OnClick; + AssociatedObject.RemoveHandler(InputElement.KeyDownEvent, Button_OnKeyDown); + // AssociatedObject.RemoveHandler(InputElement.KeyUpEvent, Button_OnKeyUp); + } + } + + private void AssociatedObject_OnClick(object? sender, RoutedEventArgs e) + { + if (AssociatedObject is { } && Key == _key) + { + _key = Key.None; + Interaction.ExecuteActions(AssociatedObject, Actions, e); + } + } + + private void Button_OnKeyDown(object? sender, KeyEventArgs e) + { + _key = e.Key; + } +} \ No newline at end of file diff --git a/DownKyi/CustomControl/CustomPager.axaml b/DownKyi/CustomControl/CustomPager.axaml new file mode 100644 index 0000000..cabf7b0 --- /dev/null +++ b/DownKyi/CustomControl/CustomPager.axaml @@ -0,0 +1,237 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/DownKyi/CustomControl/CustomPager.axaml.cs b/DownKyi/CustomControl/CustomPager.axaml.cs new file mode 100644 index 0000000..835ceb0 --- /dev/null +++ b/DownKyi/CustomControl/CustomPager.axaml.cs @@ -0,0 +1,13 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; + +namespace DownKyi.CustomControl; + +public partial class CustomPager : UserControl +{ + public CustomPager() + { + InitializeComponent(); + } +} \ No newline at end of file diff --git a/DownKyi/CustomControl/CustomPagerViewModel.cs b/DownKyi/CustomControl/CustomPagerViewModel.cs new file mode 100644 index 0000000..4787f24 --- /dev/null +++ b/DownKyi/CustomControl/CustomPagerViewModel.cs @@ -0,0 +1,509 @@ +using System; +using System.ComponentModel; +using Prism.Commands; + +namespace DownKyi.CustomControl; + +public class CustomPagerViewModel : INotifyPropertyChanged +{ + public CustomPagerViewModel(int current, int count) + { + Current = current; + Count = count; + + SetView(); + } + + public event PropertyChangedEventHandler PropertyChanged; + + // Current修改的回调 + public delegate bool CurrentChangedHandler(int old, int current); + + public event CurrentChangedHandler CurrentChanged; + + protected virtual bool OnCurrentChanged(int old, int current) + { + if (CurrentChanged == null) + { + return false; + } + else + { + return CurrentChanged.Invoke(old, current); + } + } + + // Count修改的回调 + public delegate void CountChangedHandler(int count); + + public event CountChangedHandler CountChanged; + + protected virtual void OnCountChanged(int count) + { + CountChanged?.Invoke(count); + } + + #region 绑定属性 + + private bool visibility; + + public bool Visibility + { + get { return visibility; } + set + { + visibility = value; + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Visibility")); + } + } + + private int count; + + public int Count + { + get { return count; } + set + { + if (value < Current || value < 0) + { + Visibility = false; + //throw new Exception("数值不在允许的范围内。"); + Console.WriteLine(value.ToString()); + } + else + { + count = value; + + if (count <= 1) + { + Visibility = false; + } + else + { + Visibility = true; + } + + OnCountChanged(count); + + SetView(); + + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Count")); + } + } + } + + private int current; + + public int Current + { + get + { + if (current < 1) + { + current = 1; + } + + return current; + } + set + { + if (Count > 0 && (value > Count || value < 1)) + { + //throw new Exception("数值不在允许的范围内。"); + } + else + { + bool isSuccess = OnCurrentChanged(current, value); + if (isSuccess) + { + current = value; + + SetView(); + + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Current")); + } + } + } + } + + private int first; + + public int First + { + get { return first; } + set + { + first = value; + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("First")); + } + } + + private int previousSecond; + + public int PreviousSecond + { + get { return previousSecond; } + set + { + previousSecond = value; + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("PreviousSecond")); + } + } + + private int previousFirst; + + public int PreviousFirst + { + get { return previousFirst; } + set + { + previousFirst = value; + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("PreviousFirst")); + } + } + + private int nextFirst; + + public int NextFirst + { + get { return nextFirst; } + set + { + nextFirst = value; + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("NextFirst")); + } + } + + private int nextSecond; + + public int NextSecond + { + get { return nextSecond; } + set + { + nextSecond = value; + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("NextSecond")); + } + } + + // 控制Current左边的控件 + private bool previousVisibility; + + public bool PreviousVisibility + { + get { return previousVisibility; } + set + { + previousVisibility = value; + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("PreviousVisibility")); + } + } + + private bool firstVisibility; + + public bool FirstVisibility + { + get { return firstVisibility; } + set + { + firstVisibility = value; + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("FirstVisibility")); + } + } + + private bool leftJumpVisibility; + + public bool LeftJumpVisibility + { + get { return leftJumpVisibility; } + set + { + leftJumpVisibility = value; + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("LeftJumpVisibility")); + } + } + + private bool previousSecondVisibility; + + public bool PreviousSecondVisibility + { + get { return previousSecondVisibility; } + set + { + previousSecondVisibility = value; + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("PreviousSecondVisibility")); + } + } + + private bool previousFirstVisibility; + + public bool PreviousFirstVisibility + { + get { return previousFirstVisibility; } + set + { + previousFirstVisibility = value; + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("PreviousFirstVisibility")); + } + } + + // 控制Current右边的控件 + private bool nextFirstVisibility; + + public bool NextFirstVisibility + { + get { return nextFirstVisibility; } + set + { + nextFirstVisibility = value; + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("NextFirstVisibility")); + } + } + + private bool nextSecondVisibility; + + public bool NextSecondVisibility + { + get { return nextSecondVisibility; } + set + { + nextSecondVisibility = value; + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("NextSecondVisibility")); + } + } + + private bool rightJumpVisibility; + + public bool RightJumpVisibility + { + get { return rightJumpVisibility; } + set + { + rightJumpVisibility = value; + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("RightJumpVisibility")); + } + } + + private bool lastVisibility; + + public bool LastVisibility + { + get { return lastVisibility; } + set + { + lastVisibility = value; + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("LastVisibility")); + } + } + + private bool nextVisibility; + + public bool NextVisibility + { + get { return nextVisibility; } + set + { + nextVisibility = value; + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("NextVisibility")); + } + } + + #endregion + + + private DelegateCommand previousCommand; + + public DelegateCommand PreviousCommand => + previousCommand ?? (previousCommand = new DelegateCommand(PreviousExecuted)); + + public void PreviousExecuted(object obj) + { + Current -= 1; + + SetView(); + } + + private DelegateCommand firstCommand; + + public DelegateCommand FirstCommand => + firstCommand ?? (firstCommand = new DelegateCommand(FirstExecuted)); + + public void FirstExecuted(object obj) + { + Current = 1; + + SetView(); + } + + private DelegateCommand previousSecondCommand; + + public DelegateCommand PreviousSecondCommand => previousSecondCommand ?? + (previousSecondCommand = + new DelegateCommand( + PreviousSecondExecuted)); + + public void PreviousSecondExecuted(object obj) + { + Current -= 2; + + SetView(); + } + + private DelegateCommand previousFirstCommand; + + public DelegateCommand PreviousFirstCommand => previousFirstCommand ?? + (previousFirstCommand = + new DelegateCommand(PreviousFirstExecuted)); + + public void PreviousFirstExecuted(object obj) + { + Current -= 1; + + SetView(); + } + + private DelegateCommand nextFirstCommand; + + public DelegateCommand NextFirstCommand => + nextFirstCommand ?? (nextFirstCommand = new DelegateCommand(NextFirstExecuted)); + + public void NextFirstExecuted(object obj) + { + Current += 1; + + SetView(); + } + + private DelegateCommand nextSecondCommand; + + public DelegateCommand NextSecondCommand => nextSecondCommand ?? + (nextSecondCommand = + new DelegateCommand(NextSecondExecuted)); + + public void NextSecondExecuted(object obj) + { + Current += 2; + + SetView(); + } + + private DelegateCommand lastCommand; + + public DelegateCommand LastCommand => + lastCommand ?? (lastCommand = new DelegateCommand(LastExecuted)); + + public void LastExecuted(object obj) + { + Current = Count; + + SetView(); + } + + private DelegateCommand nextCommand; + + public DelegateCommand NextCommand => + nextCommand ?? (nextCommand = new DelegateCommand(NextExecuted)); + + public void NextExecuted(object obj) + { + Current += 1; + + SetView(); + } + + /// + /// 控制显示,暴力实现,以后重构 + /// + private void SetView() + { + First = 1; + PreviousSecond = Current - 2; + PreviousFirst = Current - 1; + NextFirst = Current + 1; + NextSecond = Current + 2; + + // 控制Current左边的控件 + if (Current == 1) + { + PreviousVisibility = false; + FirstVisibility = false; + LeftJumpVisibility = false; + PreviousSecondVisibility = false; + PreviousFirstVisibility = false; + } + else if (Current == 2) + { + PreviousVisibility = true; + FirstVisibility = false; + LeftJumpVisibility = false; + PreviousSecondVisibility = false; + PreviousFirstVisibility = true; + } + else if (Current == 3) + { + PreviousVisibility = true; + FirstVisibility = false; + LeftJumpVisibility = false; + PreviousSecondVisibility = true; + PreviousFirstVisibility = true; + } + else if (Current == 4) + { + PreviousVisibility = true; + FirstVisibility = true; + LeftJumpVisibility = false; + PreviousSecondVisibility = true; + PreviousFirstVisibility = true; + } + else + { + PreviousVisibility = true; + FirstVisibility = true; + LeftJumpVisibility = true; + PreviousSecondVisibility = true; + PreviousFirstVisibility = true; + } + + // 控制Current右边的控件 + if (Current == Count) + { + NextFirstVisibility = false; + NextSecondVisibility = false; + RightJumpVisibility = false; + LastVisibility = false; + NextVisibility = false; + } + else if (Current == Count - 1) + { + NextFirstVisibility = true; + NextSecondVisibility = false; + RightJumpVisibility = false; + LastVisibility = false; + NextVisibility = true; + } + else if (Current == Count - 2) + { + NextFirstVisibility = true; + NextSecondVisibility = true; + RightJumpVisibility = false; + LastVisibility = false; + NextVisibility = true; + } + else if (Current == Count - 3) + { + NextFirstVisibility = true; + NextSecondVisibility = true; + RightJumpVisibility = false; + LastVisibility = true; + NextVisibility = true; + } + else + { + NextFirstVisibility = true; + NextSecondVisibility = true; + RightJumpVisibility = true; + LastVisibility = true; + NextVisibility = true; + } + } +} \ No newline at end of file diff --git a/DownKyi/CustomControl/Loading.cs b/DownKyi/CustomControl/Loading.cs new file mode 100644 index 0000000..1d0b1f8 --- /dev/null +++ b/DownKyi/CustomControl/Loading.cs @@ -0,0 +1,119 @@ +using System; +using Avalonia; +using Avalonia.Controls.Primitives; + +namespace DownKyi.CustomControl; + +public class Loading: TemplatedControl +{ + private const string LargeState = ":large"; + private const string SmallState = ":small"; + + private const string InactiveState = ":inactive"; + private const string ActiveState = ":active"; + + private double _maxSideLength = 10; + private double _ellipseDiameter = 10; + private Thickness _ellipseOffset = new Thickness(2); + + static Loading() + { + //DefaultStyleKeyProperty.OverrideMetadata(typeof(ProgressRing), + // new FrameworkPropertyMetadata(typeof(ProgressRing))); + } + + public Loading() + { + } + + #region IsActive + + public bool IsActive + { + get => (bool)GetValue(IsActiveProperty); + set => SetValue(IsActiveProperty, value); + } + + + public static readonly StyledProperty IsActiveProperty = + AvaloniaProperty.Register( + nameof(IsActive), + defaultValue: true); + + private static void OnIsActiveChanged(AvaloniaObject obj, bool arg2) + { + ((Loading)obj).UpdateVisualStates(); + } + + public static readonly DirectProperty MaxSideLengthProperty = + AvaloniaProperty.RegisterDirect( + nameof(MaxSideLength), + o => o.MaxSideLength); + + public double MaxSideLength + { + get { return _maxSideLength; } + private set { SetAndRaise(MaxSideLengthProperty, ref _maxSideLength, value); } + } + + public static readonly DirectProperty EllipseDiameterProperty = + AvaloniaProperty.RegisterDirect( + nameof(EllipseDiameter), + o => o.EllipseDiameter); + + public double EllipseDiameter + { + get { return _ellipseDiameter; } + private set { SetAndRaise(EllipseDiameterProperty, ref _ellipseDiameter, value); } + } + + public static readonly DirectProperty EllipseOffsetProperty = + AvaloniaProperty.RegisterDirect( + nameof(EllipseOffset), + o => o.EllipseOffset); + + public Thickness EllipseOffset + { + get { return _ellipseOffset; } + private set { SetAndRaise(EllipseOffsetProperty, ref _ellipseOffset, value); } + } + + #endregion + + + protected override void OnApplyTemplate(TemplateAppliedEventArgs e) + { + base.OnApplyTemplate(e); + double maxSideLength = Math.Min(this.Width, this.Height); + double ellipseDiameter = 0.1 * maxSideLength; + if (maxSideLength <= 40) + { + ellipseDiameter += 1; + } + + EllipseDiameter = ellipseDiameter; + MaxSideLength = maxSideLength; + EllipseOffset = new Thickness(0, maxSideLength / 2 - ellipseDiameter, 0, 0); + UpdateVisualStates(); + } + + protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) + { + base.OnPropertyChanged(change); + + if (change.Property == IsActiveProperty) + { + UpdateVisualStates(); + } + } + + private void UpdateVisualStates() + { + PseudoClasses.Remove(ActiveState); + PseudoClasses.Remove(InactiveState); + PseudoClasses.Remove(SmallState); + PseudoClasses.Remove(LargeState); + PseudoClasses.Add(IsActive ? ActiveState : InactiveState); + PseudoClasses.Add(_maxSideLength < 60 ? SmallState : LargeState); + } +} \ No newline at end of file diff --git a/DownKyi/DownKyi.csproj b/DownKyi/DownKyi.csproj new file mode 100644 index 0000000..78ae400 --- /dev/null +++ b/DownKyi/DownKyi.csproj @@ -0,0 +1,36 @@ + + + WinExe + net6.0 + enable + true + app.manifest + true + favicon.ico + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/DownKyi/Events/MessageEvent.cs b/DownKyi/Events/MessageEvent.cs new file mode 100644 index 0000000..2126800 --- /dev/null +++ b/DownKyi/Events/MessageEvent.cs @@ -0,0 +1,7 @@ +using Prism.Events; + +namespace DownKyi.Events; + +public class MessageEvent : PubSubEvent +{ +} \ No newline at end of file diff --git a/DownKyi/Events/NavigationEvent.cs b/DownKyi/Events/NavigationEvent.cs new file mode 100644 index 0000000..f9f0eb4 --- /dev/null +++ b/DownKyi/Events/NavigationEvent.cs @@ -0,0 +1,7 @@ +using Prism.Events; + +namespace DownKyi.Events; + +public class NavigationEvent : PubSubEvent +{ +} \ No newline at end of file diff --git a/DownKyi/Events/NavigationParam.cs b/DownKyi/Events/NavigationParam.cs new file mode 100644 index 0000000..de8798d --- /dev/null +++ b/DownKyi/Events/NavigationParam.cs @@ -0,0 +1,8 @@ +namespace DownKyi.Events; + +public class NavigationParam +{ + public string ViewName { get; set; } + public string? ParentViewName { get; set; } + public object Parameter { get; set; } +} \ No newline at end of file diff --git a/DownKyi/Images/ButtonIcon.cs b/DownKyi/Images/ButtonIcon.cs new file mode 100644 index 0000000..1231879 --- /dev/null +++ b/DownKyi/Images/ButtonIcon.cs @@ -0,0 +1,120 @@ +namespace DownKyi.Images; + +public class ButtonIcon +{ + private static ButtonIcon instance; + + public static ButtonIcon Instance() + { + if (instance == null) + { + instance = new ButtonIcon(); + } + + return instance; + } + + public ButtonIcon() + { + GeneralSearch = new VectorImage + { + Height = 20, + Width = 20, + Data = + @"M697.91 755.7 q-132.36 103.48 -290.59 98.06 q-158.23 -5.41 -278.56 -120.92 q-127.54 -133.56 -128.75 -304.43
 q-1.21 -170.86 120.33 -304.43 q127.55 -126.34 297.21 -123.94 q169.66 2.41 303.22 123.94 q110.71 114.31 122.14 263.52
 q11.43 149.21 -75.21 275.55 l238.25 239.45 q18.05 18.05 18.05 42.12 q0 24.06 -18.05 41.51 q-18.05 17.45 -42.12 17.45
 q-24.07 0 -42.12 -16.85 l-223.81 -231.03 ZM643.76 647.41 q92.66 -96.26 92.66 -219 q0 -122.73 -92.66 -218.99 q-96.26 -92.66 -219 -92.66
 q-122.74 0 -218.99 92.66 q-92.65 96.26 -92.65 218.99 q0 122.74 92.65 219 q96.26 92.65 218.99 90.25 q122.74 -2.4 219 -90.25 Z", + Fill = "#FF000000" + }; + + Settings = new VectorImage + { + Height = 32, + Width = 32, + Data = + @"M19.4,13c0-0.3,0.1-0.6,0.1-1s0-0.7-0.1-1l2.1-1.7c0.2-0.2,0.2-0.4,0.1-0.6l-2-3.5C19.5,5,19.3,5,19,5l-2.5,1
 c-0.5-0.4-1.1-0.7-1.7-1l-0.4-2.7C14.5,2.2,14.3,2,14,2h-4C9.8,2,9.5,2.2,9.5,2.4L9.1,5.1C8.5,5.3,8,5.7,7.4,6L5,5
 C4.7,5,4.5,5,4.3,5.3l-2,3.5C2.2,9,2.3,9.2,2.5,9.4L4.6,11c0,0.3-0.1,0.6-0.1,1s0,0.7,0.1,1l-2.1,1.7c-0.2,0.1-0.2,0.4-0.1,0.6
 l2,3.5C4.5,19,4.7,19,5,19l2.5-1c0.5,0.4,1.1,0.7,1.7,1l0.4,2.7c0,0.2,0.2,0.4,0.5,0.4h4c0.3,0,0.5-0.2,0.5-0.4l0.4-2.7
 c0.6-0.3,1.2-0.6,1.7-1l2.5,1c0.2,0.1,0.5,0,0.6-0.2l2-3.5c0.1-0.2,0.1-0.5-0.1-0.6L19.4,13z M12,15.5c-1.9,0-3.5-1.6-3.5-3.5
 s1.6-3.5,3.5-3.5s3.5,1.6,3.5,3.5S13.9,15.5,12,15.5z", + Fill = "#FF000000" + }; + + DownloadManage = new VectorImage + { + Height = 27, + Width = 32, + //Height = 20, + //Width = 24, + Data = + @"M24,34c-2.4,0-4.9,0-7.3,0c-2.8,0-4.6-1.9-4.6-4.7c0-3.5,0-7,0-10.5c0-2.9,1.9-4.7,4.6-4.7c1.3,0,2.6,0,3.9,0
 c1.1-0.1,2,0.4,2.7,1.3c1.1,1.7,2.6,2.3,4.6,2.1c1.3-0.2,2.6-0.1,4,0c2.5,0.2,4,1.7,4.2,4.3c0.2,2.7,0.2,5.5,0,8.3
 c-0.2,2.4-2,4-4.3,4C29,34,26.5,34,24,34L24,34z
 M23.9,32.6c2.5,0,5,0,7.5,0c1.7,0,2.9-1,3-2.7c0.2-2.8,0.2-5.6,0-8.5
 c-0.1-1.5-1.1-2.4-2.5-2.6c-1.3-0.2-2.6-0.1-3.9-0.1c-4.1-0.1-3,0.5-6-2.6c-0.5-0.5-1-0.8-1.7-0.8c-1.3,0-2.5,0-3.8,0
 c-2,0-3.2,1.2-3.3,3.2c0,3.6,0,7.1,0,10.7c0,2,1.2,3.2,3.2,3.2C19,32.6,21.5,32.6,23.9,32.6L23.9,32.6z
 M29.9,14.2h3.3c0.5,0,0.9,0,0.9,0.7c0,0.7-0.4,0.8-0.9,0.8c-2.2,0-4.5,0-6.7,0c-0.5,0-0.9-0.1-0.9-0.7
 s0.4-0.7,0.9-0.7C27.6,14.2,28.7,14.2,29.9,14.2L29.9,14.2z M23.3,27.6v-5.4c0-0.5,0-1.1,0.7-1.1c0.7,0,0.6,0.6,0.6,1v5.2
 c0.7-0.7,1.2-1.2,1.7-1.7c0.3-0.4,0.7-0.7,1.2-0.2c0.5,0.5,0.1,0.9-0.2,1.2c-0.9,1-1.8,1.9-2.7,2.8c-0.4,0.5-0.8,0.5-1.3,0.1
 c-1-1-2-2.1-3-3.1c-0.3-0.3-0.4-0.7-0.1-1c0.3-0.4,0.7-0.3,1,0.1C22,26.1,22.6,26.7,23.3,27.6L23.3,27.6z", + Fill = "#FF000000" + }; + + Toolbox = new VectorImage + { + Height = 28, // 21 + Width = 32, // 24 + Data = @"M20.2,14.5c-0.8,2.3-3.4,3.6-5.7,2.7c-1.3-0.5-2.3-1.5-2.7-2.7H5.5V13h21v1.5H20.2z M18.6,14.5h-5.2
 c0.8,1.4,2.7,1.9,4.1,1.1C18,15.3,18.3,15,18.6,14.5L18.6,14.5z M10,8.5V7c0-0.8,0.7-1.5,1.5-1.5h9C21.3,5.5,22,6.2,22,7v1.5h4.5
 c0.8,0,1.5,0.7,1.5,1.5v15c0,0.8-0.7,1.5-1.5,1.5l0,0h-21C4.7,26.5,4,25.8,4,25l0,0V10c0-0.8,0.7-1.5,1.5-1.5H10z M11.5,8.5h9V7h-9
 V8.5z M5.5,10v15h21V10H5.5z", + Fill = "#FF000000" + }; + + Trash = new VectorImage + { + Height = 20, + Width = 20, + Data = + @"M683 85 q0 -27 -20.5 -55 q-20.5 -28 -65.5 -30 l-170 0 q-39 1 -62 23.5 q-23 22.5 -24 61.5 l-341 0 l0 86 l1024 0 l0 -86
 l-341 0 ZM341 256 l86 0 l0 597 l-86 0 l0 -597 ZM597 256 l86 0 l0 597 l-86 0 l0 -597 ZM853 853 q0 39 -23 62
 q-23 23 -62 24 l-512 0 q-39 -1 -62 -24 q-23 -23 -23 -62 l0 -597 l-86 0 l0 597 q2 73 50.5 121 q48.5 48 120.5 50 l512 0
 q72 -2 120.5 -50 q48.5 -48 50.5 -121 l0 -597 l-86 0 l0 597 Z", + Fill = "#FF000000" + }; + + Delete = new VectorImage + { + Height = 18, + Width = 18, + Data = + @"M634.29 513.52 l364.34 -363.32 q25.37 -27.4 25.37 -60.89 q0 -33.49 -26.38 -59.88 q-26.38 -26.39 -59.88 -26.39
 q-33.49 0 -60.9 25.38 l-363.32 364.33 l-363.32 -372.45 q-28.42 -20.3 -65.46 -20.3 q-37.04 0 -64.44 20.3
 q-20.3 27.4 -20.3 64.44 q0 37.04 20.3 65.46 l372.45 363.32 l-364.33 363.32 q-25.38 27.41 -25.38 60.9 q0 33.49 26.39 59.88
 q26.39 26.38 59.88 26.38 q33.49 0 60.89 -25.37 l363.32 -364.34 l363.32 364.34 q27.41 25.37 60.9 25.37 q33.49 0 59.88 -26.38
 q26.38 -26.38 26.38 -59.88 q0 -33.49 -25.37 -60.9 l-364.34 -363.32 Z", + Fill = "#FF000000" + }; + + Start = new VectorImage + { + Height = 20, + Width = 17, + Data = + @"M895.12 402.34 l-633.28 -383.81 q-30.16 -17.82 -64.43 -18.51 q-34.27 -0.69 -65.11 16.45 q-30.84 17.13 -47.97 47.29
 q-17.13 30.16 -17.13 64.42 l0 767.62 q0 34.27 17.13 63.74 q17.14 29.47 47.97 47.29 q30.84 17.82 65.11 17.13
 q34.27 -0.69 64.43 -18.5 l633.28 -383.81 q28.79 -17.82 45.24 -46.6 q16.45 -28.79 16.45 -63.06 q0 -34.27 -16.45 -63.05
 q-16.45 -28.79 -45.24 -46.61 Z", + Fill = "#FF000000" + }; + + Pause = new VectorImage + { + Height = 20, + Width = 15, + Data = + @"M255.66 0 q-53.75 0 -90.97 37.21 q-37.21 37.21 -37.21 90.96 l0 769.04 q1.38 55.12 37.21 90.95 q35.84 35.84 90.28 35.84
 q54.44 0 90.96 -35.84 q36.52 -35.83 37.9 -90.95 l0 -769.04 q-1.38 -53.75 -38.59 -90.96 q-37.21 -37.21 -89.58 -37.21
 ZM768.34 0 q-52.37 0 -89.58 37.21 q-37.21 37.21 -38.59 90.96 l0 769.04 q1.38 55.12 37.9 90.95 q36.52 35.84 90.96 35.84
 q54.44 0 90.28 -35.84 q35.83 -35.83 37.21 -90.95 l0 -769.04 q0 -53.75 -37.21 -90.96 q-37.22 -37.21 -90.97 -37.21 Z", + Fill = "#FF000000" + }; + + Retry = new VectorImage + { + Height = 20, + Width = 20, + Data = @"M536.69 128.65 q-161.14 5.2 -270.3 113.71 q-109.15 108.5 -113.05 269.64 q3.9 161.14 113.05 269.64
 q109.16 108.5 270.3 113.71 q101.36 -1.3 185.82 -47.43 q84.47 -46.13 140.35 -129.3 q6.5 -14.3 22.09 -24.7
 q15.6 -10.39 31.19 -10.39 q28.59 0 47.44 18.85 q18.84 18.85 20.14 48.74 q0 11.69 -5.2 20.79 q0 3.9 0 7.8 l-3.9 5.19
 q-72.77 111.76 -185.82 174.78 q-113.06 63.03 -246.91 64.33 q-102.66 0 -196.22 -38.34 q-93.57 -38.33 -166.34 -111.11
 q-72.77 -72.77 -111.1 -166.34 q-38.33 -93.56 -38.33 -196.22 q0 -102.66 38.33 -196.23 q38.34 -93.56 111.1 -166.33
 q72.77 -72.77 166.34 -111.1 q93.56 -38.34 196.22 -38.34 q92.26 0 176.73 31.19 q84.47 31.19 152.04 89.66 l0 -25.99
 q1.3 -27.29 18.2 -44.83 q16.89 -17.54 42.88 -17.54 q25.99 0 44.18 18.19 q18.19 18.19 18.19 44.18 l0 189.73
 q0 24.69 -18.19 42.88 q-18.19 18.19 -42.88 18.19 l-191.03 0 q-24.69 0 -42.88 -18.19 q-18.2 -18.19 -18.2 -42.88
 q0 -28.59 16.25 -47.43 q16.25 -18.84 44.84 -20.13 l37.69 0 q-51.98 -42.89 -114.36 -65.63 q-62.38 -22.74 -128.65 -22.74 Z", + Fill = "#FF000000" + }; + + Folder = new VectorImage + { + Height = 16, + Width = 20, + Data = @"M18,2H10L8,0H2A2,2,0,0,0,0,2V14a2,2,0,0,0,2,2H18a2,2,0,0,0,2-2V4A2,2,0,0,0,18,2Zm0,12H2V4H18Z", + Fill = "#FF000000" + }; + } + + public VectorImage GeneralSearch { get; private set; } + public VectorImage Settings { get; private set; } + public VectorImage DownloadManage { get; private set; } + public VectorImage Toolbox { get; private set; } + + public VectorImage Trash { get; private set; } + public VectorImage Delete { get; private set; } + public VectorImage Start { get; private set; } + public VectorImage Pause { get; private set; } + public VectorImage Retry { get; private set; } + public VectorImage Folder { get; private set; } +} \ No newline at end of file diff --git a/DownKyi/Images/LogoIcon.cs b/DownKyi/Images/LogoIcon.cs new file mode 100644 index 0000000..8d75881 --- /dev/null +++ b/DownKyi/Images/LogoIcon.cs @@ -0,0 +1,56 @@ +namespace DownKyi.Images; + +public class LogoIcon +{ + private static LogoIcon instance; + + public static LogoIcon Instance() + { + if (instance == null) + { + instance = new LogoIcon(); + } + + return instance; + } + + private LogoIcon() + { + TextLogo = new VectorImage + { + Height = 100, + Width = 336, + Data = + @"M602.247902 495.326917q0-146.045116 60.22479-219.820484a198.13956 198.13956 0 0 1 308.953174 0q61.73041 + 74.076492 62.031534 213.798005 0 150.561976-60.22479 225.54184a198.13956 198.13956 0 0 1-309.254298 0Q602.247902 640.468662 + 602.247902 495.326917z m80.098971 0A273.721671 273.721671 0 0 0 722.697482 657.331603a120.44958 120.44958 0 0 0 98.467532 + 53.298939 115.029349 115.029349 0 0 0 94.251797-53.901187 273.420548 273.420548 0 0 0 39.447238-161.703562 271.011556 + 271.011556 0 0 0-39.748362-162.004685 120.44958 120.44958 0 0 0-98.467532-53.29894A114.125977 114.125977 0 0 0 722.697482 + 333.322232a271.011556 271.011556 0 0 0-39.748361 161.703561zM1212.023903 776.275564L1070.194522 214.077147h80.701219l73.474244 + 324.611619 27.101155 120.449581 24.391041-116.836093L1349.035301 214.077147h80.701218l68.656261 326.117239 23.186545 107.501251 + 26.498907-108.705747L1626.069336 214.077147h76.184359l-143.335001 562.198417h-81.303466l-73.474244-336.656578-17.46519-95.757416L1294.832989 + 776.275564zM1768.500964 776.275564V214.077147h70.463005v79.496723a180.674371 180.674371 0 0 1 62.031534-69.258509 154.476587 + 154.476587 0 0 1 84.314706-22.88542 161.703562 161.703562 0 0 1 68.355137 14.45395 140.624885 140.624885 0 0 1 50.588824 + 38.242742 153.874339 153.874339 0 0 1 30.112395 60.22479 509.802849 509.802849 0 0 1 9.635966 + 115.330473v346.593668h-79.195599V433.897631a279.141903 279.141903 0 0 0-10.539338-90.337185 87.62707 87.62707 0 0 + 0-85.218078-60.22479 109.00687 109.00687 0 0 0-90.337186 41.856229q-33.424759 42.157353-33.424758 143.636125v307.447554zM2270.775715 + 776.275564V0.279142h84.314706v384.836409L2670.969446 0.279142h114.427101l-267.096945 314.674529 278.539655 + 461.321893h-111.114738l-225.842963-391.461137-104.791135 123.46082v268.903689zM2853.149436 993.98818l-8.732595-90.337185a146.34624 + 146.34624 0 0 0 44.566345 8.431471 78.292227 78.292227 0 0 0 41.253981-9.937091 76.786608 76.786608 0 0 0 26.498908-30.112395c2.710116-5.119107 + 12.94833-36.134874 30.112395-93.348425L2812.196579 214.077147h84.314706l96.359664 325.514991c12.044958 40.350609 + 22.88542 83.712458 33.123635 130.085547 9.033719-43.662973 19.573057-86.422574 31.919139-127.977679l98.467532-327.622859h78.292227l-174.953016 + 572.135507a1012.679847 1012.679847 0 0 1-54.202311 147.550736 141.227133 141.227133 0 0 1-45.168592 53.600063 103.285515 103.285515 0 0 + 1-56.912427 16.561818 132.494538 132.494538 0 0 1-50.2877-9.937091zM3300.318503 109.88826V0.279142h77.68998v109.609118z + m0 666.387304V214.077147h77.68998v562.198417zM0 776.275564V0.279142h219.51936a417.357796 417.357796 0 0 1 124.063068 + 14.152826 210.786766 210.786766 0 0 1 96.359664 67.752889 358.337502 358.337502 0 0 1 63.537154 124.364191 616.400728 616.400728 0 0 1 + 22.584296 177.362008 579.663606 579.663606 0 0 1-38.543865 223.735095 273.420548 273.420548 0 0 1-99.370904 130.386671 294.1981 + 294.1981 0 0 1-158.391198 38.242742zM463.730885 391.740278q10.840462-7.528099 + 0-16.260693l-51.79332-30.112395q-136.40915-82.507963-276.431787-150.561976l-13.249454-6.624727a22.283172 22.283172 + 0 0 0-16.561817 0v405.613962a18.669685 18.669685 0 0 0 14.755073-4.817983q148.152984-76.786608 296.607092-164.413677c15.357322-10.238214 + 31.015767-21.379801 46.674213-32.822511z", + Fill = "#FF000000" + }; + } + + public VectorImage TextLogo { get; private set; } +} \ No newline at end of file diff --git a/DownKyi/Images/NavigationIcon.cs b/DownKyi/Images/NavigationIcon.cs new file mode 100644 index 0000000..ad23a13 --- /dev/null +++ b/DownKyi/Images/NavigationIcon.cs @@ -0,0 +1,46 @@ +namespace DownKyi.Images; + +public class NavigationIcon +{ + private static NavigationIcon instance; + public static NavigationIcon Instance() + { + if (instance == null) + { + instance = new NavigationIcon(); + } + return instance; + } + + public NavigationIcon() + { + ArrowBack = new VectorImage + { + Height = 24, + Width = 24, + Data = @"M16.62 2.99c-.49-.49-1.28-.49-1.77 0L6.54 11.3c-.39.39-.39 1.02 0 1.41l8.31 8.31c.49.49 1.28.49 1.77 + 0s.49-1.28 0-1.77L9.38 12l7.25-7.25c.48-.48.48-1.28-.01-1.76z", + Fill = "#FF000000" + }; + + Logout = new VectorImage + { + Height = 18.75,//100, + Width = 24,//128, + Data = @"M21.5,11.3l-2.8-2.7c-0.2-0.2-0.2-0.4-0.2-0.7c0.1-0.3,0.2-0.4,0.5-0.5c0.3-0.1,0.5,0,0.7,0.2l4,3.9 + c0.1,0.1,0.2,0.3,0.2,0.5c0,0.2-0.1,0.4-0.2,0.5l-4,3.9c-0.2,0.2-0.4,0.2-0.7,0.2c-0.3-0.1-0.4-0.2-0.5-0.5c-0.1-0.3,0-0.5,0.2-0.7 + l2.8-2.7h-8.7c-0.2,0-0.4-0.1-0.5-0.2c-0.1-0.1-0.2-0.3-0.2-0.5c0-0.2,0.1-0.4,0.2-0.5c0.1-0.1,0.3-0.2,0.5-0.2 + C12.8,11.3,21.5,11.3,21.5,11.3z M16,18.2c0-0.2,0.1-0.4,0.2-0.5c0.1-0.1,0.3-0.2,0.5-0.2c0.2,0,0.4,0.1,0.5,0.2 + c0.1,0.1,0.2,0.3,0.2,0.5v0.4c0,0.8-0.3,1.5-0.9,2c-0.6,0.5-1.2,0.8-2,0.8H2.9c-0.8,0-1.5-0.3-2-0.8S0,19.3,0,18.5V5.4 + c0-0.8,0.3-1.5,0.8-2s1.2-0.8,2-0.8h11.7c0.8,0,1.5,0.3,2,0.8c0.5,0.5,0.8,1.2,0.8,2v0.4c0,0.3-0.1,0.5-0.4,0.6 + c-0.2,0.1-0.5,0.1-0.7,0C16.1,6.3,16,6.1,16,5.8V5.4c0-0.4-0.1-0.7-0.4-1c-0.3-0.3-0.6-0.4-1-0.4H2.9c-0.4,0-0.7,0.1-1,0.4 + C1.6,4.7,1.4,5,1.4,5.4v13.1c0,0.4,0.2,0.7,0.4,1c0.3,0.3,0.6,0.4,1,0.4h11.7c0.4,0,0.7-0.1,1-0.4c0.3-0.3,0.4-0.6,0.4-1L16,18.2 + L16,18.2z", + Fill = "#FF000000" + }; + } + + public VectorImage ArrowBack { get; private set; } + public VectorImage Logout { get; private set; } + +} \ No newline at end of file diff --git a/DownKyi/Images/NormalIcon.cs b/DownKyi/Images/NormalIcon.cs new file mode 100644 index 0000000..54b6d0e --- /dev/null +++ b/DownKyi/Images/NormalIcon.cs @@ -0,0 +1,429 @@ +// using DownKyi.ViewModels.UserSpace; + +namespace DownKyi.Images; + +public class NormalIcon +{ + private static NormalIcon instance; + + public static NormalIcon Instance() + { + if (instance == null) + { + instance = new NormalIcon(); + } + + return instance; + } + + public NormalIcon() + { + Play = new VectorImage + { + Height = 16, + Width = 14.75, + Data = + @"M869.03 707.93 l-465.29 281.31 q-86.66 49.32 -178.65 28.65 q-91.99 -20.66 -146.65 -103.31 q-36 -56 -36 -121.33 + l0 -562.61 q2.67 -97.32 69.33 -162.64 q66.66 -65.32 167.98 -67.99 q66.66 0 123.99 34.66 l465.29 281.31 + q83.99 53.33 105.99 143.32 q22 89.99 -30 173.98 q-29.33 46.66 -75.99 74.66 Z", + Fill = "#FF000000" + }; + + Like = new VectorImage + { + Height = 14, + Width = 16, + Data = @"M291.53 894.6 l0 -642.53 l4.66 0 l179.59 -220.4 q29.15 -29.15 69.97 -31.49 q40.81 -2.33 72.29 24.5 + q16.33 16.32 25.66 37.31 q9.33 20.99 7 45.48 l-7 144.6 l274.04 0 q25.65 0 48.39 11.08 q22.74 11.08 39.07 32.07 + q13.99 19.82 17.49 44.31 q3.5 24.49 -2.33 46.64 l-116.62 382.49 q-15.16 54.81 -57.14 88.63 q-41.98 33.81 -100.28 37.31 + l-454.79 0 ZM225.06 894.6 l-93.29 0 q-34.98 2.33 -65.3 -14 q-30.32 -16.33 -47.81 -47.81 q-17.49 -31.49 -18.66 -64.13 + l0 -385.99 q0 -36.15 17.49 -65.89 q17.49 -29.73 48.98 -46.05 q16.32 -8.17 32.65 -12.25 q16.33 -4.08 32.65 -6.41 l93.29 0 + l0 642.53 Z", + Fill = "#FF000000" + }; + + Favorite = new VectorImage + { + Height = 16, + Width = 16, + Data = + @"M772.12 303.28 q-37.33 -5.83 -66.49 -28 q-29.16 -22.16 -44.32 -55.99 l-83.99 -176.13 q-22.16 -43.16 -65.91 -43.16 + q-43.74 0 -69.4 43.16 l-79.32 176.13 q-17.49 33.83 -46.07 55.99 q-28.58 22.17 -64.74 28 l-188.97 29.16 + q-45.49 9.33 -58.9 48.99 q-13.42 39.66 18.09 75.82 l142.31 146.98 q25.66 24.49 35.57 58.32 q9.91 33.83 5.25 69.99 + l-32.66 204.13 q-5.83 48.99 29.75 73.49 q35.57 24.5 79.9 3.5 l159.8 -87.48 q33.83 -19.83 71.74 -19.83 + q37.91 0 71.74 19.83 l160.97 87.48 q43.16 21 77.57 -3.5 q34.41 -24.5 32.08 -73.49 l-37.33 -204.13 + q-4.67 -36.16 5.25 -69.99 q9.91 -33.83 35.57 -58.32 l142.31 -146.98 q31.5 -36.16 18.09 -75.82 + q-13.42 -39.66 -58.91 -48.99 l-188.97 -29.16 Z", + Fill = "#FF000000" + }; + + Share = new VectorImage + { + Height = 14, + Width = 16, + Data = + @"M453.23 283.64 l0 -219.44 q1.16 -26.85 18.67 -45.53 q17.51 -18.68 44.36 -18.68 q23.34 0 40.85 15.17 l441.21 375.85 + q25.68 22.18 25.68 56.61 q0 34.43 -25.68 57.78 l-441.21 375.85 q-19.84 16.34 -46.11 14 q-26.26 -2.34 -42.61 -22.18 + q-15.17 -18.67 -15.17 -42.02 l0 -201.93 q-156.41 0 -249.79 61.87 q-93.38 61.87 -178.58 183.25 q-4.67 5.84 -14.01 5.25 + q-9.34 -0.59 -10.51 -19.25 q-5.83 -241.62 87.54 -405.62 q93.38 -164 365.35 -171 Z", + Fill = "#FF000000" + }; + + CloudDownload = new VectorImage + { + Height = 32, + Width = 48, + Data = + @"M19.4,10c-0.7-3.4-3.7-6-7.4-6C9.1,4,6.6,5.6,5.3,8C2.3,8.4,0,10.9,0,14c0,3.3,2.7,6,6,6h13c2.8,0,5-2.2,5-5 + C24,12.4,22,10.2,19.4,10z M19,18H6c-2.2,0-4-1.8-4-4c0-2.1,1.5-3.8,3.6-4l1.1-0.1L7.1,9C8.1,7.1,9.9,6,12,6c2.6,0,4.9,1.9,5.4,4.4 + l0.3,1.5l1.5,0.1c1.6,0.1,2.8,1.4,2.8,3C22,16.6,20.6,18,19,18z M13.4,10h-2.9v3H8l4,4l4-4h-2.6V10z", + Fill = "#FF000000" + }; + + Folder = new VectorImage + { + Height = 32, + Width = 40, + Data = + @"M20 6h-8l-2-2H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2zm0 12H4V8h16v10z", + Fill = "#FF000000" + }; + + Downloading = new VectorImage + { + Height = 16, + Width = 16, + Data = + @"M1,11.7c0.6,0,1,0.5,1,1V24H1.4C0.6,24,0,23.4,0,22.6c0,0,0,0,0,0v-9.9C0,12.1,0.5,11.7,1,11.7C1,11.7,1,11.7,1,11.7z + M0,21.9h24v0.7c0,0.8-0.6,1.4-1.3,1.4H1.4C0.6,24,0,23.4,0,22.6V21.9z + M23,11.7c0.6,0,1,0.5,1,1v9.9c0,0.8-0.6,1.4-1.3,1.4H22V12.7C22,12.1,22.5,11.7,23,11.7C23,11.7,23,11.7,23,11.7z M13,17.4 + h-2V1c0-0.6,0.4-1,1-1s1,0.5,1,1c0,0,0,0,0,0V17.4z + M6.9,12.5c0.4-0.4,1-0.4,1.4,0l4.9,5.1L12.8,18c-0.5,0.5-1.4,0.5-1.9,0l-4-4.1C6.5,13.5,6.5,12.9,6.9,12.5L6.9,12.5z + M16.8,12.5c0.4,0.4,0.4,1.1,0,1.5l-4,4.1c-0.5,0.5-1.4,0.5-1.9,0l-0.5-0.5l4.9-5.1C15.8,12.1,16.4,12.1,16.8,12.5L16.8,12.5z", + Fill = "#FF000000" + }; + + DownloadFinished = new VectorImage + { + Height = 16, + Width = 16, + Data = + @"M12,0C8.6,0.1,5.8,1.3,3.5,3.5S0.1,8.6,0,12c0.1,3.4,1.3,6.2,3.5,8.5S8.6,23.9,12,24c3.4-0.1,6.2-1.3,8.5-3.5 + s3.4-5.1,3.5-8.5c-0.1-3.4-1.3-6.2-3.5-8.5S15.4,0.1,12,0z M12,22.5c-3-0.1-5.5-1.1-7.4-3.1S1.6,15,1.5,12c0.1-3,1.1-5.5,3.1-7.4 + S9,1.6,12,1.5c3,0.1,5.5,1.1,7.4,3.1s3,4.4,3.1,7.4c-0.1,3-1.1,5.5-3.1,7.4S15,22.4,12,22.5z + M16.5,8.1c0.2-0.2,0.4-0.2,0.6-0.2c0.5,0,0.9,0.4,0.9,0.9c0,0.2-0.1,0.5-0.2,0.6l-6.5,6.5 + c-0.2,0.2-0.4,0.3-0.6,0.3c-0.2,0-0.5-0.1-0.7-0.3l-3.8-3.7C6.1,12,6,11.7,6,11.5c0-0.2,0.1-0.5,0.3-0.6c0.2-0.2,0.4-0.3,0.6-0.3 + c0.2,0,0.5,0.1,0.6,0.2l3.1,3.1L16.5,8.1L16.5,8.1z", + Fill = "#FF000000" + }; + + CoinIcon = new VectorImage + { + Height = 20, + Width = 20, + Data = + @"M473.7 358.8 l0 -54.42 l-129.01 0 q-16.12 0 -27.21 -11.09 q-11.09 -11.09 -11.09 -27.72 q0 -16.63 11.09 -27.21 + q11.09 -10.58 27.21 -11.59 l334.62 0 q22.17 1.01 32.76 20.16 q10.58 19.15 0 37.8 q-10.59 18.64 -32.76 19.65 l-129.01 0 + l0 54.42 q93.73 16.13 153.7 83.66 q59.97 67.52 61.98 163.27 l0 23.18 q-1 17.14 -11.59 27.72 q-10.59 10.58 -27.22 10.58 + q-16.63 0 -27.72 -10.58 q-11.08 -10.58 -11.08 -27.72 l0 -23.18 q-1.01 -62.49 -39.31 -108.35 q-38.3 -45.86 -98.77 -59.96 + l0 332.6 q0 16.12 -11.09 27.2 q-11.08 11.09 -27.21 11.09 q-16.13 0 -27.22 -11.09 q-11.08 -11.08 -11.08 -27.2 l0 -332.6 + q-60.47 14.11 -98.77 59.96 q-38.3 45.86 -39.31 108.35 l0 23.18 q0 17.14 -11.09 27.72 q-11.08 10.58 -27.71 10.58 + q-16.63 0 -27.21 -10.58 q-10.59 -10.58 -11.59 -27.72 l0 -23.18 q2.01 -95.75 61.98 -163.27 q59.97 -67.53 153.7 -83.66 + ZM512 1024 q-217.7 -6.05 -361.82 -150.17 q-144.13 -144.13 -150.18 -361.83 q6.05 -217.7 150.18 -361.82 + q144.13 -144.13 361.82 -150.18 q217.7 6.05 361.83 150.18 q144.13 144.13 150.17 361.82 q-6.05 217.7 -150.17 361.83 + q-144.13 144.13 -361.83 150.17 ZM512 946.39 q184.44 -5.04 306.89 -127.5 q122.46 -122.45 127.5 -306.89 + q-5.04 -184.44 -127.5 -306.89 q-122.45 -122.46 -306.89 -127.5 q-184.44 5.04 -306.89 127.5 q-122.46 122.45 -127.5 306.89 + q5.04 184.44 127.5 306.89 q122.45 122.46 306.89 127.5 Z", + Fill = "#FF000000" + }; + + MoneyIcon = new VectorImage + { + Height = 20, + Width = 20, + Data = + @"M409.2 444.47 l138.08 0 q28.22 -1.01 46.36 -19.15 q18.14 -18.14 18.14 -45.85 q0 -27.72 -18.14 -46.36 + q-18.14 -18.65 -46.36 -19.66 l-129.01 0 q-4.03 0 -6.55 3.03 q-2.52 3.02 -2.52 6.04 l0 121.95 ZM658.14 469.67 + q48.38 30.24 68.03 80.63 q19.66 50.39 4.03 105.32 q-15.63 54.93 -58.96 87.18 q-43.34 32.25 -99.78 33.25 l-153.19 0 + q-36.29 -1 -60.98 -25.19 q-24.69 -24.19 -25.7 -61.48 l0 -366.87 q1.01 -36.28 25.7 -60.47 q24.69 -24.19 60.98 -25.2 + l129.01 0 q42.33 0 76.6 21.67 q34.26 21.67 52.41 59.47 q18.14 37.79 13.11 78.11 q-5.04 40.31 -31.25 73.57 ZM571.46 522.08 + l-162.26 0 l0 167.31 q1 9.07 9.07 9.07 l153.19 0 q36.29 -1.01 60.48 -26.21 q24.19 -25.2 24.19 -61.99 q0 -36.79 -24.19 -61.48 + q-24.19 -24.7 -60.48 -26.71 ZM512 1024 q-217.7 -6.05 -361.82 -150.17 q-144.13 -144.13 -150.18 -361.83 + q6.05 -217.7 150.18 -361.82 q144.13 -144.13 361.82 -150.18 q217.7 6.05 361.83 150.18 q144.13 144.13 150.17 361.82 + q-6.05 217.7 -150.17 361.83 q-144.13 144.13 -361.83 150.17 ZM512 946.39 q184.44 -5.04 306.89 -127.5 + q122.46 -122.45 127.5 -306.89 q-5.04 -184.44 -127.5 -306.89 q-122.45 -122.46 -306.89 -127.5 q-184.44 5.04 -306.89 127.5 + q-122.46 122.45 -127.5 306.89 q5.04 184.44 127.5 306.89 q122.45 122.46 306.89 127.5 Z", + Fill = "#FF000000" + }; + + BindingEmail = new VectorImage + { + Height = 20, + Width = 20, + Data = + @"M512 1024 q-218 -5 -362.5 -149.5 q-144.5 -144.5 -149.5 -362.5 q5 -218 149.5 -362.5 q144.5 -144.5 362.5 -149.5 + q218 5 362.5 149.5 q144.5 144.5 149.5 362.5 q-5 218 -149.5 362.5 q-144.5 144.5 -362.5 149.5 ZM282 278 l214 164 + q8 6 16 6 q8 0 16 -6 l214 -164 l0 257 l-230 77 l-230 -77 l0 -257 ZM305 232 q7 -2 15 -2 l384 0 q8 0 15 2 q-3 2 -5 4 + l-202 154 l-202 -154 q-2 -2 -5 -4 ZM794 518 l0 -262 q-1 -34 -27 -55 q-26 -21 -63 -22 l-384 0 q-37 1 -63 22 + q-26 21 -27 55 l0 262 l-9 -3 q-25 -8 -46 7 q-21 15 -21 41 l0 154 q1 43 29.5 72 q28.5 29 72.5 30 l512 0 q44 -1 72.5 -30 + q28.5 -29 29.5 -72 l0 -154 q0 -26 -21 -41 q-21 -15 -46 -7 l-9 3 ZM205 563 l307 103 l307 -103 l0 154 q0 21 -15 36 + q-15 15 -36 15 l-512 0 q-22 -1 -36.5 -15 q-14.5 -14 -14.5 -36 l0 -154 Z", + Fill = "#FF000000" + }; + + BindingPhone = new VectorImage + { + Height = 20, + Width = 20, + Data = + @"M512 1024 q-218 -5 -362.5 -149.5 q-144.5 -144.5 -149.5 -362.5 q5 -218 149.5 -362.5 q144.5 -144.5 362.5 -149.5 + q218 5 362.5 149.5 q144.5 144.5 149.5 362.5 q-5 218 -149.5 362.5 q-144.5 144.5 -362.5 149.5 ZM307 614 l0 -307 + l410 0 l0 461 q0 21 -15 36 q-15 15 -36 15 l-308 0 q-21 0 -35.5 -14.5 q-14.5 -14.5 -15.5 -36.5 l0 -102 l333 0 + q11 -1 18 -8 q7 -7 7 -18 q0 -11 -7 -18 q-7 -7 -18 -8 l-333 0 ZM307 256 q0 -21 15 -36 q15 -15 36 -15 l308 0 + q21 0 36 15 q15 15 15 36 l-410 0 ZM358 154 q-43 1 -72 29.5 q-29 28.5 -30 72.5 l0 512 q1 44 30 72.5 q29 28.5 72 29.5 + l308 0 q43 -1 72 -29.5 q29 -28.5 30 -72.5 l0 -512 q-1 -44 -30 -72.5 q-29 -28.5 -72 -29.5 l-308 0 ZM512 794 + q22 -1 36.5 -15.5 q14.5 -14.5 14.5 -36 q0 -21.5 -14.5 -36 q-14.5 -14.5 -36.5 -14.5 q-22 0 -36.5 14.5 q-14.5 14.5 -14.5 36 + q0 21.5 14.5 36 q14.5 14.5 36.5 15.5 Z", + Fill = "#FF000000" + }; + + FavoriteOutline = new VectorImage + { + Height = 24, + Width = 24, + Data = + @"M755.8 1021.89 q-13.98 -1 -28.45 -4.5 q-14.47 -3.5 -29.45 -8.49 l-146.74 -76.87 q-18.97 -13.97 -39.93 -13.97 + q-20.97 0 -35.94 13.97 l-146.75 76.87 q-33.94 14.97 -69.38 12.98 q-35.44 -2 -65.39 -25.96 q-23.96 -19.96 -35.44 -49.41 + q-11.48 -29.45 -2.5 -59.4 l31.95 -184.68 q3.99 -22.96 -3.49 -40.43 q-7.49 -17.47 -22.47 -36.43 l-126.77 -133.77 + q-24.96 -19.96 -32.45 -50.41 q-7.49 -30.45 6.49 -64.39 q9.98 -28.95 34.94 -49.91 q24.96 -20.97 54.9 -26.96 + l171.71 -24.95 q19.96 -1 36.93 -12.98 q16.97 -11.98 26.95 -31.94 l69.88 -159.73 q14.98 -33.94 45.42 -53.91 + q30.44 -19.97 69.38 -15.97 q34.94 0 60.39 20.96 q25.45 20.96 35.44 55.9 l76.86 152.74 q9.98 18.96 26.96 32.44 + q16.98 13.48 36.93 18.47 l172.7 25.95 q28.95 4.99 51.91 22.96 q22.96 17.97 36.93 46.92 q9.99 28.95 5 59.89 + q-5 30.95 -23.96 54.91 l-127.78 133.77 q-14.97 14.97 -22.46 33.94 q-7.49 18.97 -3.49 42.92 l31.94 184.68 + q4.99 34.94 -8.49 65.39 q-13.48 30.45 -42.43 50.41 q-13.98 8.98 -32.44 13.98 q-18.47 5 -37.44 5 ZM513.22 817.24 + q23.96 0 46.92 5.99 q22.96 5.99 42.93 19.97 l139.75 75.87 q9.99 4.99 15.48 2.99 q5.49 -2 10.48 -2.49 + q4.99 -0.5 7.99 -4.99 q3 -4.5 -2 -14.48 l-31.95 -184.68 q-4.99 -47.92 6.49 -87.35 q11.48 -39.43 44.42 -72.37 + l127.78 -133.77 q3.99 -4.99 2.5 -9.98 q-1.5 -4.99 -2 -9.48 q-0.5 -4.5 -4.49 -5.49 q-3.99 -1 -8.99 -1 l-171.7 -24.96 + q-43.92 -5.99 -79.86 -32.44 q-35.94 -26.45 -60.89 -70.38 l-69.88 -159.72 q0 -8.99 -4 -10.98 q-4 -2 -8.99 -2 + q-4.99 0 -9.48 2 q-4.49 1.99 -9.48 10.98 l-69.88 159.72 q-24.96 43.92 -61.39 70.38 q-36.44 26.45 -79.37 32.44 + l-172.7 24.96 q-4.99 0 -8.48 3.99 q-3.5 3.99 -3.99 8.98 q-0.49 5 0.5 8.99 q1 3.99 5.99 3.99 l127.78 133.77 + q32.94 33.94 44.42 71.88 q11.48 37.93 6.49 80.85 l-25.95 185.68 q0 4.99 1 9.49 q1 4.5 5.99 9.49 q5 4.99 13.48 4.99 + q8.49 0 18.47 -4.99 l139.76 -76.87 q10.98 -4.99 31.44 -11.48 q20.47 -6.49 45.42 -7.49 Z", + Fill = "#FF000000" + }; + + Subscription = new VectorImage + { + Height = 24, + Width = 24, + Data = + @"M512 945.07 q-6.15 0 -13.53 -2.46 q-7.39 -2.46 -13.54 -4.92 q-43.07 -32 -190.74 -153.83 q-147.67 -121.83 -211.65 -200.59 + q-51.69 -68.91 -67.69 -119.97 q-16 -51.06 -14.77 -116.29 q3.69 -146.44 91.06 -244.88 q87.37 -98.45 220.27 -102.14 + q56.6 0 107.67 20.3 q51.07 20.3 92.91 58.46 q41.84 -38.15 92.91 -58.46 q51.07 -20.3 107.67 -20.3 + q132.9 3.69 220.27 102.14 q87.37 98.45 91.06 244.88 q1.23 61.53 -14.76 113.21 q-16 51.68 -67.68 123.05 + q-63.98 76.3 -212.88 199.36 q-148.9 123.06 -189.51 155.06 q-6.15 2.46 -13.54 4.92 q-7.38 2.46 -13.53 2.46 ZM322.49 78.76 + q-97.21 3.69 -168.58 85.52 q-71.37 81.83 -75.07 197.5 q-1.23 35.69 8 79.99 q9.23 44.3 51.07 105.83 q44.3 52.91 163.66 148.9 + l210.43 169.81 l210.43 -169.81 q119.36 -95.99 163.66 -148.9 q43.07 -61.53 52.3 -107.06 q9.23 -45.53 6.77 -78.76 + q-3.7 -115.67 -75.07 -197.5 q-71.37 -81.83 -168.58 -85.52 q-49.23 0 -87.38 21.53 q-38.14 21.53 -78.75 57.21 + q-11.07 8.62 -17.23 10.47 q-6.15 1.84 -6.15 1.84 l-4.92 -1.23 q-6.16 -1.23 -14.77 -7.39 q-43.07 -35.68 -81.83 -58.44 + q-38.76 -22.77 -87.99 -23.99 Z", + Fill = "#FF000000" + }; + + ToView = new VectorImage + { + Height = 24, + Width = 24, + Data = @"M837.18 92.91 q38.96 1 65.44 27.48 q26.48 26.48 27.48 65.43 l0 651.36 q-1 39.96 -27.48 65.94 + q-26.48 25.98 -65.44 26.98 l-651.36 0 q-38.96 -1 -65.43 -26.98 q-26.48 -25.98 -27.48 -65.94 l0 -651.36 + q1 -38.96 27.48 -65.43 q26.48 -26.48 65.43 -27.48 l651.36 0 ZM837.18 0 l-651.36 0 q-78.92 2 -131.37 54.45 + q-52.45 52.45 -54.45 131.37 l0 651.36 q2 78.93 54.45 131.38 q52.45 52.44 131.37 54.44 l651.36 0 q78.93 -2 131.88 -54.44 + q52.94 -52.45 54.94 -131.38 l0 -651.36 q-3 -78.92 -55.44 -131.37 q-52.45 -52.45 -131.38 -54.45 ZM697.32 744.27 + q-12.99 0 -24.98 -7.99 l-242.76 -159.84 q-20.98 -13.99 -20.98 -38.96 l0 -278.73 q0 -19.98 12.99 -33.47 + q12.99 -13.49 32.97 -13.49 q19.98 0 32.96 13.49 q12.99 13.49 13.99 33.47 l0 252.75 l221.78 143.86 + q17.99 7.99 24.98 24.98 q6.99 16.99 0 35.96 q-6.99 14.99 -20.98 22.48 q-13.99 7.49 -29.97 5.49 Z", + Fill = "#FF000000" + }; + + History = new VectorImage + { + Height = 24, + Width = 24, + Data = @"M512 0 q-217 6 -361.5 150.5 q-144.5 144.5 -150.5 361.5 q6 217 150.5 361.5 q144.5 144.5 361.5 150.5 + q217 -6 361.5 -150.5 q144.5 -144.5 150.5 -361.5 q-6 -217 -150.5 -361.5 q-144.5 -144.5 -361.5 -150.5 ZM512 939 + q-183 -5 -302.5 -124.5 q-119.5 -119.5 -124.5 -302.5 q5 -183 124.5 -302.5 q119.5 -119.5 302.5 -124.5 + q183 5 302.5 124.5 q119.5 119.5 124.5 302.5 q-5 183 -124.5 302.5 q-119.5 119.5 -302.5 124.5 ZM512 256 + l-85 0 l0 341 l341 0 l0 -85 l-256 0 l0 -256 Z", + Fill = "#FF000000" + }; + + VideoUp = new VectorImage + { + Height = 24, + Width = 24, + Data = + @"M711,212.3l47-47c41.7-47.6-25-112.2-72-71l-107,106c-3.3,3.3-6,7-8,11H454c-1.3-2.7-3.3-5-6-7l-112-111 + c-21.3-17.3-51-17-71,3s-20.3,49.7-3,71l45,44H198c-56.7,0-105,48.3-105,105v417c0,56.7,48.3,105,105,105h57 + c-17.9,49.6,19.9,105,73.5,105c55.4,0,90.4-55.3,74.5-105h218c-15.9,49.7,19.1,105,74.5,105c53.6,0,91.4-55.4,73.5-105h57 + c56.7,0,105-48.3,105-105v-417c0-57.6-48.3-104-105-104H711L711,212.3z", + Fill = "#FF000000" + }; + + Channel = new VectorImage + { + Height = 24, + Width = 24, + Data = @"M921.6 211.41 q1.1 -6.61 7.15 -10.47 q6.05 -3.85 12.66 -0.54 q38.54 19.82 60.56 56.16 + q22.02 36.33 22.02 80.38 l0 329.22 q-1.1 64.96 -44.6 108.46 q-43.5 43.5 -108.45 44.6 + l-483.37 0 q-44.04 0 -80.38 -22.02 q-36.34 -22.02 -56.15 -61.66 q-3.31 -5.51 0.54 -11.57 + q3.85 -6.05 10.47 -7.15 l557.14 0 q44.04 -1.1 72.67 -29.73 q28.63 -28.63 29.73 -72.67 + l0 -402.99 ZM102.4 0 l666.15 0 q41.84 0 71.57 29.73 q29.73 29.73 30.83 72.67 l0 461.35 + q-1.1 41.84 -30.83 71.57 q-29.73 29.73 -71.57 30.83 l-666.15 0 q-42.94 -1.1 -72.67 -30.83 + q-29.73 -29.73 -29.73 -71.57 l0 -461.35 q0 -42.94 29.73 -72.67 q29.73 -29.73 72.67 -29.73 + ZM559.35 353.45 q9.91 -7.71 9.91 -20.93 q0 -13.21 -9.91 -20.92 l-186.09 -129.92 q-13.21 -8.81 -26.42 -1.66 + q-13.21 7.16 -14.32 22.57 l0 259.85 q1.11 15.42 14.32 22.57 q13.21 7.16 26.42 -1.65 l186.09 -129.92 Z", + Fill = "#FF000000" + }; + + Channel1 = new VectorImage + { + Height = 24, + Width = 24, + Data = + @"M116.57 0 q-30.86 0 -57.71 16 q-26.85 16 -42.85 42.85 q-16 26.85 -16 57.71 l0 468.57 q0 30.86 16 57.72 + q16 26.86 42.85 42.86 q26.85 16 57.71 16 l643.43 0 q32 0 58.86 -16 q26.86 -16 42.86 -42.86 + q16 -26.86 16 -57.72 l0 -468.57 q0 -30.86 -16 -57.71 q-16 -26.85 -42.86 -42.85 q-26.86 -16 -58.86 -16 + l-643.43 0 ZM262.86 848 q-40 0 -72.57 -25.71 q-32.58 -25.72 -39.43 -62.29 l697.14 0 q36.57 0 62.29 -25.71 + q25.71 -25.72 25.71 -62.29 l0 -521.14 q37.71 11.43 62.86 42.28 q25.14 30.86 25.14 69.72 l0 468.57 + q0 30.86 -16 57.72 q-16 26.86 -42.86 42.86 q-26.86 16 -58.86 16 l-643.43 0 ZM88 174.86 + q0 -36.57 25.14 -62.29 q25.14 -25.71 61.72 -25.71 l526.85 0 q36.58 0 62.29 25.71 q25.71 25.72 25.71 62.29 + l0 350.85 q0 36.58 -25.71 62.29 q-25.71 25.71 -62.29 25.71 l-526.85 0 q-36.57 0 -61.72 -25.71 + q-25.14 -25.71 -25.14 -62.29 l0 -350.85 ZM609.14 374.86 q11.43 -6.86 11.43 -22.29 q0 -15.43 -11.43 -26.86 + l-214.85 -146.28 q-13.72 -10.29 -28.57 -1.72 q-14.86 8.58 -14.86 26.86 l0 297.14 q0 18.29 14.86 26.86 + q14.85 8.57 28.57 -2.86 l214.85 -150.85 Z", + Fill = "#FF000000" + }; + + SeasonsSeries = new VectorImage + { + Height = 24, + Width = 24, + Data = @"M974.2 382.22 l-401.47 177.37 q-28.88 13.75 -60.5 13.75 q-31.62 0 -60.5 -13.75 l-400.09 -177.37 + q-20.63 -11 -33 -30.25 q-12.38 -19.25 -13.06 -43.31 q-0.68 -24.06 10.32 -45.38 q11 -21.32 31.62 -35.07 + l402.85 -210.36 q28.87 -17.87 63.25 -17.87 q34.38 0 63.25 19.25 l398.72 207.61 q22 12.37 33.69 34.37 + q11.68 22 10.31 46.06 q-1.38 24.06 -13.06 44 q-11.69 19.94 -32.31 30.94 ZM939.83 292.86 l-400.1 -207.62 + q-11 -8.25 -24.75 -9.62 q-16.5 1.37 -30.25 9.62 l-400.1 207.62 q-2.75 6.87 -2.75 12.37 q0 5.5 4.13 9.62 + l397.35 175.99 q20.62 9.63 28.18 9.63 q7.56 0 26.81 -8.25 l404.22 -178.74 q1.38 -11 -4.12 -20.62 + l1.38 0 ZM20.01 512.84 q8.25 -4.12 19.25 -4.12 q11 0 19.25 5.5 q16.5 9.62 39.87 20.62 l413.85 186.99 + l394.6 -178.74 l60.49 -30.25 q9.63 -4.12 19.94 -4.12 q10.31 0 19.25 5.5 q8.94 5.5 13.75 15.12 + q4.81 9.63 3.43 19.25 q-1.37 23.37 -21.99 31.62 l-64.62 31.62 l-424.85 193.87 l-422.1 -192.49 + q-35.74 -12.38 -68.74 -33 q-9.63 -5.5 -15.13 -14.43 q-5.5 -8.94 -6.18 -19.25 q-0.69 -10.32 4.82 -19.25 + q5.5 -8.94 15.12 -14.44 l0 0 ZM58.51 732.83 q17.87 9.62 41.25 20.62 l412.47 186.99 l394.6 -178.74 + l60.49 -30.25 q9.63 -5.5 19.94 -4.81 q10.31 0.69 19.25 6.18 q8.94 5.5 13.75 15.12 q4.81 9.63 3.43 19.94 + q-1.37 10.32 -6.87 18.57 q-5.5 8.25 -15.12 12.37 l-64.62 31.62 l-424.85 192.49 l-422.1 -191.11 + q-35.74 -13.75 -68.74 -34.37 q-13.75 -6.88 -17.88 -22 q-4.13 -15.13 3.44 -28.87 q7.56 -13.75 22.68 -17.87 + q15.13 -4.13 28.88 4.13 Z", + Fill = "#FF000000" + }; + + PlatformIpad = new VectorImage + { + Height = 16, + Width = 16, + Data = + @"M804.57 0 q40 0 73.72 19.43 q33.71 19.43 53.14 53.15 q19.43 33.72 19.43 73.71 l0 731.42 q0 40 -19.43 73.71 + q-19.43 33.72 -53.14 53.14 q-33.72 19.43 -73.72 19.43 l-585.14 0 q-40 0 -73.72 -19.43 q-33.72 -19.43 -53.15 -53.14 + q-19.43 -33.71 -19.43 -73.71 l0 -731.42 q0 -40 19.43 -73.71 q19.43 -33.72 53.15 -53.15 q33.72 -19.43 73.72 -19.43 + l585.14 0 ZM512 877.71 q-22.86 0 -38.86 16 q-16 16 -16 38.86 q0 22.86 16 38.86 q16 16 38.86 16 q22.86 0 38.86 -16 + q16 -16 16 -38.86 q0 -22.86 -16 -38.86 q-16 -16 -38.86 -16 ZM804.57 73.14 l-585.14 0 q-27.43 0 -48.57 18.28 + q-21.15 18.28 -24.57 46.86 l0 8 l0 621.71 q0 27.43 18.28 48.57 q18.29 21.14 46.86 24.57 l8 0 l585.14 0 + q27.43 0 48.57 -18.28 q21.14 -18.28 24.57 -46.86 l0 -8 l0 -621.71 q0 -30.86 -21.14 -52 q-21.14 -21.14 -52 -21.14 Z", + Fill = "#FF000000" + }; + + PlatformMobile = new VectorImage + { + Height = 16, + Width = 16, + Data = + @"M694.86 0 q40 0 73.72 19.43 q33.71 19.43 53.14 53.15 q19.43 33.72 19.43 73.71 l0 731.42 q0 40 -19.43 73.71 + q-19.42 33.72 -53.14 53.14 q-33.72 19.43 -73.72 19.43 l-365.72 0 q-40 0 -73.71 -19.43 q-33.72 -19.43 -53.14 -53.14 + q-19.43 -33.71 -19.43 -73.71 l0 -731.42 q0 -40 19.43 -73.71 q19.42 -33.72 53.14 -53.15 q33.71 -19.43 73.71 -19.43 + l365.72 0 ZM512 877.71 q-22.86 0 -38.86 16 q-16 16 -16 38.86 q0 22.86 16 38.86 q16 16 38.86 16 q22.86 0 38.86 -16 + q16 -16 16 -38.86 q0 -22.86 -16 -38.86 q-16 -16 -38.86 -16 ZM694.86 73.14 l-365.72 0 q-27.43 0 -48.57 18.28 + q-21.14 18.28 -24.57 46.86 l0 8 l0 621.71 q0 27.43 18.28 48.57 q18.29 21.14 46.86 24.57 l8 0 l365.72 0 + q27.43 0 48.57 -18.28 q21.14 -18.28 24.57 -46.86 l0 -8 l0 -621.71 q0 -30.86 -21.14 -52 q-21.14 -21.14 -52 -21.14 Z", + Fill = "#FF000000" + }; + + PlatformPC = new VectorImage + { + Height = 16, + Width = 16, + Data = + @"M694.86 804.57 q14.85 0 25.71 10.86 q10.86 10.86 10.86 25.71 q0 14.86 -10.86 25.71 q-10.86 10.86 -25.71 10.86 + l-365.72 0 q-14.85 0 -25.71 -10.86 q-10.86 -10.86 -10.86 -25.71 q0 -14.86 10.86 -25.71 q10.86 -10.86 25.71 -10.86 + l365.72 0 ZM877.71 0 q40 0 73.71 19.43 q33.72 19.43 53.14 53.15 q19.43 33.72 19.43 73.71 l0 438.85 q0 40 -19.43 73.72 + q-19.43 33.72 -53.14 53.14 q-33.71 19.43 -73.71 19.43 l-731.42 0 q-40 0 -73.71 -19.43 q-33.72 -19.43 -53.15 -53.14 + q-19.43 -33.72 -19.43 -73.72 l0 -438.85 q0 -40 19.43 -73.71 q19.43 -33.72 53.15 -53.15 q33.72 -19.43 73.71 -19.43 + l731.42 0 ZM877.71 73.14 l-731.42 0 q-27.43 0 -48.57 18.28 q-21.15 18.28 -24.58 46.86 l0 8 l0 438.85 + q0 27.43 18.28 48.58 q18.28 21.14 46.86 24.57 l8 0 l731.42 0 q27.43 0 48.57 -18.29 q21.14 -18.29 24.58 -46.86 + l0 -8 l0 -438.85 q0 -30.86 -21.14 -52 q-21.14 -21.14 -52 -21.14 ZM347.43 182.86 q34.28 0 63.99 17.14 + q29.72 17.14 46.86 46.85 q17.15 29.72 17.15 64 q0 34.28 -17.15 64 q-17.14 29.71 -46.86 46.86 + q-29.71 17.14 -63.99 17.14 l-91.43 0 l0 109.71 l-73.14 0 l0 -365.71 l164.57 0 ZM694.86 182.86 + q44.57 0 82.85 19.43 q38.29 19.42 63.43 53.71 l-60.57 41.14 q-22.86 -27.43 -56 -37.14 q-33.14 -9.71 -66.28 2.29 + q-33.14 12 -53.14 40.57 q-20 28.57 -20 62.86 q0 34.28 20 62.85 q20 28.57 53.14 40.57 q33.14 12 66.28 2.28 + q33.14 -9.71 56 -37.13 l60.57 41.14 q-38.85 51.43 -101.14 67.43 q-62.29 16 -121.14 -10.86 + q-58.86 -26.86 -87.42 -84.58 q-28.57 -57.71 -14.86 -120.57 q13.71 -62.86 64 -103.43 q50.28 -40.57 114.28 -40.57 + ZM347.43 256 l-91.43 0 l0 109.71 l91.43 0 q22.86 0 38.86 -16 q16 -16 16 -38.85 q0 -22.86 -16 -38.86 q-16 -16 -38.86 -16 Z", + Fill = "#FF000000" + }; + + PlatformTV = new VectorImage + { + Height = 16, + Width = 16, + Data = + @"M768 804.57 q14.86 0 25.72 10.86 q10.86 10.86 10.86 25.71 q0 14.86 -10.86 25.71 q-10.86 10.86 -25.72 10.86 + l-512 0 q-14.86 0 -25.72 -10.86 q-10.85 -10.86 -10.85 -25.71 q0 -14.86 10.85 -25.71 q10.85 -10.86 25.72 -10.86 + l512 0 ZM877.71 0 q40 0 73.71 19.43 q33.72 19.43 53.14 53.15 q19.43 33.72 19.43 73.71 l0 438.85 q0 40 -19.43 73.72 + q-19.43 33.72 -53.14 53.14 q-33.71 19.43 -73.71 19.43 l-731.42 0 q-40 0 -73.71 -19.43 q-33.72 -19.43 -53.15 -53.14 + q-19.43 -33.72 -19.43 -73.72 l0 -438.85 q0 -40 19.43 -73.71 q19.43 -33.72 53.15 -53.15 q33.72 -19.43 73.71 -19.43 + l731.42 0 ZM877.71 73.14 l-731.42 0 q-27.43 0 -48.57 18.28 q-21.15 18.28 -24.58 46.86 l0 8 l0 438.85 + q0 27.43 18.28 48.58 q18.28 21.14 46.86 24.57 l8 0 l731.42 0 q27.43 0 48.57 -18.29 q21.14 -18.29 24.58 -46.86 + l0 -8 l0 -438.85 q0 -30.86 -21.14 -52 q-21.14 -21.14 -52 -21.14 ZM585.14 182.86 l109.72 274.28 l109.71 -274.28 + l73.14 0 l-146.28 365.71 l-73.14 0 l-116.58 -292.57 l-176 0 l0 292.57 l-73.14 0 l0 -292.57 l-146.28 0 l0 -73.14 l438.85 0 Z", + Fill = "#FF000000" + }; + } + + public VectorImage Play { get; private set; } + public VectorImage Like { get; private set; } + public VectorImage Favorite { get; private set; } + public VectorImage Share { get; private set; } + + public VectorImage CloudDownload { get; private set; } + public VectorImage Folder { get; private set; } + public VectorImage Downloading { get; private set; } + public VectorImage DownloadFinished { get; private set; } + + public VectorImage CoinIcon { get; private set; } + public VectorImage MoneyIcon { get; private set; } + public VectorImage BindingEmail { get; private set; } + public VectorImage BindingPhone { get; private set; } + + public VectorImage FavoriteOutline { get; private set; } + public VectorImage Subscription { get; private set; } + public VectorImage ToView { get; private set; } + public VectorImage History { get; private set; } + + public VectorImage VideoUp { get; private set; } + public VectorImage Channel { get; private set; } + public VectorImage Channel1 { get; private set; } + public VectorImage SeasonsSeries { get; private set; } + + public VectorImage PlatformIpad { get; private set; } + public VectorImage PlatformMobile { get; private set; } + public VectorImage PlatformPC { get; private set; } + public VectorImage PlatformTV { get; private set; } +} \ No newline at end of file diff --git a/DownKyi/Images/SystemIcon.cs b/DownKyi/Images/SystemIcon.cs new file mode 100644 index 0000000..06ee24d --- /dev/null +++ b/DownKyi/Images/SystemIcon.cs @@ -0,0 +1,114 @@ +namespace DownKyi.Images; + +public class SystemIcon +{ + private static SystemIcon instance; + + public static SystemIcon Instance() + { + if (instance == null) + { + instance = new SystemIcon(); + } + + return instance; + } + + private SystemIcon() + { + Close = new VectorImage + { + Height = 12, + Width = 12, + Data = + @"M25,23.9l-6.6-6.6c-0.3-0.3-0.9-0.3-1.1,0c-0.3,0.3-0.3,0.9,0,1.1l0,0l6.6,6.6l-6.6,6.6c-0.3,0.3-0.3,0.9,0,1.1 + c0.3,0.3,0.9,0.3,1.1,0l0,0l6.6-6.6l6.6,6.6c0.3,0.3,0.9,0.3,1.1,0.1c0.3-0.3,0.3-0.9,0.1-1.1c0,0,0,0-0.1-0.1L26.1,25l6.6-6.6 + c0.3-0.3,0.3-0.9,0-1.1c-0.3-0.3-0.9-0.3-1.1,0l0,0L25,23.9L25,23.9z", + Fill = "#FF000000" + }; + + Maximize = new VectorImage + { + Height = 12, + Width = 12, + Data = + @"M31.1,33H18.9c-1,0-1.9-0.9-1.9-1.9V18.9c0-1,0.9-1.9,1.9-1.9h12.3c1,0,1.9,0.9,1.9,1.9v12.3C33,32.1,32.1,33,31.1,33z + M18.9,18.3c-0.3,0-0.6,0.3-0.6,0.6v12.3c0,0.3,0.3,0.6,0.6,0.6h12.3c0.3,0,0.6-0.3,0.6-0.6V18.9c0-0.3-0.3-0.6-0.6-0.6 + C31.1,18.3,18.9,18.3,18.9,18.3z", + Fill = "#FF000000" + }; + + Minimize = new VectorImage + { + Height = 1.2, + Width = 12, + Data = + @"M17.8,25.8c-0.5,0-0.8-0.3-0.8-0.8s0.3-0.8,0.8-0.8h14.4c0.5,0,0.8,0.3,0.8,0.8s-0.3,0.8-0.8,0.8H17.8z", + Fill = "#FF000000" + }; + + Restore = new VectorImage + { + Height = 12, + Width = 12, + Data = + @"M29,33H18.3c-0.7,0-1.3-0.6-1.3-1.3V21c0-0.7,0.6-1.3,1.3-1.3H29c0.7,0,1.3,0.6,1.3,1.3v10.7C30.4,32.4,29.8,33,29,33z + M18.3,20.9c-0.1,0-0.1,0.1-0.1,0.1v10.7c0,0.1,0.1,0.1,0.1,0.1H29c0.1,0,0.1-0.1,0.1-0.1V21c0-0.1-0.1-0.1-0.1-0.1H18.3z + M31.7,30.4h-1.9v-1.2h1.9c0.1,0,0.1-0.1,0.1-0.1V18.3c0-0.1-0.1-0.1-0.1-0.1H21c-0.1,0-0.1,0.1-0.1,0.1v1.9h-1.2v-1.9 + c0-0.7,0.6-1.3,1.3-1.3h10.7c0.7,0,1.3,0.6,1.3,1.3v10.7C33,29.8,32.4,30.4,31.7,30.4z", + Fill = "#FF000000" + }; + + Skin = new VectorImage + { + Height = 12, + Width = 12, + Data = + @"M29.1,18.1l2.7,3.2l-1.3,1.6c-0.1-0.1-0.3-0.1-0.5-0.1c-0.6,0-1,0.5-1,1.2v8.1h-8.2v-8.1c0-0.7-0.5-1.2-1-1.2 + c-0.1,0-0.3,0-0.5,0.1l-1.3-1.6l2.7-3.2h0.8c0.7,0.9,2.4,1.5,3.3,1.5c0.9,0,2.6-0.4,3.3-1.5H29.1 M29.2,17h-0.9 + c-0.2,0-0.5,0.1-0.7,0.4c-0.5,0.5-1.8,1.1-2.6,1.1c-0.8,0-2.2-0.5-2.6-1.2c-0.2-0.1-0.5-0.3-0.7-0.3h-0.9c-0.2,0-0.5,0.1-0.6,0.3 + l-3.1,3.6c-0.1,0.3-0.1,0.7,0,0.8l1.8,2.2C19,24,19.3,24,19.4,24s0.2,0,0.3-0.1v-0.1h0.1c0,0,0.1,0,0.1,0.1v8.2 + c0,0.5,0.3,0.9,0.8,0.9h8.6c0.5,0,0.8-0.4,0.8-0.9v-8.2c0-0.1,0-0.1,0.1-0.1h0.1l0.1,0.1c0.1,0.1,0.2,0.1,0.3,0.1s0.2,0,0.3-0.1 + l1.8-2.2c0-0.1,0-0.5-0.1-0.8l-3.1-3.6C29.7,17.1,29.5,17,29.2,17z", + Fill = "#FF000000" + }; + + Info = new VectorImage + { + Height = 20, + Width = 20, + Data = @"M11 7h2v2h-2zm0 4h2v6h-2zm1-9C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 + 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8z", + Fill = "#FF00bcf2" + }; + + Warning = new VectorImage + { + Height = 20, + Width = 20, + Data = @"M12 5.99L19.53 19H4.47L12 5.99M2.74 18c-.77 1.33.19 3 1.73 3h15.06c1.54 0 2.5-1.67 1.73-3L13.73 + 4.99c-.77-1.33-2.69-1.33-3.46 0L2.74 18zM11 11v2c0 .55.45 1 1 1s1-.45 1-1v-2c0-.55-.45-1-1-1s-1 .45-1 1zm0 5h2v2h-2z", + Fill = "#FFffb900" + }; + + Error = new VectorImage + { + Height = 20, + Width = 20, + Data = @"M12 7c.55 0 1 .45 1 1v4c0 .55-.45 1-1 1s-1-.45-1-1V8c0-.55.45-1 1-1zm-.01-5C6.47 2 2 6.48 2 12s4.47 + 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 + 8-3.58 8-8 8zm1-3h-2v-2h2v2z", + Fill = "#FFd83b01" + }; + } + + public VectorImage Close { get; private set; } + public VectorImage Maximize { get; private set; } + public VectorImage Minimize { get; private set; } + public VectorImage Restore { get; private set; } + public VectorImage Skin { get; private set; } + + public VectorImage Info { get; private set; } + public VectorImage Warning { get; private set; } + public VectorImage Error { get; private set; } +} \ No newline at end of file diff --git a/DownKyi/Images/VectorImage.cs b/DownKyi/Images/VectorImage.cs new file mode 100644 index 0000000..fbdff96 --- /dev/null +++ b/DownKyi/Images/VectorImage.cs @@ -0,0 +1,38 @@ +using Prism.Mvvm; + +namespace DownKyi.Images; + +public class VectorImage : BindableBase +{ + private double width; + + public double Width + { + get => width; + set => SetProperty(ref width, value); + } + + private double height; + + public double Height + { + get => height; + set => SetProperty(ref height, value); + } + + private string data; + + public string Data + { + get => data; + set => SetProperty(ref data, value); + } + + private string fill; + + public string Fill + { + get => fill; + set => SetProperty(ref fill, value); + } +} \ No newline at end of file diff --git a/DownKyi/Languanges/Default.axaml b/DownKyi/Languanges/Default.axaml new file mode 100644 index 0000000..4a77d45 --- /dev/null +++ b/DownKyi/Languanges/Default.axaml @@ -0,0 +1,336 @@ + + + 哔哩下载姬 + 未知 + + + 关闭 + 最大化 + 最小化 + 还原 + 皮肤 + + + 登录 + 请输入B站网址链接或av、BV号等…… + 请输入B站视频播放地址…… + 设置 + 下载管理 + 工具箱 + + + 扫描二维码登录 + 请使用哔哩哔哩客户端 扫码登录 或扫码下载APP + 获取登录链接失败! + 密钥错误!尝试重新获取! + 已超时!尝试重新获取二维码! + 登录成功!(3秒后自动回到主页) + 未保存登录信息!(3秒后自动回到主页) + + + 我的个人空间退出登录 + 请稍等,马上就好~ + 等级 + 关注数 + 悄悄关注数 + 粉丝数 + 黑名单数 + 节操值 + 封禁状态 + 收藏夹 + 我的订阅 + 稍后再看 + 历史记录 + 正常 + 封停 + + + 个人空间 + 已关注 + 未关注 + 关注数 + 粉丝数 + 获赞数 + 播放数 + 阅读数 + 全部 + 投稿视频 + 频道 + 合集和列表 + 请稍等,马上就好~ + + + 收藏夹 + 个内容 + + + 播放: + 收藏: + UP主: + 投稿: + 收藏于: + + + 我的订阅 + 追番 + 追剧 + 尚未观看 + + + 历史记录 + 已看完 + 刚开始 + 看到 + + + 稍后再看 + + + 下载选中项 + 下载全部 + 请稍等,马上就好~ + + + 好友 + 关注 + 粉丝 + 请稍等,马上就好~ + 请稍等,马上就好~ + 全部关注 + 悄悄关注 + + + 复制封面图片 + 复制封面URL + 播放 + 弹幕 + 点赞 + 投币 + 收藏 + 分享 + 评论 + 番剧 + 电影 + 纪录片 + 国创 + 电视剧 + 综艺 + 课程 + 序号 + 名称 + 时长 + 音质 + 画质 + 视频编码 + 全选 + 搜索 + 搜索视频名称 + 解析 + 解析视频 + 下载选中项 + 下载全部 + 已经添加到下载列表~ + 已经下载完成~ + 没有选中项符合下载要求! + 成功添加了 + 项~ + + + 正在下载 + 已下载 + 下载完成 + 音频 + 视频 + 弹幕 + 字幕 + 封面 + 正在解析…… + 下载中…… + 混流中…… + 暂停中…… + 等待中…… + 下载失败 + 正在下载 + 个视频! + 全部暂停 + 全部开始 + 全部删除 + 已下载 + 个视频! + 按下载先后排序 + 按序号排序 + 清空所有记录 + 开始 + 暂停 + 重试 + 移除 + 打开文件夹 + 播放 + + + 按回车键应用设置 + 基本 + 下载完成后的动作: + + 关闭程序 + 关闭计算机 + 监听剪贴板 + 视频自动解析 + 视频解析范围: + 解析后自动下载已解析视频 + 网络 + 启用https(若下载器提示SSL错误,则关闭此项) + UserAgent: + 选择下载器(重启生效): + 内建下载器 + Aria2下载器 + 自定义Aria2下载器 + Aria服务器地址: + Aria服务器端口: + Aria服务器Token: + Aria日志等级: + Aria同时下载数: + Aria最大线程数: + Aria下载速度限制(KB/s) + 全局下载速度限制[0: 无限制] + 单任务下载速度限制[0: 无限制] + Aria文件预分配: + 使用Http代理 + 代理地址: + 端口: + 同时下载数: + 最大线程数: + 视频 + 优先下载的视频编码: + 优先下载的视频画质: + 优先下载的视频音质: + 下载FLV视频后转码为mp4 + 使用默认下载目录 + 默认下载目录: + 默认将文件下载到该文件夹中 + 更改目录 + 文件命名格式 + 文件名: + 可选字段: + 序号 + 视频章节 + 视频标题 + 分P标题 + 视频分区 + 音质 + 画质 + 视频编码 + 视频发布时间 + 空格 + UP主ID + UP主昵称 + 恢复默认 + 时间格式: + 序号格式: + 自然数 + 前导零填充 + 弹幕 + 按类型屏蔽 + 顶部 + 底部 + 滚动 + 分辨率: + 字体名称: + 字体大小: + 限制行数: + 布局算法: + 速度同步 + 每一条滚动弹幕的移动速度都是相同的 + 速度异步 + 弹幕滚动速度取决于它的文本长度 + 关于 + 访问主页 + 当前版本: + 检查更新 + 意见反馈 + 接收测试版更新 + 启动时检查更新 + 设置已更新~ + 设置失败! + 第三方 + 名称 + 作者 + 版本 + 许可证 + 免责申明 + 1. 本软件只提供视频解析,不提供任何资源上传、存储到服务器的功能。 + 2. 本软件仅解析来自B站的内容,不会对解析到的音视频进行二次编码,部分视频会进行有限的格式转换、拼接等操作。 + 3. 本软件解析得到的所有内容均来自B站UP主上传、分享,其版权均归原作者所有。内容提供者、上传者(UP主)应对其提供、上传的内容承担全部责任。 + 4. 本软件提供的所有资源,仅可用作学习交流使用,未经原作者授权,禁止用于其他用途。请在下载24小时内删除。为尊重作者版权,请前往资源的原始发布网站观看,支持原创,谢谢。 + 5. 任何涉及商业盈利目的均不得使用,否则产生的一切后果将由您自己承担。 + 6. 因使用本软件产生的版权问题,软件作者概不负责。 + + + B站助手 + AV和BV互转 + AV号形如"av123",BV号形如"BVxxx"。 + AVID: + BVID: + 访问网页 + 弹幕中的userID: + 查询弹幕发送者-> + 去水印 + 视频地址: + 选择视频 + 水印尺寸与位置(左上角为原点,单位:像素) + 宽: + 高: + X: + Y: + 请等待当前任务完成! + 没有选择视频! + 请输入正确的宽度(正整数)! + 请输入正确的高度(正整数)! + 请输入正确的X(正整数)! + 请输入正确的Y(正整数)! + 输出信息: + 音视频分离 + 提取音频 + 提取视频 + + + 信息 + 警告 + 错误 + 确定 + 取消 + 此项需重启生效,您确定要重新启动吗? + 您确定要删除吗? + 请选择文件夹 + 路径错误! + + + 下载设置 + 位置: + 浏览 + 盘剩余空间: + 下载内容: + 下载内容 + 所有 + 音频 + 视频 + 弹幕 + 字幕 + 封面 + 设此文件夹为默认下载文件夹 + 选中后下次将不会弹出此窗口 + 下载 + 文件夹路径不能为空 + 该磁盘不存在 + + + 选择解析项 + + 解析选中项 + 解析当前页视频 + 解析所有视频 + 设为默认,下次不再弹出 + + \ No newline at end of file diff --git a/DownKyi/Models/AppInfo.cs b/DownKyi/Models/AppInfo.cs new file mode 100644 index 0000000..cca97a5 --- /dev/null +++ b/DownKyi/Models/AppInfo.cs @@ -0,0 +1,51 @@ +using System; +using System.Text.RegularExpressions; + +namespace DownKyi.Models; + +public class AppInfo +{ + public string Name { get; } = "哔哩下载姬"; + public int VersionCode { get; } + public string VersionName { get; } + + const int a = 1; + const int b = 0; + const int c = 0; + + public AppInfo() + { + VersionCode = a * 10000 + b * 100 + c; + +#if DEBUG + VersionName = $"{a}.{b}.{c}-debug"; +#else + VersionName = $"{a}.{b}.{c}"; +#endif + } + + public static int VersionNameToCode(string versionName) + { + int code = 0; + + var isMatch = Regex.IsMatch(versionName, @"^v?([1-9]\d|\d).([1-9]\d|\d).([1-9]\d|\d)$"); + if (!isMatch) + { + return 0; + } + + string pattern = @"([1-9]\d|\d)"; + var m = Regex.Matches(versionName, pattern); + if (m.Count == 3) + { + int i = 2; + foreach (var item in m) + { + code += int.Parse(item.ToString()) * (int)Math.Pow(100, i); + i--; + } + } + + return code; + } +} \ No newline at end of file diff --git a/DownKyi/Models/DownloadBase.cs b/DownKyi/Models/DownloadBase.cs new file mode 100644 index 0000000..86779c9 --- /dev/null +++ b/DownKyi/Models/DownloadBase.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections.Generic; +using DownKyi.Core.BiliApi.BiliUtils; + +namespace DownKyi.Models; + +[Serializable] +public class DownloadBase +{ + public DownloadBase() + { + // 唯一id + Uuid = Guid.NewGuid().ToString("N"); + + // 初始化需要下载的内容 + NeedDownloadContent = new Dictionary + { + { "downloadAudio", true }, + { "downloadVideo", true }, + { "downloadDanmaku", true }, + { "downloadSubtitle", true }, + { "downloadCover", true } + }; + } + + // 此条下载项的id + public string Uuid { get; } + + // 需要下载的内容 + public Dictionary NeedDownloadContent { get; set; } + + // 视频的id + public string Bvid { get; set; } + public long Avid { get; set; } + public long Cid { get; set; } + public long EpisodeId { get; set; } + + // 视频封面的url + public string CoverUrl { get; set; } + + // 视频page的封面的url + public string PageCoverUrl { get; set; } + + // 分区id + public int ZoneId { get; set; } + + // 视频序号 + public int Order { get; set; } + + // 视频主标题 + public string MainTitle { get; set; } + + // 视频标题 + public string Name { get; set; } + + // 时长 + public string Duration { get; set; } + + // 视频编码名称,AVC、HEVC + public string VideoCodecName { get; set; } + + // 视频画质 + public Quality Resolution { get; set; } + + // 音频编码 + public Quality AudioCodec { get; set; } + + // 文件路径,不包含扩展名,所有内容均以此路径下载 + public string FilePath { get; set; } + + // 文件大小 + public string FileSize { get; set; } +} \ No newline at end of file diff --git a/DownKyi/Models/DownloadStatus.cs b/DownKyi/Models/DownloadStatus.cs new file mode 100644 index 0000000..c021c91 --- /dev/null +++ b/DownKyi/Models/DownloadStatus.cs @@ -0,0 +1,14 @@ +namespace DownKyi.Models; + +public enum DownloadStatus +{ + NOT_STARTED, // 未开始,从未开始下载 + WAIT_FOR_DOWNLOAD, // 等待下载,下载过,但是启动本次下载周期未开始,如重启程序后未开始 + PAUSE_STARTED, // 暂停启动下载 + PAUSE, // 暂停 + + //PAUSE_TO_WAIT, // 暂停后等待 + DOWNLOADING, // 下载中 + DOWNLOAD_SUCCEED, // 下载成功 + DOWNLOAD_FAILED, // 下载失败 +} \ No newline at end of file diff --git a/DownKyi/Models/Downloaded.cs b/DownKyi/Models/Downloaded.cs new file mode 100644 index 0000000..cf492e9 --- /dev/null +++ b/DownKyi/Models/Downloaded.cs @@ -0,0 +1,29 @@ +using System; + +namespace DownKyi.Models; + +[Serializable] +public class Downloaded // : DownloadBase +{ + public Downloaded() : base() + { + } + + // 下载速度 + public string MaxSpeedDisplay { get; set; } + + // 完成时间戳 + public long FinishedTimestamp { get; set; } + + public void SetFinishedTimestamp(long finishedTimestamp) + { + FinishedTimestamp = finishedTimestamp; + + DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1)); // 当地时区 + DateTime dateTime = startTime.AddSeconds(finishedTimestamp); + FinishedTime = dateTime.ToString("yyyy-MM-dd HH:mm:ss"); + } + + // 完成时间 + public string FinishedTime { get; set; } +} \ No newline at end of file diff --git a/DownKyi/Models/Downloading.cs b/DownKyi/Models/Downloading.cs new file mode 100644 index 0000000..2a5528b --- /dev/null +++ b/DownKyi/Models/Downloading.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using DownKyi.Core.BiliApi.VideoStream; + +namespace DownKyi.Models; + +[Serializable] +public class Downloading // : DownloadBase +{ + public Downloading() : base() + { + // 初始化下载的文件列表 + DownloadFiles = new Dictionary(); + DownloadedFiles = new List(); + } + + // Aria相关 + public string Gid { get; set; } + + // 下载的文件 + public Dictionary DownloadFiles { get; set; } + + // 已下载的文件 + public List DownloadedFiles { get; set; } + + // 视频类别 + public PlayStreamType PlayStreamType { get; set; } + + // 下载状态 + public DownloadStatus DownloadStatus { get; set; } + + // 正在下载内容(音频、视频、弹幕、字幕、封面) + public string DownloadContent { get; set; } + + // 下载状态显示 + public string DownloadStatusTitle { get; set; } + + // 下载进度 + public float Progress { get; set; } + + // 已下载大小/文件大小 + public string DownloadingFileSize { get; set; } + + // 下载的最高速度 + public long MaxSpeed { get; set; } + + // 下载速度 + public string SpeedDisplay { get; set; } +} \ No newline at end of file diff --git a/DownKyi/Models/OrderFormatDisplay.cs b/DownKyi/Models/OrderFormatDisplay.cs new file mode 100644 index 0000000..8438b89 --- /dev/null +++ b/DownKyi/Models/OrderFormatDisplay.cs @@ -0,0 +1,9 @@ +using DownKyi.Core.Settings; + +namespace DownKyi.Models; + +public class OrderFormatDisplay +{ + public string Name { get; set; } + public OrderFormat OrderFormat { get; set; } +} \ No newline at end of file diff --git a/DownKyi/Models/ParseScopeDisplay.cs b/DownKyi/Models/ParseScopeDisplay.cs new file mode 100644 index 0000000..9527b93 --- /dev/null +++ b/DownKyi/Models/ParseScopeDisplay.cs @@ -0,0 +1,9 @@ +using DownKyi.Core.Settings; + +namespace DownKyi.Models; + +public class ParseScopeDisplay +{ + public string Name { get; set; } + public ParseScope ParseScope { get; set; } +} \ No newline at end of file diff --git a/DownKyi/Program.cs b/DownKyi/Program.cs new file mode 100644 index 0000000..82691fa --- /dev/null +++ b/DownKyi/Program.cs @@ -0,0 +1,26 @@ +using Avalonia; +using Avalonia.ReactiveUI; +using System; + +namespace DownKyi; + +sealed class Program +{ + // Initialization code. Don't use any Avalonia, third-party APIs or any + // SynchronizationContext-reliant code before AppMain is called: things aren't initialized + // yet and stuff might break. + [STAThread] + public static void Main(string[] args) => BuildAvaloniaApp() + .StartWithClassicDesktopLifetime(args); + + // Avalonia configuration, don't remove; also used by visual designer. + public static AppBuilder BuildAvaloniaApp() + => AppBuilder.Configure() + .UsePlatformDetect() + .With(new X11PlatformOptions { EnableMultiTouch = true, UseDBusMenu = true, }) + .WithInterFont() +#if DEBUG + .LogToTrace() +#endif + .UseReactiveUI(); +} \ No newline at end of file diff --git a/DownKyi/Resources/backgound/9-绿荫秘境.png b/DownKyi/Resources/backgound/9-绿荫秘境.png new file mode 100644 index 0000000..dcc5c10 Binary files /dev/null and b/DownKyi/Resources/backgound/9-绿荫秘境.png differ diff --git a/DownKyi/Resources/channel.png b/DownKyi/Resources/channel.png new file mode 100644 index 0000000..9f532cb Binary files /dev/null and b/DownKyi/Resources/channel.png differ diff --git a/DownKyi/Resources/checked.png b/DownKyi/Resources/checked.png new file mode 100644 index 0000000..d011e83 Binary files /dev/null and b/DownKyi/Resources/checked.png differ diff --git a/DownKyi/Resources/default_header.jpg b/DownKyi/Resources/default_header.jpg new file mode 100644 index 0000000..5e5ea0b Binary files /dev/null and b/DownKyi/Resources/default_header.jpg differ diff --git a/DownKyi/Resources/favicon.ico b/DownKyi/Resources/favicon.ico new file mode 100644 index 0000000..0145cb9 Binary files /dev/null and b/DownKyi/Resources/favicon.ico differ diff --git a/DownKyi/Resources/level/lv0.png b/DownKyi/Resources/level/lv0.png new file mode 100644 index 0000000..e7a5ae1 Binary files /dev/null and b/DownKyi/Resources/level/lv0.png differ diff --git a/DownKyi/Resources/level/lv1.png b/DownKyi/Resources/level/lv1.png new file mode 100644 index 0000000..510b9b2 Binary files /dev/null and b/DownKyi/Resources/level/lv1.png differ diff --git a/DownKyi/Resources/level/lv2.png b/DownKyi/Resources/level/lv2.png new file mode 100644 index 0000000..bf66798 Binary files /dev/null and b/DownKyi/Resources/level/lv2.png differ diff --git a/DownKyi/Resources/level/lv3.png b/DownKyi/Resources/level/lv3.png new file mode 100644 index 0000000..f08ca24 Binary files /dev/null and b/DownKyi/Resources/level/lv3.png differ diff --git a/DownKyi/Resources/level/lv4.png b/DownKyi/Resources/level/lv4.png new file mode 100644 index 0000000..1e09484 Binary files /dev/null and b/DownKyi/Resources/level/lv4.png differ diff --git a/DownKyi/Resources/level/lv5.png b/DownKyi/Resources/level/lv5.png new file mode 100644 index 0000000..8276e09 Binary files /dev/null and b/DownKyi/Resources/level/lv5.png differ diff --git a/DownKyi/Resources/level/lv6.png b/DownKyi/Resources/level/lv6.png new file mode 100644 index 0000000..f2e6645 Binary files /dev/null and b/DownKyi/Resources/level/lv6.png differ diff --git a/DownKyi/Resources/level/lv7.png b/DownKyi/Resources/level/lv7.png new file mode 100644 index 0000000..224ff01 Binary files /dev/null and b/DownKyi/Resources/level/lv7.png differ diff --git a/DownKyi/Resources/level/lv8.png b/DownKyi/Resources/level/lv8.png new file mode 100644 index 0000000..9eca702 Binary files /dev/null and b/DownKyi/Resources/level/lv8.png differ diff --git a/DownKyi/Resources/level/lv9.png b/DownKyi/Resources/level/lv9.png new file mode 100644 index 0000000..8aac354 Binary files /dev/null and b/DownKyi/Resources/level/lv9.png differ diff --git a/DownKyi/Resources/loading/loading.gif b/DownKyi/Resources/loading/loading.gif new file mode 100644 index 0000000..31f8504 Binary files /dev/null and b/DownKyi/Resources/loading/loading.gif differ diff --git a/DownKyi/Resources/login/login_top_bar.png b/DownKyi/Resources/login/login_top_bar.png new file mode 100644 index 0000000..68dc5d3 Binary files /dev/null and b/DownKyi/Resources/login/login_top_bar.png differ diff --git a/DownKyi/Resources/login/qrcode_login_2233.png b/DownKyi/Resources/login/qrcode_login_2233.png new file mode 100644 index 0000000..3d9ff56 Binary files /dev/null and b/DownKyi/Resources/login/qrcode_login_2233.png differ diff --git a/DownKyi/Resources/login/qrcode_login_tip.png b/DownKyi/Resources/login/qrcode_login_tip.png new file mode 100644 index 0000000..177018b Binary files /dev/null and b/DownKyi/Resources/login/qrcode_login_tip.png differ diff --git a/DownKyi/Resources/login/scan_succeed.png b/DownKyi/Resources/login/scan_succeed.png new file mode 100644 index 0000000..2e3f72e Binary files /dev/null and b/DownKyi/Resources/login/scan_succeed.png differ diff --git a/DownKyi/Resources/no-data.png b/DownKyi/Resources/no-data.png new file mode 100644 index 0000000..7f1b5c4 Binary files /dev/null and b/DownKyi/Resources/no-data.png differ diff --git a/DownKyi/Resources/nodata02.png b/DownKyi/Resources/nodata02.png new file mode 100644 index 0000000..301f3df Binary files /dev/null and b/DownKyi/Resources/nodata02.png differ diff --git a/DownKyi/Resources/play.png b/DownKyi/Resources/play.png new file mode 100644 index 0000000..6377dca Binary files /dev/null and b/DownKyi/Resources/play.png differ diff --git a/DownKyi/Resources/sex/female.png b/DownKyi/Resources/sex/female.png new file mode 100644 index 0000000..abffaa5 Binary files /dev/null and b/DownKyi/Resources/sex/female.png differ diff --git a/DownKyi/Resources/sex/male.png b/DownKyi/Resources/sex/male.png new file mode 100644 index 0000000..3c3044c Binary files /dev/null and b/DownKyi/Resources/sex/male.png differ diff --git a/DownKyi/Resources/time.png b/DownKyi/Resources/time.png new file mode 100644 index 0000000..25c18ed Binary files /dev/null and b/DownKyi/Resources/time.png differ diff --git a/DownKyi/Resources/video-placeholder.png b/DownKyi/Resources/video-placeholder.png new file mode 100644 index 0000000..157a110 Binary files /dev/null and b/DownKyi/Resources/video-placeholder.png differ diff --git a/DownKyi/Services/AlertService.cs b/DownKyi/Services/AlertService.cs new file mode 100644 index 0000000..69f9d43 --- /dev/null +++ b/DownKyi/Services/AlertService.cs @@ -0,0 +1,74 @@ +using DownKyi.Images; +using DownKyi.Utils; +using DownKyi.ViewModels.Dialogs; +using Prism.Services.Dialogs; + +namespace DownKyi.Services; + +public class AlertService +{ + private readonly IDialogService dialogService; + + public AlertService(IDialogService dialogService) + { + this.dialogService = dialogService; + } + + /// + /// 显示一个信息弹窗 + /// + /// + /// + /// + public ButtonResult ShowInfo(string message, int buttonNumber = 2) + { + VectorImage image = SystemIcon.Instance().Info; + string title = DictionaryResource.GetString("Info"); + return ShowMessage(image, title, message, buttonNumber); + } + + /// + /// 显示一个警告弹窗 + /// + /// + /// + /// + public ButtonResult ShowWarning(string message, int buttonNumber = 1) + { + VectorImage image = SystemIcon.Instance().Warning; + string title = DictionaryResource.GetString("Warning"); + return ShowMessage(image, title, message, buttonNumber); + } + + /// + /// 显示一个错误弹窗 + /// + /// + /// + public ButtonResult ShowError(string message) + { + VectorImage image = SystemIcon.Instance().Error; + string title = DictionaryResource.GetString("Error"); + return ShowMessage(image, title, message, 1); + } + + public ButtonResult ShowMessage(VectorImage image, string type, string message, int buttonNumber) + { + ButtonResult result = ButtonResult.None; + if (dialogService == null) + { + return result; + } + + DialogParameters param = new DialogParameters + { + { "image", image }, + { "title", type }, + { "message", message }, + { "button_number", buttonNumber } + }; + dialogService.ShowDialog(ViewAlertDialogViewModel.Tag, param, + buttonResult => { result = buttonResult.Result; }); + return result; + } +} \ No newline at end of file diff --git a/DownKyi/Services/BangumiInfoService.cs b/DownKyi/Services/BangumiInfoService.cs new file mode 100644 index 0000000..bdab375 --- /dev/null +++ b/DownKyi/Services/BangumiInfoService.cs @@ -0,0 +1,336 @@ +using System; +using System.Collections.Generic; +using System.Text.RegularExpressions; +using DownKyi.Core.BiliApi.Bangumi; +using DownKyi.Core.BiliApi.Bangumi.Models; +using DownKyi.Core.BiliApi.BiliUtils; +using DownKyi.Core.BiliApi.Models; +using DownKyi.Core.BiliApi.VideoStream; +using DownKyi.Core.BiliApi.VideoStream.Models; +using DownKyi.Core.Settings; +using DownKyi.Core.Storage; +using DownKyi.Core.Utils; +using DownKyi.Utils; +using DownKyi.ViewModels.PageViewModels; + +namespace DownKyi.Services; + +public class BangumiInfoService : IInfoService +{ + private readonly BangumiSeason bangumiSeason; + + public BangumiInfoService(string input) + { + if (input == null) + { + return; + } + + if (ParseEntrance.IsBangumiSeasonId(input) || ParseEntrance.IsBangumiSeasonUrl(input)) + { + long seasonId = ParseEntrance.GetBangumiSeasonId(input); + bangumiSeason = BangumiInfo.BangumiSeasonInfo(seasonId); + } + + if (ParseEntrance.IsBangumiEpisodeId(input) || ParseEntrance.IsBangumiEpisodeUrl(input)) + { + long episodeId = ParseEntrance.GetBangumiEpisodeId(input); + bangumiSeason = BangumiInfo.BangumiSeasonInfo(-1, episodeId); + } + + if (ParseEntrance.IsBangumiMediaId(input) || ParseEntrance.IsBangumiMediaUrl(input)) + { + long mediaId = ParseEntrance.GetBangumiMediaId(input); + BangumiMedia bangumiMedia = BangumiInfo.BangumiMediaInfo(mediaId); + bangumiSeason = BangumiInfo.BangumiSeasonInfo(bangumiMedia.SeasonId); + } + } + + /// + /// 获取视频剧集 + /// + /// + public List GetVideoPages() + { + List pages = new List(); + if (bangumiSeason == null) + { + return pages; + } + + if (bangumiSeason.Episodes == null) + { + return pages; + } + + if (bangumiSeason.Episodes.Count == 0) + { + return pages; + } + + int order = 0; + foreach (BangumiEpisode episode in bangumiSeason.Episodes) + { + order++; + + // 标题 + string name; + + // 判断title是否为数字,如果是,则将share_copy作为name,否则将title作为name + //if (int.TryParse(episode.Title, out int result)) + //{ + // name = Regex.Replace(episode.ShareCopy, @"《.*?》", ""); + // //name = episode.ShareCopy; + //} + //else + //{ + // if (episode.LongTitle != null && episode.LongTitle != "") + // { + // name = $"{episode.Title} {episode.LongTitle}"; + // } + // else + // { + // name = episode.Title; + // } + //} + + // 将share_copy作为name,删除《》中的标题 + name = Regex.Replace(episode.ShareCopy, @"^《.*?》", ""); + + // 删除前后空白符 + name = name.Trim(); + + VideoPage page = new VideoPage + { + Avid = episode.Aid, + Bvid = episode.Bvid, + Cid = episode.Cid, + EpisodeId = -1, + FirstFrame = episode.Cover, + Order = order, + Name = name, + Duration = "N/A" + }; + + // UP主信息 + if (bangumiSeason.UpInfo != null) + { + page.Owner = new VideoOwner + { + Name = bangumiSeason.UpInfo.Name, + Face = bangumiSeason.UpInfo.Avatar, + Mid = bangumiSeason.UpInfo.Mid, + }; + } + else + { + page.Owner = new VideoOwner + { + Name = "", + Face = "", + Mid = -1, + }; + } + + // 文件命名中的时间格式 + string timeFormat = SettingsManager.GetInstance().GetFileNamePartTimeFormat(); + // 视频发布时间 + DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1)); // 当地时区 + DateTime dateTime = startTime.AddSeconds(episode.PubTime); + page.PublishTime = dateTime.ToString(timeFormat); + + pages.Add(page); + } + + return pages; + } + + /// + /// 获取视频章节与剧集 + /// + /// + public List GetVideoSections(bool noUgc = false) + { + if (bangumiSeason == null) + { + return null; + } + + List videoSections = new List + { + new VideoSection + { + Id = bangumiSeason.Positive.Id, + Title = bangumiSeason.Positive.Title, + IsSelected = true, + VideoPages = GetVideoPages() + } + }; + + // 不需要其他季或花絮内容 + if (noUgc) + { + return videoSections; + } + + if (bangumiSeason.Section == null) + { + return null; + } + + if (bangumiSeason.Section.Count == 0) + { + return null; + } + + foreach (BangumiSection section in bangumiSeason.Section) + { + List pages = new List(); + int order = 0; + foreach (BangumiEpisode episode in section.Episodes) + { + order++; + + // 标题 + string name = episode.LongTitle != null && episode.LongTitle != "" + ? $"{episode.Title} {episode.LongTitle}" + : episode.Title; + VideoPage page = new VideoPage + { + Avid = episode.Aid, + Bvid = episode.Bvid, + Cid = episode.Cid, + EpisodeId = -1, + FirstFrame = episode.Cover, + Order = order, + Name = name, + Duration = "N/A" + }; + + // UP主信息 + if (bangumiSeason.UpInfo != null) + { + page.Owner = new VideoOwner + { + Name = bangumiSeason.UpInfo.Name, + Face = bangumiSeason.UpInfo.Avatar, + Mid = bangumiSeason.UpInfo.Mid, + }; + } + else + { + page.Owner = new VideoOwner + { + Name = "", + Face = "", + Mid = -1, + }; + } + + // 文件命名中的时间格式 + string timeFormat = SettingsManager.GetInstance().GetFileNamePartTimeFormat(); + // 视频发布时间 + DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1)); // 当地时区 + DateTime dateTime = startTime.AddSeconds(episode.PubTime); + page.PublishTime = dateTime.ToString(timeFormat); + + pages.Add(page); + } + + VideoSection videoSection = new VideoSection + { + Id = section.Id, + Title = section.Title, + VideoPages = pages + }; + videoSections.Add(videoSection); + } + + return videoSections; + } + + /// + /// 获取视频流的信息,从VideoPage返回 + /// + /// + public void GetVideoStream(VideoPage page) + { + PlayUrl playUrl = VideoStream.GetBangumiPlayUrl(page.Avid, page.Bvid, page.Cid); + Utils.VideoPageInfo(playUrl, page); + } + + /// + /// 获取视频信息 + /// + /// + public VideoInfoView GetVideoView() + { + if (bangumiSeason == null) + { + return null; + } + + // 查询、保存封面 + // 将SeasonId保存到avid字段中 + // 每集封面的cid保存到cid字段,EpisodeId保存到bvid字段中 + StorageCover storageCover = new StorageCover(); + string coverUrl = bangumiSeason.Cover; + string cover = storageCover.GetCover(bangumiSeason.SeasonId, "bangumi", -1, coverUrl); + + // 获取用户头像 + string upName; + string header; + if (bangumiSeason.UpInfo != null) + { + upName = bangumiSeason.UpInfo.Name; + + StorageHeader storageHeader = new StorageHeader(); + header = storageHeader.GetHeader(bangumiSeason.UpInfo.Mid, bangumiSeason.UpInfo.Name, + bangumiSeason.UpInfo.Avatar); + } + else + { + upName = ""; + header = null; + } + + // 为videoInfoView赋值 + VideoInfoView videoInfoView = new VideoInfoView(); + App.PropertyChangeAsync(new Action(() => + { + videoInfoView.CoverUrl = coverUrl; + + videoInfoView.Cover = cover == null ? null : ImageHelper.LoadFromResource(new Uri(cover)); + videoInfoView.Title = bangumiSeason.Title; + + // 分区id + videoInfoView.TypeId = BangumiType.TypeId[bangumiSeason.Type]; + + videoInfoView.VideoZone = DictionaryResource.GetString(BangumiType.Type[bangumiSeason.Type]); + + videoInfoView.PlayNumber = Format.FormatNumber(bangumiSeason.Stat.Views); + videoInfoView.DanmakuNumber = Format.FormatNumber(bangumiSeason.Stat.Danmakus); + videoInfoView.LikeNumber = Format.FormatNumber(bangumiSeason.Stat.Likes); + videoInfoView.CoinNumber = Format.FormatNumber(bangumiSeason.Stat.Coins); + videoInfoView.FavoriteNumber = Format.FormatNumber(bangumiSeason.Stat.Favorites); + videoInfoView.ShareNumber = Format.FormatNumber(bangumiSeason.Stat.Share); + videoInfoView.ReplyNumber = Format.FormatNumber(bangumiSeason.Stat.Reply); + videoInfoView.Description = bangumiSeason.Evaluate; + + videoInfoView.UpName = upName; + if (header != null) + { + StorageHeader storageHeader = new StorageHeader(); + videoInfoView.UpHeader = storageHeader.GetHeaderThumbnail(header, 48, 48); + + videoInfoView.UpperMid = bangumiSeason.UpInfo.Mid; + } + else + { + videoInfoView.UpHeader = null; + } + })); + + return videoInfoView; + } +} \ No newline at end of file diff --git a/DownKyi/Services/CheeseInfoService.cs b/DownKyi/Services/CheeseInfoService.cs new file mode 100644 index 0000000..a6daa5e --- /dev/null +++ b/DownKyi/Services/CheeseInfoService.cs @@ -0,0 +1,209 @@ +using System; +using System.Collections.Generic; +using DownKyi.Core.BiliApi.BiliUtils; +using DownKyi.Core.BiliApi.Cheese; +using DownKyi.Core.BiliApi.Cheese.Models; +using DownKyi.Core.BiliApi.Models; +using DownKyi.Core.BiliApi.VideoStream; +using DownKyi.Core.BiliApi.VideoStream.Models; +using DownKyi.Core.Settings; +using DownKyi.Core.Storage; +using DownKyi.Core.Utils; +using DownKyi.Utils; +using DownKyi.ViewModels.PageViewModels; + +namespace DownKyi.Services; + +public class CheeseInfoService : IInfoService +{ + private readonly CheeseView cheeseView; + + public CheeseInfoService(string input) + { + if (input == null) + { + return; + } + + if (ParseEntrance.IsCheeseSeasonUrl(input)) + { + long seasonId = ParseEntrance.GetCheeseSeasonId(input); + cheeseView = CheeseInfo.CheeseViewInfo(seasonId); + } + + if (ParseEntrance.IsCheeseEpisodeUrl(input)) + { + long episodeId = ParseEntrance.GetCheeseEpisodeId(input); + cheeseView = CheeseInfo.CheeseViewInfo(-1, episodeId); + } + } + + /// + /// 获取视频剧集 + /// + /// + public List GetVideoPages() + { + List pages = new List(); + if (cheeseView == null) + { + return pages; + } + + if (cheeseView.Episodes == null) + { + return pages; + } + + if (cheeseView.Episodes.Count == 0) + { + return pages; + } + + int order = 0; + foreach (CheeseEpisode episode in cheeseView.Episodes) + { + order++; + string name = episode.Title; + + string duration = Format.FormatDuration(episode.Duration - 1); + + VideoPage page = new VideoPage + { + Avid = episode.Aid, + Bvid = null, + Cid = episode.Cid, + EpisodeId = episode.Id, + FirstFrame = episode.Cover, + Order = order, + Name = name, + Duration = "N/A" + }; + + // UP主信息 + if (cheeseView.UpInfo != null) + { + page.Owner = new VideoOwner + { + Name = cheeseView.UpInfo.Name, + Face = cheeseView.UpInfo.Avatar, + Mid = cheeseView.UpInfo.Mid, + }; + } + else + { + page.Owner = new VideoOwner + { + Name = "", + Face = "", + Mid = -1, + }; + } + + // 文件命名中的时间格式 + string timeFormat = SettingsManager.GetInstance().GetFileNamePartTimeFormat(); + // 视频发布时间 + DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1)); // 当地时区 + DateTime dateTime = startTime.AddSeconds(episode.ReleaseDate); + page.PublishTime = dateTime.ToString(timeFormat); + + pages.Add(page); + } + + return pages; + } + + /// + /// 获取视频章节与剧集 + /// + /// + public List GetVideoSections(bool noUgc = false) + { + return null; + } + + /// + /// 获取视频流的信息,从VideoPage返回 + /// + /// + public void GetVideoStream(VideoPage page) + { + PlayUrl playUrl = VideoStream.GetCheesePlayUrl(page.Avid, page.Bvid, page.Cid, page.EpisodeId); + Utils.VideoPageInfo(playUrl, page); + } + + /// + /// 获取视频信息 + /// + /// + public VideoInfoView GetVideoView() + { + if (cheeseView == null) + { + return null; + } + + // 查询、保存封面 + // 将SeasonId保存到avid字段中 + // 每集封面的cid保存到cid字段,EpisodeId保存到bvid字段中 + StorageCover storageCover = new StorageCover(); + string coverUrl = cheeseView.Cover; + string cover = storageCover.GetCover(cheeseView.SeasonId, "cheese", -1, coverUrl); + + // 获取用户头像 + string upName; + string header; + if (cheeseView.UpInfo != null) + { + upName = cheeseView.UpInfo.Name; + StorageHeader storageHeader = new StorageHeader(); + header = storageHeader.GetHeader(cheeseView.UpInfo.Mid, cheeseView.UpInfo.Name, cheeseView.UpInfo.Avatar); + } + else + { + upName = ""; + header = null; + } + + // 为videoInfoView赋值 + VideoInfoView videoInfoView = new VideoInfoView(); + App.PropertyChangeAsync(new Action(() => + { + videoInfoView.CoverUrl = coverUrl; + + videoInfoView.Cover = cover == null ? null : ImageHelper.LoadFromResource(new Uri(cover)); + videoInfoView.Title = cheeseView.Title; + + // 分区id + // 课堂的type id B站没有定义,这里自定义为-10 + videoInfoView.TypeId = -10; + + videoInfoView.VideoZone = DictionaryResource.GetString("Cheese"); + videoInfoView.CreateTime = ""; + + videoInfoView.PlayNumber = Format.FormatNumber(cheeseView.Stat.Play); + videoInfoView.DanmakuNumber = Format.FormatNumber(0); + videoInfoView.LikeNumber = Format.FormatNumber(0); + videoInfoView.CoinNumber = Format.FormatNumber(0); + videoInfoView.FavoriteNumber = Format.FormatNumber(0); + videoInfoView.ShareNumber = Format.FormatNumber(0); + videoInfoView.ReplyNumber = Format.FormatNumber(0); + videoInfoView.Description = cheeseView.Subtitle; + + videoInfoView.UpName = upName; + if (header != null) + { + StorageHeader storageHeader = new StorageHeader(); + videoInfoView.UpHeader = storageHeader.GetHeaderThumbnail(header, 48, 48); + + videoInfoView.UpperMid = cheeseView.UpInfo.Mid; + } + else + { + videoInfoView.UpHeader = null; + } + })); + + return videoInfoView; + } +} \ No newline at end of file diff --git a/DownKyi/Services/Download/AddToDownloadService.cs b/DownKyi/Services/Download/AddToDownloadService.cs new file mode 100644 index 0000000..1fb94cd --- /dev/null +++ b/DownKyi/Services/Download/AddToDownloadService.cs @@ -0,0 +1,513 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using DownKyi.Core.BiliApi.BiliUtils; +using DownKyi.Core.BiliApi.VideoStream; +using DownKyi.Core.BiliApi.Zone; +using DownKyi.Core.FileName; +using DownKyi.Core.Logging; +using DownKyi.Core.Settings; +using DownKyi.Core.Settings.Models; +using DownKyi.Core.Utils; +using DownKyi.Events; +using DownKyi.Models; +using DownKyi.Utils; +using DownKyi.ViewModels.Dialogs; +using DownKyi.ViewModels.DownloadManager; +using DownKyi.ViewModels.PageViewModels; +using Prism.Events; +using Prism.Services.Dialogs; + +namespace DownKyi.Services.Download; + +/// +/// 添加到下载列表服务 +/// +public class AddToDownloadService +{ + private readonly string Tag = "AddToDownloadService"; + private IInfoService videoInfoService; + private VideoInfoView videoInfoView; + private List videoSections; + + // 下载内容 + private bool downloadAudio = true; + private bool downloadVideo = true; + private bool downloadDanmaku = true; + private bool downloadSubtitle = true; + private bool downloadCover = true; + + /// + /// 添加下载 + /// + /// + public AddToDownloadService(PlayStreamType streamType) + { + switch (streamType) + { + case PlayStreamType.VIDEO: + videoInfoService = new VideoInfoService(null); + break; + case PlayStreamType.BANGUMI: + videoInfoService = new BangumiInfoService(null); + break; + case PlayStreamType.CHEESE: + videoInfoService = new CheeseInfoService(null); + break; + default: + break; + } + } + + /// + /// 添加下载 + /// + /// + /// + public AddToDownloadService(string id, PlayStreamType streamType) + { + switch (streamType) + { + case PlayStreamType.VIDEO: + videoInfoService = new VideoInfoService(id); + break; + case PlayStreamType.BANGUMI: + videoInfoService = new BangumiInfoService(id); + break; + case PlayStreamType.CHEESE: + videoInfoService = new CheeseInfoService(id); + break; + default: + break; + } + } + + public void SetVideoInfoService(IInfoService videoInfoService) + { + this.videoInfoService = videoInfoService; + } + + public void GetVideo(VideoInfoView videoInfoView, List videoSections, List selectedVideo) + { + this.videoInfoView = videoInfoView; + this.videoSections = videoSections; + foreach (VideoSection section in videoSections.Where(videoSection => videoSection.IsSelected)) + { + foreach (var item in section.VideoPages) + { + if (selectedVideo.Contains(item.Order)) + { + item.IsSelected = true; + } + } + } + } + + public void GetVideo() + { + videoInfoView = videoInfoService.GetVideoView(); + if (videoInfoView == null) + { + LogManager.Debug(Tag, "VideoInfoView is null."); + return; + } + + videoSections = videoInfoService.GetVideoSections(true); + if (videoSections == null) + { + LogManager.Debug(Tag, "videoSections is not exist."); + + videoSections = new List + { + new VideoSection + { + Id = 0, + Title = "default", + IsSelected = true, + VideoPages = videoInfoService.GetVideoPages() + } + }; + } + + // 将所有视频设置为选中 + foreach (VideoSection section in videoSections) + { + foreach (var item in section.VideoPages) + { + item.IsSelected = true; + } + } + } + + /// + /// 解析视频流 + /// + /// + public void ParseVideo(IInfoService videoInfoService) + { + if (videoSections == null) + { + return; + } + + foreach (VideoSection section in videoSections) + { + foreach (VideoPage page in section.VideoPages) + { + // 执行解析任务 + videoInfoService.GetVideoStream(page); + } + } + } + + /// + /// 选择文件夹和下载项 + /// + /// + public async Task SetDirectory(IDialogService dialogService) + { + // 选择的下载文件夹 + string directory = string.Empty; + + // 是否使用默认下载目录 + if (SettingsManager.GetInstance().IsUseSaveVideoRootPath() == AllowStatus.YES) + { + // 下载内容 + VideoContentSettings videoContent = SettingsManager.GetInstance().GetVideoContent(); + downloadAudio = videoContent.DownloadAudio; + downloadVideo = videoContent.DownloadVideo; + downloadDanmaku = videoContent.DownloadDanmaku; + downloadSubtitle = videoContent.DownloadSubtitle; + downloadCover = videoContent.DownloadCover; + + directory = SettingsManager.GetInstance().GetSaveVideoRootPath(); + } + else + { + bool run = true; + // 打开文件夹选择器 + dialogService.ShowDialog(ViewDownloadSetterViewModel.Tag, null, result => + { + if (result.Result == ButtonResult.OK) + { + // 选择的下载文件夹 + directory = result.Parameters.GetValue("directory"); + + // 下载内容 + downloadAudio = result.Parameters.GetValue("downloadAudio"); + downloadVideo = result.Parameters.GetValue("downloadVideo"); + downloadDanmaku = result.Parameters.GetValue("downloadDanmaku"); + downloadSubtitle = result.Parameters.GetValue("downloadSubtitle"); + downloadCover = result.Parameters.GetValue("downloadCover"); + } + + run = false; + }); + await Task.Run(() => + { + while (true) + { + if (!run) break; + } + }); + } + + if (directory == String.Empty) + { + return null; + } + + + if (!Directory.Exists(Directory.GetDirectoryRoot(directory))) + { + var alert = new AlertService(dialogService); + alert.ShowError(DictionaryResource.GetString("DriveNotFound")); + + directory = string.Empty; + } + + // 下载设置dialog中如果点击取消或者关闭窗口, + // 会返回空字符串, + // 这时直接退出 + if (directory == null || directory == string.Empty) + { + return null; + } + + // 文件夹不存在则创建 + if (!Directory.Exists(directory)) + { + Directory.CreateDirectory(directory); + } + + return directory; + } + + /// + /// 添加到下载列表 + /// + /// 传递事件的对象 + /// 下载路径 + /// 是否下载所有,包括未选中项 + /// 添加的数量 + public int AddToDownload(IEventAggregator eventAggregator, string directory, bool isAll = false) + { + if (directory == null || directory == string.Empty) + { + return -1; + } + + if (videoSections == null) + { + return -1; + } + + // 视频计数 + int i = 0; + + // 添加到下载 + foreach (VideoSection section in videoSections) + { + if (section.VideoPages == null) + { + continue; + } + + foreach (VideoPage page in section.VideoPages) + { + // 只下载选中项,跳过未选中项 + if (!isAll && !page.IsSelected) + { + continue; + } + + // 没有解析的也跳过 + if (page.PlayUrl == null) + { + continue; + } + + // 判断VideoQuality + int retry = 0; + while (page.VideoQuality == null && retry < 5) + { + // 执行解析任务 + videoInfoService.GetVideoStream(page); + retry++; + } + + if (page.VideoQuality == null) + { + continue; + } + + // 判断是否同一个视频,需要cid、画质、音质、视频编码都相同 + + // 如果存在正在下载列表,则跳过,并提示 + bool isDownloading = false; + foreach (DownloadingItem item in App.DownloadingList) + { + if (item.DownloadBase == null) + { + continue; + } + + if (item.DownloadBase.Cid == page.Cid && item.Resolution.Id == page.VideoQuality.Quality && + item.AudioCodec.Name == page.AudioQualityFormat && + item.VideoCodecName == page.VideoQuality.SelectedVideoCodec) + { + eventAggregator.GetEvent() + .Publish($"{page.Name}{DictionaryResource.GetString("TipAlreadyToAddDownloading")}"); + isDownloading = true; + break; + } + } + + if (isDownloading) + { + continue; + } + + // TODO 如果存在下载完成列表,弹出选择框是否再次下载 + bool isDownloaded = false; + foreach (DownloadedItem item in App.DownloadedList) + { + if (item.DownloadBase == null) + { + continue; + } + + if (item.DownloadBase.Cid == page.Cid && item.Resolution.Id == page.VideoQuality.Quality && + item.AudioCodec.Name == page.AudioQualityFormat && + item.VideoCodecName == page.VideoQuality.SelectedVideoCodec) + { + eventAggregator.GetEvent() + .Publish($"{page.Name}{DictionaryResource.GetString("TipAlreadyToAddDownloaded")}"); + isDownloaded = true; + break; + } + } + + if (isDownloaded) + { + continue; + } + + // 视频分区 + int zoneId = -1; + List zoneList = VideoZone.Instance().GetZones(); + ZoneAttr zone = zoneList.Find(it => it.Id == videoInfoView.TypeId); + if (zone != null) + { + if (zone.ParentId == 0) + { + zoneId = zone.Id; + } + else + { + ZoneAttr zoneParent = zoneList.Find(it => it.Id == zone.ParentId); + if (zoneParent != null) + { + zoneId = zoneParent.Id; + } + } + } + + // 如果只有一个视频章节,则不在命名中出现 + string sectionName = string.Empty; + if (videoSections.Count > 1) + { + sectionName = section.Title; + } + + // 文件路径 + List fileNameParts = SettingsManager.GetInstance().GetFileNameParts(); + FileName fileName = FileName.Builder(fileNameParts) + .SetSection(Format.FormatFileName(sectionName)) + .SetMainTitle(Format.FormatFileName(videoInfoView.Title)) + .SetPageTitle(Format.FormatFileName(page.Name)) + .SetVideoZone(videoInfoView.VideoZone.Split('>')[0]) + .SetAudioQuality(page.AudioQualityFormat) + .SetVideoQuality(page.VideoQuality == null ? "" : page.VideoQuality.QualityFormat) + .SetVideoCodec(page.VideoQuality == null ? "" : + page.VideoQuality.SelectedVideoCodec.Contains("AVC") ? "AVC" : + page.VideoQuality.SelectedVideoCodec.Contains("HEVC") ? "HEVC" : + page.VideoQuality.SelectedVideoCodec.Contains("Dolby") ? "Dolby Vision" : + page.VideoQuality.SelectedVideoCodec.Contains("AV1") ? "AV1" : "") + .SetVideoPublishTime(page.PublishTime) + .SetAvid(page.Avid) + .SetBvid(page.Bvid) + .SetCid(page.Cid) + .SetUpMid(page.Owner.Mid) + .SetUpName(Format.FormatFileName(page.Owner.Name)); + + // 序号设置 + OrderFormat orderFormat = SettingsManager.GetInstance().GetOrderFormat(); + switch (orderFormat) + { + case OrderFormat.NATURAL: + fileName.SetOrder(page.Order); + break; + case OrderFormat.LEADING_ZEROS: + fileName.SetOrder(page.Order, section.VideoPages.Count); + break; + } + + // 合成绝对路径 + string filePath = Path.Combine(directory, fileName.RelativePath()); + + // 视频类别 + PlayStreamType playStreamType; + switch (videoInfoView.TypeId) + { + case -10: + playStreamType = PlayStreamType.CHEESE; + break; + case 13: + case 23: + case 177: + case 167: + case 11: + playStreamType = PlayStreamType.BANGUMI; + break; + case 1: + case 3: + case 129: + case 4: + case 36: + case 188: + case 234: + case 223: + case 160: + case 211: + case 217: + case 119: + case 155: + case 202: + case 5: + case 181: + default: + playStreamType = PlayStreamType.VIDEO; + break; + } + + // 添加到下载列表 + App.PropertyChangeAsync(new Action(() => + { + // 如果不存在,直接添加到下载列表 + DownloadBase downloadBase = new DownloadBase + { + Bvid = page.Bvid, + Avid = page.Avid, + Cid = page.Cid, + EpisodeId = page.EpisodeId, + CoverUrl = videoInfoView.CoverUrl, + PageCoverUrl = page.FirstFrame, + ZoneId = zoneId, + FilePath = filePath, + + Order = page.Order, + MainTitle = videoInfoView.Title, + Name = page.Name, + Duration = page.Duration, + VideoCodecName = page.VideoQuality.SelectedVideoCodec, + Resolution = new Quality + { Name = page.VideoQuality.QualityFormat, Id = page.VideoQuality.Quality }, + AudioCodec = Constant.GetAudioQualities().FirstOrDefault(t => + { + return t.Name == page.AudioQualityFormat; + }), + }; + Downloading downloading = new Downloading + { + PlayStreamType = playStreamType, + DownloadStatus = DownloadStatus.NOT_STARTED, + }; + + // 需要下载的内容 + downloadBase.NeedDownloadContent["downloadAudio"] = downloadAudio; + downloadBase.NeedDownloadContent["downloadVideo"] = downloadVideo; + downloadBase.NeedDownloadContent["downloadDanmaku"] = downloadDanmaku; + downloadBase.NeedDownloadContent["downloadSubtitle"] = downloadSubtitle; + downloadBase.NeedDownloadContent["downloadCover"] = downloadCover; + + DownloadingItem downloadingItem = new DownloadingItem + { + DownloadBase = downloadBase, + Downloading = downloading, + PlayUrl = page.PlayUrl, + }; + + App.DownloadingList.Add(downloadingItem); + Thread.Sleep(10); + })); + i++; + } + } + + return i; + } +} \ No newline at end of file diff --git a/DownKyi/Services/Download/BuiltinDownloadService.cs b/DownKyi/Services/Download/BuiltinDownloadService.cs new file mode 100644 index 0000000..38ef0da --- /dev/null +++ b/DownKyi/Services/Download/BuiltinDownloadService.cs @@ -0,0 +1,428 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.IO; +using System.Net; +using System.Threading; +using System.Threading.Tasks; +using DownKyi.Core.BiliApi.Login; +using DownKyi.Core.BiliApi.VideoStream.Models; +using DownKyi.Core.Downloader; +using DownKyi.Core.Logging; +using DownKyi.Core.Settings; +using DownKyi.Core.Utils; +using DownKyi.Models; +using DownKyi.Utils; +using DownKyi.ViewModels.DownloadManager; +using Prism.Services.Dialogs; +using Console = DownKyi.Core.Utils.Debugging.Console; + +namespace DownKyi.Services.Download; + +public class BuiltinDownloadService : DownloadService, IDownloadService +{ + public BuiltinDownloadService(ObservableCollection downloadingList, + ObservableCollection downloadedList, + IDialogService dialogService + ) : base(downloadingList, downloadedList, dialogService) + { + Tag = "BuiltinDownloadService"; + } + + #region 音视频 + + /// + /// 下载音频,返回下载文件路径 + /// + /// + /// + public override string DownloadAudio(DownloadingItem downloading) + { + PlayUrlDashVideo downloadAudio = BaseDownloadAudio(downloading); + + return DownloadVideo(downloading, downloadAudio); + } + + /// + /// 下载视频,返回下载文件路径 + /// + /// + /// + public override string DownloadVideo(DownloadingItem downloading) + { + PlayUrlDashVideo downloadVideo = BaseDownloadVideo(downloading); + + return DownloadVideo(downloading, downloadVideo); + } + + /// + /// 将下载音频和视频的函数中相同代码抽象出来 + /// + /// + /// + /// + private string DownloadVideo(DownloadingItem downloading, PlayUrlDashVideo downloadVideo) + { + // 如果为空,说明没有匹配到可下载的音频视频 + if (downloadVideo == null) + { + return null; + } + + // 下载链接 + List urls = new List(); + if (downloadVideo.BaseUrl != null) + { + urls.Add(downloadVideo.BaseUrl); + } + + if (downloadVideo.BackupUrl != null) + { + urls.AddRange(downloadVideo.BackupUrl); + } + + // 路径 + downloading.DownloadBase.FilePath = downloading.DownloadBase.FilePath.Replace("\\", "/"); + string[] temp = downloading.DownloadBase.FilePath.Split('/'); + //string path = downloading.DownloadBase.FilePath.Replace(temp[temp.Length - 1], ""); + string path = downloading.DownloadBase.FilePath.TrimEnd(temp[temp.Length - 1].ToCharArray()); + + // 下载文件名 + string fileName = Guid.NewGuid().ToString("N"); + string key = $"{downloadVideo.Id}_{downloadVideo.Codecs}"; + + // 老版本数据库没有这一项,会变成null + if (downloading.Downloading.DownloadedFiles == null) + { + downloading.Downloading.DownloadedFiles = new List(); + } + + if (downloading.Downloading.DownloadFiles.ContainsKey(key)) + { + // 如果存在,表示下载过, + // 则继续使用上次下载的文件名 + fileName = downloading.Downloading.DownloadFiles[key]; + + // 还要检查一下文件有没有被人删掉,删掉的话重新下载 + // 如果下载视频之后音频文件被人删了。此时gid还是视频的,会下错文件 + if (downloading.Downloading.DownloadedFiles.Contains(key) && File.Exists(Path.Combine(path, fileName))) + { + return Path.Combine(path, fileName); + } + } + else + { + // 记录本次下载的文件 + try + { + downloading.Downloading.DownloadFiles.Add(key, fileName); + } + catch (ArgumentException) + { + } + + // Gid最好能是每个文件单独存储,现在复用有可能会混 + // 不过好消息是下载是按固定顺序的,而且下载了两个音频会混流不过 + downloading.Downloading.Gid = null; + } + + // 启用https + AllowStatus useSSL = SettingsManager.GetInstance().UseSSL(); + if (useSSL == AllowStatus.YES) + { + for (int i = 0; i < urls.Count; i++) + { + string url = urls[i]; + if (url.StartsWith("http://")) + { + urls[i] = url.Replace("http://", "https://"); + } + } + } + else + { + for (int i = 0; i < urls.Count; i++) + { + string url = urls[i]; + if (url.StartsWith("https://")) + { + urls[i] = url.Replace("https://", "http://"); + } + } + } + + // 开始下载 + try + { + var downloadStatus = DownloadByBuiltin(downloading, urls, path, fileName); + if (downloadStatus) + { + downloading.Downloading.DownloadedFiles.Add(key); + downloading.Downloading.Gid = null; + return Path.Combine(path, fileName); + } + else + { + return nullMark; + } + } + catch (FileNotFoundException e) + { + Console.PrintLine("BuiltinDownloadService.DownloadVideo()发生异常: {0}", e); + LogManager.Error("BuiltinDownloadService.DownloadVideo()", e); + + return nullMark; + } + } + + #endregion + + /// + /// 下载封面 + /// + /// + /// + /// + /// + public override string DownloadCover(DownloadingItem downloading, string coverUrl, string fileName) + { + return BaseDownloadCover(downloading, coverUrl, fileName); + } + + /// + /// 下载弹幕 + /// + /// + /// + public override string DownloadDanmaku(DownloadingItem downloading) + { + return BaseDownloadDanmaku(downloading); + } + + /// + /// 下载字幕 + /// + /// + /// + public override List DownloadSubtitle(DownloadingItem downloading) + { + return BaseDownloadSubtitle(downloading); + } + + /// + /// 混流音频和视频 + /// + /// + /// + /// + /// + public override string MixedFlow(DownloadingItem downloading, string audioUid, string videoUid) + { + return BaseMixedFlow(downloading, audioUid, videoUid); + } + + /// + /// 解析视频流的下载链接 + /// + /// + public override void Parse(DownloadingItem downloading) + { + BaseParse(downloading); + } + + /// + /// 停止下载服务(转换await和Task.Wait两种调用形式) + /// + private async Task EndTask() + { + // 停止基本任务 + await BaseEndTask(); + } + + /// + /// 停止下载服务 + /// + public void End() + { + Task.Run(EndTask).Wait(); + } + + public void Start() + { + // 启动基本服务 + BaseStart(); + } + + /// + /// 强制暂停 + /// + /// + /// + protected override void Pause(DownloadingItem downloading) + { + cancellationToken.ThrowIfCancellationRequested(); + + downloading.DownloadStatusTitle = DictionaryResource.GetString("Pausing"); + if (downloading.Downloading.DownloadStatus == DownloadStatus.PAUSE) + { + throw new OperationCanceledException("Stop thread by pause"); + } + + // 是否存在 + var isExist = IsExist(downloading); + if (!isExist) + { + throw new OperationCanceledException("Task is deleted"); + } + } + + /// + /// 是否存在于下载列表中 + /// + /// + /// + private bool IsExist(DownloadingItem downloading) + { + bool isExist = downloadingList.Contains(downloading); + if (isExist) + { + return true; + } + else + { + return false; + } + } + + #region 内建下载器 + + /// + /// 下载文件 + /// + /// + /// + /// + /// + /// + private bool DownloadByBuiltin(DownloadingItem downloading, List urls, string path, string localFileName) + { + // path已斜杠结尾,去掉斜杠 + path = path.TrimEnd('/').TrimEnd('\\'); + + foreach (var url in urls) + { + // 创建下载器 + var mtd = new MultiThreadDownloader(url, + Path.GetTempPath(), + Path.Combine(path, localFileName), + SettingsManager.GetInstance().GetSplit()); + // 配置网络请求 + mtd.Configure(req => + { + req.CookieContainer = LoginHelper.GetLoginInfoCookies(); + req.UserAgent = SettingsManager.GetInstance().GetUserAgent(); + req.Referer = "https://www.bilibili.com"; + req.Headers.Add("Origin", "https://www.bilibili.com"); + + if (SettingsManager.GetInstance().IsHttpProxy() == AllowStatus.YES) + { + req.Proxy = new WebProxy(SettingsManager.GetInstance().GetHttpProxy(), + SettingsManager.GetInstance().GetHttpProxyListenPort()); + } + }); + + // 下载进度回调 + mtd.TotalProgressChanged += (sender, e) => + { + try + { + // 状态更新 + var downloader = sender as MultiThreadDownloader; + + // 下载进度百分比 + float percent = downloader.TotalProgress; + + // 根据进度判断本次是否需要更新UI + if (Math.Abs(percent - downloading.Progress) < 0.01) + { + return; + } + + if (Math.Abs(percent - downloading.Progress) > 5) + { + return; + } + + // 下载进度 + downloading.Progress = percent; + + // 下载大小 + downloading.DownloadingFileSize = Format.FormatFileSize(downloader.TotalBytesReceived) + "/" + + Format.FormatFileSize(downloader.Size); + + // 下载速度 + long speed = (long)downloader.TotalSpeedInBytes; + + // 下载速度显示 + downloading.SpeedDisplay = Format.FormatSpeed(speed); + + // 最大下载速度 + if (downloading.Downloading.MaxSpeed < speed) + { + downloading.Downloading.MaxSpeed = speed; + } + } + catch (InvalidOperationException ex) + { + Console.PrintLine( + $"{Tag}.DownloadByBuiltin()发生InvalidOperationException异常: {0}", ex); + LogManager.Error($"{Tag}.DownloadByBuiltin()", ex); + } + catch (Exception ex) + { + Console.PrintLine($"{Tag}.DownloadByBuiltin()发生异常: {0}", ex); + LogManager.Error($"{Tag}.DownloadByBuiltin()", ex); + } + }; + + // 文件合并完成回调 + bool isComplete = false; + mtd.FileMergedComplete += (sender, e) => + { + // 跳出循环 + if (File.Exists(Path.Combine(path, localFileName))) + { + isComplete = true; + } + }; + + // 开始下载 + mtd.Start(); + + // 阻塞当前任务,监听暂停事件 + while (!isComplete) + { + cancellationToken.ThrowIfCancellationRequested(); + switch (downloading.Downloading.DownloadStatus) + { + case DownloadStatus.PAUSE: + // 暂停下载 + mtd.Pause(); + // 通知UI,并阻塞当前线程 + Pause(downloading); + break; + case DownloadStatus.DOWNLOADING: + break; + } + + Thread.Sleep(100); + } + + return isComplete; + } + + return false; + } + + #endregion +} \ No newline at end of file diff --git a/DownKyi/Services/Download/DownloadService.cs b/DownKyi/Services/Download/DownloadService.cs new file mode 100644 index 0000000..2807126 --- /dev/null +++ b/DownKyi/Services/Download/DownloadService.cs @@ -0,0 +1,867 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using DownKyi.Core.BiliApi.BiliUtils; +using DownKyi.Core.BiliApi.VideoStream; +using DownKyi.Core.BiliApi.VideoStream.Models; +using DownKyi.Core.Danmaku2Ass; +using DownKyi.Core.FFmpeg; +using DownKyi.Core.Logging; +using DownKyi.Core.Settings; +using DownKyi.Core.Storage; +using DownKyi.Core.Utils; +using DownKyi.Images; +using DownKyi.Models; +using DownKyi.Utils; +using DownKyi.ViewModels.DownloadManager; +using Prism.Services.Dialogs; +using Console = DownKyi.Core.Utils.Debugging.Console; + +namespace DownKyi.Services.Download; + +public abstract class DownloadService +{ + protected string Tag = "DownloadService"; + + // protected TaskbarIcon _notifyIcon; + protected IDialogService dialogService; + protected ObservableCollection downloadingList; + protected ObservableCollection downloadedList; + + protected Task workTask; + protected CancellationTokenSource tokenSource; + protected CancellationToken cancellationToken; + protected List downloadingTasks = new List(); + + protected readonly int retry = 5; + protected readonly string nullMark = ""; + + /// + /// 初始化 + /// + /// + /// + public DownloadService(ObservableCollection downloadingList, + ObservableCollection downloadedList, + IDialogService dialogService) + { + this.downloadingList = downloadingList; + this.downloadedList = downloadedList; + this.dialogService = dialogService; + } + + protected PlayUrlDashVideo BaseDownloadAudio(DownloadingItem downloading) + { + // 更新状态显示 + downloading.DownloadStatusTitle = DictionaryResource.GetString("WhileDownloading"); + downloading.DownloadContent = DictionaryResource.GetString("DownloadingAudio"); + // 下载大小 + downloading.DownloadingFileSize = string.Empty; + downloading.Progress = 0; + // 下载速度 + downloading.SpeedDisplay = string.Empty; + + // 如果没有Dash,返回null + if (downloading.PlayUrl == null || downloading.PlayUrl.Dash == null) + { + return null; + } + + // 如果audio列表没有内容,则返回null + if (downloading.PlayUrl.Dash.Audio == null) + { + return null; + } + else if (downloading.PlayUrl.Dash.Audio.Count == 0) + { + return null; + } + + // 根据音频id匹配 + PlayUrlDashVideo downloadAudio = null; + foreach (PlayUrlDashVideo audio in downloading.PlayUrl.Dash.Audio) + { + if (audio.Id == downloading.AudioCodec.Id) + { + downloadAudio = audio; + break; + } + } + + // 避免Dolby==null及其它未知情况,直接使用异常捕获 + try + { + // Dolby Atmos + if (downloading.AudioCodec.Id == 30250) + { + downloadAudio = downloading.PlayUrl.Dash.Dolby.Audio[0]; + } + + // Hi-Res无损 + if (downloading.AudioCodec.Id == 30251) + { + downloadAudio = downloading.PlayUrl.Dash.Flac.Audio; + } + } + catch (Exception) + { + } + + return downloadAudio; + } + + protected PlayUrlDashVideo BaseDownloadVideo(DownloadingItem downloading) + { + // 更新状态显示 + downloading.DownloadStatusTitle = DictionaryResource.GetString("WhileDownloading"); + downloading.DownloadContent = DictionaryResource.GetString("DownloadingVideo"); + // 下载大小 + downloading.DownloadingFileSize = string.Empty; + downloading.Progress = 0; + // 下载速度 + downloading.SpeedDisplay = string.Empty; + + // 如果没有Dash,返回null + if (downloading.PlayUrl == null || downloading.PlayUrl.Dash == null) + { + return null; + } + + // 如果Video列表没有内容,则返回null + if (downloading.PlayUrl.Dash.Video == null) + { + return null; + } + else if (downloading.PlayUrl.Dash.Video.Count == 0) + { + return null; + } + + // 根据视频编码匹配 + PlayUrlDashVideo downloadVideo = null; + foreach (PlayUrlDashVideo video in downloading.PlayUrl.Dash.Video) + { + Quality codecs = Constant.GetCodecIds().FirstOrDefault(t => t.Id == video.CodecId); + if (video.Id == downloading.Resolution.Id && codecs.Name == downloading.VideoCodecName) + { + downloadVideo = video; + break; + } + } + + return downloadVideo; + } + + protected string BaseDownloadCover(DownloadingItem downloading, string coverUrl, string fileName) + { + // 更新状态显示 + downloading.DownloadStatusTitle = DictionaryResource.GetString("WhileDownloading"); + downloading.DownloadContent = DictionaryResource.GetString("DownloadingCover"); + // 下载大小 + downloading.DownloadingFileSize = string.Empty; + // 下载速度 + downloading.SpeedDisplay = string.Empty; + + // 查询、保存封面 + StorageCover storageCover = new StorageCover(); + string cover = storageCover.GetCover(downloading.DownloadBase.Avid, downloading.DownloadBase.Bvid, + downloading.DownloadBase.Cid, coverUrl); + if (cover == null) + { + return null; + } + + // 复制图片到指定位置 + try + { + File.Copy(cover, fileName, true); + + // 记录本次下载的文件 + if (!downloading.Downloading.DownloadFiles.ContainsKey(coverUrl)) + { + downloading.Downloading.DownloadFiles.Add(coverUrl, fileName); + } + + return fileName; + } + catch (Exception e) + { + Console.PrintLine($"{Tag}.DownloadCover()发生异常: {0}", e); + LogManager.Error($"{Tag}.DownloadCover()", e); + } + + return null; + } + + protected string BaseDownloadDanmaku(DownloadingItem downloading) + { + // 更新状态显示 + downloading.DownloadStatusTitle = DictionaryResource.GetString("WhileDownloading"); + downloading.DownloadContent = DictionaryResource.GetString("DownloadingDanmaku"); + // 下载大小 + downloading.DownloadingFileSize = string.Empty; + // 下载速度 + downloading.SpeedDisplay = string.Empty; + + string title = $"{downloading.Name}"; + string assFile = $"{downloading.DownloadBase.FilePath}.ass"; + + // 记录本次下载的文件 + if (!downloading.Downloading.DownloadFiles.ContainsKey("danmaku")) + { + downloading.Downloading.DownloadFiles.Add("danmaku", assFile); + } + + int screenWidth = SettingsManager.GetInstance().GetDanmakuScreenWidth(); + int screenHeight = SettingsManager.GetInstance().GetDanmakuScreenHeight(); + //if (SettingsManager.GetInstance().IsCustomDanmakuResolution() != AllowStatus.YES) + //{ + // if (downloadingEntity.Width > 0 && downloadingEntity.Height > 0) + // { + // screenWidth = downloadingEntity.Width; + // screenHeight = downloadingEntity.Height; + // } + //} + + // 字幕配置 + Config subtitleConfig = new Config + { + Title = title, + ScreenWidth = screenWidth, + ScreenHeight = screenHeight, + FontName = SettingsManager.GetInstance().GetDanmakuFontName(), + BaseFontSize = SettingsManager.GetInstance().GetDanmakuFontSize(), + LineCount = SettingsManager.GetInstance().GetDanmakuLineCount(), + LayoutAlgorithm = + SettingsManager.GetInstance().GetDanmakuLayoutAlgorithm().ToString("G").ToLower(), // async/sync + TuneDuration = 0, + DropOffset = 0, + BottomMargin = 0, + CustomOffset = 0 + }; + + Core.Danmaku2Ass.Bilibili.GetInstance() + .SetTopFilter(SettingsManager.GetInstance().GetDanmakuTopFilter() == AllowStatus.YES) + .SetBottomFilter(SettingsManager.GetInstance().GetDanmakuBottomFilter() == AllowStatus.YES) + .SetScrollFilter(SettingsManager.GetInstance().GetDanmakuScrollFilter() == AllowStatus.YES) + .Create(downloading.DownloadBase.Avid, downloading.DownloadBase.Cid, subtitleConfig, assFile); + + return assFile; + } + + protected List BaseDownloadSubtitle(DownloadingItem downloading) + { + // 更新状态显示 + downloading.DownloadStatusTitle = DictionaryResource.GetString("WhileDownloading"); + downloading.DownloadContent = DictionaryResource.GetString("DownloadingSubtitle"); + // 下载大小 + downloading.DownloadingFileSize = string.Empty; + // 下载速度 + downloading.SpeedDisplay = string.Empty; + + List srtFiles = new List(); + + var subRipTexts = VideoStream.GetSubtitle(downloading.DownloadBase.Avid, downloading.DownloadBase.Bvid, + downloading.DownloadBase.Cid); + if (subRipTexts == null) + { + return null; + } + + foreach (var subRip in subRipTexts) + { + string srtFile = $"{downloading.DownloadBase.FilePath}_{subRip.LanDoc}.srt"; + try + { + File.WriteAllText(srtFile, subRip.SrtString); + + // 记录本次下载的文件 + if (!downloading.Downloading.DownloadFiles.ContainsKey("subtitle")) + { + downloading.Downloading.DownloadFiles.Add("subtitle", srtFile); + } + + srtFiles.Add(srtFile); + } + catch (Exception e) + { + Console.PrintLine($"{Tag}.DownloadSubtitle()发生异常: {0}", e); + LogManager.Error($"{Tag}.DownloadSubtitle()", e); + } + } + + return srtFiles; + } + + protected string BaseMixedFlow(DownloadingItem downloading, string audioUid, string videoUid) + { + // 更新状态显示 + downloading.DownloadStatusTitle = DictionaryResource.GetString("MixedFlow"); + downloading.DownloadContent = DictionaryResource.GetString("DownloadingVideo"); + // 下载大小 + downloading.DownloadingFileSize = string.Empty; + // 下载速度 + downloading.SpeedDisplay = string.Empty; + + //if (videoUid == nullMark) + //{ + // return null; + //} + + var finalFile = $"{downloading.DownloadBase.FilePath}.mp4"; + if (videoUid == null) + { + finalFile = $"{downloading.DownloadBase.FilePath}.aac"; + } + + // 合并音视频 + FFmpegHelper.MergeVideo(audioUid, videoUid, finalFile); + + // 获取文件大小 + if (File.Exists(finalFile)) + { + var info = new FileInfo(finalFile); + downloading.FileSize = Format.FormatFileSize(info.Length); + } + else + { + downloading.FileSize = Format.FormatFileSize(0); + } + + return finalFile; + } + + protected void BaseParse(DownloadingItem downloading) + { + // 更新状态显示 + downloading.DownloadStatusTitle = DictionaryResource.GetString("Parsing"); + downloading.DownloadContent = string.Empty; + // 下载大小 + downloading.DownloadingFileSize = string.Empty; + downloading.Progress = 0; + // 下载速度 + downloading.SpeedDisplay = string.Empty; + + if (downloading.PlayUrl != null && downloading.Downloading.DownloadStatus == DownloadStatus.NOT_STARTED) + { + // 设置下载状态 + downloading.Downloading.DownloadStatus = DownloadStatus.DOWNLOADING; + + return; + } + + // 设置下载状态 + downloading.Downloading.DownloadStatus = DownloadStatus.DOWNLOADING; + + // 解析 + switch (downloading.Downloading.PlayStreamType) + { + case PlayStreamType.VIDEO: + downloading.PlayUrl = VideoStream.GetVideoPlayUrl(downloading.DownloadBase.Avid, + downloading.DownloadBase.Bvid, downloading.DownloadBase.Cid); + break; + case PlayStreamType.BANGUMI: + downloading.PlayUrl = VideoStream.GetBangumiPlayUrl(downloading.DownloadBase.Avid, + downloading.DownloadBase.Bvid, downloading.DownloadBase.Cid); + break; + case PlayStreamType.CHEESE: + downloading.PlayUrl = VideoStream.GetCheesePlayUrl(downloading.DownloadBase.Avid, + downloading.DownloadBase.Bvid, downloading.DownloadBase.Cid, + downloading.DownloadBase.EpisodeId); + break; + default: + break; + } + } + + /// + /// 执行任务 + /// + protected async Task DoWork() + { + // 上次循环时正在下载的数量 + int lastDownloadingCount = 0; + + while (true) + { + int maxDownloading = SettingsManager.GetInstance().GetMaxCurrentDownloads(); + int downloadingCount = 0; + + try + { + downloadingTasks.RemoveAll((m) => m.IsCompleted); + foreach (DownloadingItem downloading in downloadingList) + { + if (downloading.Downloading.DownloadStatus == DownloadStatus.DOWNLOADING) + { + downloadingCount++; + } + } + + foreach (DownloadingItem downloading in downloadingList) + { + if (downloadingCount >= maxDownloading) + { + break; + } + + // 开始下载 + if (downloading.Downloading.DownloadStatus == DownloadStatus.NOT_STARTED || + downloading.Downloading.DownloadStatus == DownloadStatus.WAIT_FOR_DOWNLOAD) + { + //这里需要立刻设置状态,否则如果SingleDownload没有及时执行,会重复创建任务 + downloading.Downloading.DownloadStatus = DownloadStatus.DOWNLOADING; + downloadingTasks.Add(SingleDownload(downloading)); + downloadingCount++; + } + } + } + catch (InvalidOperationException e) + { + Console.PrintLine($"{Tag}.DoWork()发生InvalidOperationException异常: {0}", e); + LogManager.Error($"{Tag}.DoWork() InvalidOperationException", e); + } + catch (Exception e) + { + Console.PrintLine($"{Tag}.DoWork()发生异常: {0}", e); + LogManager.Error($"{Tag}.DoWork()", e); + } + + // 判断是否该结束线程,若为true,跳出while循环 + if (cancellationToken.IsCancellationRequested) + { + Console.PrintLine($"{Tag}.DoWork() 下载服务结束,跳出while循环"); + LogManager.Debug($"{Tag}.DoWork()", "下载服务结束"); + break; + } + + // 判断下载列表中的视频是否全部下载完成 + if (lastDownloadingCount > 0 && downloadingList.Count == 0 && downloadedList.Count > 0) + { + AfterDownload(); + } + + lastDownloadingCount = downloadingList.Count; + + // 降低CPU占用 + await Task.Delay(500); + } + + await Task.WhenAny(Task.WhenAll(downloadingTasks), Task.Delay(30000)); + foreach (Task tsk in downloadingTasks.FindAll((m) => !m.IsCompleted)) + { + Console.PrintLine($"{Tag}.DoWork() 任务结束超时"); + LogManager.Debug($"{Tag}.DoWork()", "任务结束超时"); + } + } + + /// + /// 下载一个视频 + /// + /// + /// + private async Task SingleDownload(DownloadingItem downloading) + { + // 路径 + downloading.DownloadBase.FilePath = downloading.DownloadBase.FilePath.Replace("\\", "/"); + string[] temp = downloading.DownloadBase.FilePath.Split('/'); + //string path = downloading.DownloadBase.FilePath.Replace(temp[temp.Length - 1], ""); + string path = downloading.DownloadBase.FilePath.TrimEnd(temp[temp.Length - 1].ToCharArray()); + + // 路径不存在则创建 + if (!Directory.Exists(path)) + { + try + { + Directory.CreateDirectory(path); + } + catch (Exception e) + { + Console.PrintLine(Tag, e.ToString()); + LogManager.Debug(Tag, e.Message); + + AlertService alertService = new AlertService(dialogService); + ButtonResult result = + alertService.ShowError($"{path}{DictionaryResource.GetString("DirectoryError")}"); + + return; + } + } + + try + { + await Task.Run(() => + { + // 初始化 + downloading.DownloadStatusTitle = string.Empty; + downloading.DownloadContent = string.Empty; + //downloading.Downloading.DownloadFiles.Clear(); + + // 解析并依次下载音频、视频、弹幕、字幕、封面等内容 + Parse(downloading); + + // 暂停 + Pause(downloading); + + string audioUid = null; + // 如果需要下载音频 + if (downloading.DownloadBase.NeedDownloadContent["downloadAudio"]) + { + //audioUid = DownloadAudio(downloading); + for (int i = 0; i < retry; i++) + { + audioUid = DownloadAudio(downloading); + if (audioUid != null && audioUid != nullMark) + { + break; + } + } + } + + if (audioUid == nullMark) + { + DownloadFailed(downloading); + return; + } + + // 暂停 + Pause(downloading); + + string videoUid = null; + // 如果需要下载视频 + if (downloading.DownloadBase.NeedDownloadContent["downloadVideo"]) + { + //videoUid = DownloadVideo(downloading); + for (int i = 0; i < retry; i++) + { + videoUid = DownloadVideo(downloading); + if (videoUid != null && videoUid != nullMark) + { + break; + } + } + } + + if (videoUid == nullMark) + { + DownloadFailed(downloading); + return; + } + + // 暂停 + Pause(downloading); + + string outputDanmaku = null; + // 如果需要下载弹幕 + if (downloading.DownloadBase.NeedDownloadContent["downloadDanmaku"]) + { + outputDanmaku = DownloadDanmaku(downloading); + } + + // 暂停 + Pause(downloading); + + List outputSubtitles = null; + // 如果需要下载字幕 + if (downloading.DownloadBase.NeedDownloadContent["downloadSubtitle"]) + { + outputSubtitles = DownloadSubtitle(downloading); + } + + // 暂停 + Pause(downloading); + + string outputCover = null; + string outputPageCover = null; + // 如果需要下载封面 + if (downloading.DownloadBase.NeedDownloadContent["downloadCover"]) + { + // page的封面 + string pageCoverFileName = + $"{downloading.DownloadBase.FilePath}.{GetImageExtension(downloading.DownloadBase.PageCoverUrl)}"; + outputPageCover = DownloadCover(downloading, downloading.DownloadBase.PageCoverUrl, + pageCoverFileName); + + + string coverFileName = + $"{downloading.DownloadBase.FilePath}.Cover.{GetImageExtension(downloading.DownloadBase.CoverUrl)}"; + // 封面 + //outputCover = DownloadCover(downloading, downloading.DownloadBase.CoverUrl, $"{path}/Cover.{GetImageExtension(downloading.DownloadBase.CoverUrl)}"); + outputCover = DownloadCover(downloading, downloading.DownloadBase.CoverUrl, coverFileName); + } + + // 暂停 + Pause(downloading); + + // 混流 + string outputMedia = string.Empty; + if (downloading.DownloadBase.NeedDownloadContent["downloadAudio"] || + downloading.DownloadBase.NeedDownloadContent["downloadVideo"]) + { + outputMedia = MixedFlow(downloading, audioUid, videoUid); + } + + // 这里本来只有IsExist,没有pause,不知道怎么处理 + // 是否存在 + //isExist = IsExist(downloading); + //if (!isExist.Result) + //{ + // return; + //} + + // 检测音频、视频是否下载成功 + bool isMediaSuccess = true; + if (downloading.DownloadBase.NeedDownloadContent["downloadAudio"] || + downloading.DownloadBase.NeedDownloadContent["downloadVideo"]) + { + // 只有下载音频不下载视频时才输出aac + // 只要下载视频就输出mp4 + if (File.Exists(outputMedia)) + { + // 成功 + isMediaSuccess = true; + } + else + { + isMediaSuccess = false; + } + } + + // 检测弹幕是否下载成功 + bool isDanmakuSuccess = true; + if (downloading.DownloadBase.NeedDownloadContent["downloadDanmaku"]) + { + if (File.Exists(outputDanmaku)) + { + // 成功 + isDanmakuSuccess = true; + } + else + { + isDanmakuSuccess = false; + } + } + + // 检测字幕是否下载成功 + bool isSubtitleSuccess = true; + if (downloading.DownloadBase.NeedDownloadContent["downloadSubtitle"]) + { + if (outputSubtitles == null) + { + // 为null时表示不存在字幕 + } + else + { + foreach (string subtitle in outputSubtitles) + { + if (!File.Exists(subtitle)) + { + // 如果有一个不存在则失败 + isSubtitleSuccess = false; + } + } + } + } + + // 检测封面是否下载成功 + bool isCover = true; + if (downloading.DownloadBase.NeedDownloadContent["downloadCover"]) + { + if (File.Exists(outputCover) || File.Exists(outputPageCover)) + { + // 成功 + isCover = true; + } + else + { + isCover = false; + } + } + + if (!isMediaSuccess || !isDanmakuSuccess || !isSubtitleSuccess || !isCover) + { + DownloadFailed(downloading); + return; + } + + // 下载完成后处理 + Downloaded downloaded = new Downloaded + { + MaxSpeedDisplay = Format.FormatSpeed(downloading.Downloading.MaxSpeed), + }; + // 设置完成时间 + downloaded.SetFinishedTimestamp(new DateTimeOffset(DateTime.UtcNow).ToUnixTimeSeconds()); + + DownloadedItem downloadedItem = new DownloadedItem + { + DownloadBase = downloading.DownloadBase, + Downloaded = downloaded + }; + + App.PropertyChangeAsync(new Action(() => + { + // 加入到下载完成list中,并从下载中list去除 + downloadedList.Add(downloadedItem); + downloadingList.Remove(downloading); + + // 下载完成列表排序 + DownloadFinishedSort finishedSort = SettingsManager.GetInstance().GetDownloadFinishedSort(); + App.SortDownloadedList(finishedSort); + })); + // _notifyIcon.ShowBalloonTip(DictionaryResource.GetString("DownloadSuccess"), $"{downloadedItem.DownloadBase.Name}", BalloonIcon.Info); + }); + } + catch (OperationCanceledException e) + { + Console.PrintLine(Tag, e.ToString()); + LogManager.Debug(Tag, e.Message); + } + } + + /// + /// 下载失败后的处理 + /// + /// + protected void DownloadFailed(DownloadingItem downloading) + { + downloading.DownloadStatusTitle = DictionaryResource.GetString("DownloadFailed"); + downloading.DownloadContent = string.Empty; + downloading.DownloadingFileSize = string.Empty; + downloading.SpeedDisplay = string.Empty; + downloading.Progress = 0; + + downloading.Downloading.DownloadStatus = DownloadStatus.DOWNLOAD_FAILED; + downloading.StartOrPause = ButtonIcon.Instance().Retry; + downloading.StartOrPause.Fill = DictionaryResource.GetColor("ColorPrimary"); + } + + /// + /// 获取图片的扩展名 + /// + /// + /// + protected string GetImageExtension(string coverUrl) + { + if (coverUrl == null) + { + return string.Empty; + } + + // 图片的扩展名 + string[] temp = coverUrl.Split('.'); + string fileExtension = temp[temp.Length - 1]; + return fileExtension; + } + + /// + /// 下载完成后的操作 + /// + protected void AfterDownload() + { + AfterDownloadOperation operation = SettingsManager.GetInstance().GetAfterDownloadOperation(); + switch (operation) + { + case AfterDownloadOperation.NONE: + // 没有操作 + break; + case AfterDownloadOperation.OPEN_FOLDER: + // 打开文件夹 + break; + case AfterDownloadOperation.CLOSE_APP: + // 关闭程序 + App.PropertyChangeAsync(() => + { + // System.Windows.Application.Current.Shutdown(); + }); + break; + case AfterDownloadOperation.CLOSE_SYSTEM: + // 关机 + Process.Start("shutdown.exe", "-s"); + break; + default: + break; + } + } + + /// + /// 停止基本下载服务(转换await和Task.Wait两种调用形式) + /// + protected async Task BaseEndTask() + { + // 结束任务 + tokenSource.Cancel(); + + await workTask; + + //先简单等待一下 + + // 下载数据存储服务 + // DownloadStorageService downloadStorageService = new DownloadStorageService(); + // 保存数据 + foreach (DownloadingItem item in downloadingList) + { + switch (item.Downloading.DownloadStatus) + { + case DownloadStatus.NOT_STARTED: + break; + case DownloadStatus.WAIT_FOR_DOWNLOAD: + break; + case DownloadStatus.PAUSE_STARTED: + break; + case DownloadStatus.PAUSE: + break; + case DownloadStatus.DOWNLOADING: + // TODO 添加设置让用户选择重启后是否自动开始下载 + item.Downloading.DownloadStatus = DownloadStatus.WAIT_FOR_DOWNLOAD; + //item.Downloading.DownloadStatus = DownloadStatus.PAUSE; + break; + case DownloadStatus.DOWNLOAD_SUCCEED: + case DownloadStatus.DOWNLOAD_FAILED: + break; + default: + break; + } + + item.Progress = 0; + + // downloadStorageService.UpdateDownloading(item); + } + + foreach (DownloadedItem item in downloadedList) + { + // downloadStorageService.UpdateDownloaded(item); + } + } + + /// + /// 启动基本下载服务 + /// + protected void BaseStart() + { + tokenSource = new CancellationTokenSource(); + cancellationToken = tokenSource.Token; + // _notifyIcon = new TaskbarIcon(); + // _notifyIcon.IconSource = new BitmapImage(new Uri("pack://application:,,,/Resources/favicon.ico")); + + workTask = Task.Run(DoWork); + } + + #region 抽象接口函数 + + public abstract void Parse(DownloadingItem downloading); + public abstract string DownloadAudio(DownloadingItem downloading); + public abstract string DownloadVideo(DownloadingItem downloading); + public abstract string DownloadDanmaku(DownloadingItem downloading); + public abstract List DownloadSubtitle(DownloadingItem downloading); + public abstract string DownloadCover(DownloadingItem downloading, string coverUrl, string fileName); + public abstract string MixedFlow(DownloadingItem downloading, string audioUid, string videoUid); + + protected abstract void Pause(DownloadingItem downloading); + + #endregion +} \ No newline at end of file diff --git a/DownKyi/Services/Download/DownloadStorageService.cs b/DownKyi/Services/Download/DownloadStorageService.cs new file mode 100644 index 0000000..77373ca --- /dev/null +++ b/DownKyi/Services/Download/DownloadStorageService.cs @@ -0,0 +1,277 @@ +using DownKyi.Core.Storage.Database.Download; +using DownKyi.Models; +using DownKyi.ViewModels.DownloadManager; +using System.Collections.Generic; + +namespace DownKyi.Services.Download; + +public class DownloadStorageService +{ + ~DownloadStorageService() + { + DownloadingDb downloadingDb = new DownloadingDb(); + downloadingDb.Close(); + DownloadedDb downloadedDb = new DownloadedDb(); + downloadedDb.Close(); + DownloadBaseDb downloadBaseDb = new DownloadBaseDb(); + downloadBaseDb.Close(); + } + + #region 下载中数据 + + /// + /// 添加下载中数据 + /// + /// + public void AddDownloading(DownloadingItem downloadingItem) + { + if (downloadingItem == null || downloadingItem.DownloadBase == null) + { + return; + } + + AddDownloadBase(downloadingItem.DownloadBase); + + DownloadingDb downloadingDb = new DownloadingDb(); + object obj = downloadingDb.QueryById(downloadingItem.DownloadBase.Uuid); + if (obj == null) + { + downloadingDb.Insert(downloadingItem.DownloadBase.Uuid, downloadingItem.Downloading); + } + //downloadingDb.Close(); + } + + /// + /// 删除下载中数据 + /// + /// + public void RemoveDownloading(DownloadingItem downloadingItem) + { + if (downloadingItem == null || downloadingItem.DownloadBase == null) + { + return; + } + + RemoveDownloadBase(downloadingItem.DownloadBase.Uuid); + + DownloadingDb downloadingDb = new DownloadingDb(); + downloadingDb.Delete(downloadingItem.DownloadBase.Uuid); + //downloadingDb.Close(); + } + + /// + /// 获取所有的下载中数据 + /// + /// + public List GetDownloading() + { + // 从数据库获取数据 + DownloadingDb downloadingDb = new DownloadingDb(); + Dictionary dic = downloadingDb.QueryAll(); + //downloadingDb.Close(); + + // 遍历 + List list = new List(); + foreach (KeyValuePair item in dic) + { + if (item.Value is Downloading downloading) + { + DownloadingItem downloadingItem = new DownloadingItem + { + DownloadBase = GetDownloadBase(item.Key), + Downloading = downloading + }; + + if (downloadingItem.DownloadBase == null) + { + continue; + } + + list.Add(downloadingItem); + } + } + + return list; + } + + /// + /// 修改下载中数据 + /// + /// + public void UpdateDownloading(DownloadingItem downloadingItem) + { + if (downloadingItem == null || downloadingItem.DownloadBase == null) + { + return; + } + + UpdateDownloadBase(downloadingItem.DownloadBase); + + DownloadingDb downloadingDb = new DownloadingDb(); + downloadingDb.Update(downloadingItem.DownloadBase.Uuid, downloadingItem.Downloading); + //downloadingDb.Close(); + } + + #endregion + + #region 下载完成数据 + + /// + /// 添加下载完成数据 + /// + /// + public void AddDownloaded(DownloadedItem downloadedItem) + { + if (downloadedItem == null || downloadedItem.DownloadBase == null) + { + return; + } + + AddDownloadBase(downloadedItem.DownloadBase); + + DownloadedDb downloadedDb = new DownloadedDb(); + object obj = downloadedDb.QueryById(downloadedItem.DownloadBase.Uuid); + if (obj == null) + { + downloadedDb.Insert(downloadedItem.DownloadBase.Uuid, downloadedItem.Downloaded); + } + //downloadedDb.Close(); + } + + /// + /// 删除下载完成数据 + /// + /// + public void RemoveDownloaded(DownloadedItem downloadedItem) + { + if (downloadedItem == null || downloadedItem.DownloadBase == null) + { + return; + } + + RemoveDownloadBase(downloadedItem.DownloadBase.Uuid); + + DownloadedDb downloadedDb = new DownloadedDb(); + downloadedDb.Delete(downloadedItem.DownloadBase.Uuid); + //downloadedDb.Close(); + } + + /// + /// 获取所有的下载完成数据 + /// + /// + public List GetDownloaded() + { + // 从数据库获取数据 + DownloadedDb downloadedDb = new DownloadedDb(); + Dictionary dic = downloadedDb.QueryAll(); + //downloadedDb.Close(); + + // 遍历 + List list = new List(); + foreach (KeyValuePair item in dic) + { + if (item.Value is Downloaded downloaded) + { + DownloadedItem downloadedItem = new DownloadedItem + { + DownloadBase = GetDownloadBase(item.Key), + Downloaded = downloaded + }; + + if (downloadedItem.DownloadBase == null) + { + continue; + } + + list.Add(downloadedItem); + } + } + + return list; + } + + /// + /// 修改下载完成数据 + /// + /// + public void UpdateDownloaded(DownloadedItem downloadedItem) + { + if (downloadedItem == null || downloadedItem.DownloadBase == null) + { + return; + } + + UpdateDownloadBase(downloadedItem.DownloadBase); + + DownloadedDb downloadedDb = new DownloadedDb(); + downloadedDb.Update(downloadedItem.DownloadBase.Uuid, downloadedItem.Downloaded); + //downloadedDb.Close(); + } + + #endregion + + #region DownloadBase + + /// + /// 向数据库添加DownloadBase + /// + /// + private void AddDownloadBase(DownloadBase downloadBase) + { + if (downloadBase == null) + { + return; + } + + DownloadBaseDb downloadBaseDb = new DownloadBaseDb(); + object obj = downloadBaseDb.QueryById(downloadBase.Uuid); + if (obj == null) + { + downloadBaseDb.Insert(downloadBase.Uuid, downloadBase); + } + //downloadBaseDb.Close(); + } + + /// + /// 从数据库删除DownloadBase + /// + /// + private void RemoveDownloadBase(string uuid) + { + DownloadBaseDb downloadBaseDb = new DownloadBaseDb(); + downloadBaseDb.Delete(uuid); + //downloadBaseDb.Close(); + } + + /// + /// 从数据库获取所有的DownloadBase + /// + /// + private DownloadBase GetDownloadBase(string uuid) + { + DownloadBaseDb downloadBaseDb = new DownloadBaseDb(); + object obj = downloadBaseDb.QueryById(uuid); + //downloadBaseDb.Close(); + + return obj is DownloadBase downloadBase ? downloadBase : null; + } + + /// + /// 从数据库修改DownloadBase + /// + /// + private void UpdateDownloadBase(DownloadBase downloadBase) + { + if (downloadBase == null) + { + return; + } + + DownloadBaseDb downloadBaseDb = new DownloadBaseDb(); + downloadBaseDb.Update(downloadBase.Uuid, downloadBase); + //downloadBaseDb.Close(); + } + + #endregion +} \ No newline at end of file diff --git a/DownKyi/Services/Download/IDownloadService.cs b/DownKyi/Services/Download/IDownloadService.cs new file mode 100644 index 0000000..6455f1c --- /dev/null +++ b/DownKyi/Services/Download/IDownloadService.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; +using DownKyi.ViewModels.DownloadManager; + +namespace DownKyi.Services.Download; + +public interface IDownloadService +{ + void Parse(DownloadingItem downloading); + string DownloadAudio(DownloadingItem downloading); + string DownloadVideo(DownloadingItem downloading); + string DownloadDanmaku(DownloadingItem downloading); + List DownloadSubtitle(DownloadingItem downloading); + string DownloadCover(DownloadingItem downloading, string coverUrl, string fileName); + string MixedFlow(DownloadingItem downloading, string audioUid, string videoUid); + + void Start(); + void End(); +} \ No newline at end of file diff --git a/DownKyi/Services/FavoritesService.cs b/DownKyi/Services/FavoritesService.cs new file mode 100644 index 0000000..e164156 --- /dev/null +++ b/DownKyi/Services/FavoritesService.cs @@ -0,0 +1,252 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Threading; +using Avalonia.Media.Imaging; +using DownKyi.Core.BiliApi.Favorites; +using DownKyi.Core.Storage; +using DownKyi.Core.Utils; +using DownKyi.ViewModels.PageViewModels; +using Prism.Events; +using FavoritesMedia = DownKyi.Core.BiliApi.Favorites.Models.FavoritesMedia; + +namespace DownKyi.Services; + +public class FavoritesService : IFavoritesService +{ + /// + /// 获取收藏夹元数据 + /// + /// + /// + public Favorites GetFavorites(long mediaId) + { + var favoritesMetaInfo = FavoritesInfo.GetFavoritesInfo(mediaId); + if (favoritesMetaInfo == null) + { + return null; + } + + // 查询、保存封面 + StorageCover storageCover = new StorageCover(); + string coverUrl = favoritesMetaInfo.Cover; + Bitmap cover = storageCover.GetCoverThumbnail(favoritesMetaInfo.Id, "Favorites", favoritesMetaInfo.Mid, + coverUrl, 300, 188); + + // 获取用户头像 + string upName; + string header; + if (favoritesMetaInfo.Upper != null) + { + upName = favoritesMetaInfo.Upper.Name; + StorageHeader storageHeader = new StorageHeader(); + header = storageHeader.GetHeader(favoritesMetaInfo.Upper.Mid, favoritesMetaInfo.Upper.Name, + favoritesMetaInfo.Upper.Face); + } + else + { + upName = ""; + header = null; + } + + // 为Favorites赋值 + Favorites favorites = new Favorites(); + App.PropertyChangeAsync(new Action(() => + { + favorites.CoverUrl = coverUrl; + + favorites.Cover = cover; + favorites.Title = favoritesMetaInfo.Title; + + DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1)); // 当地时区 + DateTime dateTime = startTime.AddSeconds(favoritesMetaInfo.Ctime); + favorites.CreateTime = dateTime.ToString("yyyy-MM-dd HH:mm:ss"); + + favorites.PlayNumber = Format.FormatNumber(favoritesMetaInfo.CntInfo.Play); + favorites.LikeNumber = Format.FormatNumber(favoritesMetaInfo.CntInfo.ThumbUp); + favorites.FavoriteNumber = Format.FormatNumber(favoritesMetaInfo.CntInfo.Collect); + favorites.ShareNumber = Format.FormatNumber(favoritesMetaInfo.CntInfo.Share); + favorites.Description = favoritesMetaInfo.Intro; + favorites.MediaCount = favoritesMetaInfo.MediaCount; + + favorites.UpName = upName; + if (header != null) + { + StorageHeader storageHeader = new StorageHeader(); + favorites.UpHeader = storageHeader.GetHeaderThumbnail(header, 48, 48); + + favorites.UpperMid = favoritesMetaInfo.Upper.Mid; + } + else + { + favorites.UpHeader = null; + } + })); + + return favorites; + } + + ///// + ///// 获取收藏夹所有内容明细列表 + ///// + ///// + ///// + ///// + //public void GetFavoritesMediaList(long mediaId, ObservableCollection result, IEventAggregator eventAggregator, CancellationToken cancellationToken) + //{ + // List medias = FavoritesResource.GetAllFavoritesMedia(mediaId); + // if (medias.Count == 0) { return; } + + // GetFavoritesMediaList(medias, result, eventAggregator, cancellationToken); + //} + + ///// + ///// 获取收藏夹指定页的内容明细列表 + ///// + ///// + ///// + ///// + ///// + ///// + //public void GetFavoritesMediaList(long mediaId, int pn, int ps, ObservableCollection result, IEventAggregator eventAggregator, CancellationToken cancellationToken) + //{ + // List medias = FavoritesResource.GetFavoritesMedia(mediaId, pn, ps); + // if (medias.Count == 0) { return; } + + // GetFavoritesMediaList(medias, result, eventAggregator, cancellationToken); + //} + + /// + /// 获取收藏夹内容明细列表 + /// + /// + /// + /// + public void GetFavoritesMediaList(List medias, + ObservableCollection result, IEventAggregator eventAggregator, + CancellationToken cancellationToken) + { + int order = 0; + foreach (var media in medias) + { + if (media.Title == "已失效视频") + { + continue; + } + + order++; + + // 查询、保存封面 + StorageCover storageCover = new StorageCover(); + string coverUrl = media.Cover; + Bitmap cover = storageCover.GetCoverThumbnail(media.Id, media.Bvid, -1, coverUrl, 200, 125); + + // 当地时区 + DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1)); + + // 创建时间 + DateTime dateCTime = startTime.AddSeconds(media.Ctime); + string ctime = dateCTime.ToString("yyyy-MM-dd"); + + // 收藏时间 + DateTime dateFavTime = startTime.AddSeconds(media.FavTime); + string favTime = dateFavTime.ToString("yyyy-MM-dd"); + + App.PropertyChangeAsync(new Action(() => + { + ViewModels.PageViewModels.FavoritesMedia newMedia = + new ViewModels.PageViewModels.FavoritesMedia(eventAggregator) + { + Avid = media.Id, + Bvid = media.Bvid, + Order = order, + Cover = cover, + Title = media.Title, + PlayNumber = media.CntInfo != null ? Format.FormatNumber(media.CntInfo.Play) : "0", + DanmakuNumber = media.CntInfo != null ? Format.FormatNumber(media.CntInfo.Danmaku) : "0", + FavoriteNumber = media.CntInfo != null ? Format.FormatNumber(media.CntInfo.Collect) : "0", + Duration = Format.FormatDuration2(media.Duration), + UpName = media.Upper != null ? media.Upper.Name : string.Empty, + UpMid = media.Upper != null ? media.Upper.Mid : -1, + CreateTime = ctime, + FavTime = favTime + }; + + if (!result.ToList().Exists(t => t.Avid == newMedia.Avid)) + { + result.Add(newMedia); + Thread.Sleep(10); + } + })); + + // 判断是否该结束线程,若为true,跳出循环 + if (cancellationToken.IsCancellationRequested) + { + break; + } + } + } + + /// + /// 更新我创建的收藏夹列表 + /// + /// + /// + public void GetCreatedFavorites(long mid, ObservableCollection tabHeaders, + CancellationToken cancellationToken) + { + var favorites = FavoritesInfo.GetAllCreatedFavorites(mid); + if (favorites.Count == 0) + { + return; + } + + foreach (var item in favorites) + { + //cancellationToken.ThrowIfCancellationRequested(); + + // 判断是否该结束线程,若为true,跳出循环 + if (cancellationToken.IsCancellationRequested) + { + break; + } + + App.PropertyChangeAsync(new Action(() => + { + tabHeaders.Add(new TabHeader + { Id = item.Id, Title = item.Title, SubTitle = item.MediaCount.ToString() }); + })); + } + } + + /// + /// 更新我收藏的收藏夹列表 + /// + /// + /// + public void GetCollectedFavorites(long mid, ObservableCollection tabHeaders, + CancellationToken cancellationToken) + { + var favorites = FavoritesInfo.GetAllCollectedFavorites(mid); + if (favorites.Count == 0) + { + return; + } + + foreach (var item in favorites) + { + // 判断是否该结束线程,若为true,跳出循环 + if (cancellationToken.IsCancellationRequested) + { + break; + } + + App.PropertyChangeAsync(new Action(() => + { + tabHeaders.Add(new TabHeader + { Id = item.Id, Title = item.Title, SubTitle = item.MediaCount.ToString() }); + })); + } + } +} \ No newline at end of file diff --git a/DownKyi/Services/IFavoritesService.cs b/DownKyi/Services/IFavoritesService.cs new file mode 100644 index 0000000..5f36e6e --- /dev/null +++ b/DownKyi/Services/IFavoritesService.cs @@ -0,0 +1,25 @@ +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Threading; +using DownKyi.ViewModels.PageViewModels; +using Prism.Events; +using FavoritesMedia = DownKyi.Core.BiliApi.Favorites.Models.FavoritesMedia; + +namespace DownKyi.Services; + +public interface IFavoritesService +{ + Favorites GetFavorites(long mediaId); + + //void GetFavoritesMediaList(long mediaId, ObservableCollection result, IEventAggregator eventAggregator, CancellationToken cancellationToken); + //void GetFavoritesMediaList(long mediaId, int pn, int ps, ObservableCollection result, IEventAggregator eventAggregator, CancellationToken cancellationToken); + void GetFavoritesMediaList(List medias, + ObservableCollection result, IEventAggregator eventAggregator, + CancellationToken cancellationToken); + + void GetCreatedFavorites(long mid, ObservableCollection tabHeaders, + CancellationToken cancellationToken); + + void GetCollectedFavorites(long mid, ObservableCollection tabHeaders, + CancellationToken cancellationToken); +} \ No newline at end of file diff --git a/DownKyi/Services/IInfoService.cs b/DownKyi/Services/IInfoService.cs new file mode 100644 index 0000000..e3d25ac --- /dev/null +++ b/DownKyi/Services/IInfoService.cs @@ -0,0 +1,15 @@ +using System.Collections.Generic; +using DownKyi.ViewModels.PageViewModels; + +namespace DownKyi.Services; + +public interface IInfoService +{ + VideoInfoView GetVideoView(); + + List GetVideoSections(bool noUgc); + + List GetVideoPages(); + + void GetVideoStream(VideoPage page); +} \ No newline at end of file diff --git a/DownKyi/Services/SearchService.cs b/DownKyi/Services/SearchService.cs new file mode 100644 index 0000000..7fd0660 --- /dev/null +++ b/DownKyi/Services/SearchService.cs @@ -0,0 +1,123 @@ +using DownKyi.Core.BiliApi.BiliUtils; +using DownKyi.Utils; +using DownKyi.ViewModels; +using Prism.Events; + +namespace DownKyi.Services; + +public class SearchService +{ + /// + /// 解析支持的输入, + /// 支持的格式有: + /// av号:av170001, AV170001, https://www.bilibili.com/video/av170001 + /// BV号:BV17x411w7KC, https://www.bilibili.com/video/BV17x411w7KC, https://b23.tv/BV17x411w7KC + /// 番剧(电影、电视剧)ss号:ss32982, SS32982, https://www.bilibili.com/bangumi/play/ss32982 + /// 番剧(电影、电视剧)ep号:ep317925, EP317925, https://www.bilibili.com/bangumi/play/ep317925 + /// 番剧(电影、电视剧)md号:md28228367, MD28228367, https://www.bilibili.com/bangumi/media/md28228367 + /// 课程ss号:https://www.bilibili.com/cheese/play/ss205 + /// 课程ep号:https://www.bilibili.com/cheese/play/ep3489 + /// 收藏夹:ml1329019876, ML1329019876, https://www.bilibili.com/medialist/detail/ml1329019876, https://www.bilibili.com/medialist/play/ml1329019876/ + /// 用户空间:uid928123, UID928123, uid:928123, UID:928123, https://space.bilibili.com/928123 + /// + /// + /// + /// + /// + public bool BiliInput(string input, string parentViewName, IEventAggregator eventAggregator) + { + // 移除剪贴板id + string justId = input.Replace(AppConstant.ClipboardId, ""); + + // 视频 + if (ParseEntrance.IsAvId(justId)) + { + NavigateToView.NavigationView(eventAggregator, ViewVideoDetailViewModel.Tag, parentViewName, + $"{ParseEntrance.VideoUrl}{input.ToLower()}"); + } + else if (ParseEntrance.IsAvUrl(justId)) + { + NavigateToView.NavigationView(eventAggregator, ViewVideoDetailViewModel.Tag, parentViewName, input); + } + else if (ParseEntrance.IsBvId(justId)) + { + NavigateToView.NavigationView(eventAggregator, ViewVideoDetailViewModel.Tag, parentViewName, + $"{ParseEntrance.VideoUrl}{input}"); + } + else if (ParseEntrance.IsBvUrl(justId)) + { + NavigateToView.NavigationView(eventAggregator, ViewVideoDetailViewModel.Tag, parentViewName, input); + } + // 番剧(电影、电视剧) + else if (ParseEntrance.IsBangumiSeasonId(justId)) + { + NavigateToView.NavigationView(eventAggregator, ViewVideoDetailViewModel.Tag, parentViewName, + $"{ParseEntrance.BangumiUrl}{input.ToLower()}"); + } + else if (ParseEntrance.IsBangumiSeasonUrl(justId)) + { + NavigateToView.NavigationView(eventAggregator, ViewVideoDetailViewModel.Tag, parentViewName, input); + } + else if (ParseEntrance.IsBangumiEpisodeId(justId)) + { + NavigateToView.NavigationView(eventAggregator, ViewVideoDetailViewModel.Tag, parentViewName, + $"{ParseEntrance.BangumiUrl}{input.ToLower()}"); + } + else if (ParseEntrance.IsBangumiEpisodeUrl(justId)) + { + NavigateToView.NavigationView(eventAggregator, ViewVideoDetailViewModel.Tag, parentViewName, input); + } + else if (ParseEntrance.IsBangumiMediaId(justId)) + { + NavigateToView.NavigationView(eventAggregator, ViewVideoDetailViewModel.Tag, parentViewName, + $"{ParseEntrance.BangumiMediaUrl}{input.ToLower()}"); + } + else if (ParseEntrance.IsBangumiMediaUrl(justId)) + { + NavigateToView.NavigationView(eventAggregator, ViewVideoDetailViewModel.Tag, parentViewName, input); + } + // 课程 + else if (ParseEntrance.IsCheeseSeasonUrl(justId) + || ParseEntrance.IsCheeseEpisodeUrl(justId)) + { + NavigateToView.NavigationView(eventAggregator, ViewVideoDetailViewModel.Tag, parentViewName, input); + } + // 用户(参数传入mid) + else if (ParseEntrance.IsUserId(justId)) + { + NavigateToView.NavigateToViewUserSpace(eventAggregator, ViewIndexViewModel.Tag, + ParseEntrance.GetUserId(input)); + } + else if (ParseEntrance.IsUserUrl(justId)) + { + NavigateToView.NavigateToViewUserSpace(eventAggregator, ViewIndexViewModel.Tag, + ParseEntrance.GetUserId(input)); + } + // // 收藏夹 + // else if (ParseEntrance.IsFavoritesId(justId)) + // { + // NavigateToView.NavigationView(eventAggregator, ViewPublicFavoritesViewModel.Tag, parentViewName, ParseEntrance.GetFavoritesId(input)); + // } + // else if (ParseEntrance.IsFavoritesUrl(justId)) + // { + // NavigateToView.NavigationView(eventAggregator, ViewPublicFavoritesViewModel.Tag, parentViewName, ParseEntrance.GetFavoritesId(input)); + // } + else + { + return false; + } + + return true; + } + + /// + /// 搜索关键词 + /// + /// + /// + /// + public void SearchKey(string key, string parentViewName, IEventAggregator eventAggregator) + { + // TODO + } +} \ No newline at end of file diff --git a/DownKyi/Services/Utils.cs b/DownKyi/Services/Utils.cs new file mode 100644 index 0000000..c330b0d --- /dev/null +++ b/DownKyi/Services/Utils.cs @@ -0,0 +1,287 @@ +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using DownKyi.Core.BiliApi.BiliUtils; +using DownKyi.Core.BiliApi.VideoStream.Models; +using DownKyi.Core.Settings; +using DownKyi.Core.Settings.Models; +using DownKyi.Core.Utils; +using DownKyi.ViewModels.PageViewModels; + +namespace DownKyi.Services; + +internal static class Utils +{ + /// + /// 从视频流更新VideoPage + /// + /// + /// + internal static void VideoPageInfo(PlayUrl playUrl, VideoPage page) + { + if (playUrl == null) + { + return; + } + + // 视频流信息 + page.PlayUrl = playUrl; + + // 获取设置 + UserInfoSettings userInfo = SettingsManager.GetInstance().GetUserInfo(); + int defaultQuality = SettingsManager.GetInstance().GetQuality(); + int videoCodecs = SettingsManager.GetInstance().GetVideoCodecs(); + int defaultAudioQuality = SettingsManager.GetInstance().GetAudioQuality(); + + // 未登录时,最高仅720P + if (userInfo.Mid == -1) + { + if (defaultQuality > 64) + { + defaultQuality = 64; + } + } + + // 非大会员账户登录时,如果设置的画质高于1080P,则这里限制为1080P + if (!userInfo.IsVip) + { + if (defaultQuality > 80) + { + defaultQuality = 80; + } + } + + if (playUrl.Durl != null) + { + // 音质 + + // 画质 + + // 视频编码 + + // 时长 + + return; + } + + if (playUrl.Dash != null) + { + // 如果video列表或者audio列表没有内容,则返回false + if (playUrl.Dash.Video == null) + { + return; + } + + if (playUrl.Dash.Video.Count == 0) + { + return; + } + + // 音质 + page.AudioQualityFormatList = GetAudioQualityFormatList(playUrl, defaultAudioQuality); + if (page.AudioQualityFormatList.Count > 0) + { + page.AudioQualityFormat = page.AudioQualityFormatList[0]; + } + + // 画质 & 视频编码 + page.VideoQualityList = GetVideoQualityList(playUrl, userInfo, defaultQuality, videoCodecs); + if (page.VideoQualityList.Count > 0) + { + page.VideoQuality = page.VideoQualityList[0]; + } + + // 时长 + page.Duration = Format.FormatDuration(playUrl.Dash.Duration); + + return; + } + } + + /// + /// 设置音质 + /// + /// + /// + /// + private static ObservableCollection GetAudioQualityFormatList(PlayUrl playUrl, int defaultAudioQuality) + { + List audioQualityFormatList = new List(); + List sortList = new List(); + List audioQualities = Constant.GetAudioQualities(); + + if (playUrl.Dash.Audio != null && playUrl.Dash.Audio.Count > 0) + { + foreach (PlayUrlDashVideo audio in playUrl.Dash.Audio) + { + // 音质id大于设置音质时,跳过 + if (audio.Id > defaultAudioQuality) + { + continue; + } + + Quality audioQuality = audioQualities.FirstOrDefault(t => { return t.Id == audio.Id; }); + if (audioQuality != null) + { + ListHelper.AddUnique(audioQualityFormatList, audioQuality.Name); + } + } + } + + if (audioQualities[3].Id <= defaultAudioQuality - 1000 && playUrl.Dash.Dolby != null) + { + if (playUrl.Dash.Dolby.Audio != null && playUrl.Dash.Dolby.Audio.Count > 0) + { + ListHelper.AddUnique(audioQualityFormatList, audioQualities[3].Name); + } + } + + if (audioQualities[4].Id <= defaultAudioQuality - 1000 && playUrl.Dash.Flac != null) + { + if (playUrl.Dash.Flac.Audio != null) + { + ListHelper.AddUnique(audioQualityFormatList, audioQualities[4].Name); + } + } + + //audioQualityFormatList.Sort(new StringLogicalComparer()); + //audioQualityFormatList.Reverse(); + + foreach (var item in audioQualities) + { + if (audioQualityFormatList.Contains(item.Name)) + { + sortList.Add(item.Name); + } + } + + sortList.Reverse(); + + return new ObservableCollection(sortList); + } + + /// + /// 设置画质 & 视频编码 + /// + /// + /// + /// + /// + /// + private static List GetVideoQualityList(PlayUrl playUrl, UserInfoSettings userInfo, + int defaultQuality, int videoCodecs) + { + List videoQualityList = new List(); + List codeIds = Constant.GetCodecIds(); + + if (playUrl.Dash.Video == null) + { + return videoQualityList; + } + + foreach (PlayUrlDashVideo video in playUrl.Dash.Video) + { + // 画质id大于设置画质时,跳过 + if (video.Id > defaultQuality) + { + continue; + } + + // 非大会员账户登录时 + if (!userInfo.IsVip) + { + // 如果画质为720P60,跳过 + if (video.Id == 74) + { + continue; + } + } + + string qualityFormat = string.Empty; + PlayUrlSupportFormat selectedQuality = playUrl.SupportFormats.FirstOrDefault(t => t.Quality == video.Id); + if (selectedQuality != null) + { + qualityFormat = selectedQuality.NewDescription; + } + + // 寻找是否已存在这个画质 + // 不存在则添加,存在则修改 + //string codecName = GetVideoCodecName(video.Codecs); + string codecName = codeIds.FirstOrDefault(t => t.Id == video.CodecId).Name; + VideoQuality videoQualityExist = videoQualityList.FirstOrDefault(t => t.Quality == video.Id); + if (videoQualityExist == null) + { + List videoCodecList = new List(); + if (codecName != string.Empty) + { + ListHelper.AddUnique(videoCodecList, codecName); + } + + VideoQuality videoQuality = new VideoQuality() + { + Quality = video.Id, + QualityFormat = qualityFormat, + VideoCodecList = videoCodecList + }; + videoQualityList.Add(videoQuality); + } + else + { + if (!videoQualityList[videoQualityList.IndexOf(videoQualityExist)].VideoCodecList + .Exists(t => t.Equals(codecName))) + { + if (codecName != string.Empty) + { + videoQualityList[videoQualityList.IndexOf(videoQualityExist)].VideoCodecList.Add(codecName); + } + } + } + + // 设置选中的视频编码 + VideoQuality selectedVideoQuality = videoQualityList.FirstOrDefault(t => t.Quality == video.Id); + if (selectedVideoQuality == null) + { + continue; + } + + // 设置选中的视频编码 + string videoCodecsName = codeIds.FirstOrDefault(t => t.Id == videoCodecs).Name; + if (videoQualityList[videoQualityList.IndexOf(selectedVideoQuality)].VideoCodecList + .Contains(videoCodecsName)) + { + videoQualityList[videoQualityList.IndexOf(selectedVideoQuality)].SelectedVideoCodec = videoCodecsName; + } + else + { + // 当获取的视频没有设置的视频编码时 + foreach (Quality codec in codeIds) + { + if (videoQualityList[videoQualityList.IndexOf(selectedVideoQuality)].VideoCodecList + .Contains(codec.Name)) + { + videoQualityList[videoQualityList.IndexOf(selectedVideoQuality)].SelectedVideoCodec = + codec.Name; + } + + if (codec.Id == videoCodecs) + { + break; + } + } + + // 若默认编码为AVC,但画质为杜比视界时, + // 上面的foreach不会选中HEVC编码, + // 而杜比视界只有HEVC编码, + // 因此这里再判断并设置一次 + if (videoQualityList[videoQualityList.IndexOf(selectedVideoQuality)].SelectedVideoCodec == null && + videoQualityList[videoQualityList.IndexOf(selectedVideoQuality)].VideoCodecList.Count() > 0) + { + videoQualityList[videoQualityList.IndexOf(selectedVideoQuality)].SelectedVideoCodec = + videoQualityList[videoQualityList.IndexOf(selectedVideoQuality)].VideoCodecList[0]; + } + } + } + + return videoQualityList; + } +} \ No newline at end of file diff --git a/DownKyi/Services/VideoInfoService.cs b/DownKyi/Services/VideoInfoService.cs new file mode 100644 index 0000000..934fd0e --- /dev/null +++ b/DownKyi/Services/VideoInfoService.cs @@ -0,0 +1,337 @@ +using System; +using System.Collections.Generic; +using Avalonia.Media.Imaging; +using Avalonia.Threading; +using DownKyi.Core.BiliApi.BiliUtils; +using DownKyi.Core.BiliApi.Models; +using DownKyi.Core.BiliApi.Video; +using DownKyi.Core.BiliApi.Video.Models; +using DownKyi.Core.BiliApi.VideoStream; +using DownKyi.Core.BiliApi.Zone; +using DownKyi.Core.Settings; +using DownKyi.Core.Storage; +using DownKyi.Core.Utils; +using DownKyi.ViewModels.PageViewModels; +using VideoPage = DownKyi.ViewModels.PageViewModels.VideoPage; + +namespace DownKyi.Services; + +public class VideoInfoService : IInfoService +{ + private readonly VideoView videoView; + + public VideoInfoService(string input) + { + if (input == null) + { + return; + } + + if (ParseEntrance.IsAvId(input) || ParseEntrance.IsAvUrl(input)) + { + long avid = ParseEntrance.GetAvId(input); + videoView = VideoInfo.VideoViewInfo(null, avid); + } + + if (ParseEntrance.IsBvId(input) || ParseEntrance.IsBvUrl(input)) + { + string bvid = ParseEntrance.GetBvId(input); + videoView = VideoInfo.VideoViewInfo(bvid); + } + } + + /// + /// 获取视频剧集 + /// + /// + public List GetVideoPages() + { + if (videoView == null) + { + return null; + } + + if (videoView.Pages == null) + { + return null; + } + + if (videoView.Pages.Count == 0) + { + return null; + } + + List videoPages = new List(); + + int order = 0; + foreach (var page in videoView.Pages) + { + order++; + + // 标题 + string name; + if (videoView.Pages.Count == 1) + { + name = videoView.Title; + } + else + { + //name = page.part; + if (page.Part == "") + { + // 如果page.part为空字符串 + name = $"{videoView.Title}-P{order}"; + } + else + { + name = page.Part; + } + } + + VideoPage videoPage = new VideoPage + { + Avid = videoView.Aid, + Bvid = videoView.Bvid, + Cid = page.Cid, + EpisodeId = -1, + FirstFrame = page.FirstFrame, + Order = order, + Name = name, + Duration = "N/A" + }; + + // UP主信息 + videoPage.Owner = videoView.Owner; + if (videoPage.Owner == null) + { + videoPage.Owner = new VideoOwner + { + Name = "", + Face = "", + Mid = -1, + }; + } + + // 文件命名中的时间格式 + string timeFormat = SettingsManager.GetInstance().GetFileNamePartTimeFormat(); + // 视频发布时间 + DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1)); // 当地时区 + DateTime dateTime = startTime.AddSeconds(videoView.Pubdate); + videoPage.PublishTime = dateTime.ToString(timeFormat); + + videoPages.Add(videoPage); + } + + return videoPages; + } + + /// + /// 获取视频章节与剧集 + /// + /// + public List GetVideoSections(bool noUgc = false) + { + if (videoView == null) + { + return null; + } + + List videoSections = new List(); + + // 不需要ugc内容 + if (noUgc) + { + videoSections.Add(new VideoSection + { + Id = 0, + Title = "default", + IsSelected = true, + VideoPages = GetVideoPages() + }); + + return videoSections; + } + + if (videoView.UgcSeason == null) + { + return null; + } + + if (videoView.UgcSeason.Sections == null) + { + return null; + } + + if (videoView.UgcSeason.Sections.Count == 0) + { + return null; + } + + foreach (UgcSection section in videoView.UgcSeason.Sections) + { + List pages = new List(); + int order = 0; + foreach (var episode in section.Episodes) + { + order++; + VideoPage page = new VideoPage + { + Avid = episode.Aid, + Bvid = episode.Bvid, + Cid = episode.Cid, + EpisodeId = -1, + FirstFrame = episode.Page.FirstFrame, + Order = order, + Name = episode.Title, + Duration = "N/A" + }; + + // UP主信息 + page.Owner = videoView.Owner; + if (page.Owner == null) + { + page.Owner = new VideoOwner + { + Name = "", + Face = "", + Mid = -1, + }; + } + + // 文件命名中的时间格式 + string timeFormat = SettingsManager.GetInstance().GetFileNamePartTimeFormat(); + // 视频发布时间 + DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1)); // 当地时区 + DateTime dateTime = startTime.AddSeconds(videoView.Pubdate); + page.PublishTime = dateTime.ToString(timeFormat); + // 这里的发布时间有问题, + // 如果是合集,也会执行这里, + // 但是发布时间是入口视频的,不是所有视频的 + // TODO 修复 + + pages.Add(page); + } + + VideoSection videoSection = new VideoSection + { + Id = section.Id, + Title = section.Title, + VideoPages = pages + }; + videoSections.Add(videoSection); + } + + videoSections[0].IsSelected = true; + + return videoSections; + } + + /// + /// 获取视频流的信息,从VideoPage返回 + /// + /// + public void GetVideoStream(VideoPage page) + { + var playUrl = VideoStream.GetVideoPlayUrl(page.Avid, page.Bvid, page.Cid); + Dispatcher.UIThread.InvokeAsync(() => + { + Utils.VideoPageInfo(playUrl, page); + }); + } + + /// + /// 获取视频信息 + /// + /// + public VideoInfoView GetVideoView() + { + if (videoView == null) + { + return null; + } + + // 查询、保存封面 + StorageCover storageCover = new StorageCover(); + string coverUrl = videoView.Pic; + string cover = storageCover.GetCover(videoView.Aid, videoView.Bvid, videoView.Cid, coverUrl); + + // 分区 + string videoZone = string.Empty; + var zoneList = VideoZone.Instance().GetZones(); + var zone = zoneList.Find(it => it.Id == videoView.Tid); + if (zone != null) + { + var zoneParent = zoneList.Find(it => it.Id == zone.ParentId); + if (zoneParent != null) + { + videoZone = zoneParent.Name + ">" + zone.Name; + } + else + { + videoZone = zone.Name; + } + } + else + { + videoZone = videoView.Tname; + } + + // 获取用户头像 + string upName; + string header; + if (videoView.Owner != null) + { + upName = videoView.Owner.Name; + StorageHeader storageHeader = new StorageHeader(); + header = storageHeader.GetHeader(videoView.Owner.Mid, videoView.Owner.Name, videoView.Owner.Face); + } + else + { + upName = ""; + header = null; + } + + // 为videoInfoView赋值 + VideoInfoView videoInfoView = new VideoInfoView(); + App.PropertyChangeAsync(new Action(() => + { + videoInfoView.CoverUrl = coverUrl; + + videoInfoView.Cover = cover == null ? null : new Bitmap(cover); + videoInfoView.Title = videoView.Title; + + // 分区id + videoInfoView.TypeId = videoView.Tid; + + videoInfoView.VideoZone = videoZone; + + DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1)); // 当地时区 + DateTime dateTime = startTime.AddSeconds(videoView.Pubdate); + videoInfoView.CreateTime = dateTime.ToString("yyyy-MM-dd HH:mm:ss"); + + videoInfoView.PlayNumber = Format.FormatNumber(videoView.Stat.View); + videoInfoView.DanmakuNumber = Format.FormatNumber(videoView.Stat.Danmaku); + videoInfoView.LikeNumber = Format.FormatNumber(videoView.Stat.Like); + videoInfoView.CoinNumber = Format.FormatNumber(videoView.Stat.Coin); + videoInfoView.FavoriteNumber = Format.FormatNumber(videoView.Stat.Favorite); + videoInfoView.ShareNumber = Format.FormatNumber(videoView.Stat.Share); + videoInfoView.ReplyNumber = Format.FormatNumber(videoView.Stat.Reply); + videoInfoView.Description = videoView.Desc; + + videoInfoView.UpName = upName; + if (header != null) + { + StorageHeader storageHeader = new StorageHeader(); + videoInfoView.UpHeader = storageHeader.GetHeaderThumbnail(header, 48, 48); + + videoInfoView.UpperMid = videoView.Owner.Mid; + } + else + { + videoInfoView.UpHeader = null; + } + })); + + return videoInfoView; + } +} \ No newline at end of file diff --git a/DownKyi/Themes/ColorBrush.axaml b/DownKyi/Themes/ColorBrush.axaml new file mode 100644 index 0000000..9e36f36 --- /dev/null +++ b/DownKyi/Themes/ColorBrush.axaml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/DownKyi/Themes/Colors/ColorDefault.axaml b/DownKyi/Themes/Colors/ColorDefault.axaml new file mode 100644 index 0000000..6277975 --- /dev/null +++ b/DownKyi/Themes/Colors/ColorDefault.axaml @@ -0,0 +1,60 @@ + + Black + Black + white + + white + black + #FF6ECEF8 + #FF30B8F6 + #FFE81123 + #FFF1707A + + #FFFF4D3C + + #FF00A1D6 + #C800A1D6 + #7F00A1D6 + #3300A1D6 + + #FFFB7299 + + #FF00A1D6 + #FFFFFFFF + #FFFFFFFF + #FF00A1D6 + #FFBDBDBD + #FFE4E4E4 + #FFBDBDBD + #C8BDBDBD + #7FBDBDBD + #33BDBDBD + + #7F000000 + #33999999 + + #FFF4F4F4 + + #FFF4F4F4 + + #FF999999 + #7F999999 + #99000000 + + #7FD0D0D0 + #7FFFFFFF + #7FD0D0D0 + + #FFE4E4E4 + #FFF3CB85 + + white + black + #FF999999 + #FF757575 + + #FFFFAE00 + #FF02B5DA + + diff --git a/DownKyi/Themes/Styles/StyleBtn.axaml b/DownKyi/Themes/Styles/StyleBtn.axaml new file mode 100644 index 0000000..6c86cdb --- /dev/null +++ b/DownKyi/Themes/Styles/StyleBtn.axaml @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/DownKyi/Themes/Styles/StyleCheckBox.axaml b/DownKyi/Themes/Styles/StyleCheckBox.axaml new file mode 100644 index 0000000..83cb3f6 --- /dev/null +++ b/DownKyi/Themes/Styles/StyleCheckBox.axaml @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/DownKyi/Themes/Styles/StyleImageBtn.axaml b/DownKyi/Themes/Styles/StyleImageBtn.axaml new file mode 100644 index 0000000..05e0001 --- /dev/null +++ b/DownKyi/Themes/Styles/StyleImageBtn.axaml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + diff --git a/DownKyi/Themes/Styles/StyleListBox.axaml b/DownKyi/Themes/Styles/StyleListBox.axaml new file mode 100644 index 0000000..4978f8a --- /dev/null +++ b/DownKyi/Themes/Styles/StyleListBox.axaml @@ -0,0 +1,254 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/DownKyi/Themes/Styles/StyleRadio.axaml b/DownKyi/Themes/Styles/StyleRadio.axaml new file mode 100644 index 0000000..b456e73 --- /dev/null +++ b/DownKyi/Themes/Styles/StyleRadio.axaml @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/DownKyi/Themes/Styles/loading.axaml b/DownKyi/Themes/Styles/loading.axaml new file mode 100644 index 0000000..b0c8c71 --- /dev/null +++ b/DownKyi/Themes/Styles/loading.axaml @@ -0,0 +1,415 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/DownKyi/Themes/ThemeDefault.axaml b/DownKyi/Themes/ThemeDefault.axaml new file mode 100644 index 0000000..86d80f7 --- /dev/null +++ b/DownKyi/Themes/ThemeDefault.axaml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + diff --git a/DownKyi/Utils/DialogUtils.cs b/DownKyi/Utils/DialogUtils.cs new file mode 100644 index 0000000..f4e3317 --- /dev/null +++ b/DownKyi/Utils/DialogUtils.cs @@ -0,0 +1,80 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Threading.Tasks; +using Avalonia; +using Avalonia.Controls; +using Avalonia.Controls.ApplicationLifetimes; +using Avalonia.Platform.Storage; + +namespace DownKyi.Utils; + +public static class DialogUtils +{ + private static readonly string DefaultDirectory = Environment.CurrentDirectory; + + /// + /// 弹出选择文件夹弹窗 + /// + /// + public static async Task SetDownloadDirectory() + { + if (Application.Current?.ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime desktop || + desktop.MainWindow?.StorageProvider is not { } provider) + throw new NullReferenceException("Missing StorageProvider instance."); + var folders = await provider.OpenFolderPickerAsync(new FolderPickerOpenOptions + { + Title = "选择文件夹", + SuggestedStartLocation = await provider.TryGetFolderFromPathAsync(new Uri(DefaultDirectory)), + AllowMultiple = false + }); + return folders.Count > 0 ? folders[0].Path.LocalPath : null; + } + + /// + /// 选择视频dialog + /// + /// + public static async Task SelectVideoFile() + { + if (Application.Current?.ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime desktop || + desktop.MainWindow?.StorageProvider is not { } provider) + throw new NullReferenceException("Missing StorageProvider instance."); + var files = await provider.OpenFilePickerAsync(new FilePickerOpenOptions + { + Title = "选择视频", + SuggestedStartLocation = await provider.TryGetFolderFromPathAsync(new Uri(DefaultDirectory)), + AllowMultiple = false, + FileTypeFilter = new FilePickerFileType[] + { new("select") { Patterns = new[] { "*.mp4" }, MimeTypes = new[] { "video/mp4" } } } + }); + + // 选择文件 + return files.Count > 0 ? files[0].Path.LocalPath : null; + } + + /// + /// 选择多个视频dialog + /// + /// + public static async Task SelectMultiVideoFile() + { + if (Application.Current?.ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime desktop || + desktop.MainWindow?.StorageProvider is not { } provider) + throw new NullReferenceException("Missing StorageProvider instance."); + var files = await provider.OpenFilePickerAsync( + new FilePickerOpenOptions + { + Title = "选择视频", + SuggestedStartLocation = await provider.TryGetFolderFromPathAsync(new Uri(DefaultDirectory)), + AllowMultiple = true, + FileTypeFilter = new FilePickerFileType[] + { new("select") { Patterns = new[] { "*.mp4" } } } + } + ); + + // 选择文件 + return files.Select(file => file.Path.LocalPath).ToArray(); + } +} \ No newline at end of file diff --git a/DownKyi/Utils/DictionaryResource.cs b/DownKyi/Utils/DictionaryResource.cs new file mode 100644 index 0000000..6a3ac7c --- /dev/null +++ b/DownKyi/Utils/DictionaryResource.cs @@ -0,0 +1,48 @@ +using Avalonia; +using Avalonia.Media; +using Avalonia.Threading; + +namespace DownKyi.Utils; + +public static class DictionaryResource +{ + /// + /// 从资源获取颜色的16进制字符串 + /// + /// + /// + public static string GetColor(string resourceKey) + { + var obj = Dispatcher.UIThread.Invoke(() => + { + Application.Current.TryGetResource(resourceKey, Application.Current.ActualThemeVariant, out object obj); + return obj; + }); + return obj == null ? "#00000000" : ((Color)obj).ToString(); + } + + /// + /// 从资源获取字符串 + /// + /// + /// + public static string GetString(string resourceKey) + { + var obj = Dispatcher.UIThread.Invoke(() => + { + Application.Current.TryGetResource(resourceKey, Application.Current.ActualThemeVariant, out object obj); + return obj; + }); + return obj == null ? "" : (string)obj; + } + + public static T Get(string resourceKey) + { + var obj = Dispatcher.UIThread.Invoke(() => + { + Application.Current.TryGetResource(resourceKey, Application.Current.ActualThemeVariant, out object obj); + return obj; + }); + return (T)obj; + } +} \ No newline at end of file diff --git a/DownKyi/Utils/ImageHelper.cs b/DownKyi/Utils/ImageHelper.cs new file mode 100644 index 0000000..af5602f --- /dev/null +++ b/DownKyi/Utils/ImageHelper.cs @@ -0,0 +1,48 @@ +using System; +using System.IO; +using System.Net.Http; +using System.Threading.Tasks; +using Avalonia.Media.Imaging; +using Avalonia.Platform; + +namespace DownKyi.Utils; + +public static class ImageHelper +{ + public static Bitmap LoadFromResource(Uri resourceUri) + { + return resourceUri.Scheme switch + { + "avares" => new Bitmap(AssetLoader.Open(resourceUri)), + "file" => LoadFromFile(resourceUri), + _ => new Bitmap("") + }; + } + + private static Bitmap LoadFromAvares(Uri resourceUri) + { + return new Bitmap(AssetLoader.Open(resourceUri)); + } + + private static Bitmap LoadFromFile(Uri resourceUri) + { + return new Bitmap(resourceUri.AbsolutePath); + } + + public static async Task LoadFromWeb(Uri url) + { + using var httpClient = new HttpClient(); + try + { + var response = await httpClient.GetAsync(url); + response.EnsureSuccessStatusCode(); + var data = await response.Content.ReadAsByteArrayAsync(); + return new Bitmap(new MemoryStream(data)); + } + catch (HttpRequestException ex) + { + Console.WriteLine($"An error occurred while downloading image '{url}' : {ex.Message}"); + return null; + } + } +} \ No newline at end of file diff --git a/DownKyi/Utils/NavigateToView.cs b/DownKyi/Utils/NavigateToView.cs new file mode 100644 index 0000000..67f165c --- /dev/null +++ b/DownKyi/Utils/NavigateToView.cs @@ -0,0 +1,49 @@ +using DownKyi.Core.Settings; +using DownKyi.Core.Settings.Models; +using DownKyi.Events; +using DownKyi.ViewModels; +using Prism.Events; + +namespace DownKyi.Utils; + +public static class NavigateToView +{ + public static string Tag = "NavigateToView"; + + /// + /// 导航到用户空间, + /// 如果传入的mid与本地登录的mid一致, + /// 则进入我的用户空间。 + /// + /// + public static void NavigateToViewUserSpace(IEventAggregator eventAggregator, string parentViewName, long mid) + { + UserInfoSettings userInfo = SettingsManager.GetInstance().GetUserInfo(); + if (userInfo != null && userInfo.Mid == mid) + { + NavigationView(eventAggregator, ViewMySpaceViewModel.Tag, parentViewName, mid); + } + else + { + NavigationView(eventAggregator, ViewUserSpaceViewModel.Tag, parentViewName, mid); + } + } + + /// + /// 导航到其他页面 + /// + /// + /// + public static void NavigationView(IEventAggregator eventAggregator, string viewName, string parentViewName, + object param) + { + // LogManager.Debug(Tag, $"NavigationView: {viewName}, Parameter: {param}"); + NavigationParam parameter = new NavigationParam + { + ViewName = viewName, + ParentViewName = parentViewName, + Parameter = param + }; + eventAggregator.GetEvent().Publish(parameter); + } +} \ No newline at end of file diff --git a/DownKyi/ViewModels/Dialogs/BaseDialogViewModel.cs b/DownKyi/ViewModels/Dialogs/BaseDialogViewModel.cs new file mode 100644 index 0000000..28d3135 --- /dev/null +++ b/DownKyi/ViewModels/Dialogs/BaseDialogViewModel.cs @@ -0,0 +1,135 @@ +using System; +using DownKyi.Images; +using DownKyi.Utils; +using Prism.Commands; +using Prism.Mvvm; +using Prism.Services.Dialogs; + +namespace DownKyi.ViewModels.Dialogs; + +public class BaseDialogViewModel : BindableBase, IDialogAware +{ + #region 页面属性申明 + + private string title; + + public string Title + { + get { return title; } + set { SetProperty(ref title, value); } + } + + private VectorImage closeIcon; + + public VectorImage CloseIcon + { + get { return closeIcon; } + set { SetProperty(ref closeIcon, value); } + } + + #endregion + + public BaseDialogViewModel() + { + #region 属性初始化 + + // Title = new AppInfo().Name; + // CloseIcon = new VectorImage + // { + // Height = SystemIcon.Instance().Close.Height, + // Width = SystemIcon.Instance().Close.Width, + // Data = SystemIcon.Instance().Close.Data, + // Fill = SystemIcon.Instance().Close.Fill + // }; + + #endregion + } + + #region 命令申明 + + // 鼠标进入关闭按钮事件 + private DelegateCommand closeEnterCommand; + + public DelegateCommand CloseEnterCommand => + closeEnterCommand ?? (closeEnterCommand = new DelegateCommand(ExecuteCloseEnterCommand)); + + /// + /// 鼠标进入关闭按钮事件 + /// + private void ExecuteCloseEnterCommand() + { + SetEnterStyle(CloseIcon); + } + + // 鼠标离开关闭按钮事件 + private DelegateCommand closeLeaveCommand; + + public DelegateCommand CloseLeaveCommand => + closeLeaveCommand ?? (closeLeaveCommand = new DelegateCommand(ExecuteCloseLeaveCommand)); + + /// + /// 鼠标离开关闭按钮事件 + /// + private void ExecuteCloseLeaveCommand() + { + SetLeaveStyle(CloseIcon); + } + + // 关闭窗口事件 + private DelegateCommand closeCommand; + public DelegateCommand CloseCommand => closeCommand ?? (closeCommand = new DelegateCommand(ExecuteCloseCommand)); + + /// + /// 关闭窗口事件 + /// + private void ExecuteCloseCommand() + { + ButtonResult result = ButtonResult.Cancel; + RaiseRequestClose(new DialogResult(result)); + } + + #endregion + + /// + /// 鼠标进入系统按钮时的图标样式 + /// + /// 图标 + private void SetEnterStyle(VectorImage icon) + { + icon.Fill = DictionaryResource.GetColor("ColorSystemBtnTint"); + } + + /// + /// 鼠标离开系统按钮时的图标样式 + /// + /// 图标 + private void SetLeaveStyle(VectorImage icon) + { + icon.Fill = DictionaryResource.GetColor("ColorSystemBtnTintDark"); + } + + #region 接口实现 + + //触发窗体关闭事件 + public virtual void RaiseRequestClose(IDialogResult dialogResult) + { + RequestClose?.Invoke(dialogResult); + } + + public event Action RequestClose; + + public virtual bool CanCloseDialog() + { + return true; + } + + public virtual void OnDialogClosed() + { + } + + public virtual void OnDialogOpened(IDialogParameters parameters) + { + } + + #endregion +} \ No newline at end of file diff --git a/DownKyi/ViewModels/Dialogs/ViewAlertDialogViewModel.cs b/DownKyi/ViewModels/Dialogs/ViewAlertDialogViewModel.cs new file mode 100644 index 0000000..4ab866a --- /dev/null +++ b/DownKyi/ViewModels/Dialogs/ViewAlertDialogViewModel.cs @@ -0,0 +1,98 @@ +using DownKyi.Images; +using Prism.Commands; +using Prism.Services.Dialogs; + +namespace DownKyi.ViewModels.Dialogs; + +public class ViewAlertDialogViewModel : BaseDialogViewModel +{ + public const string Tag = "DialogAlert"; + + #region 页面属性申明 + + private VectorImage image; + + public VectorImage Image + { + get => image; + set => SetProperty(ref image, value); + } + + private string message; + + public string Message + { + get => message; + set => SetProperty(ref message, value); + } + + + private bool aloneButton; + + public bool AloneButton + { + get => aloneButton; + set => SetProperty(ref aloneButton, value); + } + + private bool twoButton; + + public bool TwoButton + { + get => twoButton; + set => SetProperty(ref twoButton, value); + } + + #endregion + + public ViewAlertDialogViewModel() + { + } + + #region 命令申明 + + // 确认事件 + private DelegateCommand allowCommand; + public DelegateCommand AllowCommand => allowCommand ?? (allowCommand = new DelegateCommand(ExecuteAllowCommand)); + + /// + /// 确认事件 + /// + private void ExecuteAllowCommand() + { + ButtonResult result = ButtonResult.OK; + RaiseRequestClose(new DialogResult(result)); + } + + #endregion + + #region 接口实现 + + public override void OnDialogOpened(IDialogParameters parameters) + { + base.OnDialogOpened(parameters); + + Image = parameters.GetValue("image"); + Title = parameters.GetValue("title"); + Message = parameters.GetValue("message"); + int number = parameters.GetValue("button_number"); + + switch (number) + { + case 1: + AloneButton = true; + TwoButton = false; + break; + case 2: + AloneButton = false; + TwoButton = true; + break; + default: + AloneButton = false; + TwoButton = true; + break; + } + } + + #endregion +} \ No newline at end of file diff --git a/DownKyi/ViewModels/Dialogs/ViewDownloadSetterViewModel.cs b/DownKyi/ViewModels/Dialogs/ViewDownloadSetterViewModel.cs new file mode 100644 index 0000000..614b5b6 --- /dev/null +++ b/DownKyi/ViewModels/Dialogs/ViewDownloadSetterViewModel.cs @@ -0,0 +1,459 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using DownKyi.Core.Settings; +using DownKyi.Core.Settings.Models; +using DownKyi.Core.Utils; +using DownKyi.Events; +using DownKyi.Images; +using DownKyi.Utils; +using Prism.Commands; +using Prism.Events; +using Prism.Services.Dialogs; + +namespace DownKyi.ViewModels.Dialogs; + +public class ViewDownloadSetterViewModel : BaseDialogViewModel +{ + public const string Tag = "DialogDownloadSetter"; + private readonly IEventAggregator eventAggregator; + + // 历史文件夹的数量 + private readonly int maxDirectoryListCount = 20; + + #region 页面属性申明 + + private VectorImage cloudDownloadIcon; + + public VectorImage CloudDownloadIcon + { + get { return cloudDownloadIcon; } + set { SetProperty(ref cloudDownloadIcon, value); } + } + + private VectorImage folderIcon; + + public VectorImage FolderIcon + { + get { return folderIcon; } + set { SetProperty(ref folderIcon, value); } + } + + private bool isDefaultDownloadDirectory; + + public bool IsDefaultDownloadDirectory + { + get { return isDefaultDownloadDirectory; } + set { SetProperty(ref isDefaultDownloadDirectory, value); } + } + + private List directoryList; + + public List DirectoryList + { + get { return directoryList; } + set { SetProperty(ref directoryList, value); } + } + + private string directory; + + public string Directory + { + get { return directory; } + set + { + SetProperty(ref directory, value); + + if (directory != null && directory != string.Empty) + { + DriveName = directory.Substring(0, 1).ToUpper(); + DriveNameFreeSpace = Format.FormatFileSize(HardDisk.GetHardDiskFreeSpace(DriveName)); + } + } + } + + private string driveName; + + public string DriveName + { + get { return driveName; } + set { SetProperty(ref driveName, value); } + } + + private string driveNameFreeSpace; + + public string DriveNameFreeSpace + { + get { return driveNameFreeSpace; } + set { SetProperty(ref driveNameFreeSpace, value); } + } + + private bool downloadAll; + + public bool DownloadAll + { + get { return downloadAll; } + set { SetProperty(ref downloadAll, value); } + } + + private bool downloadAudio; + + public bool DownloadAudio + { + get { return downloadAudio; } + set { SetProperty(ref downloadAudio, value); } + } + + private bool downloadVideo; + + public bool DownloadVideo + { + get { return downloadVideo; } + set { SetProperty(ref downloadVideo, value); } + } + + private bool downloadDanmaku; + + public bool DownloadDanmaku + { + get { return downloadDanmaku; } + set { SetProperty(ref downloadDanmaku, value); } + } + + private bool downloadSubtitle; + + public bool DownloadSubtitle + { + get { return downloadSubtitle; } + set { SetProperty(ref downloadSubtitle, value); } + } + + private bool downloadCover; + + public bool DownloadCover + { + get { return downloadCover; } + set { SetProperty(ref downloadCover, value); } + } + + #endregion + + public ViewDownloadSetterViewModel(IEventAggregator eventAggregator) + { + this.eventAggregator = eventAggregator; + + #region 属性初始化 + + Title = DictionaryResource.GetString("DownloadSetter"); + + CloudDownloadIcon = NormalIcon.Instance().CloudDownload; + CloudDownloadIcon.Fill = DictionaryResource.GetColor("ColorPrimary"); + + FolderIcon = NormalIcon.Instance().Folder; + FolderIcon.Fill = DictionaryResource.GetColor("ColorPrimary"); + + // 下载内容 + VideoContentSettings videoContent = SettingsManager.GetInstance().GetVideoContent(); + + DownloadAudio = videoContent.DownloadAudio; + DownloadVideo = videoContent.DownloadVideo; + DownloadDanmaku = videoContent.DownloadDanmaku; + DownloadSubtitle = videoContent.DownloadSubtitle; + DownloadCover = videoContent.DownloadCover; + + if (DownloadAudio && DownloadVideo && DownloadDanmaku && DownloadSubtitle && DownloadCover) + { + DownloadAll = true; + } + else + { + DownloadAll = false; + } + + // 历史下载目录 + DirectoryList = SettingsManager.GetInstance().GetHistoryVideoRootPaths(); + string directory = SettingsManager.GetInstance().GetSaveVideoRootPath(); + if (!DirectoryList.Contains(directory)) + { + ListHelper.InsertUnique(DirectoryList, directory, 0); + } + + Directory = directory; + + // 是否使用默认下载目录 + IsDefaultDownloadDirectory = SettingsManager.GetInstance().IsUseSaveVideoRootPath() == AllowStatus.YES; + + #endregion + } + + #region 命令申明 + + // 浏览文件夹事件 + private DelegateCommand browseCommand; + + public DelegateCommand BrowseCommand => + browseCommand ?? (browseCommand = new DelegateCommand(ExecuteBrowseCommand)); + + /// + /// 浏览文件夹事件 + /// + private async void ExecuteBrowseCommand() + { + var directory = await SetDirectory(); + + if (directory == null) + { + eventAggregator.GetEvent().Publish(DictionaryResource.GetString("WarningNullDirectory")); + Directory = string.Empty; + } + else + { + ListHelper.InsertUnique(DirectoryList, directory, 0); + Directory = directory; + + if (DirectoryList.Count > maxDirectoryListCount) + { + DirectoryList.RemoveAt(maxDirectoryListCount); + } + } + } + + // 所有内容选择事件 + private DelegateCommand downloadAllCommand; + + public DelegateCommand DownloadAllCommand => + downloadAllCommand ?? (downloadAllCommand = new DelegateCommand(ExecuteDownloadAllCommand)); + + /// + /// 所有内容选择事件 + /// + private void ExecuteDownloadAllCommand() + { + if (DownloadAll) + { + DownloadAudio = true; + DownloadVideo = true; + DownloadDanmaku = true; + DownloadSubtitle = true; + DownloadCover = true; + } + else + { + DownloadAudio = false; + DownloadVideo = false; + DownloadDanmaku = false; + DownloadSubtitle = false; + DownloadCover = false; + } + + SetVideoContent(); + } + + // 音频选择事件 + private DelegateCommand downloadAudioCommand; + + public DelegateCommand DownloadAudioCommand => downloadAudioCommand ?? + (downloadAudioCommand = + new DelegateCommand(ExecuteDownloadAudioCommand)); + + /// + /// 音频选择事件 + /// + private void ExecuteDownloadAudioCommand() + { + if (!DownloadAudio) + { + DownloadAll = false; + } + + if (DownloadAudio && DownloadVideo && DownloadDanmaku && DownloadSubtitle && DownloadCover) + { + DownloadAll = true; + } + + SetVideoContent(); + } + + // 视频选择事件 + private DelegateCommand downloadVideoCommand; + + public DelegateCommand DownloadVideoCommand => downloadVideoCommand ?? + (downloadVideoCommand = + new DelegateCommand(ExecuteDownloadVideoCommand)); + + /// + /// 视频选择事件 + /// + private void ExecuteDownloadVideoCommand() + { + if (!DownloadVideo) + { + DownloadAll = false; + } + + if (DownloadAudio && DownloadVideo && DownloadDanmaku && DownloadSubtitle && DownloadCover) + { + DownloadAll = true; + } + + SetVideoContent(); + } + + // 弹幕选择事件 + private DelegateCommand downloadDanmakuCommand; + + public DelegateCommand DownloadDanmakuCommand => downloadDanmakuCommand ?? + (downloadDanmakuCommand = + new DelegateCommand(ExecuteDownloadDanmakuCommand)); + + /// + /// 弹幕选择事件 + /// + private void ExecuteDownloadDanmakuCommand() + { + if (!DownloadDanmaku) + { + DownloadAll = false; + } + + if (DownloadAudio && DownloadVideo && DownloadDanmaku && DownloadSubtitle && DownloadCover) + { + DownloadAll = true; + } + + SetVideoContent(); + } + + // 字幕选择事件 + private DelegateCommand downloadSubtitleCommand; + + public DelegateCommand DownloadSubtitleCommand => downloadSubtitleCommand ?? + (downloadSubtitleCommand = + new DelegateCommand(ExecuteDownloadSubtitleCommand)); + + /// + /// 字幕选择事件 + /// + private void ExecuteDownloadSubtitleCommand() + { + if (!DownloadSubtitle) + { + DownloadAll = false; + } + + if (DownloadAudio && DownloadVideo && DownloadDanmaku && DownloadSubtitle && DownloadCover) + { + DownloadAll = true; + } + + SetVideoContent(); + } + + // 封面选择事件 + private DelegateCommand downloadCoverCommand; + + public DelegateCommand DownloadCoverCommand => downloadCoverCommand ?? + (downloadCoverCommand = + new DelegateCommand(ExecuteDownloadCoverCommand)); + + /// + /// 封面选择事件 + /// + private void ExecuteDownloadCoverCommand() + { + if (!DownloadCover) + { + DownloadAll = false; + } + + if (DownloadAudio && DownloadVideo && DownloadDanmaku && DownloadSubtitle && DownloadCover) + { + DownloadAll = true; + } + + SetVideoContent(); + } + + // 确认下载事件 + private DelegateCommand downloadCommand; + + public DelegateCommand DownloadCommand => + downloadCommand ?? (downloadCommand = new DelegateCommand(ExecuteDownloadCommand)); + + /// + /// 确认下载事件 + /// + private void ExecuteDownloadCommand() + { + if (Directory == null || Directory == string.Empty) + { + return; + } + + // 设此文件夹为默认下载文件夹 + if (IsDefaultDownloadDirectory) + { + SettingsManager.GetInstance().IsUseSaveVideoRootPath(AllowStatus.YES); + } + else + { + SettingsManager.GetInstance().IsUseSaveVideoRootPath(AllowStatus.NO); + } + + // 将Directory移动到第一项 + // 如果直接在ComboBox中选择的就需要 + // 否则选中项不会在下次出现在第一项 + ListHelper.InsertUnique(DirectoryList, Directory, 0); + + // 将更新后的DirectoryList写入历史中 + SettingsManager.GetInstance().SetSaveVideoRootPath(Directory); + SettingsManager.GetInstance().SetHistoryVideoRootPaths(DirectoryList); + + // 返回数据 + ButtonResult result = ButtonResult.OK; + IDialogParameters parameters = new DialogParameters + { + { "directory", Directory }, + { "downloadAudio", DownloadAudio }, + { "downloadVideo", DownloadVideo }, + { "downloadDanmaku", DownloadDanmaku }, + { "downloadSubtitle", DownloadSubtitle }, + { "downloadCover", DownloadCover } + }; + + RaiseRequestClose(new DialogResult(result, parameters)); + } + + #endregion + + /// + /// 保存下载视频内容到设置 + /// + private void SetVideoContent() + { + VideoContentSettings videoContent = new VideoContentSettings + { + DownloadAudio = DownloadAudio, + DownloadVideo = DownloadVideo, + DownloadDanmaku = DownloadDanmaku, + DownloadSubtitle = DownloadSubtitle, + DownloadCover = DownloadCover + }; + + SettingsManager.GetInstance().SetVideoContent(videoContent); + } + + /// + /// 设置下载路径 + /// + /// + private async Task SetDirectory() + { + // 下载目录 + // 弹出选择下载目录的窗口 + return await DialogUtils.SetDownloadDirectory(); + // if (path == null || path == string.Empty) + // { + // return null; + // } + } +} \ No newline at end of file diff --git a/DownKyi/ViewModels/Dialogs/ViewParsingSelectorViewModel.cs b/DownKyi/ViewModels/Dialogs/ViewParsingSelectorViewModel.cs new file mode 100644 index 0000000..8ffba88 --- /dev/null +++ b/DownKyi/ViewModels/Dialogs/ViewParsingSelectorViewModel.cs @@ -0,0 +1,124 @@ +using DownKyi.Core.Settings; +using DownKyi.Utils; +using Prism.Commands; +using Prism.Services.Dialogs; + +namespace DownKyi.ViewModels.Dialogs; + +public class ViewParsingSelectorViewModel : BaseDialogViewModel +{ + public const string Tag = "DialogParsingSelector"; + + #region 页面属性申明 + + private bool isParseDefault; + + public bool IsParseDefault + { + get { return isParseDefault; } + set { SetProperty(ref isParseDefault, value); } + } + + #endregion + + public ViewParsingSelectorViewModel() + { + #region 属性初始化 + + Title = DictionaryResource.GetString("ParsingSelector"); + + // 解析范围 + ParseScope parseScope = SettingsManager.GetInstance().GetParseScope(); + IsParseDefault = parseScope != ParseScope.NONE; + + #endregion + } + + #region 命令申明 + + // 解析当前项事件 + private DelegateCommand parseSelectedItemCommand; + + public DelegateCommand ParseSelectedItemCommand => parseSelectedItemCommand ?? + (parseSelectedItemCommand = + new DelegateCommand(ExecuteParseSelectedItemCommand)); + + /// + /// 解析当前项事件 + /// + private void ExecuteParseSelectedItemCommand() + { + SetParseScopeSetting(ParseScope.SELECTED_ITEM); + + ButtonResult result = ButtonResult.OK; + IDialogParameters parameters = new DialogParameters + { + { "parseScope", ParseScope.SELECTED_ITEM } + }; + + RaiseRequestClose(new DialogResult(result, parameters)); + } + + // 解析当前页视频事件 + private DelegateCommand parseCurrentSectionCommand; + + public DelegateCommand ParseCurrentSectionCommand => parseCurrentSectionCommand ?? + (parseCurrentSectionCommand = + new DelegateCommand(ExecuteParseCurrentSectionCommand)); + + /// + /// 解析当前页视频事件 + /// + private void ExecuteParseCurrentSectionCommand() + { + SetParseScopeSetting(ParseScope.CURRENT_SECTION); + + ButtonResult result = ButtonResult.OK; + IDialogParameters parameters = new DialogParameters + { + { "parseScope", ParseScope.CURRENT_SECTION } + }; + + RaiseRequestClose(new DialogResult(result, parameters)); + } + + // 解析所有视频事件 + private DelegateCommand parseAllCommand; + + public DelegateCommand ParseAllCommand => + parseAllCommand ?? (parseAllCommand = new DelegateCommand(ExecuteParseAllCommand)); + + /// + /// 解析所有视频事件 + /// + private void ExecuteParseAllCommand() + { + SetParseScopeSetting(ParseScope.ALL); + + ButtonResult result = ButtonResult.OK; + IDialogParameters parameters = new DialogParameters + { + { "parseScope", ParseScope.ALL } + }; + + RaiseRequestClose(new DialogResult(result, parameters)); + } + + #endregion + + /// + /// 写入设置 + /// + /// + private void SetParseScopeSetting(ParseScope parseScope) + { + if (IsParseDefault) + { + SettingsManager.GetInstance().SetParseScope(parseScope); + } + else + { + SettingsManager.GetInstance().SetParseScope(ParseScope.NONE); + } + } +} \ No newline at end of file diff --git a/DownKyi/ViewModels/DownloadManager/DownloadBaseItem.cs b/DownKyi/ViewModels/DownloadManager/DownloadBaseItem.cs new file mode 100644 index 0000000..1ef395b --- /dev/null +++ b/DownKyi/ViewModels/DownloadManager/DownloadBaseItem.cs @@ -0,0 +1,141 @@ +using DownKyi.Core.BiliApi.BiliUtils; +using DownKyi.Core.BiliApi.Zone; +using DownKyi.Models; +using Prism.Mvvm; +using Prism.Services.Dialogs; +using Avalonia; +using Avalonia.Media; +using DownKyi.Utils; + +namespace DownKyi.ViewModels.DownloadManager +{ + public class DownloadBaseItem : BindableBase + { + public IDialogService DialogService; + + public DownloadBaseItem() + { + DialogService = null; + } + + public DownloadBaseItem(IDialogService dialogService) + { + DialogService = dialogService; + } + + // model数据 + private DownloadBase downloadBase; + + public DownloadBase DownloadBase + { + get => downloadBase; + set + { + downloadBase = value; + + if (value != null) + { + ZoneImage = DictionaryResource.Get(VideoZoneIcon.Instance() + .GetZoneImageKey(DownloadBase.ZoneId)); + } + } + } + + // 视频分区image + private DrawingImage zoneImage; + + public DrawingImage ZoneImage + { + get => zoneImage; + set => SetProperty(ref zoneImage, value); + } + + // 视频序号 + public int Order + { + get => DownloadBase == null ? 0 : DownloadBase.Order; + set + { + DownloadBase.Order = value; + RaisePropertyChanged("Order"); + } + } + + // 视频主标题 + public string MainTitle + { + get => DownloadBase == null ? "" : DownloadBase.MainTitle; + set + { + DownloadBase.MainTitle = value; + RaisePropertyChanged("MainTitle"); + } + } + + // 视频标题 + public string Name + { + get => DownloadBase == null ? "" : DownloadBase.Name; + set + { + DownloadBase.Name = value; + RaisePropertyChanged("Name"); + } + } + + // 时长 + public string Duration + { + get => DownloadBase == null ? "" : DownloadBase.Duration; + set + { + DownloadBase.Duration = value; + RaisePropertyChanged("Duration"); + } + } + + // 视频编码名称,AVC、HEVC + public string VideoCodecName + { + get => DownloadBase == null ? "" : DownloadBase.VideoCodecName; + set + { + DownloadBase.VideoCodecName = value; + RaisePropertyChanged("VideoCodecName"); + } + } + + // 视频画质 + public Quality Resolution + { + get => DownloadBase == null ? null : DownloadBase.Resolution; + set + { + DownloadBase.Resolution = value; + RaisePropertyChanged("Resolution"); + } + } + + // 音频编码 + public Quality AudioCodec + { + get => DownloadBase == null ? null : DownloadBase.AudioCodec; + set + { + DownloadBase.AudioCodec = value; + RaisePropertyChanged("AudioCodec"); + } + } + + // 文件大小 + public string FileSize + { + get => DownloadBase == null ? "" : DownloadBase.FileSize; + set + { + DownloadBase.FileSize = value; + RaisePropertyChanged("FileSize"); + } + } + } +} \ No newline at end of file diff --git a/DownKyi/ViewModels/DownloadManager/DownloadedItem.cs b/DownKyi/ViewModels/DownloadManager/DownloadedItem.cs new file mode 100644 index 0000000..cc5324d --- /dev/null +++ b/DownKyi/ViewModels/DownloadManager/DownloadedItem.cs @@ -0,0 +1,178 @@ +using System; +using System.Diagnostics; +using System.IO; +using System.Linq; +using DownKyi.Images; +using DownKyi.Models; +using DownKyi.Services; +using DownKyi.Utils; +using Prism.Commands; +using Prism.Services.Dialogs; + +namespace DownKyi.ViewModels.DownloadManager +{ + public class DownloadedItem : DownloadBaseItem + { + public DownloadedItem() : this(null) + { + } + + public DownloadedItem(IDialogService dialogService) : base(dialogService) + { + // 打开文件夹按钮 + OpenFolder = ButtonIcon.Instance().Folder; + OpenFolder.Fill = DictionaryResource.GetColor("ColorPrimary"); + + // 打开视频按钮 + OpenVideo = ButtonIcon.Instance().Start; + OpenVideo.Fill = DictionaryResource.GetColor("ColorPrimary"); + + // 删除按钮 + RemoveVideo = ButtonIcon.Instance().Trash; + RemoveVideo.Fill = DictionaryResource.GetColor("ColorWarning"); + } + + // model数据 + public Downloaded Downloaded { get; set; } + + // 下载速度 + public string MaxSpeedDisplay + { + get => Downloaded.MaxSpeedDisplay; + set + { + Downloaded.MaxSpeedDisplay = value; + RaisePropertyChanged("MaxSpeedDisplay"); + } + } + + // 完成时间 + public string FinishedTime + { + get => Downloaded.FinishedTime; + set + { + Downloaded.FinishedTime = value; + RaisePropertyChanged("FinishedTime"); + } + } + + #region 控制按钮 + + private VectorImage openFolder; + public VectorImage OpenFolder + { + get => openFolder; + set => SetProperty(ref openFolder, value); + } + + private VectorImage openVideo; + public VectorImage OpenVideo + { + get => openVideo; + set => SetProperty(ref openVideo, value); + } + + private VectorImage removeVideo; + public VectorImage RemoveVideo + { + get => removeVideo; + set => SetProperty(ref removeVideo, value); + } + + #endregion + + #region 命令申明 + + // 打开文件夹事件 + private DelegateCommand openFolderCommand; + public DelegateCommand OpenFolderCommand => openFolderCommand ?? (openFolderCommand = new DelegateCommand(ExecuteOpenFolderCommand)); + + /// + /// 打开文件夹事件 + /// + private void ExecuteOpenFolderCommand() + { + if (DownloadBase == null) { return; } + //TODO:这里不光有mp4视频文件,也可能存在音频文件、字幕,或者其他文件类型 + //fix bug:Issues #709 + //这里根据需要下载的类型判断,具体对应的文件后缀名 + var downLoadContents = DownloadBase.NeedDownloadContent.Where(e => e.Value == true).Select(e => e.Key); + string fileSuffix = string.Empty; + if (downLoadContents.Contains("downloadVideo")) + { + fileSuffix = ".mp4"; + } + else if (downLoadContents.Contains("downloadAudio")) + { + fileSuffix = ".aac"; + } + else if (downLoadContents.Contains("downloadCover")) + { + fileSuffix = ".jpg"; + } + string videoPath = $"{DownloadBase.FilePath}{fileSuffix}"; + FileInfo fileInfo = new FileInfo(videoPath); + if (File.Exists(fileInfo.FullName)) + { + if (OperatingSystem.IsWindows()) + { + Process.Start("Explorer", "/select," + fileInfo.FullName); + } + } + else + { + //eventAggregator.GetEvent().Publish("没有找到视频文件,可能被删除或移动!"); + } + } + + // 打开视频事件 + private DelegateCommand? _openVideoCommand; + public DelegateCommand OpenVideoCommand => _openVideoCommand ??= new DelegateCommand(ExecuteOpenVideoCommand); + + /// + /// 打开视频事件 + /// + private void ExecuteOpenVideoCommand() + { + if (DownloadBase == null) { return; } + + string videoPath = $"{DownloadBase.FilePath}.mp4"; + var fileInfo = new FileInfo(videoPath); + if (File.Exists(fileInfo.FullName)) + { + if (OperatingSystem.IsWindows()) + { + Process.Start(fileInfo.FullName); + } + } + else + { + //eventAggregator.GetEvent().Publish(DictionaryResource.GetString("TipAddDownloadingZero")); + //eventAggregator.GetEvent().Publish("没有找到视频文件,可能被删除或移动!"); + } + } + + // 删除事件 + private DelegateCommand removeVideoCommand; + public DelegateCommand RemoveVideoCommand => removeVideoCommand ?? (removeVideoCommand = new DelegateCommand(ExecuteRemoveVideoCommand)); + + /// + /// 删除事件 + /// + private void ExecuteRemoveVideoCommand() + { + AlertService alertService = new AlertService(DialogService); + ButtonResult result = alertService.ShowWarning(DictionaryResource.GetString("ConfirmDelete"), 2); + if (result != ButtonResult.OK) + { + return; + } + + App.DownloadedList.Remove(this); + } + + #endregion + + } +} diff --git a/DownKyi/ViewModels/DownloadManager/DownloadingItem.cs b/DownKyi/ViewModels/DownloadManager/DownloadingItem.cs new file mode 100644 index 0000000..2c58ad9 --- /dev/null +++ b/DownKyi/ViewModels/DownloadManager/DownloadingItem.cs @@ -0,0 +1,233 @@ +using DownKyi.Core.BiliApi.VideoStream.Models; +using DownKyi.Images; +using DownKyi.Models; +using DownKyi.Services; +using DownKyi.Utils; +using Prism.Commands; +using Prism.Services.Dialogs; + +namespace DownKyi.ViewModels.DownloadManager +{ + public class DownloadingItem : DownloadBaseItem + { + public DownloadingItem() : this(null) + { + } + + public DownloadingItem(IDialogService dialogService) : base(dialogService) + { + // 暂停继续按钮 + StartOrPause = ButtonIcon.Instance().Pause; + StartOrPause.Fill = DictionaryResource.GetColor("ColorPrimary"); + + // 删除按钮 + Delete = ButtonIcon.Instance().Delete; + Delete.Fill = DictionaryResource.GetColor("ColorPrimary"); + } + + // model数据 + private Downloading downloading; + public Downloading Downloading + { + get => downloading; + set + { + downloading = value; + + switch (value.DownloadStatus) + { + case DownloadStatus.NOT_STARTED: + case DownloadStatus.WAIT_FOR_DOWNLOAD: + StartOrPause = ButtonIcon.Instance().Pause; + break; + case DownloadStatus.PAUSE_STARTED: + StartOrPause = ButtonIcon.Instance().Start; + break; + case DownloadStatus.PAUSE: + StartOrPause = ButtonIcon.Instance().Start; + break; + case DownloadStatus.DOWNLOADING: + StartOrPause = ButtonIcon.Instance().Pause; + break; + case DownloadStatus.DOWNLOAD_SUCCEED: + // 下载成功后会从下载列表中删除 + // 不会出现此分支 + break; + case DownloadStatus.DOWNLOAD_FAILED: + StartOrPause = ButtonIcon.Instance().Retry; + break; + default: + break; + } + StartOrPause.Fill = DictionaryResource.GetColor("ColorPrimary"); + } + } + + // 视频流链接 + public PlayUrl PlayUrl { get; set; } + + // 正在下载内容(音频、视频、弹幕、字幕、封面) + public string DownloadContent + { + get => Downloading.DownloadContent; + set + { + Downloading.DownloadContent = value; + RaisePropertyChanged("DownloadContent"); + } + } + + // 下载状态显示 + public string DownloadStatusTitle + { + get => Downloading.DownloadStatusTitle; + set + { + Downloading.DownloadStatusTitle = value; + RaisePropertyChanged("DownloadStatusTitle"); + } + } + + // 下载进度 + public float Progress + { + get => Downloading.Progress; + set + { + Downloading.Progress = value; + RaisePropertyChanged("Progress"); + } + } + + // 已下载大小/文件大小 + public string DownloadingFileSize + { + get => Downloading.DownloadingFileSize; + set + { + Downloading.DownloadingFileSize = value; + RaisePropertyChanged("DownloadingFileSize"); + } + } + + // 下载速度 + public string SpeedDisplay + { + get => Downloading.SpeedDisplay; + set + { + Downloading.SpeedDisplay = value; + RaisePropertyChanged("SpeedDisplay"); + } + } + + // 操作提示 + private string operationTip; + public string OperationTip + { + get => operationTip; + set => SetProperty(ref operationTip, value); + } + + #region 控制按钮 + + private VectorImage startOrPause; + public VectorImage StartOrPause + { + get => startOrPause; + set + { + SetProperty(ref startOrPause, value); + + OperationTip = value.Equals(ButtonIcon.Instance().Start) ? DictionaryResource.GetString("StartDownload") + : value.Equals(ButtonIcon.Instance().Pause) ? DictionaryResource.GetString("PauseDownload") + : value.Equals(ButtonIcon.Instance().Retry) ? DictionaryResource.GetString("RetryDownload") : null; + } + } + + private VectorImage delete; + public VectorImage Delete + { + get => delete; + set => SetProperty(ref delete, value); + } + + #endregion + + #region 命令申明 + + // 下载列表暂停继续事件 + private DelegateCommand startOrPauseCommand; + public DelegateCommand StartOrPauseCommand => startOrPauseCommand ?? (startOrPauseCommand = new DelegateCommand(ExecuteStartOrPauseCommand)); + + /// + /// 下载列表暂停继续事件 + /// + private void ExecuteStartOrPauseCommand() + { + switch (Downloading.DownloadStatus) + { + case DownloadStatus.NOT_STARTED: + case DownloadStatus.WAIT_FOR_DOWNLOAD: + Downloading.DownloadStatus = DownloadStatus.PAUSE_STARTED; + DownloadStatusTitle = DictionaryResource.GetString("Pausing"); + StartOrPause = ButtonIcon.Instance().Start; + StartOrPause.Fill = DictionaryResource.GetColor("ColorPrimary"); + break; + case DownloadStatus.PAUSE_STARTED: + Downloading.DownloadStatus = DownloadStatus.WAIT_FOR_DOWNLOAD; + DownloadStatusTitle = DictionaryResource.GetString("Waiting"); + StartOrPause = ButtonIcon.Instance().Pause; + StartOrPause.Fill = DictionaryResource.GetColor("ColorPrimary"); + break; + case DownloadStatus.PAUSE: + Downloading.DownloadStatus = DownloadStatus.WAIT_FOR_DOWNLOAD; + DownloadStatusTitle = DictionaryResource.GetString("Waiting"); + StartOrPause = ButtonIcon.Instance().Pause; + StartOrPause.Fill = DictionaryResource.GetColor("ColorPrimary"); + break; + //case DownloadStatus.PAUSE_TO_WAIT: + case DownloadStatus.DOWNLOADING: + Downloading.DownloadStatus = DownloadStatus.PAUSE; + DownloadStatusTitle = DictionaryResource.GetString("Pausing"); + StartOrPause = ButtonIcon.Instance().Start; + StartOrPause.Fill = DictionaryResource.GetColor("ColorPrimary"); + break; + case DownloadStatus.DOWNLOAD_SUCCEED: + // 下载成功后会从下载列表中删除 + // 不会出现此分支 + break; + case DownloadStatus.DOWNLOAD_FAILED: + Downloading.DownloadStatus = DownloadStatus.WAIT_FOR_DOWNLOAD; + DownloadStatusTitle = DictionaryResource.GetString("Waiting"); + StartOrPause = ButtonIcon.Instance().Pause; + StartOrPause.Fill = DictionaryResource.GetColor("ColorPrimary"); + break; + default: + break; + } + } + + // 下载列表删除事件 + private DelegateCommand deleteCommand; + public DelegateCommand DeleteCommand => deleteCommand ?? (deleteCommand = new DelegateCommand(ExecuteDeleteCommand)); + + /// + /// 下载列表删除事件 + /// + private void ExecuteDeleteCommand() + { + // AlertService alertService = new AlertService(DialogService); + // ButtonResult result = alertService.ShowWarning(DictionaryResource.GetString("ConfirmDelete"), 2); + // if (result != ButtonResult.OK) + // { + // return; + // } + // + // App.DownloadingList.Remove(this); + } + + #endregion + + } +} diff --git a/DownKyi/ViewModels/DownloadManager/ViewDownloadFinishedViewModel.cs b/DownKyi/ViewModels/DownloadManager/ViewDownloadFinishedViewModel.cs new file mode 100644 index 0000000..90c8a21 --- /dev/null +++ b/DownKyi/ViewModels/DownloadManager/ViewDownloadFinishedViewModel.cs @@ -0,0 +1,169 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Collections.Specialized; +using System.Linq; +using System.Threading.Tasks; +using DownKyi.Core.Logging; +using DownKyi.Core.Settings; +using DownKyi.Services; +using DownKyi.Utils; +using Prism.Commands; +using Prism.Events; +using Prism.Regions; +using Prism.Services.Dialogs; +using Console = DownKyi.Core.Utils.Debugging.Console; + +namespace DownKyi.ViewModels.DownloadManager +{ + public class ViewDownloadFinishedViewModel : ViewModelBase + { + public const string Tag = "PageDownloadManagerDownloadFinished"; + + #region 页面属性申明 + + private ObservableCollection downloadedList; + public ObservableCollection DownloadedList + { + get => downloadedList; + set => SetProperty(ref downloadedList, value); + } + + private int finishedSortBy; + public int FinishedSortBy + { + get => finishedSortBy; + set => SetProperty(ref finishedSortBy, value); + } + + #endregion + + public ViewDownloadFinishedViewModel(IEventAggregator eventAggregator, IDialogService dialogService) : base(eventAggregator, dialogService) + { + // 初始化DownloadedList + DownloadedList = App.DownloadedList; + DownloadedList.CollectionChanged += (sender, e) => + { + if (e.Action == NotifyCollectionChangedAction.Add) + { + SetDialogService(); + } + }; + SetDialogService(); + + DownloadFinishedSort finishedSort = SettingsManager.GetInstance().GetDownloadFinishedSort(); + switch (finishedSort) + { + case DownloadFinishedSort.DOWNLOAD: + FinishedSortBy = 0; + break; + case DownloadFinishedSort.NUMBER: + FinishedSortBy = 1; + break; + default: + FinishedSortBy = 0; + break; + } + App.SortDownloadedList(finishedSort); + } + + #region 命令申明 + + // 下载完成列表排序事件 + private DelegateCommand finishedSortCommand; + public DelegateCommand FinishedSortCommand => finishedSortCommand ?? (finishedSortCommand = new DelegateCommand(ExecuteFinishedSortCommand)); + + /// + /// 下载完成列表排序事件 + /// + /// + private void ExecuteFinishedSortCommand(object parameter) + { + if (!(parameter is int index)) { return; } + + switch (index) + { + case 0: + App.SortDownloadedList(DownloadFinishedSort.DOWNLOAD); + // 更新设置 + SettingsManager.GetInstance().SetDownloadFinishedSort(DownloadFinishedSort.DOWNLOAD); + break; + case 1: + App.SortDownloadedList(DownloadFinishedSort.NUMBER); + // 更新设置 + SettingsManager.GetInstance().SetDownloadFinishedSort(DownloadFinishedSort.NUMBER); + break; + default: + App.SortDownloadedList(DownloadFinishedSort.DOWNLOAD); + // 更新设置 + SettingsManager.GetInstance().SetDownloadFinishedSort(DownloadFinishedSort.DOWNLOAD); + break; + } + } + + // 清空下载完成列表事件 + private DelegateCommand clearAllDownloadedCommand; + public DelegateCommand ClearAllDownloadedCommand => clearAllDownloadedCommand ?? (clearAllDownloadedCommand = new DelegateCommand(ExecuteClearAllDownloadedCommand)); + + /// + /// 清空下载完成列表事件 + /// + private async void ExecuteClearAllDownloadedCommand() + { + AlertService alertService = new AlertService(dialogService); + ButtonResult result = alertService.ShowWarning(DictionaryResource.GetString("ConfirmDelete")); + if (result != ButtonResult.OK) + { + return; + } + + // 使用Clear()不能触发NotifyCollectionChangedAction.Remove事件 + // 因此遍历删除 + // DownloadingList中元素被删除后不能继续遍历 + await Task.Run(() => + { + List list = DownloadedList.ToList(); + foreach (DownloadedItem item in list) + { + App.PropertyChangeAsync(() => + { + App.DownloadedList.Remove(item); + }); + } + }); + } + + #endregion + + private async void SetDialogService() + { + try + { + await Task.Run(() => + { + List list = DownloadedList.ToList(); + foreach (var item in list) + { + if (item != null && item.DialogService == null) + { + item.DialogService = dialogService; + } + } + }); + } + catch (Exception e) + { + Console.PrintLine("SetDialogService()发生异常: {0}", e); + LogManager.Error($"{Tag}.SetDialogService()", e); + } + } + + public override void OnNavigatedFrom(NavigationContext navigationContext) + { + base.OnNavigatedFrom(navigationContext); + + SetDialogService(); + } + + } +} diff --git a/DownKyi/ViewModels/DownloadManager/ViewDownloadingViewModel.cs b/DownKyi/ViewModels/DownloadManager/ViewDownloadingViewModel.cs new file mode 100644 index 0000000..8600935 --- /dev/null +++ b/DownKyi/ViewModels/DownloadManager/ViewDownloadingViewModel.cs @@ -0,0 +1,206 @@ +using DownKyi.Core.Logging; +using DownKyi.Images; +using DownKyi.Models; +using DownKyi.Services; +using DownKyi.Utils; +using Prism.Commands; +using Prism.Events; +using Prism.Regions; +using Prism.Services.Dialogs; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Collections.Specialized; +using System.Linq; +using System.Threading.Tasks; + +namespace DownKyi.ViewModels.DownloadManager +{ + public class ViewDownloadingViewModel : ViewModelBase + { + public const string Tag = "PageDownloadManagerDownloading"; + + #region 页面属性申明 + + private ObservableCollection downloadingList; + public ObservableCollection DownloadingList + { + get => downloadingList; + set => SetProperty(ref downloadingList, value); + } + + #endregion + + public ViewDownloadingViewModel(IEventAggregator eventAggregator, IDialogService dialogService) : base(eventAggregator, dialogService) + { + // 初始化DownloadingList + DownloadingList = App.DownloadingList; + DownloadingList.CollectionChanged += new NotifyCollectionChangedEventHandler((sender, e) => + { + if (e.Action == NotifyCollectionChangedAction.Add) + { + SetDialogService(); + } + }); + SetDialogService(); + + } + + #region 命令申明 + + // 暂停所有下载事件 + private DelegateCommand pauseAllDownloadingCommand; + public DelegateCommand PauseAllDownloadingCommand => pauseAllDownloadingCommand ?? (pauseAllDownloadingCommand = new DelegateCommand(ExecutePauseAllDownloadingCommand)); + + /// + /// 暂停所有下载事件 + /// + private void ExecutePauseAllDownloadingCommand() + { + foreach (DownloadingItem downloading in downloadingList) + { + switch (downloading.Downloading.DownloadStatus) + { + case DownloadStatus.NOT_STARTED: + case DownloadStatus.WAIT_FOR_DOWNLOAD: + downloading.Downloading.DownloadStatus = DownloadStatus.PAUSE; + downloading.DownloadStatusTitle = DictionaryResource.GetString("Pausing"); + downloading.StartOrPause = ButtonIcon.Instance().Start; + downloading.StartOrPause.Fill = DictionaryResource.GetColor("ColorPrimary"); + break; + case DownloadStatus.PAUSE_STARTED: + break; + case DownloadStatus.PAUSE: + break; + //case DownloadStatus.PAUSE_TO_WAIT: + case DownloadStatus.DOWNLOADING: + downloading.Downloading.DownloadStatus = DownloadStatus.PAUSE; + downloading.DownloadStatusTitle = DictionaryResource.GetString("Pausing"); + downloading.StartOrPause = ButtonIcon.Instance().Start; + downloading.StartOrPause.Fill = DictionaryResource.GetColor("ColorPrimary"); + break; + case DownloadStatus.DOWNLOAD_SUCCEED: + // 下载成功后会从下载列表中删除 + // 不会出现此分支 + break; + case DownloadStatus.DOWNLOAD_FAILED: + break; + default: + break; + } + } + } + + // 继续所有下载事件 + private DelegateCommand continueAllDownloadingCommand; + public DelegateCommand ContinueAllDownloadingCommand => continueAllDownloadingCommand ?? (continueAllDownloadingCommand = new DelegateCommand(ExecuteContinueAllDownloadingCommand)); + + /// + /// 继续所有下载事件 + /// + private void ExecuteContinueAllDownloadingCommand() + { + foreach (DownloadingItem downloading in downloadingList) + { + switch (downloading.Downloading.DownloadStatus) + { + case DownloadStatus.NOT_STARTED: + case DownloadStatus.WAIT_FOR_DOWNLOAD: + downloading.Downloading.DownloadStatus = DownloadStatus.WAIT_FOR_DOWNLOAD; + downloading.DownloadStatusTitle = DictionaryResource.GetString("Waiting"); + break; + case DownloadStatus.PAUSE_STARTED: + downloading.Downloading.DownloadStatus = DownloadStatus.WAIT_FOR_DOWNLOAD; + downloading.DownloadStatusTitle = DictionaryResource.GetString("Waiting"); + break; + case DownloadStatus.PAUSE: + downloading.Downloading.DownloadStatus = DownloadStatus.WAIT_FOR_DOWNLOAD; + downloading.DownloadStatusTitle = DictionaryResource.GetString("Waiting"); + break; + //case DownloadStatus.PAUSE_TO_WAIT: + // break; + case DownloadStatus.DOWNLOADING: + break; + case DownloadStatus.DOWNLOAD_SUCCEED: + // 下载成功后会从下载列表中删除 + // 不会出现此分支 + break; + case DownloadStatus.DOWNLOAD_FAILED: + downloading.Downloading.DownloadStatus = DownloadStatus.WAIT_FOR_DOWNLOAD; + downloading.DownloadStatusTitle = DictionaryResource.GetString("Waiting"); + break; + default: + break; + } + + downloading.StartOrPause = ButtonIcon.Instance().Pause; + downloading.StartOrPause.Fill = DictionaryResource.GetColor("ColorPrimary"); + } + } + + // 删除所有下载事件 + private DelegateCommand deleteAllDownloadingCommand; + public DelegateCommand DeleteAllDownloadingCommand => deleteAllDownloadingCommand ?? (deleteAllDownloadingCommand = new DelegateCommand(ExecuteDeleteAllDownloadingCommand)); + + /// + /// 删除所有下载事件 + /// + private async void ExecuteDeleteAllDownloadingCommand() + { + // AlertService alertService = new AlertService(dialogService); + // ButtonResult result = alertService.ShowWarning(DictionaryResource.GetString("ConfirmDelete")); + // if (result != ButtonResult.OK) + // { + // return; + // } + + // 使用Clear()不能触发NotifyCollectionChangedAction.Remove事件 + // 因此遍历删除 + // DownloadingList中元素被删除后不能继续遍历 + await Task.Run(() => + { + List list = DownloadingList.ToList(); + foreach (DownloadingItem item in list) + { + App.PropertyChangeAsync(new Action(() => + { + App.DownloadingList.Remove(item); + })); + } + }); + } + + #endregion + + private async void SetDialogService() + { + try + { + await Task.Run(() => + { + List list = DownloadingList.ToList(); + foreach (var item in list) + { + if (item != null && item.DialogService == null) + { + item.DialogService = dialogService; + } + } + }); + } + catch (Exception e) + { + Core.Utils.Debugging.Console.PrintLine("SetDialogService()发生异常: {0}", e); + LogManager.Error($"{Tag}.SetDialogService()", e); + } + } + + public override void OnNavigatedFrom(NavigationContext navigationContext) + { + base.OnNavigatedFrom(navigationContext); + + SetDialogService(); + } + + } +} diff --git a/DownKyi/ViewModels/Friends/ViewFollowerViewModel.cs b/DownKyi/ViewModels/Friends/ViewFollowerViewModel.cs new file mode 100644 index 0000000..b8b5d50 --- /dev/null +++ b/DownKyi/ViewModels/Friends/ViewFollowerViewModel.cs @@ -0,0 +1,250 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Threading.Tasks; +using Avalonia.Media.Imaging; +using DownKyi.Core.BiliApi.Users; +using DownKyi.Core.BiliApi.Users.Models; +using DownKyi.Core.Settings; +using DownKyi.Core.Settings.Models; +using DownKyi.Core.Storage; +using DownKyi.CustomControl; +using DownKyi.ViewModels.PageViewModels; +using Prism.Events; +using Prism.Regions; + +namespace DownKyi.ViewModels.Friends; + +public class ViewFollowerViewModel : ViewModelBase +{ + public const string Tag = "PageFriendsFollower"; + + // mid + private long mid = -1; + + // 每页数量,暂时在此写死,以后在设置中增加选项 + private readonly int NumberInPage = 20; + + public bool IsEnabled = true; + + #region 页面属性申明 + + private string pageName = ViewFriendsViewModel.Tag; + + public string PageName + { + get => pageName; + set => SetProperty(ref pageName, value); + } + + private bool contentVisibility; + + public bool ContentVisibility + { + get => contentVisibility; + set => SetProperty(ref contentVisibility, value); + } + + private bool loading; + public bool Loading + { + get => loading; + set => SetProperty(ref loading, value); + } + + private bool loadingVisibility; + + public bool LoadingVisibility + { + get => loadingVisibility; + set => SetProperty(ref loadingVisibility, value); + } + + private bool noDataVisibility; + + public bool NoDataVisibility + { + get => noDataVisibility; + set => SetProperty(ref noDataVisibility, value); + } + + private CustomPagerViewModel pager; + + public CustomPagerViewModel Pager + { + get => pager; + set => SetProperty(ref pager, value); + } + + private ObservableCollection contents; + + public ObservableCollection Contents + { + get => contents; + set => SetProperty(ref contents, value); + } + + #endregion + + public ViewFollowerViewModel(IEventAggregator eventAggregator) : base(eventAggregator) + { + #region 属性初始化 + + // 初始化loading + Loading = true; + LoadingVisibility = false; + NoDataVisibility = false; + + Contents = new ObservableCollection(); + + #endregion + } + + #region 命令申明 + + #endregion + + private void LoadContent(List contents) + { + ContentVisibility = true; + LoadingVisibility = false; + NoDataVisibility = false; + foreach (var item in contents) + { + StorageHeader storageHeader = new StorageHeader(); + Bitmap header = storageHeader.GetHeaderThumbnail(item.Mid, item.Name, item.Face, 64, 64); + App.PropertyChangeAsync(new Action(() => + { + Contents.Add(new FriendInfo(eventAggregator) + { Mid = item.Mid, Header = header, Name = item.Name, Sign = item.Sign }); + })); + } + } + + private async void UpdateContent(int current) + { + // 是否正在获取数据 + // 在所有的退出分支中都需要设为true + IsEnabled = false; + + Contents.Clear(); + ContentVisibility = false; + LoadingVisibility = true; + NoDataVisibility = false; + + RelationFollow data = null; + List contents = null; + await Task.Run(() => + { + data = UserRelation.GetFollowers(mid, current, NumberInPage); + if (data != null && data.List != null && data.List.Count > 0) + { + contents = data.List; + } + + if (contents == null) + { + return; + } + + LoadContent(contents); + }); + + if (data == null || contents == null) + { + ContentVisibility = false; + LoadingVisibility = false; + NoDataVisibility = true; + } + else + { + UserInfoSettings userInfo = SettingsManager.GetInstance().GetUserInfo(); + if (userInfo != null && userInfo.Mid == mid) + { + Pager.Count = (int)Math.Ceiling((double)data.Total / NumberInPage); + } + else + { + int page = (int)Math.Ceiling((double)data.Total / NumberInPage); + if (page > 5) + { + Pager.Count = 5; + } + else + { + Pager.Count = page; + } + } + + ContentVisibility = true; + LoadingVisibility = false; + NoDataVisibility = false; + } + + IsEnabled = true; + } + + private void OnCountChanged_Pager(int count) + { + } + + private bool OnCurrentChanged_Pager(int old, int current) + { + if (!IsEnabled) + { + //Pager.Current = old; + return false; + } + + UpdateContent(current); + + return true; + } + + /// + /// 初始化页面数据 + /// + private void InitView() + { + ContentVisibility = false; + LoadingVisibility = true; + NoDataVisibility = false; + + Contents.Clear(); + } + + /// + /// 导航到页面时执行 + /// + /// + public override void OnNavigatedTo(NavigationContext navigationContext) + { + base.OnNavigatedTo(navigationContext); + + // 传入mid + long parameter = navigationContext.Parameters.GetValue("mid"); + if (parameter == 0) + { + return; + } + + mid = parameter; + + // 是否是从PageFriends的headerTable的item点击进入的 + // true表示加载PageFriends后第一次进入此页面 + // false表示从headerTable的item点击进入的 + bool isFirst = navigationContext.Parameters.GetValue("isFirst"); + if (isFirst) + { + InitView(); + + //UpdateContent(1); + + // 页面选择 + Pager = new CustomPagerViewModel(1, (int)Math.Ceiling((double)1 / NumberInPage)); + Pager.CurrentChanged += OnCurrentChanged_Pager; + Pager.CountChanged += OnCountChanged_Pager; + Pager.Current = 1; + } + } +} \ No newline at end of file diff --git a/DownKyi/ViewModels/Friends/ViewFollowingViewModel.cs b/DownKyi/ViewModels/Friends/ViewFollowingViewModel.cs new file mode 100644 index 0000000..dfafdc1 --- /dev/null +++ b/DownKyi/ViewModels/Friends/ViewFollowingViewModel.cs @@ -0,0 +1,457 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Threading.Tasks; +using Avalonia.Media.Imaging; +using DownKyi.Core.BiliApi.Users; +using DownKyi.Core.BiliApi.Users.Models; +using DownKyi.Core.Settings; +using DownKyi.Core.Settings.Models; +using DownKyi.Core.Storage; +using DownKyi.CustomControl; +using DownKyi.Utils; +using DownKyi.ViewModels.PageViewModels; +using Prism.Commands; +using Prism.Events; +using Prism.Regions; + +namespace DownKyi.ViewModels.Friends; + +public class ViewFollowingViewModel : ViewModelBase +{ + public const string Tag = "PageFriendsFollowing"; + + // mid + private long mid = -1; + + // 每页数量,暂时在此写死,以后在设置中增加选项 + private readonly int NumberInPage = 20; + + #region 页面属性申明 + + private string pageName = ViewFriendsViewModel.Tag; + + public string PageName + { + get => pageName; + set => SetProperty(ref pageName, value); + } + + private bool contentVisibility; + + public bool ContentVisibility + { + get => contentVisibility; + set => SetProperty(ref contentVisibility, value); + } + + private bool innerContentVisibility; + + public bool InnerContentVisibility + { + get => innerContentVisibility; + set => SetProperty(ref innerContentVisibility, value); + } + + private bool loading; + + public bool Loading + { + get => loading; + set => SetProperty(ref loading, value); + } + + private bool loadingVisibility; + + public bool LoadingVisibility + { + get => loadingVisibility; + set => SetProperty(ref loadingVisibility, value); + } + + private bool noDataVisibility; + + public bool NoDataVisibility + { + get => noDataVisibility; + set => SetProperty(ref noDataVisibility, value); + } + + private bool contentLoading; + + public bool ContentLoading + { + get => contentLoading; + set => SetProperty(ref contentLoading, value); + } + + private bool contentLoadingVisibility; + + public bool ContentLoadingVisibility + { + get => contentLoadingVisibility; + set => SetProperty(ref contentLoadingVisibility, value); + } + + private bool contentNoDataVisibility; + + public bool ContentNoDataVisibility + { + get => contentNoDataVisibility; + set => SetProperty(ref contentNoDataVisibility, value); + } + + private ObservableCollection tabHeaders; + + public ObservableCollection TabHeaders + { + get => tabHeaders; + set => SetProperty(ref tabHeaders, value); + } + + private int selectTabId = -1; + + public int SelectTabId + { + get => selectTabId; + set => SetProperty(ref selectTabId, value); + } + + private bool isEnabled = true; + + public bool IsEnabled + { + get => isEnabled; + set => SetProperty(ref isEnabled, value); + } + + private CustomPagerViewModel pager; + + public CustomPagerViewModel Pager + { + get => pager; + set => SetProperty(ref pager, value); + } + + private ObservableCollection contents; + + public ObservableCollection Contents + { + get => contents; + set => SetProperty(ref contents, value); + } + + #endregion + + public ViewFollowingViewModel(IEventAggregator eventAggregator) : base(eventAggregator) + { + #region 属性初始化 + + // 初始化loading gif + Loading = true; + LoadingVisibility = false; + NoDataVisibility = false; + + ContentLoading = true; + ContentLoadingVisibility = false; + ContentNoDataVisibility = false; + + TabHeaders = new ObservableCollection(); + Contents = new ObservableCollection(); + + #endregion + } + + #region 命令申明 + + // 左侧tab点击事件 + private DelegateCommand leftTabHeadersCommand; + + public DelegateCommand LeftTabHeadersCommand => leftTabHeadersCommand ?? (leftTabHeadersCommand = + new DelegateCommand(ExecuteLeftTabHeadersCommand, CanExecuteLeftTabHeadersCommand)); + + /// + /// 左侧tab点击事件 + /// + /// + private void ExecuteLeftTabHeadersCommand(object parameter) + { + if (!(parameter is TabHeader tabHeader)) + { + return; + } + + // 页面选择 + Pager = new CustomPagerViewModel(1, (int)Math.Ceiling(double.Parse(tabHeader.SubTitle) / NumberInPage)); + Pager.CurrentChanged += OnCurrentChanged_Pager; + Pager.CountChanged += OnCountChanged_Pager; + Pager.Current = 1; + } + + /// + /// 左侧tab点击事件是否允许执行 + /// + /// + /// + private bool CanExecuteLeftTabHeadersCommand(object parameter) + { + return IsEnabled; + } + + #endregion + + /// + /// 初始化页面数据 + /// + private void InitView() + { + ContentVisibility = false; + InnerContentVisibility = false; + LoadingVisibility = true; + NoDataVisibility = false; + ContentLoadingVisibility = false; + ContentNoDataVisibility = false; + + TabHeaders.Clear(); + Contents.Clear(); + SelectTabId = -1; + } + + /// + /// 初始化左侧列表 + /// + private async void InitLeftTable() + { + TabHeaders.Clear(); + + UserInfoSettings userInfo = SettingsManager.GetInstance().GetUserInfo(); + if (userInfo != null && userInfo.Mid == mid) + { + // 用户的关系状态数 + UserRelationStat relationStat = null; + await Task.Run(() => { relationStat = UserStatus.GetUserRelationStat(mid); }); + if (relationStat != null) + { + TabHeaders.Add(new TabHeader + { + Id = -1, Title = DictionaryResource.GetString("AllFollowing"), + SubTitle = relationStat.Following.ToString() + }); + TabHeaders.Add(new TabHeader + { + Id = -2, Title = DictionaryResource.GetString("WhisperFollowing"), + SubTitle = relationStat.Whisper.ToString() + }); + } + + // 用户的关注分组 + List followingGroup = null; + await Task.Run(() => { followingGroup = UserRelation.GetFollowingGroup(); }); + if (followingGroup != null) + { + foreach (FollowingGroup tag in followingGroup) + { + TabHeaders.Add(new TabHeader { Id = tag.TagId, Title = tag.Name, SubTitle = tag.Count.ToString() }); + } + } + } + else + { + // 用户的关系状态数 + UserRelationStat relationStat = null; + await Task.Run(() => { relationStat = UserStatus.GetUserRelationStat(mid); }); + if (relationStat != null) + { + TabHeaders.Add(new TabHeader + { + Id = -1, Title = DictionaryResource.GetString("AllFollowing"), + SubTitle = relationStat.Following.ToString() + }); + } + } + + ContentVisibility = true; + LoadingVisibility = false; + } + + private void LoadContent(List contents) + { + InnerContentVisibility = true; + ContentLoadingVisibility = false; + ContentNoDataVisibility = false; + foreach (var item in contents) + { + StorageHeader storageHeader = new StorageHeader(); + Bitmap header = storageHeader.GetHeaderThumbnail(item.Mid, item.Name, item.Face, 64, 64); + App.PropertyChangeAsync(new Action(() => + { + Contents.Add(new FriendInfo(eventAggregator) + { Mid = item.Mid, Header = header, Name = item.Name, Sign = item.Sign }); + })); + } + } + + private async Task LoadAllFollowings(int pn, int ps) + { + List contents = null; + await Task.Run(() => + { + RelationFollow data = UserRelation.GetFollowings(mid, pn, ps); + if (data != null && data.List != null && data.List.Count > 0) + { + contents = data.List; + } + + if (contents == null) + { + return; + } + + LoadContent(contents); + }); + + if (contents == null) + { + return false; + } + + return true; + } + + private async Task LoadWhispers(int pn, int ps) + { + List contents = null; + await Task.Run(() => + { + contents = UserRelation.GetWhispers(pn, ps); + if (contents == null) + { + return; + } + + LoadContent(contents); + }); + + if (contents == null) + { + return false; + } + + return true; + } + + private async Task LoadFollowingGroupContent(long tagId, int pn, int ps) + { + List contents = null; + await Task.Run(() => + { + contents = UserRelation.GetFollowingGroupContent(tagId, pn, ps); + if (contents == null) + { + return; + } + + LoadContent(contents); + }); + + if (contents == null) + { + return false; + } + + return true; + } + + private async void UpdateContent(int current) + { + // 是否正在获取数据 + // 在所有的退出分支中都需要设为true + IsEnabled = false; + + Contents.Clear(); + InnerContentVisibility = false; + ContentLoadingVisibility = true; + ContentNoDataVisibility = false; + + TabHeader tab = TabHeaders[SelectTabId]; + + bool isSucceed; + switch (tab.Id) + { + case -1: + isSucceed = await LoadAllFollowings(current, NumberInPage); + break; + case -2: + isSucceed = await LoadWhispers(current, NumberInPage); + break; + default: + isSucceed = await LoadFollowingGroupContent(tab.Id, current, NumberInPage); + break; + } + + if (isSucceed) + { + InnerContentVisibility = true; + ContentLoadingVisibility = false; + ContentNoDataVisibility = false; + } + else + { + InnerContentVisibility = false; + ContentLoadingVisibility = false; + ContentNoDataVisibility = true; + } + + IsEnabled = true; + } + + private void OnCountChanged_Pager(int count) + { + } + + private bool OnCurrentChanged_Pager(int old, int current) + { + if (!IsEnabled) + { + //Pager.Current = old; + return false; + } + + UpdateContent(current); + + return true; + } + + /// + /// 导航到页面时执行 + /// + /// + public override void OnNavigatedTo(NavigationContext navigationContext) + { + base.OnNavigatedTo(navigationContext); + + // 传入mid + long parameter = navigationContext.Parameters.GetValue("mid"); + if (parameter == 0) + { + return; + } + + mid = parameter; + + // 是否是从PageFriends的headerTable的item点击进入的 + // true表示加载PageFriends后第一次进入此页面 + // false表示从headerTable的item点击进入的 + bool isFirst = navigationContext.Parameters.GetValue("isFirst"); + if (isFirst) + { + InitView(); + + // 初始化左侧列表 + InitLeftTable(); + + // 进入页面时显示的设置项 + SelectTabId = 0; + } + } +} \ No newline at end of file diff --git a/DownKyi/ViewModels/MainWindowViewModel.cs b/DownKyi/ViewModels/MainWindowViewModel.cs new file mode 100644 index 0000000..d9ab803 --- /dev/null +++ b/DownKyi/ViewModels/MainWindowViewModel.cs @@ -0,0 +1,101 @@ +using System.Threading; +using Avalonia.Threading; +using DownKyi.Events; +using Prism.Commands; +using Prism.Events; +using Prism.Mvvm; +using Prism.Regions; + +namespace DownKyi.ViewModels; + +public class MainWindowViewModel : BindableBase +{ + private readonly IEventAggregator _eventAggregator; + private readonly IRegionManager _regionManager; + + private bool _messageVisibility = false; + private string? _oldMessage; + + public bool MessageVisibility + { + get => _messageVisibility; + set => SetProperty(ref _messageVisibility, value); + } + + private string? _message; + + public string? Message + { + get => _message; + set => SetProperty(ref _message, value); + } + + + // 登录事件 + private DelegateCommand? _loginCommand; + public DelegateCommand LoginCommand => _loginCommand ??= new DelegateCommand(ExecuteLogin); + + public DelegateCommand? LoadedCommand { get; } + + public void ExecuteLogin() + { + NavigationParam parameter = new NavigationParam + { + ViewName = ViewLoginViewModel.Tag, + ParentViewName = null, + Parameter = null + }; + _eventAggregator.GetEvent().Publish(parameter); + } + + public MainWindowViewModel(IRegionManager regionManager, IEventAggregator eventAggregator) + { + _regionManager = regionManager; + _eventAggregator = eventAggregator; + + #region MyRegion + + _eventAggregator.GetEvent().Subscribe(view => + { + var param = new NavigationParameters + { + { "Parent", view.ParentViewName }, + { "Parameter", view.Parameter } + }; + regionManager.RequestNavigate("ContentRegion", view.ViewName, param); + }); + + // 订阅消息发送事件 + _eventAggregator.GetEvent().Subscribe(message => + { + MessageVisibility = true; + + _oldMessage = Message; + Message = message; + var sleep = 2000; + if (_oldMessage == Message) + { + sleep = 1500; + } + + Thread.Sleep(sleep); + + MessageVisibility = false; + }, ThreadOption.BackgroundThread); + + #endregion + + + LoadedCommand = new DelegateCommand(() => + { + var param = new NavigationParameters + { + { "Parent", "" }, + { "Parameter", "start" } + }; + regionManager.RequestNavigate("ContentRegion", ViewIndexViewModel.Tag, param); + }); + + Dispatcher.UIThread.InvokeAsync(() => { LoadedCommand.Execute(); }); + } +} \ No newline at end of file diff --git a/DownKyi/ViewModels/PageViewModels/BangumiFollowMedia.cs b/DownKyi/ViewModels/PageViewModels/BangumiFollowMedia.cs new file mode 100644 index 0000000..5822d17 --- /dev/null +++ b/DownKyi/ViewModels/PageViewModels/BangumiFollowMedia.cs @@ -0,0 +1,134 @@ +using Avalonia.Media.Imaging; +using DownKyi.Core.BiliApi.BiliUtils; +using DownKyi.Utils; +using Prism.Commands; +using Prism.Events; +using Prism.Mvvm; + +namespace DownKyi.ViewModels.PageViewModels; + +public class BangumiFollowMedia : BindableBase +{ + protected readonly IEventAggregator eventAggregator; + + public BangumiFollowMedia(IEventAggregator eventAggregator) + { + this.eventAggregator = eventAggregator; + } + + // media id + public long MediaId { get; set; } + + // season id + public long SeasonId { get; set; } + + #region 页面属性申明 + + // 是否选中 + private bool isSelected; + + public bool IsSelected + { + get => isSelected; + set => SetProperty(ref isSelected, value); + } + + // 封面 + private Bitmap cover; + + public Bitmap Cover + { + get => cover; + set => SetProperty(ref cover, value); + } + + // 视频标题 + private string title; + + public string Title + { + get => title; + set => SetProperty(ref title, value); + } + + // 视频类型名称 + private string seasonTypeName; + + public string SeasonTypeName + { + get => seasonTypeName; + set => SetProperty(ref seasonTypeName, value); + } + + // 地区 + private string area; + + public string Area + { + get => area; + set => SetProperty(ref area, value); + } + + // 标记是否会员 + private string badge; + + public string Badge + { + get => badge; + set => SetProperty(ref badge, value); + } + + // 简介 + private string evaluate; + + public string Evaluate + { + get => evaluate; + set => SetProperty(ref evaluate, value); + } + + // 视频更新进度 + private string indexShow; + + public string IndexShow + { + get => indexShow; + set => SetProperty(ref indexShow, value); + } + + // 观看进度 + private string progress; + + public string Progress + { + get => progress; + set => SetProperty(ref progress, value); + } + + #endregion + + #region 命令申明 + + // 视频标题点击事件 + private DelegateCommand titleCommand; + + public DelegateCommand TitleCommand => + titleCommand ?? (titleCommand = new DelegateCommand(ExecuteTitleCommand)); + + /// + /// 视频标题点击事件 + /// + /// + private void ExecuteTitleCommand(object parameter) + { + if (!(parameter is string tag)) + { + return; + } + + NavigateToView.NavigationView(eventAggregator, ViewVideoDetailViewModel.Tag, tag, + $"{ParseEntrance.BangumiMediaUrl}md{MediaId}"); + } + + #endregion +} \ No newline at end of file diff --git a/DownKyi/ViewModels/PageViewModels/ChannelMedia.cs b/DownKyi/ViewModels/PageViewModels/ChannelMedia.cs new file mode 100644 index 0000000..81176f0 --- /dev/null +++ b/DownKyi/ViewModels/PageViewModels/ChannelMedia.cs @@ -0,0 +1,100 @@ +using Avalonia.Media.Imaging; +using DownKyi.Core.BiliApi.BiliUtils; +using DownKyi.Utils; +using Prism.Commands; +using Prism.Events; +using Prism.Mvvm; + +namespace DownKyi.ViewModels.PageViewModels; + +public class ChannelMedia : BindableBase +{ + protected readonly IEventAggregator eventAggregator; + + public ChannelMedia(IEventAggregator eventAggregator) + { + this.eventAggregator = eventAggregator; + } + + public long Avid { get; set; } + public string Bvid { get; set; } + + #region 页面属性申明 + + private bool isSelected; + + public bool IsSelected + { + get => isSelected; + set => SetProperty(ref isSelected, value); + } + + private Bitmap cover; + + public Bitmap Cover + { + get => cover; + set => SetProperty(ref cover, value); + } + + private string title; + + public string Title + { + get => title; + set => SetProperty(ref title, value); + } + + private string duration; + + public string Duration + { + get => duration; + set => SetProperty(ref duration, value); + } + + private string playNumber; + + public string PlayNumber + { + get => playNumber; + set => SetProperty(ref playNumber, value); + } + + private string createTime; + + public string CreateTime + { + get => createTime; + set => SetProperty(ref createTime, value); + } + + #endregion + + #region 命令申明 + + // 视频标题点击事件 + private DelegateCommand titleCommand; + + public DelegateCommand TitleCommand => + titleCommand ?? (titleCommand = new DelegateCommand(ExecuteTitleCommand)); + + /// + /// 视频标题点击事件 + /// + /// + private void ExecuteTitleCommand(object parameter) + { + if (!(parameter is string tag)) + { + return; + } + + NavigateToView.NavigationView(eventAggregator, ViewVideoDetailViewModel.Tag, tag, + $"{ParseEntrance.VideoUrl}{Bvid}"); + //string url = "https://www.bilibili.com/video/" + tag; + //System.Diagnostics.Process.Start(url); + } + + #endregion +} \ No newline at end of file diff --git a/DownKyi/ViewModels/PageViewModels/Favorites.cs b/DownKyi/ViewModels/PageViewModels/Favorites.cs new file mode 100644 index 0000000..b5dc48d --- /dev/null +++ b/DownKyi/ViewModels/PageViewModels/Favorites.cs @@ -0,0 +1,150 @@ +using Avalonia.Media.Imaging; +using DownKyi.Images; +using Prism.Mvvm; + +namespace DownKyi.ViewModels.PageViewModels; + +public class Favorites : BindableBase +{ + public string CoverUrl { get; set; } + public long UpperMid { get; set; } + + private Bitmap cover; + + public Bitmap Cover + { + get => cover; + set => SetProperty(ref cover, value); + } + + private string title; + + public string Title + { + get => title; + set => SetProperty(ref title, value); + } + + private string createTime; + + public string CreateTime + { + get => createTime; + set => SetProperty(ref createTime, value); + } + + private string playNumber; + + public string PlayNumber + { + get => playNumber; + set => SetProperty(ref playNumber, value); + } + + private string likeNumber; + + public string LikeNumber + { + get => likeNumber; + set => SetProperty(ref likeNumber, value); + } + + private string favoriteNumber; + + public string FavoriteNumber + { + get => favoriteNumber; + set => SetProperty(ref favoriteNumber, value); + } + + private string shareNumber; + + public string ShareNumber + { + get => shareNumber; + set => SetProperty(ref shareNumber, value); + } + + private VectorImage play; + + public VectorImage Play + { + get => play; + set => SetProperty(ref play, value); + } + + private VectorImage like; + + public VectorImage Like + { + get => like; + set => SetProperty(ref like, value); + } + + private VectorImage favorite; + + public VectorImage Favorite + { + get => favorite; + set => SetProperty(ref favorite, value); + } + + private VectorImage share; + + public VectorImage Share + { + get => share; + set => SetProperty(ref share, value); + } + + private string description; + + public string Description + { + get => description; + set => SetProperty(ref description, value); + } + + private int mediaCount; + + public int MediaCount + { + get => mediaCount; + set => SetProperty(ref mediaCount, value); + } + + private string upName; + + public string UpName + { + get => upName; + set => SetProperty(ref upName, value); + } + + private Bitmap upHeader; + + public Bitmap UpHeader + { + get => upHeader; + set => SetProperty(ref upHeader, value); + } + + public Favorites() + { + #region 属性初始化 + + // Play = NormalIcon.Instance().Play; + // Play.Fill = DictionaryResource.GetColor("ColorTextGrey2"); + // + // Like = NormalIcon.Instance().Like; + // Like.Fill = DictionaryResource.GetColor("ColorTextGrey2"); + // + // Favorite = NormalIcon.Instance().Favorite; + // Favorite.Fill = DictionaryResource.GetColor("ColorTextGrey2"); + // + // Share = NormalIcon.Instance().Share; + // Share.Fill = DictionaryResource.GetColor("ColorTextGrey2"); + + #endregion + } +} \ No newline at end of file diff --git a/DownKyi/ViewModels/PageViewModels/FavoritesMedia.cs b/DownKyi/ViewModels/PageViewModels/FavoritesMedia.cs new file mode 100644 index 0000000..6b697a9 --- /dev/null +++ b/DownKyi/ViewModels/PageViewModels/FavoritesMedia.cs @@ -0,0 +1,160 @@ +using Avalonia.Media.Imaging; +using DownKyi.Core.BiliApi.BiliUtils; +using DownKyi.Utils; +using Prism.Commands; +using Prism.Events; +using Prism.Mvvm; + +namespace DownKyi.ViewModels.PageViewModels; + +public class FavoritesMedia : BindableBase +{ + protected readonly IEventAggregator eventAggregator; + + public FavoritesMedia(IEventAggregator eventAggregator) + { + this.eventAggregator = eventAggregator; + } + + public long Avid { get; set; } + public string Bvid { get; set; } + public long UpMid { get; set; } + + #region 页面属性申明 + + private bool isSelected; + + public bool IsSelected + { + get => isSelected; + set => SetProperty(ref isSelected, value); + } + + private int order; + + public int Order + { + get => order; + set => SetProperty(ref order, value); + } + + private Bitmap cover; + + public Bitmap Cover + { + get => cover; + set => SetProperty(ref cover, value); + } + + private string title; + + public string Title + { + get => title; + set => SetProperty(ref title, value); + } + + private string playNumber; + + public string PlayNumber + { + get => playNumber; + set => SetProperty(ref playNumber, value); + } + + private string danmakuNumber; + + public string DanmakuNumber + { + get => danmakuNumber; + set => SetProperty(ref danmakuNumber, value); + } + + private string favoriteNumber; + + public string FavoriteNumber + { + get => favoriteNumber; + set => SetProperty(ref favoriteNumber, value); + } + + private string duration; + + public string Duration + { + get => duration; + set => SetProperty(ref duration, value); + } + + private string upName; + + public string UpName + { + get => upName; + set => SetProperty(ref upName, value); + } + + private string createTime; + + public string CreateTime + { + get => createTime; + set => SetProperty(ref createTime, value); + } + + private string favTime; + + public string FavTime + { + get => favTime; + set => SetProperty(ref favTime, value); + } + + #endregion + + #region 命令申明 + + // 视频标题点击事件 + private DelegateCommand titleCommand; + + public DelegateCommand TitleCommand => + titleCommand ?? (titleCommand = new DelegateCommand(ExecuteTitleCommand)); + + /// + /// 视频标题点击事件 + /// + /// + private void ExecuteTitleCommand(object parameter) + { + if (!(parameter is string tag)) + { + return; + } + + NavigateToView.NavigationView(eventAggregator, ViewVideoDetailViewModel.Tag, tag, + $"{ParseEntrance.VideoUrl}{Bvid}"); + } + + // 视频的UP主点击事件 + private DelegateCommand videoUpperCommand; + + public DelegateCommand VideoUpperCommand => videoUpperCommand ?? + (videoUpperCommand = + new DelegateCommand(ExecuteVideoUpperCommand)); + + /// + /// 视频的UP主点击事件 + /// + /// + private void ExecuteVideoUpperCommand(object parameter) + { + if (!(parameter is string tag)) + { + return; + } + + // NavigateToView.NavigateToViewUserSpace(eventAggregator, tag, UpMid); + } + + #endregion +} \ No newline at end of file diff --git a/DownKyi/ViewModels/PageViewModels/FriendInfo.cs b/DownKyi/ViewModels/PageViewModels/FriendInfo.cs new file mode 100644 index 0000000..1c1c5c0 --- /dev/null +++ b/DownKyi/ViewModels/PageViewModels/FriendInfo.cs @@ -0,0 +1,70 @@ +using Avalonia.Media.Imaging; +using Prism.Commands; +using Prism.Events; +using Prism.Mvvm; + +namespace DownKyi.ViewModels.PageViewModels; + +public class FriendInfo : BindableBase +{ + protected readonly IEventAggregator eventAggregator; + + public FriendInfo(IEventAggregator eventAggregator) + { + this.eventAggregator = eventAggregator; + } + + public long Mid { get; set; } + + #region 页面属性申明 + + private Bitmap header; + + public Bitmap Header + { + get => header; + set => SetProperty(ref header, value); + } + + private string name; + + public string Name + { + get => name; + set => SetProperty(ref name, value); + } + + private string sign; + + public string Sign + { + get => sign; + set => SetProperty(ref sign, value); + } + + #endregion + + #region 命令申明 + + // 视频标题点击事件 + private DelegateCommand userCommand; + + public DelegateCommand UserCommand => + userCommand ?? (userCommand = new DelegateCommand(ExecuteUserCommand)); + + /// + /// 视频标题点击事件 + /// + /// + private void ExecuteUserCommand(object parameter) + { + if (!(parameter is string tag)) + { + return; + } + + // NavigateToView.NavigationView(eventAggregator, ViewUserSpaceViewModel.Tag, tag, Mid); + } + + #endregion +} \ No newline at end of file diff --git a/DownKyi/ViewModels/PageViewModels/HistoryMedia.cs b/DownKyi/ViewModels/PageViewModels/HistoryMedia.cs new file mode 100644 index 0000000..c5d3ecd --- /dev/null +++ b/DownKyi/ViewModels/PageViewModels/HistoryMedia.cs @@ -0,0 +1,195 @@ +using Avalonia.Media.Imaging; +using DownKyi.Images; +using DownKyi.Utils; +using Prism.Commands; +using Prism.Events; +using Prism.Mvvm; + +namespace DownKyi.ViewModels.PageViewModels; + +public class HistoryMedia : BindableBase +{ + protected readonly IEventAggregator eventAggregator; + + public HistoryMedia(IEventAggregator eventAggregator) + { + this.eventAggregator = eventAggregator; + } + + // bvid + public string Bvid { get; set; } + + // 播放url + public string Url { get; set; } + + // UP主的mid + public long UpMid { get; set; } + + // 类型 + public string Business { get; set; } + + #region 页面属性申明 + + // 是否选中 + private bool isSelected; + + public bool IsSelected + { + get => isSelected; + set => SetProperty(ref isSelected, value); + } + + // 封面 + private Bitmap cover; + + public Bitmap Cover + { + get => cover; + set => SetProperty(ref cover, value); + } + + // 视频标题 + private string title; + + public string Title + { + get => title; + set => SetProperty(ref title, value); + } + + // 分P的标题 + private string subTitle; + + public string SubTitle + { + get => subTitle; + set => SetProperty(ref subTitle, value); + } + + // 时长 + private long duration; + + public long Duration + { + get => duration; + set => SetProperty(ref duration, value); + } + + // tag标签 + private string tagName; + + public string TagName + { + get => tagName; + set => SetProperty(ref tagName, value); + } + + // new_desc 剧集或分P描述 + private string partdesc; + + public string Partdesc + { + get => partdesc; + set => SetProperty(ref partdesc, value); + } + + // 观看进度 + private string progress; + + public string Progress + { + get => progress; + set => SetProperty(ref progress, value); + } + + // 观看平台 + private VectorImage platform; + + public VectorImage Platform + { + get => platform; + set => SetProperty(ref platform, value); + } + + // UP主的昵称 + private string upName; + + public string UpName + { + get => upName; + set => SetProperty(ref upName, value); + } + + // UP主的头像 + private Bitmap upHeader; + + public Bitmap UpHeader + { + get => upHeader; + set => SetProperty(ref upHeader, value); + } + + // 是否显示Partdesc + private bool partdescVisibility; + + public bool PartdescVisibility + { + get => partdescVisibility; + set => SetProperty(ref partdescVisibility, value); + } + + // 是否显示UP主信息和分区信息 + private bool upAndTagVisibility; + + public bool UpAndTagVisibility + { + get => upAndTagVisibility; + set => SetProperty(ref upAndTagVisibility, value); + } + + #endregion + + #region 命令申明 + + // 视频标题点击事件 + private DelegateCommand titleCommand; + + public DelegateCommand TitleCommand => + titleCommand ?? (titleCommand = new DelegateCommand(ExecuteTitleCommand)); + + /// + /// 视频标题点击事件 + /// + /// + private void ExecuteTitleCommand(object parameter) + { + if (!(parameter is string tag)) + { + return; + } + + NavigateToView.NavigationView(eventAggregator, ViewVideoDetailViewModel.Tag, tag, Url); + } + + // UP主头像点击事件 + private DelegateCommand upCommand; + + public DelegateCommand UpCommand => + upCommand ?? (upCommand = new DelegateCommand(ExecuteUpCommand)); + + /// + /// UP主头像点击事件 + /// + /// + private void ExecuteUpCommand(object parameter) + { + if (!(parameter is string tag)) + { + return; + } + + NavigateToView.NavigateToViewUserSpace(eventAggregator, tag, UpMid); + } + + #endregion +} \ No newline at end of file diff --git a/DownKyi/ViewModels/PageViewModels/PublicationMedia.cs b/DownKyi/ViewModels/PageViewModels/PublicationMedia.cs new file mode 100644 index 0000000..4a03637 --- /dev/null +++ b/DownKyi/ViewModels/PageViewModels/PublicationMedia.cs @@ -0,0 +1,100 @@ +using Avalonia.Media.Imaging; +using DownKyi.Core.BiliApi.BiliUtils; +using DownKyi.Utils; +using Prism.Commands; +using Prism.Events; +using Prism.Mvvm; + +namespace DownKyi.ViewModels.PageViewModels; + +public class PublicationMedia : BindableBase +{ + protected readonly IEventAggregator eventAggregator; + + public PublicationMedia(IEventAggregator eventAggregator) + { + this.eventAggregator = eventAggregator; + } + + public long Avid { get; set; } + public string Bvid { get; set; } + + #region 页面属性申明 + + private bool isSelected; + + public bool IsSelected + { + get => isSelected; + set => SetProperty(ref isSelected, value); + } + + private Bitmap cover; + + public Bitmap Cover + { + get => cover; + set => SetProperty(ref cover, value); + } + + private string title; + + public string Title + { + get => title; + set => SetProperty(ref title, value); + } + + private string duration; + + public string Duration + { + get => duration; + set => SetProperty(ref duration, value); + } + + private string playNumber; + + public string PlayNumber + { + get => playNumber; + set => SetProperty(ref playNumber, value); + } + + private string createTime; + + public string CreateTime + { + get => createTime; + set => SetProperty(ref createTime, value); + } + + #endregion + + #region 命令申明 + + // 视频标题点击事件 + private DelegateCommand titleCommand; + + public DelegateCommand TitleCommand => + titleCommand ?? (titleCommand = new DelegateCommand(ExecuteTitleCommand)); + + /// + /// 视频标题点击事件 + /// + /// + private void ExecuteTitleCommand(object parameter) + { + if (!(parameter is string tag)) + { + return; + } + + NavigateToView.NavigationView(eventAggregator, ViewVideoDetailViewModel.Tag, tag, + $"{ParseEntrance.VideoUrl}{Bvid}"); + //string url = "https://www.bilibili.com/video/" + tag; + //System.Diagnostics.Process.Start(url); + } + + #endregion +} \ No newline at end of file diff --git a/DownKyi/ViewModels/PageViewModels/SpaceItem.cs b/DownKyi/ViewModels/PageViewModels/SpaceItem.cs new file mode 100644 index 0000000..9c456bc --- /dev/null +++ b/DownKyi/ViewModels/PageViewModels/SpaceItem.cs @@ -0,0 +1,39 @@ +using DownKyi.Images; +using Prism.Mvvm; + +namespace DownKyi.ViewModels.PageViewModels; + +public class SpaceItem : BindableBase +{ + private bool isEnabled; + + public bool IsEnabled + { + get => isEnabled; + set => SetProperty(ref isEnabled, value); + } + + private VectorImage image; + + public VectorImage Image + { + get => image; + set => SetProperty(ref image, value); + } + + private string title; + + public string Title + { + get => title; + set => SetProperty(ref title, value); + } + + private string subtitle; + + public string Subtitle + { + get => subtitle; + set => SetProperty(ref subtitle, value); + } +} \ No newline at end of file diff --git a/DownKyi/ViewModels/PageViewModels/TabHeader.cs b/DownKyi/ViewModels/PageViewModels/TabHeader.cs new file mode 100644 index 0000000..6ea5620 --- /dev/null +++ b/DownKyi/ViewModels/PageViewModels/TabHeader.cs @@ -0,0 +1,39 @@ +using DownKyi.Images; +using Prism.Mvvm; + +namespace DownKyi.ViewModels.PageViewModels; + +public class TabHeader : BindableBase +{ + private long id; + + public long Id + { + get => id; + set => SetProperty(ref id, value); + } + + private VectorImage image; + + public VectorImage Image + { + get => image; + set => SetProperty(ref image, value); + } + + private string title; + + public string Title + { + get => title; + set => SetProperty(ref title, value); + } + + private string subTitle; + + public string SubTitle + { + get => subTitle; + set => SetProperty(ref subTitle, value); + } +} \ No newline at end of file diff --git a/DownKyi/ViewModels/PageViewModels/ToViewMedia.cs b/DownKyi/ViewModels/PageViewModels/ToViewMedia.cs new file mode 100644 index 0000000..12e2be7 --- /dev/null +++ b/DownKyi/ViewModels/PageViewModels/ToViewMedia.cs @@ -0,0 +1,121 @@ +using Avalonia.Media.Imaging; +using DownKyi.Core.BiliApi.BiliUtils; +using DownKyi.Utils; +using Prism.Commands; +using Prism.Events; +using Prism.Mvvm; + +namespace DownKyi.ViewModels.PageViewModels; + +public class ToViewMedia : BindableBase +{ + protected readonly IEventAggregator eventAggregator; + + public ToViewMedia(IEventAggregator eventAggregator) + { + this.eventAggregator = eventAggregator; + } + + // aid + public long Aid { get; set; } + + // bvid + public string Bvid { get; set; } + + // UP主的mid + public long UpMid { get; set; } + + #region 页面属性申明 + + // 是否选中 + private bool isSelected; + + public bool IsSelected + { + get => isSelected; + set => SetProperty(ref isSelected, value); + } + + // 封面 + private Bitmap cover; + + public Bitmap Cover + { + get => cover; + set => SetProperty(ref cover, value); + } + + // 视频标题 + private string title; + + public string Title + { + get => title; + set => SetProperty(ref title, value); + } + + // UP主的昵称 + private string upName; + + public string UpName + { + get => upName; + set => SetProperty(ref upName, value); + } + + // UP主的头像 + private Bitmap upHeader; + + public Bitmap UpHeader + { + get => upHeader; + set => SetProperty(ref upHeader, value); + } + + #endregion + + #region 命令申明 + + // 视频标题点击事件 + private DelegateCommand titleCommand; + + public DelegateCommand TitleCommand => + titleCommand ?? (titleCommand = new DelegateCommand(ExecuteTitleCommand)); + + /// + /// 视频标题点击事件 + /// + /// + private void ExecuteTitleCommand(object parameter) + { + if (!(parameter is string tag)) + { + return; + } + + NavigateToView.NavigationView(eventAggregator, ViewVideoDetailViewModel.Tag, tag, + $"{ParseEntrance.VideoUrl}{Bvid}"); + } + + // UP主头像点击事件 + private DelegateCommand upCommand; + + public DelegateCommand UpCommand => + upCommand ?? (upCommand = new DelegateCommand(ExecuteUpCommand)); + + /// + /// UP主头像点击事件 + /// + /// + private void ExecuteUpCommand(object parameter) + { + if (!(parameter is string tag)) + { + return; + } + + // NavigateToView.NavigateToViewUserSpace(eventAggregator, tag, UpMid); + } + + #endregion +} \ No newline at end of file diff --git a/DownKyi/ViewModels/PageViewModels/VideoInfoView.cs b/DownKyi/ViewModels/PageViewModels/VideoInfoView.cs new file mode 100644 index 0000000..78ab1af --- /dev/null +++ b/DownKyi/ViewModels/PageViewModels/VideoInfoView.cs @@ -0,0 +1,123 @@ +using Avalonia.Media.Imaging; +using Prism.Mvvm; + +namespace DownKyi.ViewModels.PageViewModels; + +public class VideoInfoView : BindableBase +{ + public string CoverUrl { get; set; } + public long UpperMid { get; set; } + public int TypeId { get; set; } + + private Bitmap cover; + + public Bitmap Cover + { + get => cover; + set => SetProperty(ref cover, value); + } + + private string title; + + public string Title + { + get => title; + set => SetProperty(ref title, value); + } + + private string videoZone; + + public string VideoZone + { + get => videoZone; + set => SetProperty(ref videoZone, value); + } + + private string createTime; + + public string CreateTime + { + get => createTime; + set => SetProperty(ref createTime, value); + } + + private string playNumber; + + public string PlayNumber + { + get => playNumber; + set => SetProperty(ref playNumber, value); + } + + private string danmakuNumber; + + public string DanmakuNumber + { + get => danmakuNumber; + set => SetProperty(ref danmakuNumber, value); + } + + private string likeNumber; + + public string LikeNumber + { + get => likeNumber; + set => SetProperty(ref likeNumber, value); + } + + private string coinNumber; + + public string CoinNumber + { + get => coinNumber; + set => SetProperty(ref coinNumber, value); + } + + private string favoriteNumber; + + public string FavoriteNumber + { + get => favoriteNumber; + set => SetProperty(ref favoriteNumber, value); + } + + private string shareNumber; + + public string ShareNumber + { + get => shareNumber; + set => SetProperty(ref shareNumber, value); + } + + private string replyNumber; + + public string ReplyNumber + { + get => replyNumber; + set => SetProperty(ref replyNumber, value); + } + + private string description; + + public string Description + { + get => description; + set => SetProperty(ref description, value); + } + + private string upName; + + public string UpName + { + get => upName; + set => SetProperty(ref upName, value); + } + + private Bitmap upHeader; + + public Bitmap UpHeader + { + get => upHeader; + set => SetProperty(ref upHeader, value); + } +} \ No newline at end of file diff --git a/DownKyi/ViewModels/PageViewModels/VideoPage.cs b/DownKyi/ViewModels/PageViewModels/VideoPage.cs new file mode 100644 index 0000000..28e0544 --- /dev/null +++ b/DownKyi/ViewModels/PageViewModels/VideoPage.cs @@ -0,0 +1,136 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using DownKyi.Core.BiliApi.BiliUtils; +using DownKyi.Core.BiliApi.Models; +using DownKyi.Core.BiliApi.VideoStream.Models; +using DownKyi.Core.Logging; +using DownKyi.Core.Utils; +using Prism.Commands; +using Prism.Mvvm; +using Console = DownKyi.Core.Utils.Debugging.Console; + +namespace DownKyi.ViewModels.PageViewModels; + +public class VideoPage : BindableBase +{ + public PlayUrl PlayUrl { get; set; } + + public long Avid { get; set; } + public string Bvid { get; set; } + public long Cid { get; set; } + public long EpisodeId { get; set; } + public VideoOwner Owner { get; set; } + public string PublishTime { get; set; } + + public string FirstFrame { get; set; } + + private bool isSelected; + + public bool IsSelected + { + get => isSelected; + set => SetProperty(ref isSelected, value); + } + + private int order; + + public int Order + { + get => order; + set => SetProperty(ref order, value); + } + + private string name; + + public string Name + { + get => name; + set => SetProperty(ref name, value); + } + + private string duration; + + public string Duration + { + get => duration; + set => SetProperty(ref duration, value); + } + + private ObservableCollection audioQualityFormatList; + + public ObservableCollection AudioQualityFormatList + { + get => audioQualityFormatList; + set => SetProperty(ref audioQualityFormatList, value); + } + + private string audioQualityFormat; + + public string AudioQualityFormat + { + get => audioQualityFormat; + set => SetProperty(ref audioQualityFormat, value); + } + + private List videoQualityList; + + public List VideoQualityList + { + get => videoQualityList; + set => SetProperty(ref videoQualityList, value); + } + + private VideoQuality videoQuality; + + public VideoQuality VideoQuality + { + get => videoQuality; + set => SetProperty(ref videoQuality, value); + } + + #region + + // 视频画质选择事件 + private DelegateCommand videoQualitySelectedCommand; + + public DelegateCommand VideoQualitySelectedCommand => videoQualitySelectedCommand ?? + (videoQualitySelectedCommand = + new DelegateCommand(ExecuteVideoQualitySelectedCommand)); + + /// + /// 视频画质选择事件 + /// + private void ExecuteVideoQualitySelectedCommand() + { + // 杜比视界 + string dolby = string.Empty; + try + { + var qualities = Constant.GetAudioQualities(); + dolby = qualities[3].Name; + } + catch (Exception e) + { + Console.PrintLine("ExecuteVideoQualitySelectedCommand()发生异常: {0}", e); + LogManager.Error("ExecuteVideoQualitySelectedCommand", e); + } + + if (VideoQuality != null && VideoQuality.Quality == 126 && PlayUrl != null && PlayUrl.Dash != null && + PlayUrl.Dash.Dolby != null) + { + ListHelper.AddUnique(AudioQualityFormatList, dolby); + AudioQualityFormat = dolby; + } + else + { + if (AudioQualityFormatList.Contains(dolby)) + { + AudioQualityFormatList.Remove(dolby); + AudioQualityFormat = AudioQualityFormatList[0]; + } + } + } + + #endregion +} \ No newline at end of file diff --git a/DownKyi/ViewModels/PageViewModels/VideoQuality.cs b/DownKyi/ViewModels/PageViewModels/VideoQuality.cs new file mode 100644 index 0000000..986f721 --- /dev/null +++ b/DownKyi/ViewModels/PageViewModels/VideoQuality.cs @@ -0,0 +1,39 @@ +using System.Collections.Generic; +using Prism.Mvvm; + +namespace DownKyi.ViewModels.PageViewModels; + +public class VideoQuality : BindableBase +{ + private int quality; + + public int Quality + { + get => quality; + set => SetProperty(ref quality, value); + } + + private string qualityFormat; + + public string QualityFormat + { + get => qualityFormat; + set => SetProperty(ref qualityFormat, value); + } + + private List videoCodecList; + + public List VideoCodecList + { + get => videoCodecList; + set => SetProperty(ref videoCodecList, value); + } + + private string selectedVideoCodec; + + public string SelectedVideoCodec + { + get => selectedVideoCodec; + set => SetProperty(ref selectedVideoCodec, value); + } +} \ No newline at end of file diff --git a/DownKyi/ViewModels/PageViewModels/VideoSection.cs b/DownKyi/ViewModels/PageViewModels/VideoSection.cs new file mode 100644 index 0000000..620a2db --- /dev/null +++ b/DownKyi/ViewModels/PageViewModels/VideoSection.cs @@ -0,0 +1,33 @@ +using System.Collections.Generic; +using Prism.Mvvm; + +namespace DownKyi.ViewModels.PageViewModels; + +public class VideoSection : BindableBase +{ + public long Id { get; set; } + + private string title; + + public string Title + { + get => title; + set => SetProperty(ref title, value); + } + + private bool isSelected; + + public bool IsSelected + { + get => isSelected; + set => SetProperty(ref isSelected, value); + } + + private List videoPages; + + public List VideoPages + { + get => videoPages; + set => SetProperty(ref videoPages, value); + } +} \ No newline at end of file diff --git a/DownKyi/ViewModels/Settings/DisplayFileNamePart.cs b/DownKyi/ViewModels/Settings/DisplayFileNamePart.cs new file mode 100644 index 0000000..96c038b --- /dev/null +++ b/DownKyi/ViewModels/Settings/DisplayFileNamePart.cs @@ -0,0 +1,17 @@ +using DownKyi.Core.FileName; +using Prism.Mvvm; + +namespace DownKyi.ViewModels.Settings; + +public class DisplayFileNamePart : BindableBase +{ + public FileNamePart Id { get; set; } + + private string title; + + public string Title + { + get => title; + set => SetProperty(ref title, value); + } +} \ No newline at end of file diff --git a/DownKyi/ViewModels/Settings/ViewAboutViewModel.cs b/DownKyi/ViewModels/Settings/ViewAboutViewModel.cs new file mode 100644 index 0000000..8520a42 --- /dev/null +++ b/DownKyi/ViewModels/Settings/ViewAboutViewModel.cs @@ -0,0 +1,300 @@ +using System.Diagnostics; +using DownKyi.Core.Settings; +using DownKyi.Events; +using DownKyi.Models; +using DownKyi.Utils; +using Prism.Commands; +using Prism.Events; +using Prism.Regions; +using Prism.Services.Dialogs; + +namespace DownKyi.ViewModels.Settings; + +public class ViewAboutViewModel : ViewModelBase +{ + public const string Tag = "PageSettingsAbout"; + + private bool _isOnNavigatedTo; + + #region 页面属性申明 + + private string _appName; + + public string AppName + { + get => _appName; + set => SetProperty(ref _appName, value); + } + + private string _appVersion; + + public string AppVersion + { + get => _appVersion; + set => SetProperty(ref _appVersion, value); + } + + private bool _isReceiveBetaVersion; + + public bool IsReceiveBetaVersion + { + get => _isReceiveBetaVersion; + set => SetProperty(ref _isReceiveBetaVersion, value); + } + + private bool _autoUpdateWhenLaunch; + + public bool AutoUpdateWhenLaunch + { + get => _autoUpdateWhenLaunch; + set => SetProperty(ref _autoUpdateWhenLaunch, value); + } + + #endregion + + public ViewAboutViewModel(IEventAggregator eventAggregator, IDialogService dialogService) : base(eventAggregator, + dialogService) + { + #region 属性初始化 + + AppInfo app = new AppInfo(); + AppName = app.Name; + AppVersion = app.VersionName; + + #endregion + } + + /// + /// 导航到页面时执行 + /// + /// + public override void OnNavigatedTo(NavigationContext navigationContext) + { + base.OnNavigatedTo(navigationContext); + + _isOnNavigatedTo = true; + + // 是否接收测试版更新 + var isReceiveBetaVersion = SettingsManager.GetInstance().IsReceiveBetaVersion(); + IsReceiveBetaVersion = isReceiveBetaVersion == AllowStatus.YES; + + // 是否在启动时自动检查更新 + var isAutoUpdateWhenLaunch = SettingsManager.GetInstance().GetAutoUpdateWhenLaunch(); + AutoUpdateWhenLaunch = isAutoUpdateWhenLaunch == AllowStatus.YES; + + _isOnNavigatedTo = false; + } + + #region 命令申明 + + // 访问主页事件 + private DelegateCommand? _appNameCommand; + + public DelegateCommand AppNameCommand => _appNameCommand ??= new DelegateCommand(ExecuteAppNameCommand); + + /// + /// 访问主页事件 + /// + private void ExecuteAppNameCommand() + { + Process.Start("https://github.com/leiurayer/downkyi"); + } + + // 检查更新事件 + private DelegateCommand? _checkUpdateCommand; + + public DelegateCommand CheckUpdateCommand => _checkUpdateCommand ??= new DelegateCommand(ExecuteCheckUpdateCommand); + + /// + /// 检查更新事件 + /// + private void ExecuteCheckUpdateCommand() + { + //eventAggregator.GetEvent().Publish("开始查找更新,请稍后~"); + eventAggregator.GetEvent().Publish("请前往主页下载最新版~"); + } + + // 意见反馈事件 + private DelegateCommand? _feedbackCommand; + + public DelegateCommand FeedbackCommand => _feedbackCommand ??= new DelegateCommand(ExecuteFeedbackCommand); + + /// + /// 意见反馈事件 + /// + private void ExecuteFeedbackCommand() + { + Process.Start("https://github.com/leiurayer/downkyi/issues"); + } + + // 是否接收测试版更新事件 + private DelegateCommand? _receiveBetaVersionCommand; + + public DelegateCommand ReceiveBetaVersionCommand => + _receiveBetaVersionCommand ??= new DelegateCommand(ExecuteReceiveBetaVersionCommand); + + /// + /// 是否接收测试版更新事件 + /// + private void ExecuteReceiveBetaVersionCommand() + { + AllowStatus isReceiveBetaVersion = IsReceiveBetaVersion ? AllowStatus.YES : AllowStatus.NO; + + bool isSucceed = SettingsManager.GetInstance().IsReceiveBetaVersion(isReceiveBetaVersion); + PublishTip(isSucceed); + } + + // 是否在启动时自动检查更新事件 + private DelegateCommand? _autoUpdateWhenLaunchCommand; + + public DelegateCommand AutoUpdateWhenLaunchCommand => + _autoUpdateWhenLaunchCommand ??= new DelegateCommand(ExecuteAutoUpdateWhenLaunchCommand); + + /// + /// 是否在启动时自动检查更新事件 + /// + private void ExecuteAutoUpdateWhenLaunchCommand() + { + AllowStatus isAutoUpdateWhenLaunch = AutoUpdateWhenLaunch ? AllowStatus.YES : AllowStatus.NO; + + bool isSucceed = SettingsManager.GetInstance().SetAutoUpdateWhenLaunch(isAutoUpdateWhenLaunch); + PublishTip(isSucceed); + } + + // Brotli.NET许可证查看事件 + private DelegateCommand brotliLicenseCommand; + + public DelegateCommand BrotliLicenseCommand => brotliLicenseCommand ?? + (brotliLicenseCommand = + new DelegateCommand(ExecuteBrotliLicenseCommand)); + + /// + /// Brotli.NET许可证查看事件 + /// + private void ExecuteBrotliLicenseCommand() + { + Process.Start("https://licenses.nuget.org/MIT"); + } + + // Google.Protobuf许可证查看事件 + private DelegateCommand protobufLicenseCommand; + + public DelegateCommand ProtobufLicenseCommand => protobufLicenseCommand ?? + (protobufLicenseCommand = + new DelegateCommand(ExecuteProtobufLicenseCommand)); + + /// + /// Google.Protobuf许可证查看事件 + /// + private void ExecuteProtobufLicenseCommand() + { + Process.Start("https://github.com/protocolbuffers/protobuf/blob/master/LICENSE"); + } + + // Newtonsoft.Json许可证查看事件 + private DelegateCommand newtonsoftLicenseCommand; + + public DelegateCommand NewtonsoftLicenseCommand => newtonsoftLicenseCommand ?? + (newtonsoftLicenseCommand = + new DelegateCommand(ExecuteNewtonsoftLicenseCommand)); + + /// + /// Newtonsoft.Json许可证查看事件 + /// + private void ExecuteNewtonsoftLicenseCommand() + { + Process.Start("https://licenses.nuget.org/MIT"); + } + + // Prism.DryIoc许可证查看事件 + private DelegateCommand prismLicenseCommand; + + public DelegateCommand PrismLicenseCommand => prismLicenseCommand ?? + (prismLicenseCommand = + new DelegateCommand(ExecutePrismLicenseCommand)); + + /// + /// Prism.DryIoc许可证查看事件 + /// + private void ExecutePrismLicenseCommand() + { + Process.Start("https://www.nuget.org/packages/Prism.DryIoc/8.1.97/license"); + } + + // QRCoder许可证查看事件 + private DelegateCommand qRCoderLicenseCommand; + + public DelegateCommand QRCoderLicenseCommand => qRCoderLicenseCommand ?? + (qRCoderLicenseCommand = + new DelegateCommand(ExecuteQRCoderLicenseCommand)); + + /// + /// QRCoder许可证查看事件 + /// + private void ExecuteQRCoderLicenseCommand() + { + Process.Start("https://licenses.nuget.org/MIT"); + } + + // System.Data.SQLite.Core许可证查看事件 + private DelegateCommand sQLiteLicenseCommand; + + public DelegateCommand SQLiteLicenseCommand => sQLiteLicenseCommand ?? + (sQLiteLicenseCommand = + new DelegateCommand(ExecuteSQLiteLicenseCommand)); + + /// + /// System.Data.SQLite.Core许可证查看事件 + /// + private void ExecuteSQLiteLicenseCommand() + { + Process.Start("https://www.sqlite.org/copyright.html"); + } + + // Aria2c许可证查看事件 + private DelegateCommand ariaLicenseCommand; + + public DelegateCommand AriaLicenseCommand => + ariaLicenseCommand ?? (ariaLicenseCommand = new DelegateCommand(ExecuteAriaLicenseCommand)); + + /// + /// Aria2c许可证查看事件 + /// + private void ExecuteAriaLicenseCommand() + { + Process.Start("aria2_COPYING.txt"); + } + + // FFmpeg许可证查看事件 + private DelegateCommand fFmpegLicenseCommand; + + public DelegateCommand FFmpegLicenseCommand => fFmpegLicenseCommand ?? + (fFmpegLicenseCommand = + new DelegateCommand(ExecuteFFmpegLicenseCommand)); + + /// + /// FFmpeg许可证查看事件 + /// + private void ExecuteFFmpegLicenseCommand() + { + Process.Start("FFmpeg_LICENSE.txt"); + } + + #endregion + + /// + /// 发送需要显示的tip + /// + /// + private void PublishTip(bool isSucceed) + { + if (_isOnNavigatedTo) + { + return; + } + + eventAggregator.GetEvent().Publish(isSucceed + ? DictionaryResource.GetString("TipSettingUpdated") + : DictionaryResource.GetString("TipSettingFailed")); + } +} \ No newline at end of file diff --git a/DownKyi/ViewModels/Settings/ViewBasicViewModel.cs b/DownKyi/ViewModels/Settings/ViewBasicViewModel.cs new file mode 100644 index 0000000..f390e62 --- /dev/null +++ b/DownKyi/ViewModels/Settings/ViewBasicViewModel.cs @@ -0,0 +1,293 @@ +using System.Collections.Generic; +using System.Linq; +using DownKyi.Core.Settings; +using DownKyi.Events; +using DownKyi.Models; +using DownKyi.Utils; +using Prism.Commands; +using Prism.Events; +using Prism.Regions; + +namespace DownKyi.ViewModels.Settings; + +public class ViewBasicViewModel : ViewModelBase +{ + public const string Tag = "PageSettingsBasic"; + + private bool isOnNavigatedTo; + + #region 页面属性申明 + + private bool none; + + public bool None + { + get { return none; } + set { SetProperty(ref none, value); } + } + + private bool closeApp; + + public bool CloseApp + { + get { return closeApp; } + set { SetProperty(ref closeApp, value); } + } + + private bool closeSystem; + + public bool CloseSystem + { + get { return closeSystem; } + set { SetProperty(ref closeSystem, value); } + } + + private bool listenClipboard; + + public bool ListenClipboard + { + get { return listenClipboard; } + set { SetProperty(ref listenClipboard, value); } + } + + private bool autoParseVideo; + + public bool AutoParseVideo + { + get { return autoParseVideo; } + set { SetProperty(ref autoParseVideo, value); } + } + + private List parseScopes; + + public List ParseScopes + { + get { return parseScopes; } + set { SetProperty(ref parseScopes, value); } + } + + private ParseScopeDisplay selectedParseScope; + + public ParseScopeDisplay SelectedParseScope + { + get { return selectedParseScope; } + set { SetProperty(ref selectedParseScope, value); } + } + + private bool autoDownloadAll; + + public bool AutoDownloadAll + { + get => autoDownloadAll; + set => SetProperty(ref autoDownloadAll, value); + } + + #endregion + + public ViewBasicViewModel(IEventAggregator eventAggregator) : base(eventAggregator) + { + #region 属性初始化 + + // 解析范围 + ParseScopes = new List() + { + new ParseScopeDisplay { Name = DictionaryResource.GetString("ParseNone"), ParseScope = ParseScope.NONE }, + new ParseScopeDisplay + { Name = DictionaryResource.GetString("ParseSelectedItem"), ParseScope = ParseScope.SELECTED_ITEM }, + new ParseScopeDisplay + { Name = DictionaryResource.GetString("ParseCurrentSection"), ParseScope = ParseScope.CURRENT_SECTION }, + new ParseScopeDisplay { Name = DictionaryResource.GetString("ParseAll"), ParseScope = ParseScope.ALL } + }; + + #endregion + } + + /// + /// 导航到页面时执行 + /// + /// + public override void OnNavigatedTo(NavigationContext navigationContext) + { + base.OnNavigatedTo(navigationContext); + + isOnNavigatedTo = true; + + // 下载完成后的操作 + AfterDownloadOperation afterDownload = SettingsManager.GetInstance().GetAfterDownloadOperation(); + SetAfterDownloadOperation(afterDownload); + + // 是否监听剪贴板 + AllowStatus isListenClipboard = SettingsManager.GetInstance().IsListenClipboard(); + ListenClipboard = isListenClipboard == AllowStatus.YES; + + // 是否自动解析视频 + AllowStatus isAutoParseVideo = SettingsManager.GetInstance().IsAutoParseVideo(); + AutoParseVideo = isAutoParseVideo == AllowStatus.YES; + + // 解析范围 + ParseScope parseScope = SettingsManager.GetInstance().GetParseScope(); + SelectedParseScope = ParseScopes.FirstOrDefault(t => { return t.ParseScope == parseScope; }); + + // 解析后是否自动下载解析视频 + AllowStatus isAutoDownloadAll = SettingsManager.GetInstance().IsAutoDownloadAll(); + AutoDownloadAll = isAutoDownloadAll == AllowStatus.YES; + + isOnNavigatedTo = false; + } + + #region 命令申明 + + // 下载完成后的操作事件 + private DelegateCommand afterDownloadOperationCommand; + + public DelegateCommand AfterDownloadOperationCommand => afterDownloadOperationCommand ?? + (afterDownloadOperationCommand = + new DelegateCommand( + ExecuteAfterDownloadOperationCommand)); + + /// + /// 下载完成后的操作事件 + /// + private void ExecuteAfterDownloadOperationCommand(string parameter) + { + AfterDownloadOperation afterDownload; + switch (parameter) + { + case "None": + afterDownload = AfterDownloadOperation.NONE; + break; + case "CloseApp": + afterDownload = AfterDownloadOperation.CLOSE_APP; + break; + case "CloseSystem": + afterDownload = AfterDownloadOperation.CLOSE_SYSTEM; + break; + default: + afterDownload = AfterDownloadOperation.NONE; + break; + } + + bool isSucceed = SettingsManager.GetInstance().SetAfterDownloadOperation(afterDownload); + PublishTip(isSucceed); + } + + // 是否监听剪贴板事件 + private DelegateCommand listenClipboardCommand; + + public DelegateCommand ListenClipboardCommand => listenClipboardCommand ?? + (listenClipboardCommand = + new DelegateCommand(ExecuteListenClipboardCommand)); + + /// + /// 是否监听剪贴板事件 + /// + private void ExecuteListenClipboardCommand() + { + AllowStatus isListenClipboard = ListenClipboard ? AllowStatus.YES : AllowStatus.NO; + + bool isSucceed = SettingsManager.GetInstance().IsListenClipboard(isListenClipboard); + PublishTip(isSucceed); + } + + private DelegateCommand autoParseVideoCommand; + + public DelegateCommand AutoParseVideoCommand => autoParseVideoCommand ?? + (autoParseVideoCommand = + new DelegateCommand(ExecuteAutoParseVideoCommand)); + + /// + /// 是否自动解析视频 + /// + private void ExecuteAutoParseVideoCommand() + { + AllowStatus isAutoParseVideo = AutoParseVideo ? AllowStatus.YES : AllowStatus.NO; + + bool isSucceed = SettingsManager.GetInstance().IsAutoParseVideo(isAutoParseVideo); + PublishTip(isSucceed); + } + + // 解析范围事件 + private DelegateCommand parseScopesCommand; + + public DelegateCommand ParseScopesCommand => parseScopesCommand ?? + (parseScopesCommand = + new DelegateCommand(ExecuteParseScopesCommand)); + + /// + /// 解析范围事件 + /// + /// + private void ExecuteParseScopesCommand(object parameter) + { + if (!(parameter is ParseScopeDisplay parseScope)) + { + return; + } + + bool isSucceed = SettingsManager.GetInstance().SetParseScope(parseScope.ParseScope); + PublishTip(isSucceed); + } + + // 解析后是否自动下载解析视频 + private DelegateCommand autoDownloadAllCommand; + + public DelegateCommand AutoDownloadAllCommand => autoDownloadAllCommand ?? + (autoDownloadAllCommand = + new DelegateCommand(ExecuteAutoDownloadAllCommand)); + + /// + /// 解析后是否自动下载解析视频 + /// + private void ExecuteAutoDownloadAllCommand() + { + AllowStatus isAutoDownloadAll = AutoDownloadAll ? AllowStatus.YES : AllowStatus.NO; + + bool isSucceed = SettingsManager.GetInstance().IsAutoDownloadAll(isAutoDownloadAll); + PublishTip(isSucceed); + } + + #endregion + + /// + /// 设置下载完成后的操作 + /// + /// + private void SetAfterDownloadOperation(AfterDownloadOperation afterDownload) + { + switch (afterDownload) + { + case AfterDownloadOperation.NONE: + None = true; + break; + case AfterDownloadOperation.OPEN_FOLDER: + break; + case AfterDownloadOperation.CLOSE_APP: + CloseApp = true; + break; + case AfterDownloadOperation.CLOSE_SYSTEM: + CloseSystem = true; + break; + } + } + + /// + /// 发送需要显示的tip + /// + /// + private void PublishTip(bool isSucceed) + { + if (isOnNavigatedTo) + { + return; + } + + if (isSucceed) + { + eventAggregator.GetEvent().Publish(DictionaryResource.GetString("TipSettingUpdated")); + } + else + { + eventAggregator.GetEvent().Publish(DictionaryResource.GetString("TipSettingFailed")); + } + } +} \ No newline at end of file diff --git a/DownKyi/ViewModels/Settings/ViewDanmakuViewModel.cs b/DownKyi/ViewModels/Settings/ViewDanmakuViewModel.cs new file mode 100644 index 0000000..232dbe1 --- /dev/null +++ b/DownKyi/ViewModels/Settings/ViewDanmakuViewModel.cs @@ -0,0 +1,410 @@ +using System.Collections.Generic; +using System.Linq; +using Avalonia.Media; +using DownKyi.Core.Settings; +using DownKyi.Core.Utils.Validator; +using DownKyi.Events; +using DownKyi.Utils; +using Prism.Commands; +using Prism.Events; +using Prism.Regions; + +namespace DownKyi.ViewModels.Settings; + +public class ViewDanmakuViewModel : ViewModelBase +{ + public const string Tag = "PageSettingsDanmaku"; + + private bool isOnNavigatedTo; + + #region 页面属性申明 + + private bool topFilter; + + public bool TopFilter + { + get { return topFilter; } + set { SetProperty(ref topFilter, value); } + } + + private bool bottomFilter; + + public bool BottomFilter + { + get { return bottomFilter; } + set { SetProperty(ref bottomFilter, value); } + } + + private bool scrollFilter; + + public bool ScrollFilter + { + get { return scrollFilter; } + set { SetProperty(ref scrollFilter, value); } + } + + private int screenWidth; + + public int ScreenWidth + { + get { return screenWidth; } + set { SetProperty(ref screenWidth, value); } + } + + private int screenHeight; + + public int ScreenHeight + { + get { return screenHeight; } + set { SetProperty(ref screenHeight, value); } + } + + private List fonts; + + public List Fonts + { + get { return fonts; } + set { SetProperty(ref fonts, value); } + } + + private string selectedFont; + + public string SelectedFont + { + get { return selectedFont; } + set { SetProperty(ref selectedFont, value); } + } + + private int fontSize; + + public int FontSize + { + get { return fontSize; } + set { SetProperty(ref fontSize, value); } + } + + private int lineCount; + + public int LineCount + { + get { return lineCount; } + set { SetProperty(ref lineCount, value); } + } + + private bool sync; + + public bool Sync + { + get { return sync; } + set { SetProperty(ref sync, value); } + } + + private bool async; + + public bool Async + { + get { return async; } + set { SetProperty(ref async, value); } + } + + #endregion + + public ViewDanmakuViewModel(IEventAggregator eventAggregator) : base(eventAggregator) + { + #region 属性初始化 + + // 弹幕字体 + Fonts = new List(); + var fontCollection = FontManager.Current.SystemFonts.Select(x=>x.Name); + foreach (var font in fontCollection) + { + Fonts.Add(font); + } + + #endregion + } + + /// + /// 导航到页面时执行 + /// + /// + public override void OnNavigatedTo(NavigationContext navigationContext) + { + base.OnNavigatedTo(navigationContext); + + isOnNavigatedTo = true; + + // 屏蔽顶部弹幕 + AllowStatus danmakuTopFilter = SettingsManager.GetInstance().GetDanmakuTopFilter(); + TopFilter = danmakuTopFilter == AllowStatus.YES; + + // 屏蔽底部弹幕 + AllowStatus danmakuBottomFilter = SettingsManager.GetInstance().GetDanmakuBottomFilter(); + BottomFilter = danmakuBottomFilter == AllowStatus.YES; + + // 屏蔽滚动弹幕 + AllowStatus danmakuScrollFilter = SettingsManager.GetInstance().GetDanmakuScrollFilter(); + ScrollFilter = danmakuScrollFilter == AllowStatus.YES; + + // 分辨率-宽 + ScreenWidth = SettingsManager.GetInstance().GetDanmakuScreenWidth(); + + // 分辨率-高 + ScreenHeight = SettingsManager.GetInstance().GetDanmakuScreenHeight(); + + // 弹幕字体 + string danmakuFont = SettingsManager.GetInstance().GetDanmakuFontName(); + if (danmakuFont != null && Fonts.Contains(danmakuFont)) + { + // 只有系统中存在当前设置的字体,才能显示 + SelectedFont = danmakuFont; + } + + // 弹幕字体大小 + FontSize = SettingsManager.GetInstance().GetDanmakuFontSize(); + + // 弹幕限制行数 + LineCount = SettingsManager.GetInstance().GetDanmakuLineCount(); + + // 弹幕布局算法 + DanmakuLayoutAlgorithm layoutAlgorithm = SettingsManager.GetInstance().GetDanmakuLayoutAlgorithm(); + SetLayoutAlgorithm(layoutAlgorithm); + + isOnNavigatedTo = false; + } + + #region 命令申明 + + // 屏蔽顶部弹幕事件 + private DelegateCommand topFilterCommand; + + public DelegateCommand TopFilterCommand => + topFilterCommand ?? (topFilterCommand = new DelegateCommand(ExecuteTopFilterCommand)); + + /// + /// 屏蔽顶部弹幕事件 + /// + private void ExecuteTopFilterCommand() + { + AllowStatus isTopFilter = TopFilter ? AllowStatus.YES : AllowStatus.NO; + + bool isSucceed = SettingsManager.GetInstance().SetDanmakuTopFilter(isTopFilter); + PublishTip(isSucceed); + } + + // 屏蔽底部弹幕事件 + private DelegateCommand bottomFilterCommand; + + public DelegateCommand BottomFilterCommand => bottomFilterCommand ?? + (bottomFilterCommand = + new DelegateCommand(ExecuteBottomFilterCommand)); + + /// + /// 屏蔽底部弹幕事件 + /// + private void ExecuteBottomFilterCommand() + { + AllowStatus isBottomFilter = BottomFilter ? AllowStatus.YES : AllowStatus.NO; + + bool isSucceed = SettingsManager.GetInstance().SetDanmakuBottomFilter(isBottomFilter); + PublishTip(isSucceed); + } + + // 屏蔽滚动弹幕事件 + private DelegateCommand scrollFilterCommand; + + public DelegateCommand ScrollFilterCommand => scrollFilterCommand ?? + (scrollFilterCommand = + new DelegateCommand(ExecuteScrollFilterCommand)); + + /// + /// 屏蔽滚动弹幕事件 + /// + private void ExecuteScrollFilterCommand() + { + AllowStatus isScrollFilter = ScrollFilter ? AllowStatus.YES : AllowStatus.NO; + + bool isSucceed = SettingsManager.GetInstance().SetDanmakuScrollFilter(isScrollFilter); + PublishTip(isSucceed); + } + + // 设置分辨率-宽事件 + private DelegateCommand screenWidthCommand; + + public DelegateCommand ScreenWidthCommand => screenWidthCommand ?? + (screenWidthCommand = + new DelegateCommand(ExecuteScreenWidthCommand)); + + /// + /// 设置分辨率-宽事件 + /// + /// + private void ExecuteScreenWidthCommand(string parameter) + { + int width = (int)Number.GetInt(parameter); + ScreenWidth = width; + + bool isSucceed = SettingsManager.GetInstance().SetDanmakuScreenWidth(ScreenWidth); + PublishTip(isSucceed); + } + + // 设置分辨率-高事件 + private DelegateCommand screenHeightCommand; + + public DelegateCommand ScreenHeightCommand => screenHeightCommand ?? + (screenHeightCommand = + new DelegateCommand(ExecuteScreenHeightCommand)); + + /// + /// 设置分辨率-高事件 + /// + /// + private void ExecuteScreenHeightCommand(string parameter) + { + int height = (int)Number.GetInt(parameter); + ScreenHeight = height; + + bool isSucceed = SettingsManager.GetInstance().SetDanmakuScreenHeight(ScreenHeight); + PublishTip(isSucceed); + } + + // 弹幕字体选择事件 + private DelegateCommand fontSelectCommand; + + public DelegateCommand FontSelectCommand => fontSelectCommand ?? + (fontSelectCommand = + new DelegateCommand(ExecuteFontSelectCommand)); + + /// + /// 弹幕字体选择事件 + /// + /// + private void ExecuteFontSelectCommand(string parameter) + { + bool isSucceed = SettingsManager.GetInstance().SetDanmakuFontName(parameter); + PublishTip(isSucceed); + } + + // 弹幕字体大小事件 + private DelegateCommand fontSizeCommand; + + public DelegateCommand FontSizeCommand => + fontSizeCommand ?? (fontSizeCommand = new DelegateCommand(ExecuteFontSizeCommand)); + + /// + /// 弹幕字体大小事件 + /// + /// + private void ExecuteFontSizeCommand(string parameter) + { + int fontSize = (int)Number.GetInt(parameter); + FontSize = fontSize; + + bool isSucceed = SettingsManager.GetInstance().SetDanmakuFontSize(FontSize); + PublishTip(isSucceed); + } + + // 弹幕限制行数事件 + private DelegateCommand lineCountCommand; + + public DelegateCommand LineCountCommand => + lineCountCommand ?? (lineCountCommand = new DelegateCommand(ExecuteLineCountCommand)); + + /// + /// 弹幕限制行数事件 + /// + /// + private void ExecuteLineCountCommand(string parameter) + { + int lineCount = (int)Number.GetInt(parameter); + LineCount = lineCount; + + bool isSucceed = SettingsManager.GetInstance().SetDanmakuLineCount(LineCount); + PublishTip(isSucceed); + } + + // 弹幕布局算法事件 + private DelegateCommand layoutAlgorithmCommand; + + public DelegateCommand LayoutAlgorithmCommand => layoutAlgorithmCommand ?? + (layoutAlgorithmCommand = + new DelegateCommand( + ExecuteLayoutAlgorithmCommand)); + + /// + /// 弹幕布局算法事件 + /// + /// + private void ExecuteLayoutAlgorithmCommand(string parameter) + { + DanmakuLayoutAlgorithm layoutAlgorithm; + switch (parameter) + { + case "Sync": + layoutAlgorithm = DanmakuLayoutAlgorithm.SYNC; + break; + case "Async": + layoutAlgorithm = DanmakuLayoutAlgorithm.ASYNC; + break; + default: + layoutAlgorithm = DanmakuLayoutAlgorithm.SYNC; + break; + } + + bool isSucceed = SettingsManager.GetInstance().SetDanmakuLayoutAlgorithm(layoutAlgorithm); + PublishTip(isSucceed); + + if (isSucceed) + { + SetLayoutAlgorithm(layoutAlgorithm); + } + } + + #endregion + + /// + /// 设置弹幕同步算法 + /// + /// + private void SetLayoutAlgorithm(DanmakuLayoutAlgorithm layoutAlgorithm) + { + switch (layoutAlgorithm) + { + case DanmakuLayoutAlgorithm.SYNC: + Sync = true; + Async = false; + break; + case DanmakuLayoutAlgorithm.ASYNC: + Sync = false; + Async = true; + break; + case DanmakuLayoutAlgorithm.NONE: + Sync = false; + Async = false; + break; + default: + break; + } + } + + /// + /// 发送需要显示的tip + /// + /// + private void PublishTip(bool isSucceed) + { + if (isOnNavigatedTo) + { + return; + } + + if (isSucceed) + { + eventAggregator.GetEvent().Publish(DictionaryResource.GetString("TipSettingUpdated")); + } + else + { + eventAggregator.GetEvent().Publish(DictionaryResource.GetString("TipSettingFailed")); + } + } +} \ No newline at end of file diff --git a/DownKyi/ViewModels/Settings/ViewNetworkViewModel.cs b/DownKyi/ViewModels/Settings/ViewNetworkViewModel.cs new file mode 100644 index 0000000..15b1b65 --- /dev/null +++ b/DownKyi/ViewModels/Settings/ViewNetworkViewModel.cs @@ -0,0 +1,858 @@ +using System.Collections.Generic; +using System.Diagnostics; +using System.Reflection; +using Avalonia.Controls.ApplicationLifetimes; +using DownKyi.Core.Settings; +using DownKyi.Core.Utils.Validator; +using DownKyi.Events; +using DownKyi.Services; +using DownKyi.Utils; +using Prism.Commands; +using Prism.Events; +using Prism.Regions; +using Prism.Services.Dialogs; + +namespace DownKyi.ViewModels.Settings; + +public class ViewNetworkViewModel : ViewModelBase +{ + public const string Tag = "PageSettingsNetwork"; + + private bool isOnNavigatedTo; + + #region 页面属性申明 + + private bool useSSL; + + public bool UseSSL + { + get => useSSL; + set => SetProperty(ref useSSL, value); + } + + private string userAgent; + + public string UserAgent + { + get => userAgent; + set => SetProperty(ref userAgent, value); + } + + private bool builtin; + + public bool Builtin + { + get => builtin; + set => SetProperty(ref builtin, value); + } + + private bool aria2c; + + public bool Aria2c + { + get => aria2c; + set => SetProperty(ref aria2c, value); + } + + private bool customAria2c; + + public bool CustomAria2c + { + get => customAria2c; + set => SetProperty(ref customAria2c, value); + } + + private List maxCurrentDownloads; + + public List MaxCurrentDownloads + { + get => maxCurrentDownloads; + set => SetProperty(ref maxCurrentDownloads, value); + } + + private int selectedMaxCurrentDownload; + + public int SelectedMaxCurrentDownload + { + get => selectedMaxCurrentDownload; + set => SetProperty(ref selectedMaxCurrentDownload, value); + } + + private List splits; + + public List Splits + { + get => splits; + set => SetProperty(ref splits, value); + } + + private int selectedSplit; + + public int SelectedSplit + { + get => selectedSplit; + set => SetProperty(ref selectedSplit, value); + } + + private bool isHttpProxy; + + public bool IsHttpProxy + { + get => isHttpProxy; + set => SetProperty(ref isHttpProxy, value); + } + + private string httpProxy; + + public string HttpProxy + { + get => httpProxy; + set => SetProperty(ref httpProxy, value); + } + + private int httpProxyPort; + + public int HttpProxyPort + { + get => httpProxyPort; + set => SetProperty(ref httpProxyPort, value); + } + + private string ariaHost; + + public string AriaHost + { + get => ariaHost; + set => SetProperty(ref ariaHost, value); + } + + private int ariaListenPort; + + public int AriaListenPort + { + get => ariaListenPort; + set => SetProperty(ref ariaListenPort, value); + } + + private string ariaToken; + + public string AriaToken + { + get => ariaToken; + set => SetProperty(ref ariaToken, value); + } + + private List ariaLogLevels; + + public List AriaLogLevels + { + get => ariaLogLevels; + set => SetProperty(ref ariaLogLevels, value); + } + + private string selectedAriaLogLevel; + + public string SelectedAriaLogLevel + { + get => selectedAriaLogLevel; + set => SetProperty(ref selectedAriaLogLevel, value); + } + + private List ariaMaxConcurrentDownloads; + + public List AriaMaxConcurrentDownloads + { + get => ariaMaxConcurrentDownloads; + set => SetProperty(ref ariaMaxConcurrentDownloads, value); + } + + private int selectedAriaMaxConcurrentDownload; + + public int SelectedAriaMaxConcurrentDownload + { + get => selectedAriaMaxConcurrentDownload; + set => SetProperty(ref selectedAriaMaxConcurrentDownload, value); + } + + private List ariaSplits; + + public List AriaSplits + { + get => ariaSplits; + set => SetProperty(ref ariaSplits, value); + } + + private int selectedAriaSplit; + + public int SelectedAriaSplit + { + get => selectedAriaSplit; + set => SetProperty(ref selectedAriaSplit, value); + } + + private int ariaMaxOverallDownloadLimit; + + public int AriaMaxOverallDownloadLimit + { + get => ariaMaxOverallDownloadLimit; + set => SetProperty(ref ariaMaxOverallDownloadLimit, value); + } + + private int ariaMaxDownloadLimit; + + public int AriaMaxDownloadLimit + { + get => ariaMaxDownloadLimit; + set => SetProperty(ref ariaMaxDownloadLimit, value); + } + + private bool isAriaHttpProxy; + + public bool IsAriaHttpProxy + { + get => isAriaHttpProxy; + set => SetProperty(ref isAriaHttpProxy, value); + } + + private string ariaHttpProxy; + + public string AriaHttpProxy + { + get => ariaHttpProxy; + set => SetProperty(ref ariaHttpProxy, value); + } + + private int ariaHttpProxyPort; + + public int AriaHttpProxyPort + { + get => ariaHttpProxyPort; + set => SetProperty(ref ariaHttpProxyPort, value); + } + + private List ariaFileAllocations; + + public List AriaFileAllocations + { + get => ariaFileAllocations; + set => SetProperty(ref ariaFileAllocations, value); + } + + private string selectedAriaFileAllocation; + + public string SelectedAriaFileAllocation + { + get => selectedAriaFileAllocation; + set => SetProperty(ref selectedAriaFileAllocation, value); + } + + #endregion + + public ViewNetworkViewModel(IEventAggregator eventAggregator, IDialogService dialogService) : base(eventAggregator, + dialogService) + { + #region 属性初始化 + + // builtin同时下载数 + MaxCurrentDownloads = new List(); + for (int i = 1; i <= 10; i++) + { + MaxCurrentDownloads.Add(i); + } + + // builtin最大线程数 + Splits = new List(); + for (int i = 1; i <= 10; i++) + { + Splits.Add(i); + } + + // Aria的日志等级 + AriaLogLevels = new List + { + "DEBUG", + "INFO", + "NOTICE", + "WARN", + "ERROR" + }; + + // Aria同时下载数 + AriaMaxConcurrentDownloads = new List(); + for (int i = 1; i <= 10; i++) + { + AriaMaxConcurrentDownloads.Add(i); + } + + // Aria最大线程数 + AriaSplits = new List(); + for (int i = 1; i <= 10; i++) + { + AriaSplits.Add(i); + } + + // Aria文件预分配 + AriaFileAllocations = new List + { + "NONE", + "PREALLOC", + "FALLOC" + }; + + #endregion + } + + /// + /// 导航到页面时执行 + /// + /// + public override void OnNavigatedTo(NavigationContext navigationContext) + { + base.OnNavigatedTo(navigationContext); + + isOnNavigatedTo = true; + + // 启用https + AllowStatus useSSL = SettingsManager.GetInstance().UseSSL(); + UseSSL = useSSL == AllowStatus.YES; + + // UserAgent + UserAgent = SettingsManager.GetInstance().GetUserAgent(); + + // 选择下载器 + var downloader = SettingsManager.GetInstance().GetDownloader(); + switch (downloader) + { + case Downloader.NOT_SET: + break; + case Downloader.BUILT_IN: + Builtin = true; + break; + case Downloader.ARIA: + Aria2c = true; + break; + case Downloader.CUSTOM_ARIA: + CustomAria2c = true; + break; + } + + // builtin同时下载数 + SelectedMaxCurrentDownload = SettingsManager.GetInstance().GetMaxCurrentDownloads(); + + // builtin最大线程数 + SelectedSplit = SettingsManager.GetInstance().GetSplit(); + + // 是否开启builtin http代理 + AllowStatus isHttpProxy = SettingsManager.GetInstance().IsHttpProxy(); + IsHttpProxy = isHttpProxy == AllowStatus.YES; + + // builtin的http代理的地址 + HttpProxy = SettingsManager.GetInstance().GetHttpProxy(); + + // builtin的http代理的端口 + HttpProxyPort = SettingsManager.GetInstance().GetHttpProxyListenPort(); + + // Aria服务器host + AriaHost = SettingsManager.GetInstance().GetAriaHost(); + + // Aria服务器端口 + AriaListenPort = SettingsManager.GetInstance().GetAriaListenPort(); + + // Aria服务器Token + AriaToken = SettingsManager.GetInstance().GetAriaToken(); + + // Aria的日志等级 + // AriaConfigLogLevel ariaLogLevel = SettingsManager.GetInstance().GetAriaLogLevel(); + // SelectedAriaLogLevel = ariaLogLevel.ToString("G"); + + // Aria同时下载数 + SelectedAriaMaxConcurrentDownload = SettingsManager.GetInstance().GetMaxCurrentDownloads(); + + // Aria最大线程数 + SelectedAriaSplit = SettingsManager.GetInstance().GetAriaSplit(); + + // Aria下载速度限制 + AriaMaxOverallDownloadLimit = SettingsManager.GetInstance().GetAriaMaxOverallDownloadLimit(); + + // Aria下载单文件速度限制 + AriaMaxDownloadLimit = SettingsManager.GetInstance().GetAriaMaxDownloadLimit(); + + // 是否开启Aria http代理 + AllowStatus isAriaHttpProxy = SettingsManager.GetInstance().IsAriaHttpProxy(); + IsAriaHttpProxy = isAriaHttpProxy == AllowStatus.YES; + + // Aria的http代理的地址 + AriaHttpProxy = SettingsManager.GetInstance().GetAriaHttpProxy(); + + // Aria的http代理的端口 + AriaHttpProxyPort = SettingsManager.GetInstance().GetAriaHttpProxyListenPort(); + + // Aria文件预分配 + // AriaConfigFileAllocation ariaFileAllocation = SettingsManager.GetInstance().GetAriaFileAllocation(); + // SelectedAriaFileAllocation = ariaFileAllocation.ToString("G"); + + isOnNavigatedTo = false; + } + + #region 命令申明 + + // 是否启用https事件 + private DelegateCommand useSSLCommand; + + public DelegateCommand UseSSLCommand => + useSSLCommand ?? (useSSLCommand = new DelegateCommand(ExecuteUseSSLCommand)); + + /// + /// 是否启用https事件 + /// + private void ExecuteUseSSLCommand() + { + AllowStatus useSSL = UseSSL ? AllowStatus.YES : AllowStatus.NO; + + bool isSucceed = SettingsManager.GetInstance().UseSSL(useSSL); + PublishTip(isSucceed); + } + + // 设置UserAgent事件 + private DelegateCommand userAgentCommand; + + public DelegateCommand UserAgentCommand => + userAgentCommand ?? (userAgentCommand = new DelegateCommand(ExecuteUserAgentCommand)); + + /// + /// 设置UserAgent事件 + /// + private void ExecuteUserAgentCommand() + { + bool isSucceed = SettingsManager.GetInstance().SetUserAgent(UserAgent); + PublishTip(isSucceed); + } + + // 下载器选择事件 + private DelegateCommand selectDownloaderCommand; + + public DelegateCommand SelectDownloaderCommand => selectDownloaderCommand ?? + (selectDownloaderCommand = + new DelegateCommand( + ExecuteSelectDownloaderCommand)); + + /// + /// 下载器选择事件 + /// + /// + private void ExecuteSelectDownloaderCommand(string parameter) + { + Downloader downloader; + switch (parameter) + { + case "Builtin": + downloader = Downloader.BUILT_IN; + break; + case "Aria2c": + downloader = Downloader.ARIA; + break; + case "CustomAria2c": + downloader = Downloader.CUSTOM_ARIA; + break; + default: + downloader = SettingsManager.GetInstance().GetDownloader(); + break; + } + + bool isSucceed = SettingsManager.GetInstance().SetDownloader(downloader); + PublishTip(isSucceed); + + AlertService alertService = new AlertService(dialogService); + ButtonResult result = alertService.ShowInfo(DictionaryResource.GetString("ConfirmReboot")); + if (result == ButtonResult.OK) + { + (App.Current.ApplicationLifetime as IClassicDesktopStyleApplicationLifetime).Shutdown(0); + // System.Windows.Application.Current.Shutdown(); + Process.Start(Assembly.GetExecutingAssembly().Location); + } + } + + // builtin同时下载数事件 + private DelegateCommand maxCurrentDownloadsCommand; + + public DelegateCommand MaxCurrentDownloadsCommand => maxCurrentDownloadsCommand ?? + (maxCurrentDownloadsCommand = + new DelegateCommand( + ExecuteMaxCurrentDownloadsCommand)); + + /// + /// builtin同时下载数事件 + /// + /// + private void ExecuteMaxCurrentDownloadsCommand(object parameter) + { + // SelectedMaxCurrentDownload = (int)parameter; + + bool isSucceed = SettingsManager.GetInstance().SetMaxCurrentDownloads(SelectedMaxCurrentDownload); + PublishTip(isSucceed); + } + + // builtin最大线程数事件 + private DelegateCommand splitsCommand; + + public DelegateCommand SplitsCommand => + splitsCommand ?? (splitsCommand = new DelegateCommand(ExecuteSplitsCommand)); + + /// + /// builtin最大线程数事件 + /// + /// + private void ExecuteSplitsCommand(object parameter) + { + // SelectedSplit = (int)parameter; + + bool isSucceed = SettingsManager.GetInstance().SetSplit(SelectedSplit); + PublishTip(isSucceed); + } + + // 是否开启builtin http代理事件 + private DelegateCommand isHttpProxyCommand; + + public DelegateCommand IsHttpProxyCommand => + isHttpProxyCommand ?? (isHttpProxyCommand = new DelegateCommand(ExecuteIsHttpProxyCommand)); + + /// + /// 是否开启builtin http代理事件 + /// + private void ExecuteIsHttpProxyCommand() + { + AllowStatus isHttpProxy = IsHttpProxy ? AllowStatus.YES : AllowStatus.NO; + + bool isSucceed = SettingsManager.GetInstance().IsHttpProxy(isHttpProxy); + PublishTip(isSucceed); + } + + // builtin的http代理的地址事件 + private DelegateCommand httpProxyCommand; + + public DelegateCommand HttpProxyCommand => + httpProxyCommand ?? (httpProxyCommand = new DelegateCommand(ExecuteHttpProxyCommand)); + + /// + /// builtin的http代理的地址事件 + /// + /// + private void ExecuteHttpProxyCommand(string parameter) + { + bool isSucceed = SettingsManager.GetInstance().SetHttpProxy(parameter); + PublishTip(isSucceed); + } + + // builtin的http代理的端口事件 + private DelegateCommand httpProxyPortCommand; + + public DelegateCommand HttpProxyPortCommand => httpProxyPortCommand ?? + (httpProxyPortCommand = + new DelegateCommand( + ExecuteHttpProxyPortCommand)); + + /// + /// builtin的http代理的端口事件 + /// + /// + private void ExecuteHttpProxyPortCommand(string parameter) + { + int httpProxyPort = (int)Number.GetInt(parameter); + HttpProxyPort = httpProxyPort; + + bool isSucceed = SettingsManager.GetInstance().SetHttpProxyListenPort(HttpProxyPort); + PublishTip(isSucceed); + } + + // Aria服务器host事件 + private DelegateCommand ariaHostCommand; + + public DelegateCommand AriaHostCommand => + ariaHostCommand ?? (ariaHostCommand = new DelegateCommand(ExecuteAriaHostCommand)); + + /// + /// Aria服务器host事件 + /// + /// + private void ExecuteAriaHostCommand(string parameter) + { + AriaHost = parameter; + bool isSucceed = SettingsManager.GetInstance().SetAriaHost(AriaHost); + PublishTip(isSucceed); + } + + // Aria服务器端口事件 + private DelegateCommand ariaListenPortCommand; + + public DelegateCommand AriaListenPortCommand => ariaListenPortCommand ?? + (ariaListenPortCommand = + new DelegateCommand( + ExecuteAriaListenPortCommand)); + + /// + /// Aria服务器端口事件 + /// + /// + private void ExecuteAriaListenPortCommand(string parameter) + { + int listenPort = (int)Number.GetInt(parameter); + AriaListenPort = listenPort; + + bool isSucceed = SettingsManager.GetInstance().SetAriaListenPort(AriaListenPort); + PublishTip(isSucceed); + } + + // Aria服务器token事件 + private DelegateCommand ariaTokenCommand; + + public DelegateCommand AriaTokenCommand => + ariaTokenCommand ?? (ariaTokenCommand = new DelegateCommand(ExecuteAriaTokenCommand)); + + /// + /// Aria服务器token事件 + /// + /// + private void ExecuteAriaTokenCommand(string parameter) + { + AriaToken = parameter; + bool isSucceed = SettingsManager.GetInstance().SetAriaToken(AriaToken); + PublishTip(isSucceed); + } + + // Aria的日志等级事件 + private DelegateCommand ariaLogLevelsCommand; + + public DelegateCommand AriaLogLevelsCommand => ariaLogLevelsCommand ?? + (ariaLogLevelsCommand = + new DelegateCommand( + ExecuteAriaLogLevelsCommand)); + + /// + /// Aria的日志等级事件 + /// + /// + private void ExecuteAriaLogLevelsCommand(string parameter) + { + /*AriaConfigLogLevel ariaLogLevel; + switch (parameter) + { + case "DEBUG": + ariaLogLevel = AriaConfigLogLevel.DEBUG; + break; + case "INFO": + ariaLogLevel = AriaConfigLogLevel.INFO; + break; + case "NOTICE": + ariaLogLevel = AriaConfigLogLevel.NOTICE; + break; + case "WARN": + ariaLogLevel = AriaConfigLogLevel.WARN; + break; + case "ERROR": + ariaLogLevel = AriaConfigLogLevel.ERROR; + break; + default: + ariaLogLevel = AriaConfigLogLevel.INFO; + break; + } + + bool isSucceed = SettingsManager.GetInstance().SetAriaLogLevel(ariaLogLevel); + PublishTip(isSucceed);*/ + } + + // Aria同时下载数事件 + private DelegateCommand ariaMaxConcurrentDownloadsCommand; + + public DelegateCommand AriaMaxConcurrentDownloadsCommand => ariaMaxConcurrentDownloadsCommand ?? + (ariaMaxConcurrentDownloadsCommand = + new DelegateCommand( + ExecuteAriaMaxConcurrentDownloadsCommand)); + + /// + /// Aria同时下载数事件 + /// + /// + private void ExecuteAriaMaxConcurrentDownloadsCommand(object parameter) + { + SelectedAriaMaxConcurrentDownload = (int)parameter; + + bool isSucceed = SettingsManager.GetInstance().SetMaxCurrentDownloads(SelectedAriaMaxConcurrentDownload); + PublishTip(isSucceed); + } + + // Aria最大线程数事件 + private DelegateCommand ariaSplitsCommand; + + public DelegateCommand AriaSplitsCommand => ariaSplitsCommand ?? + (ariaSplitsCommand = + new DelegateCommand(ExecuteAriaSplitsCommand)); + + /// + /// Aria最大线程数事件 + /// + /// + private void ExecuteAriaSplitsCommand(object parameter) + { + SelectedAriaSplit = (int)parameter; + + bool isSucceed = SettingsManager.GetInstance().SetAriaSplit(SelectedAriaSplit); + PublishTip(isSucceed); + } + + // Aria下载速度限制事件 + private DelegateCommand ariaMaxOverallDownloadLimitCommand; + + public DelegateCommand AriaMaxOverallDownloadLimitCommand => ariaMaxOverallDownloadLimitCommand ?? + (ariaMaxOverallDownloadLimitCommand = + new DelegateCommand( + ExecuteAriaMaxOverallDownloadLimitCommand)); + + /// + /// Aria下载速度限制事件 + /// + /// + private void ExecuteAriaMaxOverallDownloadLimitCommand(string parameter) + { + int downloadLimit = (int)Number.GetInt(parameter); + AriaMaxOverallDownloadLimit = downloadLimit; + + bool isSucceed = SettingsManager.GetInstance().SetAriaMaxOverallDownloadLimit(AriaMaxOverallDownloadLimit); + PublishTip(isSucceed); + } + + // Aria下载单文件速度限制事件 + private DelegateCommand ariaMaxDownloadLimitCommand; + + public DelegateCommand AriaMaxDownloadLimitCommand => ariaMaxDownloadLimitCommand ?? + (ariaMaxDownloadLimitCommand = + new DelegateCommand( + ExecuteAriaMaxDownloadLimitCommand)); + + /// + /// Aria下载单文件速度限制事件 + /// + /// + private void ExecuteAriaMaxDownloadLimitCommand(string parameter) + { + int downloadLimit = (int)Number.GetInt(parameter); + AriaMaxDownloadLimit = downloadLimit; + + bool isSucceed = SettingsManager.GetInstance().SetAriaMaxDownloadLimit(AriaMaxDownloadLimit); + PublishTip(isSucceed); + } + + // 是否开启Aria http代理事件 + private DelegateCommand isAriaHttpProxyCommand; + + public DelegateCommand IsAriaHttpProxyCommand => isAriaHttpProxyCommand ?? + (isAriaHttpProxyCommand = + new DelegateCommand(ExecuteIsAriaHttpProxyCommand)); + + /// + /// 是否开启Aria http代理事件 + /// + private void ExecuteIsAriaHttpProxyCommand() + { + AllowStatus isAriaHttpProxy = IsAriaHttpProxy ? AllowStatus.YES : AllowStatus.NO; + + bool isSucceed = SettingsManager.GetInstance().IsAriaHttpProxy(isAriaHttpProxy); + PublishTip(isSucceed); + } + + // Aria的http代理的地址事件 + private DelegateCommand ariaHttpProxyCommand; + + public DelegateCommand AriaHttpProxyCommand => ariaHttpProxyCommand ?? + (ariaHttpProxyCommand = + new DelegateCommand( + ExecuteAriaHttpProxyCommand)); + + /// + /// Aria的http代理的地址事件 + /// + /// + private void ExecuteAriaHttpProxyCommand(string parameter) + { + bool isSucceed = SettingsManager.GetInstance().SetAriaHttpProxy(parameter); + PublishTip(isSucceed); + } + + // Aria的http代理的端口事件 + private DelegateCommand ariaHttpProxyPortCommand; + + public DelegateCommand AriaHttpProxyPortCommand => ariaHttpProxyPortCommand ?? + (ariaHttpProxyPortCommand = + new DelegateCommand( + ExecuteAriaHttpProxyPortCommand)); + + /// + /// Aria的http代理的端口事件 + /// + /// + private void ExecuteAriaHttpProxyPortCommand(string parameter) + { + int httpProxyPort = (int)Number.GetInt(parameter); + AriaHttpProxyPort = httpProxyPort; + + bool isSucceed = SettingsManager.GetInstance().SetAriaHttpProxyListenPort(AriaHttpProxyPort); + PublishTip(isSucceed); + } + + // Aria文件预分配事件 + private DelegateCommand ariaFileAllocationsCommand; + + public DelegateCommand AriaFileAllocationsCommand => ariaFileAllocationsCommand ?? + (ariaFileAllocationsCommand = + new DelegateCommand( + ExecuteAriaFileAllocationsCommand)); + + /// + /// Aria文件预分配事件 + /// + /// + private void ExecuteAriaFileAllocationsCommand(string parameter) + { + /*AriaConfigFileAllocation ariaFileAllocation; + switch (parameter) + { + case "NONE": + ariaFileAllocation = AriaConfigFileAllocation.NONE; + break; + case "PREALLOC": + ariaFileAllocation = AriaConfigFileAllocation.PREALLOC; + break; + case "FALLOC": + ariaFileAllocation = AriaConfigFileAllocation.FALLOC; + break; + default: + ariaFileAllocation = AriaConfigFileAllocation.PREALLOC; + break; + } + + bool isSucceed = SettingsManager.GetInstance().SetAriaFileAllocation(ariaFileAllocation); + PublishTip(isSucceed);*/ + } + + #endregion + + /// + /// 发送需要显示的tip + /// + /// + private void PublishTip(bool isSucceed) + { + if (isOnNavigatedTo) + { + return; + } + + if (isSucceed) + { + eventAggregator.GetEvent().Publish(DictionaryResource.GetString("TipSettingUpdated")); + } + else + { + eventAggregator.GetEvent().Publish(DictionaryResource.GetString("TipSettingFailed")); + } + } +} \ No newline at end of file diff --git a/DownKyi/ViewModels/Settings/ViewVideoViewModel.cs b/DownKyi/ViewModels/Settings/ViewVideoViewModel.cs new file mode 100644 index 0000000..12731d2 --- /dev/null +++ b/DownKyi/ViewModels/Settings/ViewVideoViewModel.cs @@ -0,0 +1,927 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Collections.Specialized; +using System.Linq; +using DownKyi.Core.BiliApi.BiliUtils; +using DownKyi.Core.FileName; +using DownKyi.Core.Settings; +using DownKyi.Core.Settings.Models; +using DownKyi.Events; +using DownKyi.Models; +using DownKyi.Utils; +using Prism.Commands; +using Prism.Events; +using Prism.Regions; + +namespace DownKyi.ViewModels.Settings; + +public class ViewVideoViewModel : ViewModelBase +{ + public const string Tag = "PageSettingsVideo"; + + private bool isOnNavigatedTo; + + #region 页面属性申明 + + private List videoCodecs; + + public List VideoCodecs + { + get => videoCodecs; + set => SetProperty(ref videoCodecs, value); + } + + private Quality selectedVideoCodec; + + public Quality SelectedVideoCodec + { + get => selectedVideoCodec; + set => SetProperty(ref selectedVideoCodec, value); + } + + private List videoQualityList; + + public List VideoQualityList + { + get => videoQualityList; + set => SetProperty(ref videoQualityList, value); + } + + private Quality selectedVideoQuality; + + public Quality SelectedVideoQuality + { + get => selectedVideoQuality; + set => SetProperty(ref selectedVideoQuality, value); + } + + private List audioQualityList; + + public List AudioQualityList + { + get => audioQualityList; + set => SetProperty(ref audioQualityList, value); + } + + private Quality selectedAudioQuality; + + public Quality SelectedAudioQuality + { + get => selectedAudioQuality; + set => SetProperty(ref selectedAudioQuality, value); + } + + private bool isTranscodingFlvToMp4; + + public bool IsTranscodingFlvToMp4 + { + get => isTranscodingFlvToMp4; + set => SetProperty(ref isTranscodingFlvToMp4, value); + } + + private bool isUseDefaultDirectory; + + public bool IsUseDefaultDirectory + { + get => isUseDefaultDirectory; + set => SetProperty(ref isUseDefaultDirectory, value); + } + + private string saveVideoDirectory; + + public string SaveVideoDirectory + { + get => saveVideoDirectory; + set => SetProperty(ref saveVideoDirectory, value); + } + + private bool downloadAll; + + public bool DownloadAll + { + get { return downloadAll; } + set { SetProperty(ref downloadAll, value); } + } + + private bool downloadAudio; + + public bool DownloadAudio + { + get { return downloadAudio; } + set { SetProperty(ref downloadAudio, value); } + } + + private bool downloadVideo; + + public bool DownloadVideo + { + get { return downloadVideo; } + set { SetProperty(ref downloadVideo, value); } + } + + private bool downloadDanmaku; + + public bool DownloadDanmaku + { + get { return downloadDanmaku; } + set { SetProperty(ref downloadDanmaku, value); } + } + + private bool downloadSubtitle; + + public bool DownloadSubtitle + { + get { return downloadSubtitle; } + set { SetProperty(ref downloadSubtitle, value); } + } + + private bool downloadCover; + + public bool DownloadCover + { + get { return downloadCover; } + set { SetProperty(ref downloadCover, value); } + } + + private ObservableCollection selectedFileName; + + public ObservableCollection SelectedFileName + { + get => selectedFileName; + set => SetProperty(ref selectedFileName, value); + } + + private ObservableCollection optionalFields; + + public ObservableCollection OptionalFields + { + get => optionalFields; + set => SetProperty(ref optionalFields, value); + } + + private int selectedOptionalField; + + public int SelectedOptionalField + { + get => selectedOptionalField; + set => SetProperty(ref selectedOptionalField, value); + } + + private List fileNamePartTimeFormatList; + + public List FileNamePartTimeFormatList + { + get => fileNamePartTimeFormatList; + set => SetProperty(ref fileNamePartTimeFormatList, value); + } + + private string selectedFileNamePartTimeFormat; + + public string SelectedFileNamePartTimeFormat + { + get => selectedFileNamePartTimeFormat; + set => SetProperty(ref selectedFileNamePartTimeFormat, value); + } + + private List orderFormatList; + + public List OrderFormatList + { + get => orderFormatList; + set => SetProperty(ref orderFormatList, value); + } + + private OrderFormatDisplay orderFormatDisplay; + + public OrderFormatDisplay OrderFormatDisplay + { + get => orderFormatDisplay; + set => SetProperty(ref orderFormatDisplay, value); + } + + #endregion + + public ViewVideoViewModel(IEventAggregator eventAggregator) : base(eventAggregator) + { + #region 属性初始化 + + // 优先下载的视频编码 + VideoCodecs = Constant.GetCodecIds(); + //VideoCodecs = new List + //{ + // "H.264/AVC", + // "H.265/HEVC", + //}; + + // 优先下载画质 + VideoQualityList = Constant.GetResolutions(); + + // 优先下载音质 + AudioQualityList = Constant.GetAudioQualities(); + //AudioQualityList.RemoveAt(3); + AudioQualityList[3].Id = AudioQualityList[3].Id + 1000; + AudioQualityList[4].Id = AudioQualityList[4].Id + 1000; + + // 文件命名格式 + SelectedFileName = new ObservableCollection(); + + SelectedFileName.CollectionChanged += new NotifyCollectionChangedEventHandler((sender, e) => + { + // 当前显示的命名格式part + List fileName = new List(); + foreach (DisplayFileNamePart item in SelectedFileName) + { + fileName.Add(item.Id); + } + + bool isSucceed = SettingsManager.GetInstance().SetFileNameParts(fileName); + PublishTip(isSucceed); + }); + + OptionalFields = new ObservableCollection(); + foreach (FileNamePart item in Enum.GetValues(typeof(FileNamePart))) + { + string display = DisplayFileNamePart(item); + OptionalFields.Add(new DisplayFileNamePart { Id = item, Title = display }); + } + + SelectedOptionalField = -1; + + // 文件命名中的时间格式 + FileNamePartTimeFormatList = new List + { + "yyyy-MM-dd", + "yyyy.MM.dd", + }; + + // 文件命名中的序号格式 + OrderFormatList = new List + { + new() { Name = DictionaryResource.GetString("OrderFormatNatural"), OrderFormat = OrderFormat.NATURAL }, + new() + { + Name = DictionaryResource.GetString("OrderFormatLeadingZeros"), OrderFormat = OrderFormat.LEADING_ZEROS + }, + }; + + #endregion + } + + /// + /// 导航到页面时执行 + /// + /// + public override void OnNavigatedTo(NavigationContext navigationContext) + { + base.OnNavigatedTo(navigationContext); + + isOnNavigatedTo = true; + + // 优先下载的视频编码 + int videoCodecs = SettingsManager.GetInstance().GetVideoCodecs(); + //SelectedVideoCodec = GetVideoCodecsString(videoCodecs); + SelectedVideoCodec = VideoCodecs.FirstOrDefault(t => { return t.Id == videoCodecs; }); + + // 优先下载画质 + int quality = SettingsManager.GetInstance().GetQuality(); + SelectedVideoQuality = VideoQualityList.FirstOrDefault(t => { return t.Id == quality; }); + + // 优先下载音质 + int audioQuality = SettingsManager.GetInstance().GetAudioQuality(); + SelectedAudioQuality = AudioQualityList.FirstOrDefault(t => { return t.Id == audioQuality; }); + + // 是否下载flv视频后转码为mp4 + AllowStatus isTranscodingFlvToMp4 = SettingsManager.GetInstance().IsTranscodingFlvToMp4(); + IsTranscodingFlvToMp4 = isTranscodingFlvToMp4 == AllowStatus.YES; + + // 是否使用默认下载目录 + AllowStatus isUseSaveVideoRootPath = SettingsManager.GetInstance().IsUseSaveVideoRootPath(); + IsUseDefaultDirectory = isUseSaveVideoRootPath == AllowStatus.YES; + + // 默认下载目录 + SaveVideoDirectory = SettingsManager.GetInstance().GetSaveVideoRootPath(); + + // 下载内容 + VideoContentSettings videoContent = SettingsManager.GetInstance().GetVideoContent(); + + DownloadAudio = videoContent.DownloadAudio; + DownloadVideo = videoContent.DownloadVideo; + DownloadDanmaku = videoContent.DownloadDanmaku; + DownloadSubtitle = videoContent.DownloadSubtitle; + DownloadCover = videoContent.DownloadCover; + + if (DownloadAudio && DownloadVideo && DownloadDanmaku && DownloadSubtitle && DownloadCover) + { + DownloadAll = true; + } + else + { + DownloadAll = false; + } + + // 文件命名格式 + List fileNameParts = SettingsManager.GetInstance().GetFileNameParts(); + SelectedFileName.Clear(); + foreach (FileNamePart item in fileNameParts) + { + string display = DisplayFileNamePart(item); + SelectedFileName.Add(new DisplayFileNamePart { Id = item, Title = display }); + } + + // 文件命名中的时间格式 + SelectedFileNamePartTimeFormat = SettingsManager.GetInstance().GetFileNamePartTimeFormat(); + + // 文件命名中的序号格式 + OrderFormat orderFormat = SettingsManager.GetInstance().GetOrderFormat(); + OrderFormatDisplay = OrderFormatList.FirstOrDefault(t => { return t.OrderFormat == orderFormat; }); + + isOnNavigatedTo = false; + } + + #region 命令申明 + + // 优先下载的视频编码事件 + private DelegateCommand videoCodecsCommand; + + public DelegateCommand VideoCodecsCommand => videoCodecsCommand ?? + (videoCodecsCommand = + new DelegateCommand(ExecuteVideoCodecsCommand)); + + /// + /// 优先下载的视频编码事件 + /// + /// + private void ExecuteVideoCodecsCommand(object parameter) + { + //VideoCodecs videoCodecs = GetVideoCodecs(parameter); + + if (!(parameter is Quality videoCodecs)) + { + return; + } + + bool isSucceed = SettingsManager.GetInstance().SetVideoCodecs(videoCodecs.Id); + PublishTip(isSucceed); + } + + // 优先下载画质事件 + private DelegateCommand videoQualityCommand; + + public DelegateCommand VideoQualityCommand => videoQualityCommand ?? + (videoQualityCommand = + new DelegateCommand(ExecuteVideoQualityCommand)); + + /// + /// 优先下载画质事件 + /// + /// + private void ExecuteVideoQualityCommand(object parameter) + { + if (!(parameter is Quality resolution)) + { + return; + } + + bool isSucceed = SettingsManager.GetInstance().SetQuality(resolution.Id); + PublishTip(isSucceed); + } + + // 优先下载音质事件 + private DelegateCommand audioQualityCommand; + + public DelegateCommand AudioQualityCommand => audioQualityCommand ?? + (audioQualityCommand = + new DelegateCommand(ExecuteAudioQualityCommand)); + + /// + /// 优先下载音质事件 + /// + /// + private void ExecuteAudioQualityCommand(object parameter) + { + if (!(parameter is Quality quality)) + { + return; + } + + bool isSucceed = SettingsManager.GetInstance().SetAudioQuality(quality.Id); + PublishTip(isSucceed); + } + + // 是否下载flv视频后转码为mp4事件 + private DelegateCommand isTranscodingFlvToMp4Command; + + public DelegateCommand IsTranscodingFlvToMp4Command => isTranscodingFlvToMp4Command ?? + (isTranscodingFlvToMp4Command = + new DelegateCommand( + ExecuteIsTranscodingFlvToMp4Command)); + + /// + /// 是否下载flv视频后转码为mp4事件 + /// + private void ExecuteIsTranscodingFlvToMp4Command() + { + AllowStatus isTranscodingFlvToMp4 = IsTranscodingFlvToMp4 ? AllowStatus.YES : AllowStatus.NO; + + bool isSucceed = SettingsManager.GetInstance().IsTranscodingFlvToMp4(isTranscodingFlvToMp4); + PublishTip(isSucceed); + } + + // 是否使用默认下载目录事件 + private DelegateCommand isUseDefaultDirectoryCommand; + + public DelegateCommand IsUseDefaultDirectoryCommand => isUseDefaultDirectoryCommand ?? + (isUseDefaultDirectoryCommand = + new DelegateCommand( + ExecuteIsUseDefaultDirectoryCommand)); + + /// + /// 是否使用默认下载目录事件 + /// + private void ExecuteIsUseDefaultDirectoryCommand() + { + AllowStatus isUseDefaultDirectory = IsUseDefaultDirectory ? AllowStatus.YES : AllowStatus.NO; + + bool isSucceed = SettingsManager.GetInstance().IsUseSaveVideoRootPath(isUseDefaultDirectory); + PublishTip(isSucceed); + } + + // 修改默认下载目录事件 + private DelegateCommand changeSaveVideoDirectoryCommand; + + public DelegateCommand ChangeSaveVideoDirectoryCommand => changeSaveVideoDirectoryCommand ?? + (changeSaveVideoDirectoryCommand = + new DelegateCommand( + ExecuteChangeSaveVideoDirectoryCommand)); + + /// + /// 修改默认下载目录事件 + /// + private async void ExecuteChangeSaveVideoDirectoryCommand() + { + var directory = await DialogUtils.SetDownloadDirectory(); + if (string.IsNullOrEmpty(directory)) { return; } + + bool isSucceed = SettingsManager.GetInstance().SetSaveVideoRootPath(directory); + PublishTip(isSucceed); + + if (isSucceed) + { + SaveVideoDirectory = directory; + } + } + + // 所有内容选择事件 + private DelegateCommand downloadAllCommand; + + public DelegateCommand DownloadAllCommand => + downloadAllCommand ?? (downloadAllCommand = new DelegateCommand(ExecuteDownloadAllCommand)); + + /// + /// 所有内容选择事件 + /// + private void ExecuteDownloadAllCommand() + { + if (DownloadAll) + { + DownloadAudio = true; + DownloadVideo = true; + DownloadDanmaku = true; + DownloadSubtitle = true; + DownloadCover = true; + } + else + { + DownloadAudio = false; + DownloadVideo = false; + DownloadDanmaku = false; + DownloadSubtitle = false; + DownloadCover = false; + } + + SetVideoContent(); + } + + // 音频选择事件 + private DelegateCommand downloadAudioCommand; + + public DelegateCommand DownloadAudioCommand => downloadAudioCommand ?? + (downloadAudioCommand = + new DelegateCommand(ExecuteDownloadAudioCommand)); + + /// + /// 音频选择事件 + /// + private void ExecuteDownloadAudioCommand() + { + if (!DownloadAudio) + { + DownloadAll = false; + } + + if (DownloadAudio && DownloadVideo && DownloadDanmaku && DownloadSubtitle && DownloadCover) + { + DownloadAll = true; + } + + SetVideoContent(); + } + + // 视频选择事件 + private DelegateCommand downloadVideoCommand; + + public DelegateCommand DownloadVideoCommand => downloadVideoCommand ?? + (downloadVideoCommand = + new DelegateCommand(ExecuteDownloadVideoCommand)); + + /// + /// 视频选择事件 + /// + private void ExecuteDownloadVideoCommand() + { + if (!DownloadVideo) + { + DownloadAll = false; + } + + if (DownloadAudio && DownloadVideo && DownloadDanmaku && DownloadSubtitle && DownloadCover) + { + DownloadAll = true; + } + + SetVideoContent(); + } + + // 弹幕选择事件 + private DelegateCommand downloadDanmakuCommand; + + public DelegateCommand DownloadDanmakuCommand => downloadDanmakuCommand ?? + (downloadDanmakuCommand = + new DelegateCommand(ExecuteDownloadDanmakuCommand)); + + /// + /// 弹幕选择事件 + /// + private void ExecuteDownloadDanmakuCommand() + { + if (!DownloadDanmaku) + { + DownloadAll = false; + } + + if (DownloadAudio && DownloadVideo && DownloadDanmaku && DownloadSubtitle && DownloadCover) + { + DownloadAll = true; + } + + SetVideoContent(); + } + + // 字幕选择事件 + private DelegateCommand downloadSubtitleCommand; + + public DelegateCommand DownloadSubtitleCommand => downloadSubtitleCommand ?? + (downloadSubtitleCommand = + new DelegateCommand(ExecuteDownloadSubtitleCommand)); + + /// + /// 字幕选择事件 + /// + private void ExecuteDownloadSubtitleCommand() + { + if (!DownloadSubtitle) + { + DownloadAll = false; + } + + if (DownloadAudio && DownloadVideo && DownloadDanmaku && DownloadSubtitle && DownloadCover) + { + DownloadAll = true; + } + + SetVideoContent(); + } + + // 封面选择事件 + private DelegateCommand downloadCoverCommand; + + public DelegateCommand DownloadCoverCommand => downloadCoverCommand ?? + (downloadCoverCommand = + new DelegateCommand(ExecuteDownloadCoverCommand)); + + /// + /// 封面选择事件 + /// + private void ExecuteDownloadCoverCommand() + { + if (!DownloadCover) + { + DownloadAll = false; + } + + if (DownloadAudio && DownloadVideo && DownloadDanmaku && DownloadSubtitle && DownloadCover) + { + DownloadAll = true; + } + + SetVideoContent(); + } + + // 选中文件名字段右键点击事件 + private DelegateCommand selectedFileNameRightCommand; + + public DelegateCommand SelectedFileNameRightCommand => selectedFileNameRightCommand ?? + (selectedFileNameRightCommand = + new DelegateCommand( + ExecuteSelectedFileNameRightCommand)); + + /// + /// 选中文件名字段右键点击事件 + /// + /// + private void ExecuteSelectedFileNameRightCommand(object parameter) + { + if (parameter == null) + { + return; + } + + bool isSucceed = SelectedFileName.Remove((DisplayFileNamePart)parameter); + if (!isSucceed) + { + PublishTip(isSucceed); + return; + } + + //List fileName = new List(); + //foreach (DisplayFileNamePart item in SelectedFileName) + //{ + // fileName.Add(item.Id); + //} + + //isSucceed = SettingsManager.GetInstance().SetFileNameParts(fileName); + //PublishTip(isSucceed); + + SelectedOptionalField = -1; + } + + // 可选文件名字段点击事件 + private DelegateCommand optionalFieldsCommand; + + public DelegateCommand OptionalFieldsCommand => optionalFieldsCommand ?? + (optionalFieldsCommand = + new DelegateCommand( + ExecuteOptionalFieldsCommand)); + + /// + /// 可选文件名字段点击事件 + /// + /// + private void ExecuteOptionalFieldsCommand(object parameter) + { + if (SelectedOptionalField == -1) + { + return; + } + + SelectedFileName.Add((DisplayFileNamePart)parameter); + + List fileName = new List(); + foreach (DisplayFileNamePart item in SelectedFileName) + { + fileName.Add(item.Id); + } + + bool isSucceed = SettingsManager.GetInstance().SetFileNameParts(fileName); + PublishTip(isSucceed); + + SelectedOptionalField = -1; + } + + // 重置选中文件名字段 + private DelegateCommand resetCommand; + public DelegateCommand ResetCommand => resetCommand ?? (resetCommand = new DelegateCommand(ExecuteResetCommand)); + + /// + /// 重置选中文件名字段 + /// + private void ExecuteResetCommand() + { + bool isSucceed = SettingsManager.GetInstance().SetFileNameParts(null); + PublishTip(isSucceed); + + List fileNameParts = SettingsManager.GetInstance().GetFileNameParts(); + SelectedFileName.Clear(); + foreach (FileNamePart item in fileNameParts) + { + string display = DisplayFileNamePart(item); + SelectedFileName.Add(new DisplayFileNamePart { Id = item, Title = display }); + } + + SelectedOptionalField = -1; + } + + // 文件命名中的时间格式事件 + private DelegateCommand fileNamePartTimeFormatCommand; + + public DelegateCommand FileNamePartTimeFormatCommand => fileNamePartTimeFormatCommand ?? + (fileNamePartTimeFormatCommand = + new DelegateCommand( + ExecuteFileNamePartTimeFormatCommand)); + + /// + /// 文件命名中的时间格式事件 + /// + /// + private void ExecuteFileNamePartTimeFormatCommand(object parameter) + { + if (!(parameter is string timeFormat)) + { + return; + } + + bool isSucceed = SettingsManager.GetInstance().SetFileNamePartTimeFormat(timeFormat); + PublishTip(isSucceed); + } + + // 文件命名中的序号格式事件 + private DelegateCommand orderFormatCommand; + + public DelegateCommand OrderFormatCommand => orderFormatCommand ?? + (orderFormatCommand = + new DelegateCommand( + ExecuteOrderFormatCommandCommand)); + + /// + /// 文件命名中的序号格式事件 + /// + /// + private void ExecuteOrderFormatCommandCommand(object parameter) + { + if (!(parameter is OrderFormatDisplay orderFormatDisplay)) + { + return; + } + + bool isSucceed = SettingsManager.GetInstance().SetOrderFormat(orderFormatDisplay.OrderFormat); + PublishTip(isSucceed); + } + + #endregion + + /// + /// 返回VideoCodecs的字符串 + /// + /// + /// + //private string GetVideoCodecsString(VideoCodecs videoCodecs) + //{ + // string codec; + // switch (videoCodecs) + // { + // case Core.Settings.VideoCodecs.NONE: + // codec = ""; + // break; + // case Core.Settings.VideoCodecs.AVC: + // codec = "H.264/AVC"; + // break; + // case Core.Settings.VideoCodecs.HEVC: + // codec = "H.265/HEVC"; + // break; + // default: + // codec = ""; + // break; + // } + // return codec; + //} + + /// + /// 返回VideoCodecs + /// + /// + /// + //private VideoCodecs GetVideoCodecs(string str) + //{ + // VideoCodecs videoCodecs; + // switch (str) + // { + // case "H.264/AVC": + // videoCodecs = Core.Settings.VideoCodecs.AVC; + // break; + // case "H.265/HEVC": + // videoCodecs = Core.Settings.VideoCodecs.HEVC; + // break; + // default: + // videoCodecs = Core.Settings.VideoCodecs.NONE; + // break; + // } + // return videoCodecs; + //} + + /// + /// 保存下载视频内容到设置 + /// + private void SetVideoContent() + { + VideoContentSettings videoContent = new VideoContentSettings + { + DownloadAudio = DownloadAudio, + DownloadVideo = DownloadVideo, + DownloadDanmaku = DownloadDanmaku, + DownloadSubtitle = DownloadSubtitle, + DownloadCover = DownloadCover + }; + + bool isSucceed = SettingsManager.GetInstance().SetVideoContent(videoContent); + PublishTip(isSucceed); + } + + /// + /// 文件名字段显示 + /// + /// + /// + private string DisplayFileNamePart(FileNamePart item) + { + string display = string.Empty; + switch (item) + { + case FileNamePart.ORDER: + display = DictionaryResource.GetString("DisplayOrder"); + break; + case FileNamePart.SECTION: + display = DictionaryResource.GetString("DisplaySection"); + break; + case FileNamePart.MAIN_TITLE: + display = DictionaryResource.GetString("DisplayMainTitle"); + break; + case FileNamePart.PAGE_TITLE: + display = DictionaryResource.GetString("DisplayPageTitle"); + break; + case FileNamePart.VIDEO_ZONE: + display = DictionaryResource.GetString("DisplayVideoZone"); + break; + case FileNamePart.AUDIO_QUALITY: + display = DictionaryResource.GetString("DisplayAudioQuality"); + break; + case FileNamePart.VIDEO_QUALITY: + display = DictionaryResource.GetString("DisplayVideoQuality"); + break; + case FileNamePart.VIDEO_CODEC: + display = DictionaryResource.GetString("DisplayVideoCodec"); + break; + case FileNamePart.VIDEO_PUBLISH_TIME: + display = DictionaryResource.GetString("DisplayVideoPublishTime"); + break; + case FileNamePart.AVID: + display = "avid"; + break; + case FileNamePart.BVID: + display = "bvid"; + break; + case FileNamePart.CID: + display = "cid"; + break; + case FileNamePart.UP_MID: + display = DictionaryResource.GetString("DisplayUpMid"); + break; + case FileNamePart.UP_NAME: + display = DictionaryResource.GetString("DisplayUpName"); + break; + } + + if (((int)item) >= 100) + { + display = HyphenSeparated.Hyphen[(int)item]; + } + + if (display == " ") + { + display = DictionaryResource.GetString("DisplaySpace"); + } + + return display; + } + + /// + /// 发送需要显示的tip + /// + /// + private void PublishTip(bool isSucceed) + { + if (isOnNavigatedTo) + { + return; + } + + if (isSucceed) + { + eventAggregator.GetEvent().Publish(DictionaryResource.GetString("TipSettingUpdated")); + } + else + { + eventAggregator.GetEvent().Publish(DictionaryResource.GetString("TipSettingFailed")); + } + } +} \ No newline at end of file diff --git a/DownKyi/ViewModels/Toolbox/ViewBiliHelperViewModel.cs b/DownKyi/ViewModels/Toolbox/ViewBiliHelperViewModel.cs new file mode 100644 index 0000000..fc300e7 --- /dev/null +++ b/DownKyi/ViewModels/Toolbox/ViewBiliHelperViewModel.cs @@ -0,0 +1,198 @@ +using System; +using System.Diagnostics; +using System.Runtime.InteropServices; +using System.Threading.Tasks; +using DownKyi.Core.BiliApi.BiliUtils; +using DownKyi.Core.Logging; +using Prism.Commands; +using Prism.Events; +using Console = DownKyi.Core.Utils.Debugging.Console; + +namespace DownKyi.ViewModels.Toolbox; + +public class ViewBiliHelperViewModel : ViewModelBase +{ + public const string Tag = "PageToolboxBiliHelper"; + + #region 页面属性申明 + + private string avid; + + public string Avid + { + get { return avid; } + set { SetProperty(ref avid, value); } + } + + private string bvid; + + public string Bvid + { + get { return bvid; } + set { SetProperty(ref bvid, value); } + } + + private string danmakuUserID; + + public string DanmakuUserID + { + get { return danmakuUserID; } + set { SetProperty(ref danmakuUserID, value); } + } + + private string userMid; + + public string UserMid + { + get { return userMid; } + set { SetProperty(ref userMid, value); } + } + + #endregion + + public ViewBiliHelperViewModel(IEventAggregator eventAggregator) : base(eventAggregator) + { + #region 属性初始化 + + #endregion + } + + #region 命令申明 + + // 输入avid事件 + private DelegateCommand avidCommand; + + public DelegateCommand AvidCommand => + avidCommand ?? (avidCommand = new DelegateCommand(ExecuteAvidCommand)); + + /// + /// 输入avid事件 + /// + private async void ExecuteAvidCommand(string parameter) + { + if (parameter == null) + { + return; + } + + if (!ParseEntrance.IsAvId(parameter)) + { + return; + } + + long avid = ParseEntrance.GetAvId(parameter); + if (avid == -1) + { + return; + } + + await Task.Run(() => { Bvid = BvId.Av2Bv((ulong)avid); }); + } + + // 输入bvid事件 + private DelegateCommand bvidCommand; + + public DelegateCommand BvidCommand => + bvidCommand ?? (bvidCommand = new DelegateCommand(ExecuteBvidCommand)); + + /// + /// 输入bvid事件 + /// + /// + private async void ExecuteBvidCommand(string parameter) + { + if (parameter == null) + { + return; + } + + if (!ParseEntrance.IsBvId(parameter)) + { + return; + } + + await Task.Run(() => + { + ulong avid = BvId.Bv2Av(parameter); + Avid = $"av{avid}"; + }); + } + + // 访问网页事件 + private DelegateCommand gotoWebCommand; + + public DelegateCommand GotoWebCommand => + gotoWebCommand ?? (gotoWebCommand = new DelegateCommand(ExecuteGotoWebCommand)); + + /// + /// 访问网页事件 + /// + private void ExecuteGotoWebCommand() + { + var baseUrl = "https://www.bilibili.com/video/"; + if (OperatingSystem.IsWindows()) + { + Process.Start(baseUrl + Bvid); + } + + if (OperatingSystem.IsMacOS()) + { + Process.Start(new ProcessStartInfo + { + FileName = "open", + ArgumentList = { baseUrl + Bvid }, + }); + } + } + + // 查询弹幕发送者事件 + private DelegateCommand findDanmakuSenderCommand; + + public DelegateCommand FindDanmakuSenderCommand => findDanmakuSenderCommand ?? + (findDanmakuSenderCommand = + new DelegateCommand(ExecuteFindDanmakuSenderCommand)); + + /// + /// 查询弹幕发送者事件 + /// + private async void ExecuteFindDanmakuSenderCommand() + { + await Task.Run(() => + { + try + { + UserMid = DanmakuSender.FindDanmakuSender(DanmakuUserID); + } + catch (Exception e) + { + UserMid = null; + + Console.PrintLine("FindDanmakuSenderCommand()发生异常: {0}", e); + LogManager.Error(Tag, e); + } + }); + } + + // 访问用户空间事件 + private DelegateCommand visitUserSpaceCommand; + + public DelegateCommand VisitUserSpaceCommand => visitUserSpaceCommand ?? + (visitUserSpaceCommand = + new DelegateCommand(ExecuteVisitUserSpaceCommand)); + + /// + /// 访问用户空间事件 + /// + private void ExecuteVisitUserSpaceCommand() + { + if (UserMid == null) + { + return; + } + + string baseUrl = "https://space.bilibili.com/"; + Process.Start(baseUrl + UserMid); + } + + #endregion +} \ No newline at end of file diff --git a/DownKyi/ViewModels/Toolbox/ViewDelogoViewModel.cs b/DownKyi/ViewModels/Toolbox/ViewDelogoViewModel.cs new file mode 100644 index 0000000..83a5dce --- /dev/null +++ b/DownKyi/ViewModels/Toolbox/ViewDelogoViewModel.cs @@ -0,0 +1,192 @@ +using System; +using System.Threading.Tasks; +using Avalonia.Controls; +using DownKyi.Core.FFmpeg; +using DownKyi.Events; +using DownKyi.Utils; +using Prism.Commands; +using Prism.Events; + +namespace DownKyi.ViewModels.Toolbox; + +public class ViewDelogoViewModel : ViewModelBase +{ + public const string Tag = "PageToolboxDelogo"; + + // 是否正在执行去水印任务 + private bool isDelogo = false; + + #region 页面属性申明 + + private string videoPath; + + public string VideoPath + { + get { return videoPath; } + set { SetProperty(ref videoPath, value); } + } + + private int logoWidth; + + public int LogoWidth + { + get { return logoWidth; } + set { SetProperty(ref logoWidth, value); } + } + + private int logoHeight; + + public int LogoHeight + { + get { return logoHeight; } + set { SetProperty(ref logoHeight, value); } + } + + private int logoX; + + public int LogoX + { + get { return logoX; } + set { SetProperty(ref logoX, value); } + } + + private int logoY; + + public int LogoY + { + get { return logoY; } + set { SetProperty(ref logoY, value); } + } + + private string status; + + public string Status + { + get { return status; } + set { SetProperty(ref status, value); } + } + + #endregion + + public ViewDelogoViewModel(IEventAggregator eventAggregator) : base(eventAggregator) + { + #region 属性初始化 + + VideoPath = string.Empty; + + LogoWidth = 0; + LogoHeight = 0; + LogoX = 0; + LogoY = 0; + + #endregion + } + + #region 命令申明 + + // 选择视频事件 + private DelegateCommand selectVideoCommand; + + public DelegateCommand SelectVideoCommand => + selectVideoCommand ?? (selectVideoCommand = new DelegateCommand(ExecuteSelectVideoCommand)); + + /// + /// 选择视频事件 + /// + private async void ExecuteSelectVideoCommand() + { + if (isDelogo) + { + eventAggregator.GetEvent().Publish(DictionaryResource.GetString("TipWaitTaskFinished")); + return; + } + + VideoPath = await DialogUtils.SelectVideoFile(); + } + + // 去水印事件 + private DelegateCommand delogoCommand; + + public DelegateCommand DelogoCommand => + delogoCommand ?? (delogoCommand = new DelegateCommand(ExecuteDelogoCommand)); + + /// + /// 去水印事件 + /// + private async void ExecuteDelogoCommand() + { + if (isDelogo) + { + eventAggregator.GetEvent().Publish(DictionaryResource.GetString("TipWaitTaskFinished")); + return; + } + + if (VideoPath == "") + { + eventAggregator.GetEvent().Publish(DictionaryResource.GetString("TipNoSeletedVideo")); + return; + } + + if (LogoWidth == -1) + { + eventAggregator.GetEvent().Publish(DictionaryResource.GetString("TipInputRightLogoWidth")); + return; + } + + if (LogoHeight == -1) + { + eventAggregator.GetEvent().Publish(DictionaryResource.GetString("TipInputRightLogoHeight")); + return; + } + + if (LogoX == -1) + { + eventAggregator.GetEvent().Publish(DictionaryResource.GetString("TipInputRightLogoX")); + return; + } + + if (LogoY == -1) + { + eventAggregator.GetEvent().Publish(DictionaryResource.GetString("TipInputRightLogoY")); + return; + } + + // 新文件名 + string newFileName = VideoPath.Insert(VideoPath.Length - 4, "_delogo"); + Status = string.Empty; + + await Task.Run(() => + { + // 执行去水印程序 + isDelogo = true; + FFmpegHelper.Delogo(VideoPath, newFileName, LogoX, LogoY, LogoWidth, LogoHeight, output => + { + Status += output + "\n"; + }); + isDelogo = false; + }); + } + + // Status改变事件 + private DelegateCommand statusCommand; + + public DelegateCommand StatusCommand => + statusCommand ?? (statusCommand = new DelegateCommand(ExecuteStatusCommand)); + + /// + /// Status改变事件 + /// + /// + private void ExecuteStatusCommand(object parameter) + { + if (!(parameter is TextBox output)) + { + return; + } + + // TextBox滚动到底部 + // output.ScrollToEnd(); + } + + #endregion +} \ No newline at end of file diff --git a/DownKyi/ViewModels/Toolbox/ViewExtractMediaViewModel.cs b/DownKyi/ViewModels/Toolbox/ViewExtractMediaViewModel.cs new file mode 100644 index 0000000..3d009ce --- /dev/null +++ b/DownKyi/ViewModels/Toolbox/ViewExtractMediaViewModel.cs @@ -0,0 +1,192 @@ +using System; +using System.Threading.Tasks; +using Avalonia.Controls; +using DownKyi.Core.FFmpeg; +using DownKyi.Events; +using DownKyi.Utils; +using Prism.Commands; +using Prism.Events; + +namespace DownKyi.ViewModels.Toolbox; + +public class ViewExtractMediaViewModel : ViewModelBase +{ + public const string Tag = "PageToolboxExtractMedia"; + + // 是否正在执行任务 + private bool isExtracting = false; + + #region 页面属性申明 + + private string videoPathsStr; + + public string VideoPathsStr + { + get => videoPathsStr; + set { SetProperty(ref videoPathsStr, value); } + } + + private string[] videoPaths; + + public string[] VideoPaths + { + get => videoPaths; + set + { + videoPaths = value; + VideoPathsStr = string.Join(Environment.NewLine, value); + } + } + + private string status; + + public string Status + { + get => status; + set => SetProperty(ref status, value); + } + + #endregion + + public ViewExtractMediaViewModel(IEventAggregator eventAggregator) : base(eventAggregator) + { + #region 属性初始化 + + VideoPaths = new string[0]; + + #endregion + } + + #region 命令申明 + + // 选择视频事件 + private DelegateCommand selectVideoCommand; + + public DelegateCommand SelectVideoCommand => + selectVideoCommand ?? (selectVideoCommand = new DelegateCommand(ExecuteSelectVideoCommand)); + + /// + /// 选择视频事件 + /// + private async void ExecuteSelectVideoCommand() + { + if (isExtracting) + { + eventAggregator.GetEvent().Publish(DictionaryResource.GetString("TipWaitTaskFinished")); + return; + } + + VideoPaths = await DialogUtils.SelectMultiVideoFile(); + } + + // 提取音频事件 + private DelegateCommand extractAudioCommand; + + public DelegateCommand ExtractAudioCommand => extractAudioCommand ?? + (extractAudioCommand = + new DelegateCommand(ExecuteExtractAudioCommand)); + + /// + /// 提取音频事件 + /// + private async void ExecuteExtractAudioCommand() + { + if (isExtracting) + { + eventAggregator.GetEvent().Publish(DictionaryResource.GetString("TipWaitTaskFinished")); + return; + } + + if (VideoPaths.Length <= 0) + { + eventAggregator.GetEvent().Publish(DictionaryResource.GetString("TipNoSeletedVideo")); + return; + } + + Status = string.Empty; + + await Task.Run(() => + { + isExtracting = true; + foreach (var item in VideoPaths) + { + // 音频文件名 + string audioFileName = item.Remove(item.Length - 4, 4) + ".aac"; + // 执行提取音频程序 + FFmpegHelper.ExtractAudio(item, audioFileName, output => + { + Status += output + "\n"; + }); + } + + isExtracting = false; + }); + } + + // 提取视频事件 + private DelegateCommand extractVideoCommand; + + public DelegateCommand ExtractVideoCommand => extractVideoCommand ?? + (extractVideoCommand = + new DelegateCommand(ExecuteExtractVideoCommand)); + + /// + /// 提取视频事件 + /// + private async void ExecuteExtractVideoCommand() + { + if (isExtracting) + { + eventAggregator.GetEvent().Publish(DictionaryResource.GetString("TipWaitTaskFinished")); + return; + } + + if (VideoPaths.Length <= 0) + { + eventAggregator.GetEvent().Publish(DictionaryResource.GetString("TipNoSeletedVideo")); + return; + } + + Status = string.Empty; + + await Task.Run(() => + { + isExtracting = true; + foreach (var item in VideoPaths) + { + // 视频文件名 + string videoFileName = item.Remove(item.Length - 4, 4) + "_onlyVideo.mp4"; + // 执行提取视频程序 + FFmpegHelper.ExtractVideo(item, videoFileName, new Action((output) => + { + Status += output + "\n"; + })); + } + + isExtracting = false; + }); + } + + // Status改变事件 + private DelegateCommand statusCommand; + + public DelegateCommand StatusCommand => + statusCommand ?? (statusCommand = new DelegateCommand(ExecuteStatusCommand)); + + /// + /// Status改变事件 + /// + /// + private void ExecuteStatusCommand(object parameter) + { + if (!(parameter is TextBox output)) + { + return; + } + + // TextBox滚动到底部 + // output.ScrollToEnd(); + } + + #endregion +} \ No newline at end of file diff --git a/DownKyi/ViewModels/UserSpace/Channel.cs b/DownKyi/ViewModels/UserSpace/Channel.cs new file mode 100644 index 0000000..c87bf82 --- /dev/null +++ b/DownKyi/ViewModels/UserSpace/Channel.cs @@ -0,0 +1,39 @@ +using Prism.Mvvm; + +namespace DownKyi.ViewModels.UserSpace; + +public class Channel : BindableBase +{ + public long Cid { get; set; } + + /*private ImageSource cover; + public ImageSource Cover + { + get => cover; + set => SetProperty(ref cover, value); + }*/ + + private string name; + + public string Name + { + get => name; + set => SetProperty(ref name, value); + } + + private int count; + + public int Count + { + get => count; + set => SetProperty(ref count, value); + } + + private string ctime; + + public string Ctime + { + get => ctime; + set => SetProperty(ref ctime, value); + } +} \ No newline at end of file diff --git a/DownKyi/ViewModels/UserSpace/PublicationZone.cs b/DownKyi/ViewModels/UserSpace/PublicationZone.cs new file mode 100644 index 0000000..4d8633c --- /dev/null +++ b/DownKyi/ViewModels/UserSpace/PublicationZone.cs @@ -0,0 +1,33 @@ +using Avalonia.Media; +using Prism.Mvvm; + +namespace DownKyi.ViewModels.UserSpace; + +public class PublicationZone : BindableBase +{ + public int Tid { get; set; } + + private DrawingImage icon; + + public DrawingImage Icon + { + get => icon; + set => SetProperty(ref icon, value); + } + + private string name; + + public string Name + { + get => name; + set => SetProperty(ref name, value); + } + + private int count; + + public int Count + { + get => count; + set => SetProperty(ref count, value); + } +} \ No newline at end of file diff --git a/DownKyi/ViewModels/UserSpace/SeasonsSeries.cs b/DownKyi/ViewModels/UserSpace/SeasonsSeries.cs new file mode 100644 index 0000000..3fcd09e --- /dev/null +++ b/DownKyi/ViewModels/UserSpace/SeasonsSeries.cs @@ -0,0 +1,50 @@ +using Avalonia.Media.Imaging; +using DownKyi.Images; +using Prism.Mvvm; + +namespace DownKyi.ViewModels.UserSpace; + +public class SeasonsSeries : BindableBase +{ + public long Id { get; set; } + + private Bitmap cover; + + public Bitmap Cover + { + get => cover; + set => SetProperty(ref cover, value); + } + + private VectorImage typeImage; + + public VectorImage TypeImage + { + get => typeImage; + set => SetProperty(ref typeImage, value); + } + + private string name; + + public string Name + { + get => name; + set => SetProperty(ref name, value); + } + + private int count; + + public int Count + { + get => count; + set => SetProperty(ref count, value); + } + + private string ctime; + + public string Ctime + { + get => ctime; + set => SetProperty(ref ctime, value); + } +} \ No newline at end of file diff --git a/DownKyi/ViewModels/UserSpace/TabLeftBanner.cs b/DownKyi/ViewModels/UserSpace/TabLeftBanner.cs new file mode 100644 index 0000000..797a2b6 --- /dev/null +++ b/DownKyi/ViewModels/UserSpace/TabLeftBanner.cs @@ -0,0 +1,43 @@ +using DownKyi.Images; +using Prism.Mvvm; + +namespace DownKyi.ViewModels.UserSpace; + +public class TabLeftBanner : BindableBase +{ + public object Object { get; set; } + + public int Id { get; set; } + + private bool isSelected; + + public bool IsSelected + { + get => isSelected; + set => SetProperty(ref isSelected, value); + } + + private VectorImage icon; + + public VectorImage Icon + { + get => icon; + set => SetProperty(ref icon, value); + } + + private string iconColor; + + public string IconColor + { + get => iconColor; + set => SetProperty(ref iconColor, value); + } + + private string title; + + public string Title + { + get => title; + set => SetProperty(ref title, value); + } +} \ No newline at end of file diff --git a/DownKyi/ViewModels/UserSpace/TabRightBanner.cs b/DownKyi/ViewModels/UserSpace/TabRightBanner.cs new file mode 100644 index 0000000..f71b675 --- /dev/null +++ b/DownKyi/ViewModels/UserSpace/TabRightBanner.cs @@ -0,0 +1,48 @@ +using Prism.Mvvm; + +namespace DownKyi.ViewModels.UserSpace; + +public class TabRightBanner : BindableBase +{ + public int Id { get; set; } + + private bool isEnabled; + + public bool IsEnabled + { + get => isEnabled; + set => SetProperty(ref isEnabled, value); + } + + private string labelColor; + + public string LabelColor + { + get => labelColor; + set => SetProperty(ref labelColor, value); + } + + private string countColor; + + public string CountColor + { + get => countColor; + set => SetProperty(ref countColor, value); + } + + private string label; + + public string Label + { + get => label; + set => SetProperty(ref label, value); + } + + private string count; + + public string Count + { + get => count; + set => SetProperty(ref count, value); + } +} \ No newline at end of file diff --git a/DownKyi/ViewModels/UserSpace/ViewArchiveViewModel.cs b/DownKyi/ViewModels/UserSpace/ViewArchiveViewModel.cs new file mode 100644 index 0000000..8efa6fb --- /dev/null +++ b/DownKyi/ViewModels/UserSpace/ViewArchiveViewModel.cs @@ -0,0 +1,139 @@ +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using Avalonia.Media; +using DownKyi.Core.BiliApi.Users.Models; +using DownKyi.Core.BiliApi.Zone; +using DownKyi.Utils; +using Prism.Commands; +using Prism.Events; +using Prism.Regions; + +namespace DownKyi.ViewModels.UserSpace; + +public class ViewArchiveViewModel : ViewModelBase +{ + public const string Tag = "PageUserSpaceArchive"; + + private long mid = -1; + + #region 页面属性申明 + + private ObservableCollection publicationZones; + + public ObservableCollection PublicationZones + { + get => publicationZones; + set => SetProperty(ref publicationZones, value); + } + + private int selectedItem; + + public int SelectedItem + { + get => selectedItem; + set => SetProperty(ref selectedItem, value); + } + + #endregion + + public ViewArchiveViewModel(IEventAggregator eventAggregator) : base(eventAggregator) + { + #region 属性初始化 + + PublicationZones = new ObservableCollection(); + + #endregion + } + + #region 命令申明 + + // 视频选择事件 + private DelegateCommand publicationZonesCommand; + + public DelegateCommand PublicationZonesCommand => publicationZonesCommand ?? + (publicationZonesCommand = + new DelegateCommand( + ExecutePublicationZonesCommand)); + + /// + /// 视频选择事件 + /// + /// + private void ExecutePublicationZonesCommand(object parameter) + { + if (!(parameter is PublicationZone zone)) + { + return; + } + + Dictionary data = new Dictionary + { + { "mid", mid }, + { "tid", zone.Tid }, + { "list", PublicationZones.ToList() } + }; + + // 进入视频页面 + NavigateToView.NavigationView(eventAggregator, ViewPublicationViewModel.Tag, ViewUserSpaceViewModel.Tag, + data); + + SelectedItem = -1; + } + + #endregion + + public override void OnNavigatedFrom(NavigationContext navigationContext) + { + base.OnNavigatedFrom(navigationContext); + + PublicationZones.Clear(); + SelectedItem = -1; + } + + /// + /// 接收mid参数 + /// + /// + public override void OnNavigatedTo(NavigationContext navigationContext) + { + base.OnNavigatedTo(navigationContext); + + PublicationZones.Clear(); + SelectedItem = -1; + + // 根据传入参数不同执行不同任务 + var parameter = navigationContext.Parameters.GetValue>("object"); + if (parameter == null) + { + return; + } + + // 传入mid + mid = navigationContext.Parameters.GetValue("mid"); + + int VideoCount = 0; + foreach (var zone in parameter) + { + VideoCount += zone.Count; + string iconKey = VideoZoneIcon.Instance().GetZoneImageKey(zone.Tid); + + publicationZones.Add(new PublicationZone + { + Tid = zone.Tid, + Icon = DictionaryResource.Get(iconKey), + Name = zone.Name, + Count = zone.Count + }); + } + + // 全部 + publicationZones.Insert(0, new PublicationZone + { + Tid = 0, + Icon = DictionaryResource.Get("videoUpDrawingImage"), + Name = DictionaryResource.GetString("AllPublicationZones"), + Count = VideoCount + }); + } +} \ No newline at end of file diff --git a/DownKyi/ViewModels/UserSpace/ViewChannelViewModel.cs b/DownKyi/ViewModels/UserSpace/ViewChannelViewModel.cs new file mode 100644 index 0000000..11ae232 --- /dev/null +++ b/DownKyi/ViewModels/UserSpace/ViewChannelViewModel.cs @@ -0,0 +1,149 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Threading.Tasks; +using Avalonia.Media.Imaging; +using DownKyi.Core.BiliApi.Users.Models; +using DownKyi.Core.Storage; +using DownKyi.Utils; +using Prism.Commands; +using Prism.Events; +using Prism.Regions; + +namespace DownKyi.ViewModels.UserSpace; + +public class ViewChannelViewModel : ViewModelBase +{ + public const string Tag = "PageUserSpaceChannel"; + + private long mid = -1; + + #region 页面属性申明 + + private ObservableCollection channels; + + public ObservableCollection Channels + { + get => channels; + set => SetProperty(ref channels, value); + } + + private int selectedItem; + + public int SelectedItem + { + get => selectedItem; + set => SetProperty(ref selectedItem, value); + } + + #endregion + + public ViewChannelViewModel(IEventAggregator eventAggregator) : base(eventAggregator) + { + #region 属性初始化 + + Channels = new ObservableCollection(); + + #endregion + } + + #region 命令申明 + + // 视频选择事件 + private DelegateCommand channelsCommand; + + public DelegateCommand ChannelsCommand => + channelsCommand ?? (channelsCommand = new DelegateCommand(ExecuteChannelsCommand)); + + /// + /// 视频选择事件 + /// + /// + private void ExecuteChannelsCommand(object parameter) + { + if (!(parameter is Channel channel)) + { + return; + } + + Dictionary data = new Dictionary + { + { "mid", mid }, + { "cid", channel.Cid }, + { "name", channel.Name }, + { "count", channel.Count } + }; + + // 进入视频页面 + // NavigateToView.NavigationView(eventAggregator, ViewModels.ViewChannelViewModel.Tag, ViewUserSpaceViewModel.Tag, data); + + SelectedItem = -1; + } + + #endregion + + public override void OnNavigatedFrom(NavigationContext navigationContext) + { + base.OnNavigatedFrom(navigationContext); + + Channels.Clear(); + SelectedItem = -1; + } + + /// + /// 接收mid参数 + /// + /// + public async override void OnNavigatedTo(NavigationContext navigationContext) + { + base.OnNavigatedTo(navigationContext); + + Channels.Clear(); + SelectedItem = -1; + + // 根据传入参数不同执行不同任务 + var parameter = navigationContext.Parameters.GetValue>("object"); + if (parameter == null) + { + return; + } + + // 传入mid + mid = navigationContext.Parameters.GetValue("mid"); + + foreach (var channel in parameter) + { + if (channel.Count <= 0) + { + continue; + } + + Bitmap image = null; + if (channel.Cover == null || channel.Cover == "") + { + image = ImageHelper.LoadFromResource(new Uri($"avares://DownKyi/Resources/video-placeholder.png")); + } + else + { + StorageCover storageCover = new StorageCover(); + string cover = null; + await Task.Run(() => { cover = storageCover.GetCover(channel.Cover); }); + image = storageCover.GetCoverThumbnail(cover, 190, 190); + } + + // 当地时区 + DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1)); + DateTime dateCTime = startTime.AddSeconds(channel.Mtime); + string mtime = dateCTime.ToString("yyyy-MM-dd"); + + Channels.Add(new Channel + { + Cid = channel.Cid, + // Cover = image, + Name = channel.Name, + Count = channel.Count, + Ctime = mtime + }); + } + } +} \ No newline at end of file diff --git a/DownKyi/ViewModels/UserSpace/ViewSeasonsSeriesViewModel.cs b/DownKyi/ViewModels/UserSpace/ViewSeasonsSeriesViewModel.cs new file mode 100644 index 0000000..431aece --- /dev/null +++ b/DownKyi/ViewModels/UserSpace/ViewSeasonsSeriesViewModel.cs @@ -0,0 +1,208 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Threading.Tasks; +using Avalonia.Media.Imaging; +using DownKyi.Core.BiliApi.Users.Models; +using DownKyi.Core.Storage; +using DownKyi.Events; +using DownKyi.Images; +using DownKyi.Utils; +using Prism.Commands; +using Prism.Events; +using Prism.Regions; + +namespace DownKyi.ViewModels.UserSpace; + +public class ViewSeasonsSeriesViewModel : ViewModelBase +{ + public const string Tag = "PageUserSpaceSeasonsSeries"; + + private long mid = -1; + + #region 页面属性申明 + + private ObservableCollection seasonsSeries; + + public ObservableCollection SeasonsSeries + { + get => seasonsSeries; + set => SetProperty(ref seasonsSeries, value); + } + + private int selectedItem; + + public int SelectedItem + { + get => selectedItem; + set => SetProperty(ref selectedItem, value); + } + + #endregion + + public ViewSeasonsSeriesViewModel(IEventAggregator eventAggregator) : base(eventAggregator) + { + #region 属性初始化 + + SeasonsSeries = new ObservableCollection(); + + #endregion + } + + #region 命令申明 + + // 视频选择事件 + private DelegateCommand seasonsSeriesCommand; + + public DelegateCommand SeasonsSeriesCommand => seasonsSeriesCommand ?? + (seasonsSeriesCommand = + new DelegateCommand( + ExecuteSeasonsSeriesCommand)); + + /// + /// 视频选择事件 + /// + /// + private void ExecuteSeasonsSeriesCommand(object parameter) + { + if (!(parameter is SeasonsSeries seasonsSeries)) + { + return; + } + + // 应该用枚举的,偷懒直接用数字 + int type = 0; + if (seasonsSeries.TypeImage == NormalIcon.Instance().SeasonsSeries) + { + type = 1; + } + else if (seasonsSeries.TypeImage == NormalIcon.Instance().Channel1) + { + type = 2; + } + + Dictionary data = new Dictionary + { + { "mid", mid }, + { "id", seasonsSeries.Id }, + { "name", seasonsSeries.Name }, + { "count", seasonsSeries.Count }, + { "type", type } + }; + + // 进入视频页面 + NavigationParam param = new NavigationParam + { + ViewName = ViewModels.ViewSeasonsSeriesViewModel.Tag, + ParentViewName = ViewUserSpaceViewModel.Tag, + Parameter = data + }; + eventAggregator.GetEvent().Publish(param); + + SelectedItem = -1; + } + + #endregion + + public override void OnNavigatedFrom(NavigationContext navigationContext) + { + base.OnNavigatedFrom(navigationContext); + + SeasonsSeries.Clear(); + SelectedItem = -1; + } + + /// + /// 接收mid参数 + /// + /// + public async override void OnNavigatedTo(NavigationContext navigationContext) + { + base.OnNavigatedTo(navigationContext); + + SeasonsSeries.Clear(); + SelectedItem = -1; + + // 根据传入参数不同执行不同任务 + var parameter = navigationContext.Parameters.GetValue("object"); + if (parameter == null) + { + return; + } + + // 传入mid + mid = navigationContext.Parameters.GetValue("mid"); + + foreach (var item in parameter.SeasonsList) + { + if (item.Meta.Total <= 0) + { + continue; + } + + Bitmap image = null; + if (item.Meta.Cover == null || item.Meta.Cover == "") + { + image = ImageHelper.LoadFromResource(new Uri("avares://DownKyi/Resources/video-placeholder.png")); + } + else + { + StorageCover storageCover = new StorageCover(); + string cover = null; + await Task.Run(() => { cover = storageCover.GetCover(item.Meta.Cover); }); + image = storageCover.GetCoverThumbnail(cover, 190, 190); + } + + // 当地时区 + DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1)); + DateTime dateCTime = startTime.AddSeconds(item.Meta.Ptime); + string mtime = dateCTime.ToString("yyyy-MM-dd"); + + SeasonsSeries.Add(new SeasonsSeries + { + Id = item.Meta.SeasonId, + Cover = image, + TypeImage = NormalIcon.Instance().SeasonsSeries, + Name = item.Meta.Name, + Count = item.Meta.Total, + Ctime = mtime + }); + } + + foreach (var item in parameter.SeriesList) + { + if (item.Meta.Total <= 0) + { + continue; + } + + Bitmap image = null; + if (item.Meta.Cover == null || item.Meta.Cover == "") + { + image = ImageHelper.LoadFromResource(new Uri($"avares://DownKyi/Resources/video-placeholder.png")); + } + else + { + StorageCover storageCover = new StorageCover(); + string cover = null; + await Task.Run(() => { cover = storageCover.GetCover(item.Meta.Cover); }); + image = storageCover.GetCoverThumbnail(cover, 190, 190); + } + + // 当地时区 + DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1)); + DateTime dateCTime = startTime.AddSeconds(item.Meta.Mtime); + string mtime = dateCTime.ToString("yyyy-MM-dd"); + + SeasonsSeries.Add(new SeasonsSeries + { + Id = item.Meta.SeriesId, + Cover = image, + TypeImage = NormalIcon.Instance().Channel1, + Name = item.Meta.Name, + Count = item.Meta.Total, + Ctime = mtime + }); + } + } +} \ No newline at end of file diff --git a/DownKyi/ViewModels/ViewDownloadManagerViewModel.cs b/DownKyi/ViewModels/ViewDownloadManagerViewModel.cs new file mode 100644 index 0000000..63892f1 --- /dev/null +++ b/DownKyi/ViewModels/ViewDownloadManagerViewModel.cs @@ -0,0 +1,150 @@ +using System.Collections.Generic; +using DownKyi.Events; +using DownKyi.Images; +using DownKyi.Utils; +using DownKyi.ViewModels.DownloadManager; +using DownKyi.ViewModels.PageViewModels; +using Prism.Commands; +using Prism.Events; +using Prism.Regions; + +namespace DownKyi.ViewModels; + +public class ViewDownloadManagerViewModel : ViewModelBase +{ + public const string Tag = "PageDownloadManager"; + + private readonly IRegionManager regionManager; + + #region 页面属性申明 + + private VectorImage arrowBack; + + public VectorImage ArrowBack + { + get => arrowBack; + set => SetProperty(ref arrowBack, value); + } + + private List tabHeaders; + + public List TabHeaders + { + get => tabHeaders; + set => SetProperty(ref tabHeaders, value); + } + + private int selectTabId; + + public int SelectTabId + { + get => selectTabId; + set => SetProperty(ref selectTabId, value); + } + + #endregion + + public ViewDownloadManagerViewModel(IRegionManager regionManager, IEventAggregator eventAggregator) : base( + eventAggregator) + { + this.regionManager = regionManager; + + #region 属性初始化 + + ArrowBack = NavigationIcon.Instance().ArrowBack; + ArrowBack.Fill = DictionaryResource.GetColor("ColorTextDark"); + + TabHeaders = new List + { + new() + { + Id = 0, Image = NormalIcon.Instance().Downloading, Title = DictionaryResource.GetString("Downloading") + }, + new() + { + Id = 1, Image = NormalIcon.Instance().DownloadFinished, + Title = DictionaryResource.GetString("DownloadFinished") + } + }; + + #endregion + } + + #region 命令申明 + +// 返回事件 + private DelegateCommand backSpaceCommand; + + public DelegateCommand BackSpaceCommand => + backSpaceCommand ?? (backSpaceCommand = new DelegateCommand(ExecuteBackSpace)); + + /// + /// 返回事件 + /// + private void ExecuteBackSpace() + { + NavigationParam parameter = new NavigationParam + { + ViewName = ParentView, + ParentViewName = null, + Parameter = null + }; + eventAggregator.GetEvent().Publish(parameter); + } + + // 左侧tab点击事件 + private DelegateCommand leftTabHeadersCommand; + + public DelegateCommand LeftTabHeadersCommand => leftTabHeadersCommand ?? + (leftTabHeadersCommand = + new DelegateCommand( + ExecuteLeftTabHeadersCommand)); + + /// + /// 左侧tab点击事件 + /// + /// + private void ExecuteLeftTabHeadersCommand(object parameter) + { + if (!(parameter is TabHeader tabHeader)) + { + return; + } + + NavigationParameters param = new NavigationParameters(); + + switch (tabHeader.Id) + { + case 0: + regionManager.RequestNavigate("DownloadManagerContentRegion", ViewDownloadingViewModel.Tag, param); + break; + case 1: + regionManager.RequestNavigate("DownloadManagerContentRegion", ViewDownloadFinishedViewModel.Tag, param); + break; + default: + break; + } + } + + #endregion + + /// + /// 导航到页面时执行 + /// + /// + public override void OnNavigatedTo(NavigationContext navigationContext) + { + base.OnNavigatedTo(navigationContext); + + //// 进入设置页面时显示的设置项 + SelectTabId = 0; + + PropertyChangeAsync(() => + { + regionManager.RequestNavigate("DownloadManagerContentRegion", ViewDownloadingViewModel.Tag, + new NavigationParameters()); + }); + + ArrowBack.Fill = DictionaryResource.GetColor("ColorTextDark"); + } +} \ No newline at end of file diff --git a/DownKyi/ViewModels/ViewFriendsViewModel.cs b/DownKyi/ViewModels/ViewFriendsViewModel.cs new file mode 100644 index 0000000..9a3f8c6 --- /dev/null +++ b/DownKyi/ViewModels/ViewFriendsViewModel.cs @@ -0,0 +1,173 @@ +using System.Collections.Generic; +using System.Collections.ObjectModel; +using DownKyi.Events; +using DownKyi.Images; +using DownKyi.Utils; +using DownKyi.ViewModels.Friends; +using DownKyi.ViewModels.PageViewModels; +using Prism.Commands; +using Prism.Events; +using Prism.Regions; + +namespace DownKyi.ViewModels +{ + public class ViewFriendsViewModel : ViewModelBase + { + public const string Tag = "PageFriends"; + + private readonly IRegionManager regionManager; + + private long mid = -1; + + #region 页面属性申明 + + private VectorImage arrowBack; + + public VectorImage ArrowBack + { + get => arrowBack; + set => SetProperty(ref arrowBack, value); + } + + private ObservableCollection tabHeaders; + + public ObservableCollection TabHeaders + { + get => tabHeaders; + set => SetProperty(ref tabHeaders, value); + } + + private int selectTabId = -1; + + public int SelectTabId + { + get => selectTabId; + set => SetProperty(ref selectTabId, value); + } + + #endregion + + public ViewFriendsViewModel(IRegionManager regionManager, IEventAggregator eventAggregator) : base( + eventAggregator) + { + this.regionManager = regionManager; + + #region 属性初始化 + + ArrowBack = NavigationIcon.Instance().ArrowBack; + ArrowBack.Fill = DictionaryResource.GetColor("ColorTextDark"); + + TabHeaders = new ObservableCollection + { + new() { Id = 0, Title = DictionaryResource.GetString("FriendFollowing") }, + new() { Id = 1, Title = DictionaryResource.GetString("FriendFollower") }, + }; + + #endregion + } + + #region 命令申明 + + // 返回事件 + private DelegateCommand backSpaceCommand; + + public DelegateCommand BackSpaceCommand => + backSpaceCommand ?? (backSpaceCommand = new DelegateCommand(ExecuteBackSpace)); + + /// + /// 返回事件 + /// + private void ExecuteBackSpace() + { + //InitView(); + + ArrowBack.Fill = DictionaryResource.GetColor("ColorText"); + + NavigationParam parameter = new NavigationParam + { + ViewName = ParentView, + ParentViewName = null, + Parameter = null + }; + eventAggregator.GetEvent().Publish(parameter); + } + + // 顶部tab点击事件 + private DelegateCommand tabHeadersCommand; + + public DelegateCommand TabHeadersCommand => tabHeadersCommand ?? + (tabHeadersCommand = + new DelegateCommand(ExecuteTabHeadersCommand)); + + /// + /// 顶部tab点击事件 + /// + /// + private void ExecuteTabHeadersCommand(object parameter) + { + if (!(parameter is TabHeader tabHeader)) + { + return; + } + + // TODO + // 此处应该根据具体状态传入true or false + NavigationView(tabHeader.Id, true); + } + + #endregion + + /// + /// 进入子页面 + /// + /// + /// + private void NavigationView(long id, bool isFirst) + { + // isFirst参数表示是否是从PageFriends的headerTable的item点击进入的 + // true表示加载PageFriends后第一次进入 + // false表示从headerTable的item点击进入 + NavigationParameters param = new NavigationParameters() + { + { "mid", mid }, + { "isFirst", isFirst }, + }; + + switch (id) + { + case 0: + regionManager.RequestNavigate("FriendContentRegion", ViewFollowingViewModel.Tag, param); + break; + case 1: + regionManager.RequestNavigate("FriendContentRegion", ViewFollowerViewModel.Tag, param); + break; + } + } + + /// + /// 导航到页面时执行 + /// + /// + public override void OnNavigatedTo(NavigationContext navigationContext) + { + base.OnNavigatedTo(navigationContext); + + ArrowBack.Fill = DictionaryResource.GetColor("ColorTextDark"); + + // 根据传入参数不同执行不同任务 + var parameter = navigationContext.Parameters.GetValue>("Parameter"); + if (parameter == null) + { + return; + } + + mid = (long)parameter["mid"]; + SelectTabId = (int)parameter["friendId"]; + + PropertyChangeAsync(() => + { + NavigationView(SelectTabId, true); + }); + } + } +} \ No newline at end of file diff --git a/DownKyi/ViewModels/ViewIndexViewModel.cs b/DownKyi/ViewModels/ViewIndexViewModel.cs new file mode 100644 index 0000000..c0de6d5 --- /dev/null +++ b/DownKyi/ViewModels/ViewIndexViewModel.cs @@ -0,0 +1,359 @@ +using System; +using System.IO; +using System.Linq; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using Avalonia.Media.Imaging; +using DownKyi.Core.BiliApi.Users; +using DownKyi.Core.BiliApi.Users.Models; +using DownKyi.Core.Logging; +using DownKyi.Core.Settings; +using DownKyi.Core.Settings.Models; +using DownKyi.Core.Storage; +using DownKyi.Images; +using DownKyi.Services; +using DownKyi.Utils; +using Prism.Commands; +using Prism.Events; +using Prism.Regions; +using Console = DownKyi.Core.Utils.Debugging.Console; + +namespace DownKyi.ViewModels; + +public class ViewIndexViewModel : ViewModelBase +{ + public const string Tag = "PageIndex"; + + private bool _loginPanelVisibility; + + public bool LoginPanelVisibility + { + get => _loginPanelVisibility; + set => SetProperty(ref _loginPanelVisibility, value); + } + + private string? _userName; + + public string? UserName + { + get => _userName; + set => SetProperty(ref _userName, value); + } + + private Bitmap _header; + + public Bitmap Header + { + get => _header; + set => SetProperty(ref _header, value); + } + + + private VectorImage textLogo; + + public VectorImage TextLogo + { + get => textLogo; + set => SetProperty(ref textLogo, value); + } + + private string _inputText; + + public string InputText + { + get => _inputText; + set => SetProperty(ref _inputText, value); + } + + private VectorImage _generalSearch; + + public VectorImage GeneralSearch + { + get => _generalSearch; + set => SetProperty(ref _generalSearch, value); + } + + private VectorImage _settings; + + public VectorImage Settings + { + get => _settings; + set => SetProperty(ref _settings, value); + } + + private VectorImage _downloadManager; + + public VectorImage DownloadManager + { + get => _downloadManager; + set => SetProperty(ref _downloadManager, value); + } + + private VectorImage _toolbox; + + public VectorImage Toolbox + { + get => _toolbox; + set => SetProperty(ref _toolbox, value); + } + + + public ViewIndexViewModel(IEventAggregator eventAggregator) : base(eventAggregator) + { + _loginPanelVisibility = true; + Header = ImageHelper.LoadFromResource(new Uri("avares://DownKyi/Resources/default_header.jpg")); + + TextLogo = LogoIcon.Instance().TextLogo; + TextLogo.Fill = DictionaryResource.GetColor("ColorPrimary"); + + GeneralSearch = ButtonIcon.Instance().GeneralSearch; + GeneralSearch.Fill = DictionaryResource.GetColor("ColorPrimary"); + + Settings = ButtonIcon.Instance().Settings; + Settings.Fill = DictionaryResource.GetColor("ColorPrimary"); + + DownloadManager = ButtonIcon.Instance().DownloadManage; + DownloadManager.Fill = DictionaryResource.GetColor("ColorPrimary"); + + Toolbox = ButtonIcon.Instance().Toolbox; + Toolbox.Fill = DictionaryResource.GetColor("ColorPrimary"); + + UpdateUserInfo(); + } + + // 输入确认事件 + public DelegateCommand inputCommand; + public DelegateCommand InputCommand => inputCommand ?? (inputCommand = new DelegateCommand(ExecuteInput)); + + /// + /// 处理输入事件 + /// + private void ExecuteInput(object param) + { + EnterBili(); + } + + + // 登录事件 + private DelegateCommand? _loginCommand; + public DelegateCommand LoginCommand => _loginCommand ??= new DelegateCommand(ExecuteLogin); + + /// + /// 进入登录页面 + /// + private void ExecuteLogin() + { + if (UserName == null) + { + NavigateToView.NavigationView(eventAggregator, ViewLoginViewModel.Tag, Tag, null); + } + else + { + // 进入用户空间 + var userInfo = SettingsManager.GetInstance().GetUserInfo(); + if (userInfo != null && userInfo.Mid != -1) + { + NavigateToView.NavigationView(eventAggregator, ViewMySpaceViewModel.Tag, Tag, userInfo.Mid); + } + } + } + + // 进入设置页面 + private DelegateCommand settingsCommand; + + public DelegateCommand SettingsCommand => + settingsCommand ?? (settingsCommand = new DelegateCommand(ExecuteSettingsCommand)); + + /// + /// 进入设置页面 + /// + private void ExecuteSettingsCommand() + { + NavigateToView.NavigationView(eventAggregator, ViewSettingsViewModel.Tag, Tag, null); + } + + // 进入下载管理页面 + private DelegateCommand downloadManagerCommand; + + public DelegateCommand DownloadManagerCommand => downloadManagerCommand ?? + (downloadManagerCommand = + new DelegateCommand(ExecuteDownloadManagerCommand)); + + /// + /// 进入下载管理页面 + /// + private void ExecuteDownloadManagerCommand() + { + NavigateToView.NavigationView(eventAggregator, ViewDownloadManagerViewModel.Tag, Tag, null); + } + +// 进入工具箱页面 + private DelegateCommand toolboxCommand; + + public DelegateCommand ToolboxCommand => + toolboxCommand ?? (toolboxCommand = new DelegateCommand(ExecuteToolboxCommand)); + + /// + /// 进入工具箱页面 + /// + private async void ExecuteToolboxCommand() + { + NavigateToView.NavigationView(eventAggregator, ViewToolboxViewModel.Tag, Tag, null); + } + + + /// + /// 进入B站链接的处理逻辑, + /// 只负责处理输入,并跳转到视频详情页。 + /// 不是支持的格式,则进入搜索页面。 + /// + private void EnterBili() + { + if (InputText == null || InputText == string.Empty) + { + return; + } + + LogManager.Debug(Tag, $"InputText: {InputText}"); + InputText = Regex.Replace(InputText, @"[【]*[^【]*[^】]*[】 ]", ""); + SearchService searchService = new SearchService(); + bool isSupport = searchService.BiliInput(InputText, Tag, eventAggregator); + if (!isSupport) + { + // 关键词搜索 + searchService.SearchKey(InputText, Tag, eventAggregator); + } + + InputText = string.Empty; + } + + + private async Task GetUserInfo() + { + UserInfoForNavigation userInfo = null; + await Task.Run(() => + { + // 获取用户信息 + userInfo = UserInfo.GetUserInfoForNavigation(); + if (userInfo != null) + { + SettingsManager.GetInstance().SetUserInfo(new UserInfoSettings + { + Mid = userInfo.Mid, + Name = userInfo.Name, + IsLogin = userInfo.IsLogin, + IsVip = userInfo.VipStatus == 1, + ImgKey = userInfo.Wbi.ImgUrl.Split('/').ToList().Last().Split('.')[0], + SubKey = userInfo.Wbi.SubUrl.Split('/').ToList().Last().Split('.')[0], + }); + } + else + { + SettingsManager.GetInstance().SetUserInfo(new UserInfoSettings + { + Mid = -1, + Name = "", + IsLogin = false, + IsVip = false, + }); + } + }); + return userInfo; + } + + /// + /// 更新用户登录信息 + /// + private async void UpdateUserInfo(bool isBackgroud = false) + { + try + { + if (isBackgroud) + { + // 获取用户信息 + await GetUserInfo(); + return; + } + + LoginPanelVisibility = false; + + // 获取用户信息 + var userInfo = await GetUserInfo(); + + // 检查本地是否存在login文件,没有则说明未登录 + if (!File.Exists(StorageManager.GetLogin())) + { + LoginPanelVisibility = true; + Header = ImageHelper.LoadFromResource(new Uri("avares://DownKyi/Resources/default_header.jpg")); + UserName = null; + return; + } + + LoginPanelVisibility = true; + + if (userInfo != null) + { + if (userInfo.Face != null) + { + Header = new StorageHeader().GetHeaderThumbnail(userInfo.Mid, userInfo.Name, userInfo.Face, 36, 36); + } + else + { + Header = ImageHelper.LoadFromResource(new Uri("avares://DownKyi/Resources/default_header.jpg")); + } + + UserName = userInfo.Name; + } + else + { + Header = ImageHelper.LoadFromResource(new Uri("avares://DownKyi/Resources/default_header.jpg")); + UserName = null; + } + } + catch (Exception e) + { + Console.PrintLine("UpdateUserInfo()发生异常: {0}", e); + LogManager.Error(Tag, e); + } + } + + public override void OnNavigatedTo(NavigationContext navigationContext) + { + base.OnNavigatedTo(navigationContext); + + DownloadManager = ButtonIcon.Instance().DownloadManage; + DownloadManager.Height = 27; + DownloadManager.Width = 32; + DownloadManager.Fill = DictionaryResource.GetColor("ColorPrimary"); + + // 根据传入参数不同执行不同任务 + string parameter = navigationContext.Parameters.GetValue("Parameter"); + if (parameter == null) + { + // 其他情况只更新设置的用户信息,不更新UI + UpdateUserInfo(true); + return; + } + + // 启动 + if (parameter == "start") + { + UpdateUserInfo(); + } + // 从登录页面返回 + else if (parameter == "login") + { + UpdateUserInfo(); + } + // 注销 + else if (parameter == "logout") + { + UpdateUserInfo(); + } + else + { + // 其他情况只更新设置的用户信息,不更新UI + UpdateUserInfo(true); + } + } +} \ No newline at end of file diff --git a/DownKyi/ViewModels/ViewLoginViewModel.cs b/DownKyi/ViewModels/ViewLoginViewModel.cs new file mode 100644 index 0000000..2e5c711 --- /dev/null +++ b/DownKyi/ViewModels/ViewLoginViewModel.cs @@ -0,0 +1,252 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Avalonia.Media.Imaging; +using DownKyi.Core.BiliApi.Login; +using DownKyi.Core.Logging; +using DownKyi.Events; +using DownKyi.Images; +using DownKyi.Utils; +using Prism.Commands; +using Prism.Events; +using Prism.Regions; +using Console = DownKyi.Core.Utils.Debugging.Console; + +namespace DownKyi.ViewModels; + +public class ViewLoginViewModel : ViewModelBase +{ + public const string Tag = "PageLogin"; + + private CancellationTokenSource _tokenSource; + + private VectorImage _arrowBack; + + public VectorImage ArrowBack + { + get => _arrowBack; + set => SetProperty(ref _arrowBack, value); + } + + private Bitmap? _loginQrCode; + + public Bitmap? LoginQrCode + { + get => _loginQrCode; + set => SetProperty(ref _loginQrCode, value); + } + + private double _loginQrCodeOpacity; + + public double LoginQrCodeOpacity + { + get => _loginQrCodeOpacity; + set => SetProperty(ref _loginQrCodeOpacity, value); + } + + private bool _loginQrCodeStatus; + + public bool LoginQrCodeStatus + { + get => _loginQrCodeStatus; + set => SetProperty(ref _loginQrCodeStatus, value); + } + + + public ViewLoginViewModel(IEventAggregator eventAggregator) : base(eventAggregator) + { + #region 属性初始化 + + ArrowBack = NavigationIcon.Instance().ArrowBack; + ArrowBack.Fill = DictionaryResource.GetColor("ColorTextDark"); + + #endregion + } + + private DelegateCommand? _backSpaceCommand; + + public DelegateCommand BackSpaceCommand => + _backSpaceCommand ??= new DelegateCommand(ExecuteBackSpace); + + private void ExecuteBackSpace() + { + // 初始化状态 + InitStatus(); + + // 结束任务 + _tokenSource.Cancel(); + NavigationParam parameter = new NavigationParam + { + ViewName = ParentView, + ParentViewName = null, + Parameter = "login" + }; + eventAggregator.GetEvent().Publish(parameter); + } + + /// + /// 登录 + /// + private void Login() + { + try + { + var loginUrl = LoginQR.GetLoginUrl(); + if (loginUrl == null) + { + return; + } + + if (loginUrl.Code != 0) + { + ExecuteBackSpace(); + return; + } + + if (loginUrl.Data == null || loginUrl.Data.Url == null) + { + eventAggregator.GetEvent().Publish(DictionaryResource.GetString("GetLoginUrlFailed")); + return; + } + + PropertyChangeAsync(() => { LoginQrCode = LoginQR.GetLoginQRCode(loginUrl.Data.Url); }); + Console.PrintLine(loginUrl.Data.Url + "\n"); + LogManager.Debug(Tag, loginUrl.Data.Url); + + GetLoginStatus(loginUrl.Data.QrcodeKey); + } + catch (Exception e) + { + Console.PrintLine("Login()发生异常: {0}", e); + LogManager.Error(Tag, e); + } + } + + /// + /// 循环查询登录状态 + /// + /// + private void GetLoginStatus(string oauthKey) + { + CancellationToken cancellationToken = _tokenSource.Token; + while (true) + { + Thread.Sleep(1000); + var loginStatus = LoginQR.GetLoginStatus(oauthKey); + if (loginStatus == null) + { + continue; + } + + Console.PrintLine(loginStatus.Data.Code + "\n" + loginStatus.Data.Message + "\n" + + loginStatus.Data.Url + "\n"); + + switch (loginStatus.Data.Code) + { + // case -1: + // // 没有这个oauthKey + // + // // 发送通知 + // eventAggregator.GetEvent().Publish(DictionaryResource.GetString("LoginKeyError")); + // LogManager.Info(Tag, DictionaryResource.GetString("LoginKeyError")); + // + // // 取消任务 + // tokenSource.Cancel(); + // + // // 创建新任务 + // PropertyChangeAsync(new Action(() => { Task.Run(Login, (tokenSource = new CancellationTokenSource()).Token); })); + // break; + case 86038: + // 不匹配的oauthKey,超时或已确认的oauthKey + + // 发送通知 + eventAggregator.GetEvent().Publish(DictionaryResource.GetString("LoginTimeOut")); + LogManager.Info(Tag, DictionaryResource.GetString("LoginTimeOut")); + + // 取消任务 + _tokenSource.Cancel(); + + // 创建新任务 + PropertyChangeAsync(() => + { + Task.Run(Login, (_tokenSource = new CancellationTokenSource()).Token); + }); + break; + case 86101: + // 未扫码 + break; + case 86090: + // 已扫码,未确认 + PropertyChangeAsync(() => + { + LoginQrCodeStatus = true; + LoginQrCodeOpacity = 0.3; + }); + break; + case 0: + // 确认登录 + + // 发送通知 + eventAggregator.GetEvent().Publish("登陆成功"); + // LogManager.Info(Tag, DictionaryResource.GetString("LoginSuccessful")); + + // 保存登录信息 + try + { + System.Console.Out.WriteLine(loginStatus.Data.Url); + bool isSucceed = LoginHelper.SaveLoginInfoCookies(loginStatus.Data.Url); + if (!isSucceed) + { + eventAggregator.GetEvent() + .Publish(DictionaryResource.GetString("LoginFailed")); + LogManager.Error(Tag, DictionaryResource.GetString("LoginFailed")); + } + } + catch (Exception e) + { + Console.PrintLine("PageLogin 保存登录信息发生异常: {0}", e); + LogManager.Error(e); + eventAggregator.GetEvent().Publish(DictionaryResource.GetString("LoginFailed")); + } + + // TODO 其他操作 + + + // 取消任务 + Thread.Sleep(3000); + PropertyChangeAsync(ExecuteBackSpace); + break; + } + + // 判断是否该结束线程,若为true,跳出while循环 + if (cancellationToken.IsCancellationRequested) + { + Console.PrintLine("停止Login线程,跳出while循环"); + LogManager.Debug(Tag, "登录操作结束"); + break; + } + } + } + + + /// + /// 初始化状态 + /// + private void InitStatus() + { + ArrowBack.Fill = DictionaryResource.GetColor("ColorTextDark"); + + LoginQrCode = null; + LoginQrCodeOpacity = 1; + LoginQrCodeStatus = false; + } + + public override void OnNavigatedTo(NavigationContext navigationContext) + { + base.OnNavigatedTo(navigationContext); + + InitStatus(); + + Task.Run(Login, (_tokenSource = new CancellationTokenSource()).Token); + } +} \ No newline at end of file diff --git a/DownKyi/ViewModels/ViewModelBase.cs b/DownKyi/ViewModels/ViewModelBase.cs new file mode 100644 index 0000000..36cd44f --- /dev/null +++ b/DownKyi/ViewModels/ViewModelBase.cs @@ -0,0 +1,56 @@ +using System; +using System.ComponentModel; +using Avalonia; +using Avalonia.Threading; +using Prism.Events; +using Prism.Mvvm; +using Prism.Regions; +using Prism.Services.Dialogs; + +namespace DownKyi.ViewModels; + +public class ViewModelBase : BindableBase, INavigationAware +{ + protected readonly IEventAggregator eventAggregator; + protected IDialogService dialogService; + protected string ParentView = string.Empty; + public event PropertyChangedEventHandler PropertyChanged; + + public ViewModelBase(IEventAggregator eventAggregator) + { + this.eventAggregator = eventAggregator; + } + + public ViewModelBase(IEventAggregator eventAggregator, IDialogService dialogService) + { + this.eventAggregator = eventAggregator; + this.dialogService = dialogService; + } + + public virtual void OnNavigatedTo(NavigationContext navigationContext) + { + string viewName = navigationContext.Parameters.GetValue("Parent"); + if (viewName != null) + { + ParentView = viewName; + } + } + + public bool IsNavigationTarget(NavigationContext navigationContext) + { + return true; + } + + public virtual void OnNavigatedFrom(NavigationContext navigationContext) + { + } + + /// + /// 异步修改绑定到UI的属性 + /// + /// + protected void PropertyChangeAsync(Action callback) + { + Dispatcher.UIThread.InvokeAsync(callback); + } +} \ No newline at end of file diff --git a/DownKyi/ViewModels/ViewMyBangumiFollowViewModel.cs b/DownKyi/ViewModels/ViewMyBangumiFollowViewModel.cs new file mode 100644 index 0000000..22ec1d4 --- /dev/null +++ b/DownKyi/ViewModels/ViewMyBangumiFollowViewModel.cs @@ -0,0 +1,591 @@ +using System; +using System.Collections; +using System.Collections.ObjectModel; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Avalonia.Media.Imaging; +using DownKyi.Core.BiliApi.BiliUtils; +using DownKyi.Core.BiliApi.Users.Models; +using DownKyi.Core.BiliApi.VideoStream; +using DownKyi.Core.Storage; +using DownKyi.CustomControl; +using DownKyi.Events; +using DownKyi.Images; +using DownKyi.Services; +using DownKyi.Services.Download; +using DownKyi.Utils; +using DownKyi.ViewModels.PageViewModels; +using Prism.Commands; +using Prism.Events; +using Prism.Regions; +using Prism.Services.Dialogs; + +namespace DownKyi.ViewModels; + +public class ViewMyBangumiFollowViewModel : ViewModelBase +{ + public const string Tag = "PageMyBangumiFollow"; + + private CancellationTokenSource tokenSource; + + private long mid = -1; + + // 每页视频数量,暂时在此写死,以后在设置中增加选项 + private readonly int VideoNumberInPage = 15; + + #region 页面属性申明 + + private string pageName = Tag; + + public string PageName + { + get => pageName; + set => SetProperty(ref pageName, value); + } + + private VectorImage arrowBack; + + public VectorImage ArrowBack + { + get => arrowBack; + set => SetProperty(ref arrowBack, value); + } + + private VectorImage downloadManage; + + public VectorImage DownloadManage + { + get => downloadManage; + set => SetProperty(ref downloadManage, value); + } + + private ObservableCollection tabHeaders; + + public ObservableCollection TabHeaders + { + get => tabHeaders; + set => SetProperty(ref tabHeaders, value); + } + + private int selectTabId; + + public int SelectTabId + { + get => selectTabId; + set => SetProperty(ref selectTabId, value); + } + + private bool isEnabled = true; + + public bool IsEnabled + { + get => isEnabled; + set => SetProperty(ref isEnabled, value); + } + + private bool contentVisibility; + + public bool ContentVisibility + { + get => contentVisibility; + set => SetProperty(ref contentVisibility, value); + } + + private CustomPagerViewModel pager; + + public CustomPagerViewModel Pager + { + get => pager; + set => SetProperty(ref pager, value); + } + + private ObservableCollection medias; + + public ObservableCollection Medias + { + get => medias; + set => SetProperty(ref medias, value); + } + + private bool isSelectAll; + + public bool IsSelectAll + { + get => isSelectAll; + set => SetProperty(ref isSelectAll, value); + } + + private bool loading; + public bool Loading + { + get => loading; + set => SetProperty(ref loading, value); + } + + private bool loadingVisibility; + + public bool LoadingVisibility + { + get => loadingVisibility; + set => SetProperty(ref loadingVisibility, value); + } + + private bool noDataVisibility; + + public bool NoDataVisibility + { + get => noDataVisibility; + set => SetProperty(ref noDataVisibility, value); + } + + #endregion + + public ViewMyBangumiFollowViewModel(IEventAggregator eventAggregator, IDialogService dialogService) : base( + eventAggregator) + { + this.dialogService = dialogService; + + #region 属性初始化 + + // 初始化loading + Loading = true; + LoadingVisibility = false; + NoDataVisibility = false; + + ArrowBack = NavigationIcon.Instance().ArrowBack; + ArrowBack.Fill = DictionaryResource.GetColor("ColorTextDark"); + + // 下载管理按钮 + DownloadManage = ButtonIcon.Instance().DownloadManage; + DownloadManage.Height = 24; + DownloadManage.Width = 24; + DownloadManage.Fill = DictionaryResource.GetColor("ColorPrimary"); + + TabHeaders = new ObservableCollection + { + new() { Id = (long)BangumiType.ANIME, Title = DictionaryResource.GetString("FollowAnime") }, + new() { Id = (long)BangumiType.EPISODE, Title = DictionaryResource.GetString("FollowMovie") } + }; + + Medias = new ObservableCollection(); + + #endregion + } + + #region 命令申明 + + // 返回事件 + private DelegateCommand backSpaceCommand; + + public DelegateCommand BackSpaceCommand => + backSpaceCommand ?? (backSpaceCommand = new DelegateCommand(ExecuteBackSpace)); + + /// + /// 返回事件 + /// + private void ExecuteBackSpace() + { + InitView(); + + ArrowBack.Fill = DictionaryResource.GetColor("ColorText"); + + // 结束任务 + tokenSource?.Cancel(); + + NavigationParam parameter = new NavigationParam + { + ViewName = ParentView, + ParentViewName = null, + Parameter = null + }; + eventAggregator.GetEvent().Publish(parameter); + } + + // 前往下载管理页面 + private DelegateCommand downloadManagerCommand; + + public DelegateCommand DownloadManagerCommand => downloadManagerCommand ?? + (downloadManagerCommand = + new DelegateCommand(ExecuteDownloadManagerCommand)); + + /// + /// 前往下载管理页面 + /// + private void ExecuteDownloadManagerCommand() + { + NavigationParam parameter = new NavigationParam + { + ViewName = ViewDownloadManagerViewModel.Tag, + ParentViewName = Tag, + Parameter = null + }; + eventAggregator.GetEvent().Publish(parameter); + } + + // 顶部tab点击事件 + private DelegateCommand tabHeadersCommand; + + public DelegateCommand TabHeadersCommand => tabHeadersCommand ?? (tabHeadersCommand = + new DelegateCommand(ExecuteTabHeadersCommand, CanExecuteTabHeadersCommand)); + + /// + /// 顶部tab点击事件 + /// + /// + private void ExecuteTabHeadersCommand(object parameter) + { + if (!(parameter is TabHeader tabHeader)) + { + return; + } + + // 顶部tab点击后,隐藏Content + ContentVisibility = false; + + // 页面选择 + Pager = new CustomPagerViewModel(1, 1); + Pager.CurrentChanged += OnCurrentChanged_Pager; + Pager.CountChanged += OnCountChanged_Pager; + Pager.Current = 1; + } + + /// + /// 顶部tab点击事件是否允许执行 + /// + /// + /// + private bool CanExecuteTabHeadersCommand(object parameter) + { + return IsEnabled; + } + + // 全选按钮点击事件 + private DelegateCommand selectAllCommand; + + public DelegateCommand SelectAllCommand => selectAllCommand ?? + (selectAllCommand = + new DelegateCommand(ExecuteSelectAllCommand)); + + /// + /// 全选按钮点击事件 + /// + /// + private void ExecuteSelectAllCommand(object parameter) + { + if (IsSelectAll) + { + foreach (var item in Medias) + { + item.IsSelected = true; + } + } + else + { + foreach (var item in Medias) + { + item.IsSelected = false; + } + } + } + + // 列表选择事件 + private DelegateCommand mediasCommand; + + public DelegateCommand MediasCommand => + mediasCommand ?? (mediasCommand = new DelegateCommand(ExecuteMediasCommand)); + + /// + /// 列表选择事件 + /// + /// + private void ExecuteMediasCommand(object parameter) + { + if (!(parameter is IList selectedMedia)) + { + return; + } + + if (selectedMedia.Count == Medias.Count) + { + IsSelectAll = true; + } + else + { + IsSelectAll = false; + } + } + + // 添加选中项到下载列表事件 + private DelegateCommand addToDownloadCommand; + + public DelegateCommand AddToDownloadCommand => addToDownloadCommand ?? + (addToDownloadCommand = + new DelegateCommand(ExecuteAddToDownloadCommand)); + + /// + /// 添加选中项到下载列表事件 + /// + private void ExecuteAddToDownloadCommand() + { + AddToDownload(true); + } + + // 添加所有视频到下载列表事件 + private DelegateCommand addAllToDownloadCommand; + + public DelegateCommand AddAllToDownloadCommand => addAllToDownloadCommand ?? + (addAllToDownloadCommand = + new DelegateCommand(ExecuteAddAllToDownloadCommand)); + + /// + /// 添加所有视频到下载列表事件 + /// + private void ExecuteAddAllToDownloadCommand() + { + AddToDownload(false); + } + + #endregion + + /// + /// 添加到下载 + /// + /// + private async void AddToDownload(bool isOnlySelected) + { + // 订阅里只有BANGUMI类型 + AddToDownloadService addToDownloadService = new AddToDownloadService(PlayStreamType.BANGUMI); + + // 选择文件夹 + string directory = await addToDownloadService.SetDirectory(dialogService); + + // 视频计数 + int i = 0; + await Task.Run(() => + { + // 为了避免执行其他操作时, + // Medias变化导致的异常 + var list = Medias.ToList(); + + // 添加到下载 + foreach (var media in list) + { + // 只下载选中项,跳过未选中项 + if (isOnlySelected && !media.IsSelected) + { + continue; + } + + /// 有分P的就下载全部 + + // 开启服务 + BangumiInfoService service = + new BangumiInfoService($"{ParseEntrance.BangumiMediaUrl}md{media.MediaId}"); + + addToDownloadService.SetVideoInfoService(service); + addToDownloadService.GetVideo(); + addToDownloadService.ParseVideo(service); + // 下载 + i += addToDownloadService.AddToDownload(eventAggregator, directory); + } + }); + + if (directory == null) + { + return; + } + + // 通知用户添加到下载列表的结果 + if (i <= 0) + { + eventAggregator.GetEvent().Publish(DictionaryResource.GetString("TipAddDownloadingZero")); + } + else + { + eventAggregator.GetEvent() + .Publish( + $"{DictionaryResource.GetString("TipAddDownloadingFinished1")}{i}{DictionaryResource.GetString("TipAddDownloadingFinished2")}"); + } + } + + private void OnCountChanged_Pager(int count) + { + } + + private bool OnCurrentChanged_Pager(int old, int current) + { + if (!IsEnabled) + { + //Pager.Current = old; + return false; + } + + UpdateBangumiMediaList(current); + + return true; + } + + private async void UpdateBangumiMediaList(int current) + { + Medias.Clear(); + IsSelectAll = false; + + LoadingVisibility = true; + NoDataVisibility = false; + + // 是否正在获取数据 + // 在所有的退出分支中都需要设为true + IsEnabled = false; + + var tab = TabHeaders[SelectTabId]; + BangumiType type = (BangumiType)tab.Id; + + await Task.Run(() => + { + CancellationToken cancellationToken = tokenSource.Token; + + var bangumiFollows = + Core.BiliApi.Users.UserSpace.GetBangumiFollow(mid, type, current, VideoNumberInPage); + if (bangumiFollows == null || bangumiFollows.List == null || bangumiFollows.List.Count == 0) + { + LoadingVisibility = false; + NoDataVisibility = true; + return; + } + + // 更新总页码 + Pager.Count = (int)Math.Ceiling((double)bangumiFollows.Total / VideoNumberInPage); + // 更新内容 + ContentVisibility = true; + + foreach (var bangumiFollow in bangumiFollows.List) + { + // 查询、保存封面 + string coverUrl = bangumiFollow.Cover; + Bitmap cover; + if (coverUrl == null || coverUrl == "") + { + cover = null; + } + else + { + if (!coverUrl.ToLower().StartsWith("http")) + { + coverUrl = $"https:{bangumiFollow.Cover}"; + } + + StorageCover storageCover = new StorageCover(); + cover = storageCover.GetCoverThumbnail(bangumiFollow.MediaId, bangumiFollow.SeasonId.ToString(), + -1, coverUrl, 110, 140); + } + + // 地区 + string area = string.Empty; + if (bangumiFollow.Areas != null && bangumiFollow.Areas.Count > 0) + { + area = bangumiFollow.Areas[0].Name; + } + + // 视频更新进度 + string indexShow = string.Empty; + if (bangumiFollow.NewEp != null) + { + indexShow = bangumiFollow.NewEp.IndexShow; + } + + // 观看进度 + string progress; + if (bangumiFollow.Progress == null || bangumiFollow.Progress == "") + { + progress = DictionaryResource.GetString("BangumiNotWatched"); + } + else + { + progress = bangumiFollow.Progress; + } + + App.PropertyChangeAsync(() => + { + BangumiFollowMedia media = new BangumiFollowMedia(eventAggregator) + { + MediaId = bangumiFollow.MediaId, + SeasonId = bangumiFollow.SeasonId, + Title = bangumiFollow.Title, + SeasonTypeName = bangumiFollow.SeasonTypeName, + Area = area, + Badge = bangumiFollow.Badge, + Cover = cover ?? + ImageHelper.LoadFromResource( + new Uri($"avares://DownKyi/Resources/video-placeholder.png")), + Evaluate = bangumiFollow.Evaluate, + IndexShow = indexShow, + Progress = progress + }; + + Medias.Add(media); + + LoadingVisibility = false; + NoDataVisibility = false; + }); + + // 判断是否该结束线程,若为true,跳出循环 + if (cancellationToken.IsCancellationRequested) + { + break; + } + } + }, (tokenSource = new CancellationTokenSource()).Token); + + IsEnabled = true; + } + + /// + /// 初始化页面数据 + /// + private void InitView() + { + ArrowBack.Fill = DictionaryResource.GetColor("ColorTextDark"); + + ContentVisibility = false; + LoadingVisibility = true; + NoDataVisibility = false; + + Medias.Clear(); + IsSelectAll = false; + } + + /// + /// 导航到页面时执行 + /// + /// + public override void OnNavigatedTo(NavigationContext navigationContext) + { + base.OnNavigatedTo(navigationContext); + + ArrowBack.Fill = DictionaryResource.GetColor("ColorTextDark"); + + DownloadManage = ButtonIcon.Instance().DownloadManage; + DownloadManage.Height = 24; + DownloadManage.Width = 24; + DownloadManage.Fill = DictionaryResource.GetColor("ColorPrimary"); + + // 根据传入参数不同执行不同任务 + mid = navigationContext.Parameters.GetValue("Parameter"); + if (mid == 0) + { + return; + } + + InitView(); + + // 初始选中项 + SelectTabId = 0; + + // 页面选择 + Pager = new CustomPagerViewModel(1, 1); + Pager.CurrentChanged += OnCurrentChanged_Pager; + Pager.CountChanged += OnCountChanged_Pager; + Pager.Current = 1; + } +} \ No newline at end of file diff --git a/DownKyi/ViewModels/ViewMyFavoritesViewModel.cs b/DownKyi/ViewModels/ViewMyFavoritesViewModel.cs new file mode 100644 index 0000000..dedceee --- /dev/null +++ b/DownKyi/ViewModels/ViewMyFavoritesViewModel.cs @@ -0,0 +1,571 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using DownKyi.Core.BiliApi.Favorites; +using DownKyi.Core.BiliApi.VideoStream; +using DownKyi.CustomControl; +using DownKyi.Events; +using DownKyi.Images; +using DownKyi.Services; +using DownKyi.Services.Download; +using DownKyi.Utils; +using DownKyi.ViewModels.PageViewModels; +using Prism.Commands; +using Prism.Events; +using Prism.Regions; +using Prism.Services.Dialogs; + +namespace DownKyi.ViewModels; + +public class ViewMyFavoritesViewModel : ViewModelBase +{ + public const string Tag = "PageMyFavorites"; + + //private readonly IDialogService dialogService; + + private CancellationTokenSource tokenSource1; + private CancellationTokenSource tokenSource2; + + private long mid = -1; + + // 每页视频数量,暂时在此写死,以后在设置中增加选项 + private readonly int VideoNumberInPage = 20; + + #region 页面属性申明 + + private string pageName = Tag; + + public string PageName + { + get => pageName; + set => SetProperty(ref pageName, value); + } + + private bool contentVisibility; + + public bool ContentVisibility + { + get => contentVisibility; + set => SetProperty(ref contentVisibility, value); + } + + private bool loading; + public bool Loading + { + get => loading; + set => SetProperty(ref loading, value); + } + + private bool loadingVisibility; + + public bool LoadingVisibility + { + get => loadingVisibility; + set => SetProperty(ref loadingVisibility, value); + } + + private bool noDataVisibility; + + public bool NoDataVisibility + { + get => noDataVisibility; + set => SetProperty(ref noDataVisibility, value); + } + + private bool mediaLoading; + public bool MediaLoading + { + get => mediaLoading; + set => SetProperty(ref mediaLoading, value); + } + + private bool mediaContentVisibility; + + public bool MediaContentVisibility + { + get => mediaContentVisibility; + set => SetProperty(ref mediaContentVisibility, value); + } + + private bool mediaLoadingVisibility; + + public bool MediaLoadingVisibility + { + get => mediaLoadingVisibility; + set => SetProperty(ref mediaLoadingVisibility, value); + } + + private bool mediaNoDataVisibility; + + public bool MediaNoDataVisibility + { + get => mediaNoDataVisibility; + set => SetProperty(ref mediaNoDataVisibility, value); + } + + private VectorImage arrowBack; + + public VectorImage ArrowBack + { + get => arrowBack; + set => SetProperty(ref arrowBack, value); + } + + private VectorImage downloadManage; + + public VectorImage DownloadManage + { + get => downloadManage; + set => SetProperty(ref downloadManage, value); + } + + private ObservableCollection tabHeaders; + + public ObservableCollection TabHeaders + { + get => tabHeaders; + set => SetProperty(ref tabHeaders, value); + } + + private int selectTabId; + + public int SelectTabId + { + get => selectTabId; + set => SetProperty(ref selectTabId, value); + } + + private bool isEnabled = true; + + public bool IsEnabled + { + get => isEnabled; + set => SetProperty(ref isEnabled, value); + } + + private CustomPagerViewModel pager; + + public CustomPagerViewModel Pager + { + get => pager; + set => SetProperty(ref pager, value); + } + + private ObservableCollection medias; + + public ObservableCollection Medias + { + get => medias; + set => SetProperty(ref medias, value); + } + + private bool isSelectAll; + + public bool IsSelectAll + { + get => isSelectAll; + set => SetProperty(ref isSelectAll, value); + } + + #endregion + + public ViewMyFavoritesViewModel(IEventAggregator eventAggregator, IDialogService dialogService) : base( + eventAggregator) + { + this.dialogService = dialogService; + + #region 属性初始化 + + // 初始化loading gif + Loading = true; + LoadingVisibility = false; + NoDataVisibility = false; + + MediaLoading = true; + MediaLoadingVisibility = false; + MediaNoDataVisibility = false; + + ArrowBack = NavigationIcon.Instance().ArrowBack; + ArrowBack.Fill = DictionaryResource.GetColor("ColorTextDark"); + + // 下载管理按钮 + DownloadManage = ButtonIcon.Instance().DownloadManage; + DownloadManage.Height = 24; + DownloadManage.Width = 24; + DownloadManage.Fill = DictionaryResource.GetColor("ColorPrimary"); + + TabHeaders = new ObservableCollection(); + Medias = new ObservableCollection(); + + #endregion + } + + #region 命令申明 + + // 返回事件 + private DelegateCommand backSpaceCommand; + + public DelegateCommand BackSpaceCommand => + backSpaceCommand ?? (backSpaceCommand = new DelegateCommand(ExecuteBackSpace)); + + /// + /// 返回事件 + /// + private void ExecuteBackSpace() + { + InitView(); + + ArrowBack.Fill = DictionaryResource.GetColor("ColorText"); + + // 结束任务 + tokenSource1?.Cancel(); + tokenSource2?.Cancel(); + + NavigationParam parameter = new NavigationParam + { + ViewName = ParentView, + ParentViewName = null, + Parameter = null + }; + eventAggregator.GetEvent().Publish(parameter); + } + + // 前往下载管理页面 + private DelegateCommand downloadManagerCommand; + + public DelegateCommand DownloadManagerCommand => downloadManagerCommand ?? + (downloadManagerCommand = + new DelegateCommand(ExecuteDownloadManagerCommand)); + + /// + /// 前往下载管理页面 + /// + private void ExecuteDownloadManagerCommand() + { + NavigationParam parameter = new NavigationParam + { + ViewName = ViewDownloadManagerViewModel.Tag, + ParentViewName = Tag, + Parameter = null + }; + eventAggregator.GetEvent().Publish(parameter); + } + + // 左侧tab点击事件 + private DelegateCommand leftTabHeadersCommand; + + public DelegateCommand LeftTabHeadersCommand => leftTabHeadersCommand ?? (leftTabHeadersCommand = + new DelegateCommand(ExecuteLeftTabHeadersCommand, CanExecuteLeftTabHeadersCommand)); + + /// + /// 左侧tab点击事件 + /// + /// + private void ExecuteLeftTabHeadersCommand(object parameter) + { + if (!(parameter is TabHeader tabHeader)) + { + return; + } + + // tab点击后,隐藏MediaContent + MediaContentVisibility = false; + + // 页面选择 + Pager = new CustomPagerViewModel(1, (int)Math.Ceiling(double.Parse(tabHeader.SubTitle) / VideoNumberInPage)); + Pager.CurrentChanged += OnCurrentChanged_Pager; + Pager.CountChanged += OnCountChanged_Pager; + Pager.Current = 1; + } + + /// + /// 左侧tab点击事件是否允许执行 + /// + /// + /// + private bool CanExecuteLeftTabHeadersCommand(object parameter) + { + return IsEnabled; + } + + // 全选按钮点击事件 + private DelegateCommand selectAllCommand; + + public DelegateCommand SelectAllCommand => + selectAllCommand ?? (selectAllCommand = new DelegateCommand(ExecuteSelectAllCommand)); + + /// + /// 全选按钮点击事件 + /// + /// + private void ExecuteSelectAllCommand(object parameter) + { + if (IsSelectAll) + { + foreach (var item in Medias) + { + item.IsSelected = true; + } + } + else + { + foreach (var item in Medias) + { + item.IsSelected = false; + } + } + } + + // 列表选择事件 + private DelegateCommand mediasCommand; + + public DelegateCommand MediasCommand => + mediasCommand ?? (mediasCommand = new DelegateCommand(ExecuteMediasCommand)); + + /// + /// 列表选择事件 + /// + /// + private void ExecuteMediasCommand(object parameter) + { + if (!(parameter is IList selectedMedia)) + { + return; + } + + if (selectedMedia.Count == Medias.Count) + { + IsSelectAll = true; + } + else + { + IsSelectAll = false; + } + } + + // 添加选中项到下载列表事件 + private DelegateCommand addToDownloadCommand; + + public DelegateCommand AddToDownloadCommand => addToDownloadCommand ?? + (addToDownloadCommand = + new DelegateCommand(ExecuteAddToDownloadCommand)); + + /// + /// 添加选中项到下载列表事件 + /// + private void ExecuteAddToDownloadCommand() + { + AddToDownload(true); + } + + // 添加所有视频到下载列表事件 + private DelegateCommand addAllToDownloadCommand; + + public DelegateCommand AddAllToDownloadCommand => addAllToDownloadCommand ?? + (addAllToDownloadCommand = + new DelegateCommand(ExecuteAddAllToDownloadCommand)); + + /// + /// 添加所有视频到下载列表事件 + /// + private void ExecuteAddAllToDownloadCommand() + { + AddToDownload(false); + } + + #endregion + + /// + /// 添加到下载 + /// + /// + private async void AddToDownload(bool isOnlySelected) + { + // 收藏夹里只有视频 + AddToDownloadService addToDownloadService = new AddToDownloadService(PlayStreamType.VIDEO); + + // 选择文件夹 + string directory = await addToDownloadService.SetDirectory(dialogService); + + // 视频计数 + int i = 0; + await Task.Run(() => + { + // 为了避免执行其他操作时, + // Medias变化导致的异常 + var list = Medias.ToList(); + + // 添加到下载 + foreach (var media in list) + { + // 只下载选中项,跳过未选中项 + if (isOnlySelected && !media.IsSelected) + { + continue; + } + + /// 有分P的就下载全部 + + // 开启服务 + VideoInfoService videoInfoService = new VideoInfoService(media.Bvid); + + addToDownloadService.SetVideoInfoService(videoInfoService); + addToDownloadService.GetVideo(); + addToDownloadService.ParseVideo(videoInfoService); + // 下载 + i += addToDownloadService.AddToDownload(eventAggregator, directory); + } + }); + + if (directory == null) + { + return; + } + + // 通知用户添加到下载列表的结果 + if (i <= 0) + { + eventAggregator.GetEvent().Publish(DictionaryResource.GetString("TipAddDownloadingZero")); + } + else + { + eventAggregator.GetEvent() + .Publish( + $"{DictionaryResource.GetString("TipAddDownloadingFinished1")}{i}{DictionaryResource.GetString("TipAddDownloadingFinished2")}"); + } + } + + private void OnCountChanged_Pager(int count) + { + } + + private bool OnCurrentChanged_Pager(int old, int current) + { + if (!IsEnabled) + { + //Pager.Current = old; + return false; + } + + UpdateFavoritesMediaList(current); + + return true; + } + + private async void UpdateFavoritesMediaList(int current) + { + Medias.Clear(); + IsSelectAll = false; + + MediaLoadingVisibility = true; + MediaNoDataVisibility = false; + + // 是否正在获取数据 + // 在所有的退出分支中都需要设为true + IsEnabled = false; + + var tab = TabHeaders[SelectTabId]; + + await Task.Run(new Action(() => + { + CancellationToken cancellationToken = tokenSource2.Token; + + List medias = + FavoritesResource.GetFavoritesMedia(tab.Id, current, VideoNumberInPage); + if (medias == null || medias.Count == 0) + { + MediaContentVisibility = true; + MediaLoadingVisibility = false; + MediaNoDataVisibility = true; + return; + } + + MediaContentVisibility = true; + MediaLoadingVisibility = false; + MediaNoDataVisibility = false; + + var service = new FavoritesService(); + service.GetFavoritesMediaList(medias, Medias, eventAggregator, cancellationToken); + }), (tokenSource2 = new CancellationTokenSource()).Token); + + IsEnabled = true; + } + + /// + /// 初始化页面数据 + /// + private void InitView() + { + ArrowBack.Fill = DictionaryResource.GetColor("ColorTextDark"); + + DownloadManage = ButtonIcon.Instance().DownloadManage; + DownloadManage.Height = 24; + DownloadManage.Width = 24; + DownloadManage.Fill = DictionaryResource.GetColor("ColorPrimary"); + + ContentVisibility = false; + LoadingVisibility = true; + NoDataVisibility = false; + MediaLoadingVisibility = false; + MediaNoDataVisibility = false; + + TabHeaders.Clear(); + Medias.Clear(); + SelectTabId = -1; + IsSelectAll = false; + } + + /// + /// 导航到页面时执行 + /// + /// + public override async void OnNavigatedTo(NavigationContext navigationContext) + { + base.OnNavigatedTo(navigationContext); + + // 根据传入参数不同执行不同任务 + mid = navigationContext.Parameters.GetValue("Parameter"); + if (mid == 0) + { + return; + } + + InitView(); + + await Task.Run(() => + { + CancellationToken cancellationToken = tokenSource1.Token; + + var service = new FavoritesService(); + service.GetCreatedFavorites(mid, TabHeaders, cancellationToken); + service.GetCollectedFavorites(mid, TabHeaders, cancellationToken); + }, (tokenSource1 = new CancellationTokenSource()).Token); + + if (TabHeaders.Count == 0) + { + ContentVisibility = false; + LoadingVisibility = false; + NoDataVisibility = true; + + return; + } + + ContentVisibility = true; + LoadingVisibility = false; + NoDataVisibility = false; + + // 初始选中项 + SelectTabId = 0; + + // 页面选择 + Pager = new CustomPagerViewModel(1, + (int)Math.Ceiling(double.Parse(TabHeaders[0].SubTitle) / VideoNumberInPage)); + Pager.CurrentChanged += OnCurrentChanged_Pager; + Pager.CountChanged += OnCountChanged_Pager; + Pager.Current = 1; + } +} \ No newline at end of file diff --git a/DownKyi/ViewModels/ViewMyHistoryViewModel.cs b/DownKyi/ViewModels/ViewMyHistoryViewModel.cs new file mode 100644 index 0000000..be88cba --- /dev/null +++ b/DownKyi/ViewModels/ViewMyHistoryViewModel.cs @@ -0,0 +1,587 @@ +using System; +using System.Collections; +using System.Collections.ObjectModel; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Avalonia.Media.Imaging; +using DownKyi.Core.BiliApi.History; +using DownKyi.Core.BiliApi.VideoStream; +using DownKyi.Core.Storage; +using DownKyi.Core.Utils; +using DownKyi.Events; +using DownKyi.Images; +using DownKyi.Services; +using DownKyi.Services.Download; +using DownKyi.Utils; +using DownKyi.ViewModels.PageViewModels; +using Prism.Commands; +using Prism.Events; +using Prism.Regions; +using Prism.Services.Dialogs; + +namespace DownKyi.ViewModels; + +public class ViewMyHistoryViewModel : ViewModelBase +{ + public const string Tag = "PageMyHistory"; + + private CancellationTokenSource tokenSource; + + // 每页视频数量,暂时在此写死,以后在设置中增加选项 + private readonly int VideoNumberInPage = 30; + + #region 页面属性申明 + + private string pageName = Tag; + + public string PageName + { + get => pageName; + set => SetProperty(ref pageName, value); + } + + private VectorImage arrowBack; + + public VectorImage ArrowBack + { + get => arrowBack; + set => SetProperty(ref arrowBack, value); + } + + private VectorImage downloadManage; + + public VectorImage DownloadManage + { + get => downloadManage; + set => SetProperty(ref downloadManage, value); + } + + private bool contentVisibility; + + public bool ContentVisibility + { + get => contentVisibility; + set => SetProperty(ref contentVisibility, value); + } + + private ObservableCollection medias; + + public ObservableCollection Medias + { + get => medias; + set => SetProperty(ref medias, value); + } + + private bool isSelectAll; + + public bool IsSelectAll + { + get => isSelectAll; + set => SetProperty(ref isSelectAll, value); + } + + private bool loading; + public bool Loading + { + get => loading; + set => SetProperty(ref loading, value); + } + + private bool loadingVisibility; + + public bool LoadingVisibility + { + get => loadingVisibility; + set => SetProperty(ref loadingVisibility, value); + } + + private bool noDataVisibility; + + public bool NoDataVisibility + { + get => noDataVisibility; + set => SetProperty(ref noDataVisibility, value); + } + + #endregion + + public ViewMyHistoryViewModel(IEventAggregator eventAggregator, IDialogService dialogService) : base( + eventAggregator) + { + this.dialogService = dialogService; + + #region 属性初始化 + + // 初始化loading + Loading = true; + LoadingVisibility = false; + NoDataVisibility = false; + + ArrowBack = NavigationIcon.Instance().ArrowBack; + ArrowBack.Fill = DictionaryResource.GetColor("ColorTextDark"); + + // 下载管理按钮 + DownloadManage = ButtonIcon.Instance().DownloadManage; + DownloadManage.Height = 24; + DownloadManage.Width = 24; + DownloadManage.Fill = DictionaryResource.GetColor("ColorPrimary"); + + Medias = new ObservableCollection(); + + #endregion + } + + #region 命令申明 + + // 返回事件 + private DelegateCommand backSpaceCommand; + + public DelegateCommand BackSpaceCommand => + backSpaceCommand ?? (backSpaceCommand = new DelegateCommand(ExecuteBackSpace)); + + /// + /// 返回事件 + /// + private void ExecuteBackSpace() + { + InitView(); + + ArrowBack.Fill = DictionaryResource.GetColor("ColorText"); + + // 结束任务 + tokenSource?.Cancel(); + + NavigationParam parameter = new NavigationParam + { + ViewName = ParentView, + ParentViewName = null, + Parameter = null + }; + eventAggregator.GetEvent().Publish(parameter); + } + + // 前往下载管理页面 + private DelegateCommand downloadManagerCommand; + + public DelegateCommand DownloadManagerCommand => downloadManagerCommand ?? + (downloadManagerCommand = + new DelegateCommand(ExecuteDownloadManagerCommand)); + + /// + /// 前往下载管理页面 + /// + private void ExecuteDownloadManagerCommand() + { + NavigationParam parameter = new NavigationParam + { + ViewName = ViewDownloadManagerViewModel.Tag, + ParentViewName = Tag, + Parameter = null + }; + eventAggregator.GetEvent().Publish(parameter); + } + + // 全选按钮点击事件 + private DelegateCommand selectAllCommand; + + public DelegateCommand SelectAllCommand => + selectAllCommand ?? (selectAllCommand = new DelegateCommand(ExecuteSelectAllCommand)); + + /// + /// 全选按钮点击事件 + /// + /// + private void ExecuteSelectAllCommand(object parameter) + { + if (IsSelectAll) + { + foreach (var item in Medias) + { + item.IsSelected = true; + } + } + else + { + foreach (var item in Medias) + { + item.IsSelected = false; + } + } + } + + // 列表选择事件 + private DelegateCommand mediasCommand; + + public DelegateCommand MediasCommand => + mediasCommand ?? (mediasCommand = new DelegateCommand(ExecuteMediasCommand)); + + /// + /// 列表选择事件 + /// + /// + private void ExecuteMediasCommand(object parameter) + { + if (!(parameter is IList selectedMedia)) + { + return; + } + + if (selectedMedia.Count == Medias.Count) + { + IsSelectAll = true; + } + else + { + IsSelectAll = false; + } + } + + // 添加选中项到下载列表事件 + private DelegateCommand addToDownloadCommand; + + public DelegateCommand AddToDownloadCommand => addToDownloadCommand ?? + (addToDownloadCommand = + new DelegateCommand(ExecuteAddToDownloadCommand)); + + /// + /// 添加选中项到下载列表事件 + /// + private void ExecuteAddToDownloadCommand() + { + AddToDownload(true); + } + + // 添加所有视频到下载列表事件 + private DelegateCommand addAllToDownloadCommand; + + public DelegateCommand AddAllToDownloadCommand => addAllToDownloadCommand ?? + (addAllToDownloadCommand = + new DelegateCommand(ExecuteAddAllToDownloadCommand)); + + /// + /// 添加所有视频到下载列表事件 + /// + private void ExecuteAddAllToDownloadCommand() + { + AddToDownload(false); + } + + #endregion + + /// + /// 添加到下载 + /// + /// + private async void AddToDownload(bool isOnlySelected) + { + // BANGUMI类型 + AddToDownloadService addToDownloadService = new AddToDownloadService(PlayStreamType.VIDEO); + + // 选择文件夹 + string directory = await addToDownloadService.SetDirectory(dialogService); + + // 视频计数 + int i = 0; + await Task.Run(() => + { + // 为了避免执行其他操作时, + // Medias变化导致的异常 + var list = Medias.ToList(); + + // 添加到下载 + foreach (var media in list) + { + // 只下载选中项,跳过未选中项 + if (isOnlySelected && !media.IsSelected) + { + continue; + } + + /// 有分P的就下载全部 + + // 开启服务 + IInfoService service = null; + switch (media.Business) + { + case "archive": + service = new VideoInfoService(media.Url); + break; + case "pgc": + service = new BangumiInfoService(media.Url); + break; + } + + if (service == null) + { + return; + } + + addToDownloadService.SetVideoInfoService(service); + addToDownloadService.GetVideo(); + addToDownloadService.ParseVideo(service); + // 下载 + i += addToDownloadService.AddToDownload(eventAggregator, directory); + } + }); + + if (directory == null) + { + return; + } + + // 通知用户添加到下载列表的结果 + if (i <= 0) + { + eventAggregator.GetEvent().Publish(DictionaryResource.GetString("TipAddDownloadingZero")); + } + else + { + eventAggregator.GetEvent() + .Publish( + $"{DictionaryResource.GetString("TipAddDownloadingFinished1")}{i}{DictionaryResource.GetString("TipAddDownloadingFinished2")}"); + } + } + + private async void UpdateHistoryMediaList() + { + LoadingVisibility = true; + NoDataVisibility = false; + Medias.Clear(); + + await Task.Run(() => + { + CancellationToken cancellationToken = tokenSource.Token; + + var historyList = History.GetHistory(0, 0, VideoNumberInPage); + if (historyList == null || historyList.List == null || historyList.List.Count == 0) + { + LoadingVisibility = false; + NoDataVisibility = true; + return; + } + + foreach (var history in historyList.List) + { + if (history.History == null) + { + continue; + } + + if (history.History.Business != "archive" && history.History.Business != "pgc") + { + continue; + } + + // 播放url + string url = "https://www.bilibili.com"; + switch (history.History.Business) + { + case "archive": + url = "https://www.bilibili.com/video/" + history.History.Bvid; + break; + case "pgc": + url = history.Uri; + break; + } + + // 查询、保存封面 + string coverUrl = history.Cover; + Bitmap cover; + if (coverUrl == null || coverUrl == "") + { + cover = null; + } + else + { + if (!coverUrl.ToLower().StartsWith("http")) + { + coverUrl = $"https:{history.Cover}"; + } + + StorageCover storageCover = new StorageCover(); + cover = storageCover.GetCoverThumbnail(history.History.Oid, history.History.Bvid, + history.History.Cid, coverUrl, 160, 100); + } + + // 获取用户头像 + string upName; + Bitmap upHeader; + if (history.AuthorFace != null) + { + upName = history.AuthorName; + StorageHeader storageHeader = new StorageHeader(); + upHeader = storageHeader.GetHeaderThumbnail(history.AuthorMid, upName, history.AuthorFace, 24, 24); + } + else + { + upName = ""; + upHeader = null; + } + + + // 观看平台 + VectorImage platform; + switch (history.History.Dt) + { + case 1: + case 3: + case 5: + case 7: + // 手机端 + platform = NormalIcon.Instance().PlatformMobile; + break; + case 2: + // web端 + platform = NormalIcon.Instance().PlatformPC; + break; + case 4: + case 6: + // pad端 + platform = NormalIcon.Instance().PlatformIpad; + break; + case 33: + // TV端 + platform = NormalIcon.Instance().PlatformTV; + break; + default: + // 其他 + platform = null; + break; + } + + // 是否显示Partdesc + bool partdescVisibility; + if (history.NewDesc == "") + { + partdescVisibility = false; + } + else + { + partdescVisibility = true; + } + + // 是否显示UP主信息和分区信息 + bool upAndTagVisibility; + if (history.History.Business == "archive") + { + upAndTagVisibility = true; + } + else + { + upAndTagVisibility = false; + } + + App.PropertyChangeAsync(() => + { + // 观看进度 + // -1 已看完 + // 0 刚开始 + // >0 看到 progress + string progress; + if (history.Progress == -1) + { + progress = DictionaryResource.GetString("HistoryFinished"); + } + else if (history.Progress == 0) + { + progress = DictionaryResource.GetString("HistoryStarted"); + } + else + { + progress = DictionaryResource.GetString("HistoryWatch") + " " + + Format.FormatDuration3(history.Progress); + } + + HistoryMedia media = new HistoryMedia(eventAggregator) + { + Business = history.History.Business, + Bvid = history.History.Bvid, + Url = url, + UpMid = history.AuthorMid, + Cover = cover ?? + ImageHelper.LoadFromResource( + new Uri($"avares://DownKyi/Resources/video-placeholder.png")), + Title = history.Title, + SubTitle = history.ShowTitle, + Duration = history.Duration, + TagName = history.TagName, + Partdesc = history.NewDesc, + Progress = progress, + Platform = platform, + UpName = upName, + UpHeader = upHeader, + + PartdescVisibility = partdescVisibility, + UpAndTagVisibility = upAndTagVisibility, + }; + + Medias.Add(media); + + ContentVisibility = true; + LoadingVisibility = false; + NoDataVisibility = false; + }); + + // 判断是否该结束线程,若为true,跳出循环 + if (cancellationToken.IsCancellationRequested) + { + break; + } + } + }, (tokenSource = new CancellationTokenSource()).Token); + } + + /// + /// 初始化页面数据 + /// + private void InitView() + { + ArrowBack.Fill = DictionaryResource.GetColor("ColorTextDark"); + + DownloadManage = ButtonIcon.Instance().DownloadManage; + DownloadManage.Height = 24; + DownloadManage.Width = 24; + DownloadManage.Fill = DictionaryResource.GetColor("ColorPrimary"); + + ContentVisibility = false; + LoadingVisibility = false; + NoDataVisibility = false; + + Medias.Clear(); + IsSelectAll = false; + } + + /// + /// 导航到页面时执行 + /// + /// + public override void OnNavigatedTo(NavigationContext navigationContext) + { + base.OnNavigatedTo(navigationContext); + + ArrowBack.Fill = DictionaryResource.GetColor("ColorTextDark"); + + DownloadManage = ButtonIcon.Instance().DownloadManage; + DownloadManage.Height = 24; + DownloadManage.Width = 24; + DownloadManage.Fill = DictionaryResource.GetColor("ColorPrimary"); + + // 根据传入参数不同执行不同任务 + long mid = navigationContext.Parameters.GetValue("Parameter"); + if (mid == 0) + { + IsSelectAll = false; + foreach (var media in Medias) + { + media.IsSelected = false; + } + + return; + } + + InitView(); + + UpdateHistoryMediaList(); + } +} \ No newline at end of file diff --git a/DownKyi/ViewModels/ViewMySpaceViewModel.cs b/DownKyi/ViewModels/ViewMySpaceViewModel.cs new file mode 100644 index 0000000..d0616db --- /dev/null +++ b/DownKyi/ViewModels/ViewMySpaceViewModel.cs @@ -0,0 +1,733 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Threading; +using System.Threading.Tasks; +using Avalonia.Media.Imaging; +using DownKyi.Core.BiliApi.Login; +using DownKyi.Core.BiliApi.Users; +using DownKyi.Core.BiliApi.Users.Models; +using DownKyi.Core.Storage; +using DownKyi.Events; +using DownKyi.Images; +using DownKyi.Utils; +using DownKyi.ViewModels.PageViewModels; +using Prism.Commands; +using Prism.Events; +using Prism.Regions; + +namespace DownKyi.ViewModels; + +public class ViewMySpaceViewModel : ViewModelBase +{ + public const string Tag = "PageMySpace"; + + private CancellationTokenSource tokenSource; + + // mid + private long mid = -1; + + #region 页面属性申明 + + private VectorImage arrowBack; + + public VectorImage ArrowBack + { + get => arrowBack; + set => SetProperty(ref arrowBack, value); + } + + private VectorImage logout; + + public VectorImage Logout + { + get => logout; + set => SetProperty(ref logout, value); + } + + private bool loading; + public bool Loading + { + get => loading; + set => SetProperty(ref loading, value); + } + + private bool noDataVisibility; + + public bool NoDataVisibility + { + get => noDataVisibility; + set => SetProperty(ref noDataVisibility, value); + } + + private bool loadingVisibility; + + public bool LoadingVisibility + { + get => loadingVisibility; + set => SetProperty(ref loadingVisibility, value); + } + + private bool viewVisibility; + + public bool ViewVisibility + { + get => viewVisibility; + set => SetProperty(ref viewVisibility, value); + } + + private bool contentVisibility; + + public bool ContentVisibility + { + get => contentVisibility; + set => SetProperty(ref contentVisibility, value); + } + + private string topNavigationBg; + + public string TopNavigationBg + { + get => topNavigationBg; + set => SetProperty(ref topNavigationBg, value); + } + + private Bitmap background; + + public Bitmap Background + { + get => background; + set => SetProperty(ref background, value); + } + + private Bitmap header; + + public Bitmap Header + { + get => header; + set => SetProperty(ref header, value); + } + + private string userName; + + public string UserName + { + get => userName; + set => SetProperty(ref userName, value); + } + + private Bitmap sex; + + public Bitmap Sex + { + get => sex; + set => SetProperty(ref sex, value); + } + + private Bitmap level; + + public Bitmap Level + { + get => level; + set => SetProperty(ref level, value); + } + + private bool vipTypeVisibility; + + public bool VipTypeVisibility + { + get => vipTypeVisibility; + set => SetProperty(ref vipTypeVisibility, value); + } + + private string vipType; + + public string VipType + { + get => vipType; + set => SetProperty(ref vipType, value); + } + + private string sign; + + public string Sign + { + get => sign; + set => SetProperty(ref sign, value); + } + + private VectorImage coinIcon; + + public VectorImage CoinIcon + { + get => coinIcon; + set => SetProperty(ref coinIcon, value); + } + + private string coin; + + public string Coin + { + get => coin; + set => SetProperty(ref coin, value); + } + + private VectorImage moneyIcon; + + public VectorImage MoneyIcon + { + get => moneyIcon; + set => SetProperty(ref moneyIcon, value); + } + + private string money; + + public string Money + { + get => money; + set => SetProperty(ref money, value); + } + + private VectorImage bindingEmail; + + public VectorImage BindingEmail + { + get => bindingEmail; + set => SetProperty(ref bindingEmail, value); + } + + private bool bindingEmailVisibility; + + public bool BindingEmailVisibility + { + get => bindingEmailVisibility; + set => SetProperty(ref bindingEmailVisibility, value); + } + + private VectorImage bindingPhone; + + public VectorImage BindingPhone + { + get => bindingPhone; + set => SetProperty(ref bindingPhone, value); + } + + private bool bindingPhoneVisibility; + + public bool BindingPhoneVisibility + { + get => bindingPhoneVisibility; + set => SetProperty(ref bindingPhoneVisibility, value); + } + + private string levelText; + + public string LevelText + { + get => levelText; + set => SetProperty(ref levelText, value); + } + + private string currentExp; + + public string CurrentExp + { + get => currentExp; + set => SetProperty(ref currentExp, value); + } + + private int expProgress; + + public int ExpProgress + { + get => expProgress; + set => SetProperty(ref expProgress, value); + } + + private int maxExp; + + public int MaxExp + { + get => maxExp; + set => SetProperty(ref maxExp, value); + } + + private ObservableCollection statusList; + + public ObservableCollection StatusList + { + get => statusList; + set => SetProperty(ref statusList, value); + } + + private ObservableCollection packageList; + + public ObservableCollection PackageList + { + get => packageList; + set => SetProperty(ref packageList, value); + } + + private int selectedStatus = -1; + + public int SelectedStatus + { + get => selectedStatus; + set => SetProperty(ref selectedStatus, value); + } + + private int selectedPackage = -1; + + public int SelectedPackage + { + get => selectedPackage; + set => SetProperty(ref selectedPackage, value); + } + + #endregion + + public ViewMySpaceViewModel(IEventAggregator eventAggregator) : base(eventAggregator) + { + #region 属性初始化 + + // 返回按钮 + ArrowBack = NavigationIcon.Instance().ArrowBack; + ArrowBack.Fill = DictionaryResource.GetColor("ColorTextDark"); + + // 退出登录按钮 + Logout = NavigationIcon.Instance().Logout; + Logout.Fill = DictionaryResource.GetColor("ColorTextDark"); + + // 初始化loading + Loading = true; + + TopNavigationBg = "#00FFFFFF"; // 透明 + + // B站图标 + CoinIcon = NormalIcon.Instance().CoinIcon; + CoinIcon.Fill = DictionaryResource.GetColor("ColorPrimary"); + MoneyIcon = NormalIcon.Instance().MoneyIcon; + MoneyIcon.Fill = DictionaryResource.GetColor("ColorMoney"); + BindingEmail = NormalIcon.Instance().BindingEmail; + BindingEmail.Fill = DictionaryResource.GetColor("ColorPrimary"); + BindingPhone = NormalIcon.Instance().BindingPhone; + BindingPhone.Fill = DictionaryResource.GetColor("ColorPrimary"); + + StatusList = new ObservableCollection(); + PackageList = new ObservableCollection(); + + #endregion + } + + #region 命令申明 + + // 返回事件 + private DelegateCommand backSpaceCommand; + + public DelegateCommand BackSpaceCommand => + backSpaceCommand ?? (backSpaceCommand = new DelegateCommand(ExecuteBackSpace)); + + /// + /// 返回事件 + /// + private void ExecuteBackSpace() + { + // 结束任务 + tokenSource?.Cancel(); + + NavigationParam parameter = new NavigationParam + { + ViewName = ParentView, + ParentViewName = null, + Parameter = null + }; + eventAggregator.GetEvent().Publish(parameter); + } + + // 退出登录事件 + private DelegateCommand logoutCommand; + + public DelegateCommand LogoutCommand => + logoutCommand ?? (logoutCommand = new DelegateCommand(ExecuteLogoutCommand)); + + /// + /// 退出登录事件 + /// + private void ExecuteLogoutCommand() + { + // 注销 + LoginHelper.Logout(); + + // 返回上一页 + NavigationParam parameter = new NavigationParam + { + ViewName = ParentView, + ParentViewName = null, + Parameter = "logout" + }; + eventAggregator.GetEvent().Publish(parameter); + } + + // 页面选择事件 + private DelegateCommand statusListCommand; + + public DelegateCommand StatusListCommand => + statusListCommand ?? (statusListCommand = new DelegateCommand(ExecuteStatusListCommand)); + + /// + /// 页面选择事件 + /// + private void ExecuteStatusListCommand() + { + if (SelectedStatus == -1) + { + return; + } + + Dictionary data = new Dictionary + { + { "mid", mid }, + { "friendId", 0 } + }; + + switch (SelectedStatus) + { + case 0: + data["friendId"] = 0; + NavigateToView.NavigationView(eventAggregator, ViewFriendsViewModel.Tag, Tag, data); + break; + case 1: + data["friendId"] = 0; + NavigateToView.NavigationView(eventAggregator, ViewFriendsViewModel.Tag, Tag, data); + break; + case 2: + data["friendId"] = 1; + NavigateToView.NavigationView(eventAggregator, ViewFriendsViewModel.Tag, Tag, data); + break; + default: + break; + } + + SelectedStatus = -1; + } + + // 页面选择事件 + private DelegateCommand packageListCommand; + + public DelegateCommand PackageListCommand => packageListCommand ?? + (packageListCommand = + new DelegateCommand(ExecutePackageListCommand)); + + /// + /// 页面选择事件 + /// + /// + private void ExecutePackageListCommand() + { + if (SelectedPackage == -1) + { + return; + } + + switch (SelectedPackage) + { + case 0: + NavigateToView.NavigationView(eventAggregator, ViewMyFavoritesViewModel.Tag, Tag, mid); + break; + case 1: + NavigateToView.NavigationView(eventAggregator, ViewMyBangumiFollowViewModel.Tag, Tag, mid); + break; + case 2: + NavigateToView.NavigationView(eventAggregator, ViewMyToViewVideoViewModel.Tag, Tag, mid); + break; + case 3: + NavigateToView.NavigationView(eventAggregator, ViewMyHistoryViewModel.Tag, Tag, mid); + break; + default: + break; + } + + SelectedPackage = -1; + } + + #endregion + + /// + /// 初始化页面 + /// + private void InitView() + { + TopNavigationBg = "#00FFFFFF"; // 透明 + ArrowBack.Fill = DictionaryResource.GetColor("ColorTextDark"); + Logout.Fill = DictionaryResource.GetColor("ColorTextDark"); + Background = null; + + Header = null; + UserName = ""; + Sex = null; + Level = null; + VipTypeVisibility = false; + VipType = ""; + Sign = ""; + + Coin = "0.0"; + Money = "0.0"; + + LevelText = ""; + CurrentExp = "--/--"; + + StatusList.Clear(); + StatusList.Add(new SpaceItem + { IsEnabled = true, Title = DictionaryResource.GetString("Following"), Subtitle = "--" }); + StatusList.Add(new SpaceItem + { IsEnabled = true, Title = DictionaryResource.GetString("Whisper"), Subtitle = "--" }); + StatusList.Add(new SpaceItem + { IsEnabled = true, Title = DictionaryResource.GetString("Follower"), Subtitle = "--" }); + StatusList.Add(new SpaceItem + { IsEnabled = false, Title = DictionaryResource.GetString("Black"), Subtitle = "--" }); + StatusList.Add(new SpaceItem + { IsEnabled = false, Title = DictionaryResource.GetString("Moral"), Subtitle = "--" }); + StatusList.Add(new SpaceItem + { IsEnabled = false, Title = DictionaryResource.GetString("Silence"), Subtitle = "N/A" }); + + PackageList.Clear(); + PackageList.Add(new SpaceItem + { + IsEnabled = true, Image = NormalIcon.Instance().FavoriteOutline, + Title = DictionaryResource.GetString("Favorites") + }); + PackageList.Add(new SpaceItem + { + IsEnabled = true, Image = NormalIcon.Instance().Subscription, + Title = DictionaryResource.GetString("Subscription") + }); + PackageList.Add(new SpaceItem + { + IsEnabled = true, Image = NormalIcon.Instance().ToView, Title = DictionaryResource.GetString("ToView") + }); + PackageList.Add(new SpaceItem + { + IsEnabled = true, Image = NormalIcon.Instance().History, Title = DictionaryResource.GetString("History") + }); + NormalIcon.Instance().FavoriteOutline.Fill = DictionaryResource.GetColor("ColorPrimary"); + NormalIcon.Instance().Subscription.Fill = DictionaryResource.GetColor("ColorPrimary"); + NormalIcon.Instance().ToView.Fill = DictionaryResource.GetColor("ColorPrimary"); + NormalIcon.Instance().History.Fill = DictionaryResource.GetColor("ColorPrimary"); + + SelectedStatus = -1; + SelectedPackage = -1; + + ContentVisibility = false; + ViewVisibility = false; + LoadingVisibility = true; + NoDataVisibility = false; + } + + /// + /// 更新用户信息 + /// + private async void UpdateSpaceInfo() + { + bool isCancel = false; + bool isNoData = true; + Uri toutuUri = null; + string headerUri = null; + Uri sexUri = null; + Uri levelUri = null; + + await Task.Run(() => + { + CancellationToken cancellationToken = tokenSource.Token; + + // 背景图片 + SpaceSettings spaceSettings = Core.BiliApi.Users.UserSpace.GetSpaceSettings(mid); + if (spaceSettings != null) + { + StorageCover storageCover = new StorageCover(); + string toutu = storageCover.GetCover($"https://i0.hdslb.com/{spaceSettings.Toutu.Limg}"); + toutuUri = new Uri(toutu); + } + else + { + toutuUri = new Uri("avares://DownKyi/Resources/backgound/9-绿荫秘境.png"); + } + + // 我的用户信息 + MyInfo myInfo = UserInfo.GetMyInfo(); + if (myInfo != null) + { + isNoData = false; + + // 头像 + StorageHeader storageHeader = new StorageHeader(); + headerUri = storageHeader.GetHeader(mid, myInfo.Name, myInfo.Face); + // 用户名 + UserName = myInfo.Name; + // 性别 + if (myInfo.Sex == "男") + { + sexUri = new Uri($"avares://DownKyi/Resources/sex/male.png"); + } + else if (myInfo.Sex == "女") + { + sexUri = new Uri($"avares://DownKyi/Resources/sex/female.png"); + } + + // 显示vip信息 + if (myInfo.Vip.Label.Text == null || myInfo.Vip.Label.Text == "") + { + VipTypeVisibility = false; + } + else + { + VipTypeVisibility = true; + VipType = myInfo.Vip.Label.Text; + } + + // 等级 + levelUri = new Uri($"avares://DownKyi/Resources/level/lv{myInfo.Level}.png"); + // 签名 + Sign = myInfo.Sign; + // 绑定邮箱&手机 + if (myInfo.EmailStatus == 0) + { + BindingEmailVisibility = false; + } + + if (myInfo.TelStatus == 0) + { + BindingPhoneVisibility = false; + } + + // 等级 + PropertyChangeAsync(() => + { + LevelText = $"{DictionaryResource.GetString("Level")}{myInfo.LevelExp.CurrentLevel}"; + }); + if (myInfo.LevelExp.NextExp == -1) + { + CurrentExp = $"{myInfo.LevelExp.CurrentExp}/--"; + } + else + { + CurrentExp = $"{myInfo.LevelExp.CurrentExp}/{myInfo.LevelExp.NextExp}"; + } + + // 经验 + MaxExp = myInfo.LevelExp.NextExp; + ExpProgress = myInfo.LevelExp.CurrentExp; + // 节操值 + StatusList[4].Subtitle = myInfo.Moral.ToString(); + // 封禁状态 + if (myInfo.Silence == 0) + { + PropertyChangeAsync(() => { StatusList[5].Subtitle = DictionaryResource.GetString("Normal"); }); + } + else if (myInfo.Silence == 1) + { + PropertyChangeAsync(() => { StatusList[5].Subtitle = DictionaryResource.GetString("Ban"); }); + } + } + else + { + // 没有数据 + isNoData = true; + } + + // 判断是否该结束线程 + if (cancellationToken.IsCancellationRequested) + { + isCancel = true; + } + }, (tokenSource = new CancellationTokenSource()).Token); + + // 是否该结束线程 + if (isCancel) + { + return; + } + + // 是否获取到数据 + if (isNoData) + { + TopNavigationBg = "#00FFFFFF"; // 透明 + ArrowBack.Fill = DictionaryResource.GetColor("ColorTextDark"); + Logout.Fill = DictionaryResource.GetColor("ColorTextDark"); + Background = null; + + ViewVisibility = false; + LoadingVisibility = false; + NoDataVisibility = true; + return; + } + else + { + // 头像 + StorageHeader storageHeader = new StorageHeader(); + Header = storageHeader.GetHeaderThumbnail(headerUri, 64, 64); + // 性别 + Sex = sexUri == null ? null : ImageHelper.LoadFromResource(sexUri); + // 等级 + Level = levelUri == null ? null : ImageHelper.LoadFromResource(levelUri); + + ArrowBack.Fill = DictionaryResource.GetColor("ColorText"); + Logout.Fill = DictionaryResource.GetColor("ColorText"); + TopNavigationBg = DictionaryResource.GetColor("ColorMask100"); + Background = ImageHelper.LoadFromResource(toutuUri); + + ViewVisibility = true; + LoadingVisibility = false; + NoDataVisibility = false; + } + + await Task.Run(() => + { + // 导航栏信息 + UserInfoForNavigation navData = UserInfo.GetUserInfoForNavigation(); + if (navData != null) + { + ContentVisibility = true; + + // 硬币 + Coin = navData.Money == 0 ? "0.0" : navData.Money.ToString("F1"); + // B币 + Money = navData.Wallet.BcoinBalance == 0 ? "0.0" : navData.Wallet.BcoinBalance.ToString("F1"); + } + + //用户的关系状态数 + UserRelationStat relationStat = UserStatus.GetUserRelationStat(mid); + if (relationStat != null) + { + // 关注数 + StatusList[0].Subtitle = relationStat.Following.ToString(); + // 悄悄关注数 + StatusList[1].Subtitle = relationStat.Whisper.ToString(); + // 粉丝数 + StatusList[2].Subtitle = relationStat.Follower.ToString(); + // 黑名单数 + StatusList[3].Subtitle = relationStat.Black.ToString(); + } + }); + } + + /// + /// 接收mid参数 + /// + /// + public override void OnNavigatedTo(NavigationContext navigationContext) + { + base.OnNavigatedTo(navigationContext); + + // 根据传入参数不同执行不同任务 + long parameter = navigationContext.Parameters.GetValue("Parameter"); + if (parameter == 0) + { + return; + } + + mid = parameter; + + InitView(); + UpdateSpaceInfo(); + } +} \ No newline at end of file diff --git a/DownKyi/ViewModels/ViewMyToViewVideoViewModel.cs b/DownKyi/ViewModels/ViewMyToViewVideoViewModel.cs new file mode 100644 index 0000000..650f257 --- /dev/null +++ b/DownKyi/ViewModels/ViewMyToViewVideoViewModel.cs @@ -0,0 +1,461 @@ +using System; +using System.Collections; +using System.Collections.ObjectModel; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Avalonia.Media.Imaging; +using DownKyi.Core.BiliApi.History; +using DownKyi.Core.BiliApi.VideoStream; +using DownKyi.Core.Storage; +using DownKyi.Events; +using DownKyi.Images; +using DownKyi.Services; +using DownKyi.Services.Download; +using DownKyi.Utils; +using DownKyi.ViewModels.PageViewModels; +using Prism.Commands; +using Prism.Events; +using Prism.Regions; +using Prism.Services.Dialogs; + +namespace DownKyi.ViewModels; + +public class ViewMyToViewVideoViewModel : ViewModelBase +{ + public const string Tag = "PageMyToView"; + + private CancellationTokenSource tokenSource; + + #region 页面属性申明 + + private string pageName = Tag; + + public string PageName + { + get => pageName; + set => SetProperty(ref pageName, value); + } + + private VectorImage arrowBack; + + public VectorImage ArrowBack + { + get => arrowBack; + set => SetProperty(ref arrowBack, value); + } + + private VectorImage downloadManage; + + public VectorImage DownloadManage + { + get => downloadManage; + set => SetProperty(ref downloadManage, value); + } + + private bool contentVisibility; + + public bool ContentVisibility + { + get => contentVisibility; + set => SetProperty(ref contentVisibility, value); + } + + private ObservableCollection medias; + + public ObservableCollection Medias + { + get => medias; + set => SetProperty(ref medias, value); + } + + private bool isSelectAll; + + public bool IsSelectAll + { + get => isSelectAll; + set => SetProperty(ref isSelectAll, value); + } + + private bool loading; + public bool Loading + { + get => loading; + set => SetProperty(ref loading, value); + } + + private bool loadingVisibility; + + public bool LoadingVisibility + { + get => loadingVisibility; + set => SetProperty(ref loadingVisibility, value); + } + + private bool noDataVisibility; + + public bool NoDataVisibility + { + get => noDataVisibility; + set => SetProperty(ref noDataVisibility, value); + } + + #endregion + + public ViewMyToViewVideoViewModel(IEventAggregator eventAggregator, IDialogService dialogService) : base( + eventAggregator) + { + this.dialogService = dialogService; + + #region 属性初始化 + + // 初始化loading + Loading = true; + LoadingVisibility = false; + NoDataVisibility = false; + + ArrowBack = NavigationIcon.Instance().ArrowBack; + ArrowBack.Fill = DictionaryResource.GetColor("ColorTextDark"); + + // 下载管理按钮 + DownloadManage = ButtonIcon.Instance().DownloadManage; + DownloadManage.Height = 24; + DownloadManage.Width = 24; + DownloadManage.Fill = DictionaryResource.GetColor("ColorPrimary"); + + Medias = new ObservableCollection(); + + #endregion + } + + #region 命令申明 + + // 返回事件 + private DelegateCommand backSpaceCommand; + + public DelegateCommand BackSpaceCommand => + backSpaceCommand ?? (backSpaceCommand = new DelegateCommand(ExecuteBackSpace)); + + /// + /// 返回事件 + /// + private void ExecuteBackSpace() + { + InitView(); + + ArrowBack.Fill = DictionaryResource.GetColor("ColorText"); + + // 结束任务 + tokenSource?.Cancel(); + + NavigationParam parameter = new NavigationParam + { + ViewName = ParentView, + ParentViewName = null, + Parameter = null + }; + eventAggregator.GetEvent().Publish(parameter); + } + + // 前往下载管理页面 + private DelegateCommand downloadManagerCommand; + + public DelegateCommand DownloadManagerCommand => downloadManagerCommand ?? + (downloadManagerCommand = + new DelegateCommand(ExecuteDownloadManagerCommand)); + + /// + /// 前往下载管理页面 + /// + private void ExecuteDownloadManagerCommand() + { + NavigationParam parameter = new NavigationParam + { + ViewName = ViewDownloadManagerViewModel.Tag, + ParentViewName = Tag, + Parameter = null + }; + eventAggregator.GetEvent().Publish(parameter); + } + + // 全选按钮点击事件 + private DelegateCommand selectAllCommand; + + public DelegateCommand SelectAllCommand => + selectAllCommand ?? (selectAllCommand = new DelegateCommand(ExecuteSelectAllCommand)); + + /// + /// 全选按钮点击事件 + /// + /// + private void ExecuteSelectAllCommand(object parameter) + { + if (IsSelectAll) + { + foreach (var item in Medias) + { + item.IsSelected = true; + } + } + else + { + foreach (var item in Medias) + { + item.IsSelected = false; + } + } + } + + // 列表选择事件 + private DelegateCommand mediasCommand; + + public DelegateCommand MediasCommand => + mediasCommand ?? (mediasCommand = new DelegateCommand(ExecuteMediasCommand)); + + /// + /// 列表选择事件 + /// + /// + private void ExecuteMediasCommand(object parameter) + { + if (!(parameter is IList selectedMedia)) + { + return; + } + + if (selectedMedia.Count == Medias.Count) + { + IsSelectAll = true; + } + else + { + IsSelectAll = false; + } + } + + // 添加选中项到下载列表事件 + private DelegateCommand addToDownloadCommand; + + public DelegateCommand AddToDownloadCommand => addToDownloadCommand ?? + (addToDownloadCommand = + new DelegateCommand(ExecuteAddToDownloadCommand)); + + /// + /// 添加选中项到下载列表事件 + /// + private void ExecuteAddToDownloadCommand() + { + AddToDownload(true); + } + + // 添加所有视频到下载列表事件 + private DelegateCommand addAllToDownloadCommand; + + public DelegateCommand AddAllToDownloadCommand => addAllToDownloadCommand ?? + (addAllToDownloadCommand = + new DelegateCommand(ExecuteAddAllToDownloadCommand)); + + /// + /// 添加所有视频到下载列表事件 + /// + private void ExecuteAddAllToDownloadCommand() + { + AddToDownload(false); + } + + #endregion + + /// + /// 添加到下载 + /// + /// + private async void AddToDownload(bool isOnlySelected) + { + // 稍后再看里只有视频 + AddToDownloadService addToDownloadService = new AddToDownloadService(PlayStreamType.VIDEO); + + // 选择文件夹 + string directory = await addToDownloadService.SetDirectory(dialogService); + + // 视频计数 + int i = 0; + await Task.Run(() => + { + // 为了避免执行其他操作时, + // Medias变化导致的异常 + var list = Medias.ToList(); + + // 添加到下载 + foreach (var media in list) + { + // 只下载选中项,跳过未选中项 + if (isOnlySelected && !media.IsSelected) + { + continue; + } + + /// 有分P的就下载全部 + + // 开启服务 + VideoInfoService videoInfoService = new VideoInfoService(media.Bvid); + + addToDownloadService.SetVideoInfoService(videoInfoService); + addToDownloadService.GetVideo(); + addToDownloadService.ParseVideo(videoInfoService); + // 下载 + i += addToDownloadService.AddToDownload(eventAggregator, directory); + } + }); + + if (directory == null) + { + return; + } + + // 通知用户添加到下载列表的结果 + if (i <= 0) + { + eventAggregator.GetEvent().Publish(DictionaryResource.GetString("TipAddDownloadingZero")); + } + else + { + eventAggregator.GetEvent() + .Publish( + $"{DictionaryResource.GetString("TipAddDownloadingFinished1")}{i}{DictionaryResource.GetString("TipAddDownloadingFinished2")}"); + } + } + + private async void UpdateToViewMediaList() + { + LoadingVisibility = true; + NoDataVisibility = false; + Medias.Clear(); + + await Task.Run(() => + { + CancellationToken cancellationToken = tokenSource.Token; + + var toViewList = ToView.GetToView(); + if (toViewList == null || toViewList.Count == 0) + { + LoadingVisibility = false; + NoDataVisibility = true; + return; + } + + foreach (var toView in toViewList) + { + // 查询、保存封面 + string coverUrl = toView.Pic; + Bitmap cover; + if (coverUrl == null || coverUrl == "") + { + cover = null; + } + else + { + if (!coverUrl.ToLower().StartsWith("http")) + { + coverUrl = $"https:{toView.Pic}"; + } + + StorageCover storageCover = new StorageCover(); + cover = storageCover.GetCoverThumbnail(toView.Aid, toView.Bvid, toView.Cid, coverUrl, 160, 100); + } + + // 获取用户头像 + long upMid = -1; + string upName; + Bitmap upHeader; + if (toView.Owner != null && toView.Owner.Face != null) + { + upMid = toView.Owner.Mid; + upName = toView.Owner.Name; + StorageHeader storageHeader = new StorageHeader(); + upHeader = storageHeader.GetHeaderThumbnail(toView.Owner.Mid, upName, toView.Owner.Face, 24, 24); + } + else + { + upName = ""; + upHeader = null; + } + + App.PropertyChangeAsync(() => + { + ToViewMedia media = new ToViewMedia(eventAggregator) + { + Aid = toView.Aid, + Bvid = toView.Bvid, + UpMid = upMid, + Cover = cover ?? + ImageHelper.LoadFromResource( + new Uri($"avares://DownKyi/Resources/video-placeholder.png")), + Title = toView.Title, + UpName = upName, + UpHeader = upHeader + }; + + Medias.Add(media); + + ContentVisibility = true; + LoadingVisibility = false; + NoDataVisibility = false; + }); + + // 判断是否该结束线程,若为true,跳出循环 + if (cancellationToken.IsCancellationRequested) + { + break; + } + } + }, (tokenSource = new CancellationTokenSource()).Token); + } + + /// + /// 初始化页面数据 + /// + private void InitView() + { + ArrowBack.Fill = DictionaryResource.GetColor("ColorTextDark"); + + ContentVisibility = false; + LoadingVisibility = false; + NoDataVisibility = false; + + Medias.Clear(); + IsSelectAll = false; + } + + /// + /// 导航到页面时执行 + /// + /// + public override void OnNavigatedTo(NavigationContext navigationContext) + { + base.OnNavigatedTo(navigationContext); + + ArrowBack.Fill = DictionaryResource.GetColor("ColorTextDark"); + + DownloadManage = ButtonIcon.Instance().DownloadManage; + DownloadManage.Height = 24; + DownloadManage.Width = 24; + DownloadManage.Fill = DictionaryResource.GetColor("ColorPrimary"); + + // 根据传入参数不同执行不同任务 + long mid = navigationContext.Parameters.GetValue("Parameter"); + if (mid == 0) + { + IsSelectAll = false; + foreach (var media in Medias) + { + media.IsSelected = false; + } + + return; + } + + InitView(); + + UpdateToViewMediaList(); + } +} \ No newline at end of file diff --git a/DownKyi/ViewModels/ViewPublicFavoritesViewModel.cs b/DownKyi/ViewModels/ViewPublicFavoritesViewModel.cs new file mode 100644 index 0000000..7d235bd --- /dev/null +++ b/DownKyi/ViewModels/ViewPublicFavoritesViewModel.cs @@ -0,0 +1,441 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using DownKyi.Core.BiliApi.Favorites; +using DownKyi.Core.BiliApi.VideoStream; +using DownKyi.Core.Logging; +using DownKyi.Events; +using DownKyi.Images; +using DownKyi.Services; +using DownKyi.Services.Download; +using DownKyi.Utils; +using DownKyi.ViewModels.PageViewModels; +using Prism.Commands; +using Prism.Events; +using Prism.Regions; +using Prism.Services.Dialogs; + +namespace DownKyi.ViewModels; + +public class ViewPublicFavoritesViewModel : ViewModelBase +{ + public const string Tag = "PagePublicFavorites"; + + private CancellationTokenSource tokenSource; + + #region 页面属性申明 + + private string pageName = Tag; + + public string PageName + { + get => pageName; + set => SetProperty(ref pageName, value); + } + + private VectorImage arrowBack; + + public VectorImage ArrowBack + { + get => arrowBack; + set => SetProperty(ref arrowBack, value); + } + + private VectorImage downloadManage; + + public VectorImage DownloadManage + { + get => downloadManage; + set => SetProperty(ref downloadManage, value); + } + + private Favorites favorites; + + public Favorites Favorites + { + get => favorites; + set => SetProperty(ref favorites, value); + } + + private ObservableCollection favoritesMedias; + + public ObservableCollection FavoritesMedias + { + get => favoritesMedias; + set => SetProperty(ref favoritesMedias, value); + } + + private bool contentVisibility; + + public bool ContentVisibility + { + get => contentVisibility; + set => SetProperty(ref contentVisibility, value); + } + + + private bool loading; + public bool Loading + { + get => loading; + set => SetProperty(ref loading, value); + } + + private bool loadingVisibility; + + public bool LoadingVisibility + { + get => loadingVisibility; + set => SetProperty(ref loadingVisibility, value); + } + + private bool noDataVisibility; + + public bool NoDataVisibility + { + get => noDataVisibility; + set => SetProperty(ref noDataVisibility, value); + } + + private bool mediaLoading; + public bool MediaLoading + { + get => mediaLoading; + set => SetProperty(ref mediaLoading, value); + } + + private bool mediaLoadingVisibility; + + public bool MediaLoadingVisibility + { + get => mediaLoadingVisibility; + set => SetProperty(ref mediaLoadingVisibility, value); + } + + private bool mediaNoDataVisibility; + + public bool MediaNoDataVisibility + { + get => mediaNoDataVisibility; + set => SetProperty(ref mediaNoDataVisibility, value); + } + + #endregion + + public ViewPublicFavoritesViewModel(IEventAggregator eventAggregator, IDialogService dialogService) : base( + eventAggregator) + { + this.dialogService = dialogService; + + #region 属性初始化 + + // 初始化loading + Loading = true; + LoadingVisibility = false; + NoDataVisibility = false; + + MediaLoading = true; + MediaLoadingVisibility = false; + MediaNoDataVisibility = false; + + ArrowBack = NavigationIcon.Instance().ArrowBack; + ArrowBack.Fill = DictionaryResource.GetColor("ColorTextDark"); + + // 下载管理按钮 + DownloadManage = ButtonIcon.Instance().DownloadManage; + DownloadManage.Height = 24; + DownloadManage.Width = 24; + DownloadManage.Fill = DictionaryResource.GetColor("ColorPrimary"); + + FavoritesMedias = new ObservableCollection(); + + #endregion + } + + #region 命令申明 + + // 返回 + private DelegateCommand backSpaceCommand; + + public DelegateCommand BackSpaceCommand => + backSpaceCommand ?? (backSpaceCommand = new DelegateCommand(ExecuteBackSpace)); + + /// + /// 返回 + /// + private void ExecuteBackSpace() + { + // 结束任务 + tokenSource?.Cancel(); + + NavigationParam parameter = new NavigationParam + { + ViewName = ParentView, + ParentViewName = null, + Parameter = null + }; + eventAggregator.GetEvent().Publish(parameter); + } + + // 前往下载管理页面 + private DelegateCommand downloadManagerCommand; + + public DelegateCommand DownloadManagerCommand => downloadManagerCommand ?? + (downloadManagerCommand = + new DelegateCommand(ExecuteDownloadManagerCommand)); + + /// + /// 前往下载管理页面 + /// + private void ExecuteDownloadManagerCommand() + { + NavigationParam parameter = new NavigationParam + { + ViewName = ViewDownloadManagerViewModel.Tag, + ParentViewName = Tag, + Parameter = null + }; + eventAggregator.GetEvent().Publish(parameter); + } + + // 复制封面事件 + private DelegateCommand copyCoverCommand; + + public DelegateCommand CopyCoverCommand => + copyCoverCommand ?? (copyCoverCommand = new DelegateCommand(ExecuteCopyCoverCommand)); + + /// + /// 复制封面事件 + /// + private void ExecuteCopyCoverCommand() + { + // 复制封面图片到剪贴板 + // Clipboard.SetImage(Favorites.Cover); + LogManager.Info(Tag, "复制封面图片到剪贴板"); + } + + // 复制封面URL事件 + private DelegateCommand copyCoverUrlCommand; + + public DelegateCommand CopyCoverUrlCommand => copyCoverUrlCommand ?? + (copyCoverUrlCommand = + new DelegateCommand(ExecuteCopyCoverUrlCommand)); + + /// + /// 复制封面URL事件 + /// + private void ExecuteCopyCoverUrlCommand() + { + // 复制封面url到剪贴板 + // Clipboard.SetText(Favorites.CoverUrl); + LogManager.Info(Tag, "复制封面url到剪贴板"); + } + + // 前往UP主页事件 + private DelegateCommand upperCommand; + public DelegateCommand UpperCommand => upperCommand ?? (upperCommand = new DelegateCommand(ExecuteUpperCommand)); + + /// + /// 前往UP主页事件 + /// + private void ExecuteUpperCommand() + { + NavigateToView.NavigateToViewUserSpace(eventAggregator, Tag, Favorites.UpperMid); + } + + // 添加选中项到下载列表事件 + private DelegateCommand addToDownloadCommand; + + public DelegateCommand AddToDownloadCommand => addToDownloadCommand ?? + (addToDownloadCommand = + new DelegateCommand(ExecuteAddToDownloadCommand)); + + /// + /// 添加选中项到下载列表事件 + /// + private void ExecuteAddToDownloadCommand() + { + AddToDownload(true); + } + + // 添加所有视频到下载列表事件 + private DelegateCommand addAllToDownloadCommand; + + public DelegateCommand AddAllToDownloadCommand => addAllToDownloadCommand ?? + (addAllToDownloadCommand = + new DelegateCommand(ExecuteAddAllToDownloadCommand)); + + /// + /// 添加所有视频到下载列表事件 + /// + private void ExecuteAddAllToDownloadCommand() + { + AddToDownload(false); + } + + // 列表选择事件 + private DelegateCommand favoritesMediasCommand; + + public DelegateCommand FavoritesMediasCommand => favoritesMediasCommand ?? + (favoritesMediasCommand = + new DelegateCommand( + ExecuteFavoritesMediasCommand)); + + /// + /// 列表选择事件 + /// + /// + private void ExecuteFavoritesMediasCommand(object parameter) + { + } + + #endregion + + private async void AddToDownload(bool isOnlySelected) + { + // 收藏夹里只有视频 + AddToDownloadService addToDownloadService = new AddToDownloadService(PlayStreamType.VIDEO); + + // 选择文件夹 + string directory = await addToDownloadService.SetDirectory(dialogService); + + // 视频计数 + int i = 0; + await Task.Run(() => + { + // 为了避免执行其他操作时, + // Medias变化导致的异常 + var list = FavoritesMedias.ToList(); + + // 添加到下载 + foreach (var media in list) + { + // 只下载选中项,跳过未选中项 + if (isOnlySelected && !media.IsSelected) + { + continue; + } + + /// 有分P的就下载全部 + + // 开启服务 + VideoInfoService videoInfoService = new VideoInfoService(media.Bvid); + + addToDownloadService.SetVideoInfoService(videoInfoService); + addToDownloadService.GetVideo(); + addToDownloadService.ParseVideo(videoInfoService); + // 下载 + i += addToDownloadService.AddToDownload(eventAggregator, directory); + } + }); + + if (directory == null) + { + return; + } + + // 通知用户添加到下载列表的结果 + if (i <= 0) + { + eventAggregator.GetEvent().Publish(DictionaryResource.GetString("TipAddDownloadingZero")); + } + else + { + eventAggregator.GetEvent() + .Publish( + $"{DictionaryResource.GetString("TipAddDownloadingFinished1")}{i}{DictionaryResource.GetString("TipAddDownloadingFinished2")}"); + } + } + + /// + /// 初始化页面元素 + /// + private void InitView() + { + LogManager.Debug(Tag, "初始化页面元素"); + + ArrowBack.Fill = DictionaryResource.GetColor("ColorTextDark"); + + DownloadManage = ButtonIcon.Instance().DownloadManage; + DownloadManage.Height = 24; + DownloadManage.Width = 24; + DownloadManage.Fill = DictionaryResource.GetColor("ColorPrimary"); + + ContentVisibility = false; + LoadingVisibility = false; + NoDataVisibility = false; + MediaLoadingVisibility = false; + MediaNoDataVisibility = false; + + FavoritesMedias.Clear(); + } + + /// + /// 更新页面 + /// + private void UpdateView(IFavoritesService favoritesService, long favoritesId, CancellationToken cancellationToken) + { + LoadingVisibility = true; + + Favorites = favoritesService.GetFavorites(favoritesId); + if (Favorites == null) + { + LogManager.Debug(Tag, "Favorites is null."); + + ContentVisibility = false; + LoadingVisibility = false; + NoDataVisibility = true; + return; + } + else + { + ContentVisibility = true; + LoadingVisibility = false; + NoDataVisibility = false; + } + + MediaLoadingVisibility = true; + + List medias = FavoritesResource.GetAllFavoritesMedia(favoritesId); + if (medias == null || medias.Count == 0) + { + MediaLoadingVisibility = false; + MediaNoDataVisibility = true; + return; + } + else + { + MediaLoadingVisibility = false; + MediaNoDataVisibility = false; + } + + favoritesService.GetFavoritesMediaList(medias, FavoritesMedias, eventAggregator, cancellationToken); + } + + /// + /// 接收收藏夹id参数 + /// + /// + public override async void OnNavigatedTo(NavigationContext navigationContext) + { + base.OnNavigatedTo(navigationContext); + + // 根据传入参数不同执行不同任务 + long parameter = navigationContext.Parameters.GetValue("Parameter"); + if (parameter == 0) + { + return; + } + + InitView(); + await Task.Run(new Action(() => + { + CancellationToken cancellationToken = tokenSource.Token; + + UpdateView(new FavoritesService(), parameter, cancellationToken); + }), (tokenSource = new CancellationTokenSource()).Token); + } +} \ No newline at end of file diff --git a/DownKyi/ViewModels/ViewPublicationViewModel.cs b/DownKyi/ViewModels/ViewPublicationViewModel.cs new file mode 100644 index 0000000..c89a691 --- /dev/null +++ b/DownKyi/ViewModels/ViewPublicationViewModel.cs @@ -0,0 +1,574 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Avalonia.Media.Imaging; +using DownKyi.Core.BiliApi.VideoStream; +using DownKyi.Core.Storage; +using DownKyi.Core.Utils; +using DownKyi.CustomControl; +using DownKyi.Events; +using DownKyi.Images; +using DownKyi.Services; +using DownKyi.Services.Download; +using DownKyi.Utils; +using DownKyi.ViewModels.PageViewModels; +using DownKyi.ViewModels.UserSpace; +using Prism.Commands; +using Prism.Events; +using Prism.Regions; +using Prism.Services.Dialogs; + +#nullable disable +namespace DownKyi.ViewModels +{ + public class ViewPublicationViewModel : ViewModelBase + { + public const string Tag = "PagePublication"; + + private CancellationTokenSource tokenSource; + + private long mid = -1; + + // 每页视频数量,暂时在此写死,以后在设置中增加选项 + private readonly int VideoNumberInPage = 30; + + #region 页面属性申明 + + private string pageName = Tag; + + public string PageName + { + get => pageName; + set => SetProperty(ref pageName, value); + } + + private bool loading; + public bool Loading + { + get => loading; + set => SetProperty(ref loading, value); + } + + private bool loadingVisibility; + + public bool LoadingVisibility + { + get => loadingVisibility; + set => SetProperty(ref loadingVisibility, value); + } + + private bool noDataVisibility; + + public bool NoDataVisibility + { + get => noDataVisibility; + set => SetProperty(ref noDataVisibility, value); + } + + private VectorImage arrowBack; + + public VectorImage ArrowBack + { + get => arrowBack; + set => SetProperty(ref arrowBack, value); + } + + private VectorImage downloadManage; + + public VectorImage DownloadManage + { + get => downloadManage; + set => SetProperty(ref downloadManage, value); + } + + private ObservableCollection tabHeaders; + + public ObservableCollection TabHeaders + { + get => tabHeaders; + set => SetProperty(ref tabHeaders, value); + } + + private int selectTabId; + + public int SelectTabId + { + get => selectTabId; + set => SetProperty(ref selectTabId, value); + } + + private bool isEnabled = true; + + public bool IsEnabled + { + get => isEnabled; + set => SetProperty(ref isEnabled, value); + } + + private CustomPagerViewModel pager; + + public CustomPagerViewModel Pager + { + get => pager; + set => SetProperty(ref pager, value); + } + + private ObservableCollection medias; + + public ObservableCollection Medias + { + get => medias; + set => SetProperty(ref medias, value); + } + + private bool isSelectAll; + + public bool IsSelectAll + { + get => isSelectAll; + set => SetProperty(ref isSelectAll, value); + } + + #endregion + + public ViewPublicationViewModel(IEventAggregator eventAggregator, IDialogService dialogService) : base( + eventAggregator) + { + this.dialogService = dialogService; + + #region 属性初始化 + + // 初始化loading + Loading = true; + LoadingVisibility = false; + NoDataVisibility = false; + + ArrowBack = NavigationIcon.Instance().ArrowBack; + ArrowBack.Fill = DictionaryResource.GetColor("ColorTextDark"); + + // 下载管理按钮 + DownloadManage = ButtonIcon.Instance().DownloadManage; + DownloadManage.Height = 24; + DownloadManage.Width = 24; + DownloadManage.Fill = DictionaryResource.GetColor("ColorPrimary"); + + TabHeaders = new ObservableCollection(); + Medias = new ObservableCollection(); + + #endregion + } + + #region 命令申明 + + // 返回事件 + private DelegateCommand backSpaceCommand; + + public DelegateCommand BackSpaceCommand => + backSpaceCommand ?? (backSpaceCommand = new DelegateCommand(ExecuteBackSpace)); + + /// + /// 返回事件 + /// + private void ExecuteBackSpace() + { + ArrowBack.Fill = DictionaryResource.GetColor("ColorText"); + + // 结束任务 + tokenSource?.Cancel(); + + NavigationParam parameter = new NavigationParam + { + ViewName = ParentView, + ParentViewName = null, + Parameter = null + }; + eventAggregator.GetEvent().Publish(parameter); + } + + // 前往下载管理页面 + private DelegateCommand downloadManagerCommand; + + public DelegateCommand DownloadManagerCommand => downloadManagerCommand ?? + (downloadManagerCommand = + new DelegateCommand(ExecuteDownloadManagerCommand)); + + /// + /// 前往下载管理页面 + /// + private void ExecuteDownloadManagerCommand() + { + NavigationParam parameter = new NavigationParam + { + ViewName = ViewDownloadManagerViewModel.Tag, + ParentViewName = Tag, + Parameter = null + }; + eventAggregator.GetEvent().Publish(parameter); + } + + // 左侧tab点击事件 + private DelegateCommand leftTabHeadersCommand; + + public DelegateCommand LeftTabHeadersCommand => leftTabHeadersCommand ?? (leftTabHeadersCommand = + new DelegateCommand(ExecuteLeftTabHeadersCommand, CanExecuteLeftTabHeadersCommand)); + + /// + /// 左侧tab点击事件 + /// + /// + private void ExecuteLeftTabHeadersCommand(object parameter) + { + if (!(parameter is TabHeader tabHeader)) + { + return; + } + + // 页面选择 + Pager = new CustomPagerViewModel(1, + (int)Math.Ceiling(double.Parse(tabHeader.SubTitle) / VideoNumberInPage)); + Pager.CurrentChanged += OnCurrentChanged_Pager; + Pager.CountChanged += OnCountChanged_Pager; + Pager.Current = 1; + } + + /// + /// 左侧tab点击事件是否允许执行 + /// + /// + /// + private bool CanExecuteLeftTabHeadersCommand(object parameter) + { + return IsEnabled; + } + + // 全选按钮点击事件 + private DelegateCommand selectAllCommand; + + public DelegateCommand SelectAllCommand => selectAllCommand ?? + (selectAllCommand = + new DelegateCommand(ExecuteSelectAllCommand)); + + /// + /// 全选按钮点击事件 + /// + /// + private void ExecuteSelectAllCommand(object parameter) + { + if (IsSelectAll) + { + foreach (var item in Medias) + { + item.IsSelected = true; + } + } + else + { + foreach (var item in Medias) + { + item.IsSelected = false; + } + } + } + + // 列表选择事件 + private DelegateCommand mediasCommand; + + public DelegateCommand MediasCommand => + mediasCommand ?? (mediasCommand = new DelegateCommand(ExecuteMediasCommand)); + + /// + /// 列表选择事件 + /// + /// + private void ExecuteMediasCommand(object parameter) + { + if (!(parameter is IList selectedMedia)) + { + return; + } + + if (selectedMedia.Count == Medias.Count) + { + IsSelectAll = true; + } + else + { + IsSelectAll = false; + } + } + + // 添加选中项到下载列表事件 + private DelegateCommand addToDownloadCommand; + + public DelegateCommand AddToDownloadCommand => addToDownloadCommand ?? + (addToDownloadCommand = + new DelegateCommand(ExecuteAddToDownloadCommand)); + + /// + /// 添加选中项到下载列表事件 + /// + private void ExecuteAddToDownloadCommand() + { + AddToDownload(true); + } + + // 添加所有视频到下载列表事件 + private DelegateCommand addAllToDownloadCommand; + + public DelegateCommand AddAllToDownloadCommand => addAllToDownloadCommand ?? + (addAllToDownloadCommand = + new DelegateCommand(ExecuteAddAllToDownloadCommand)); + + /// + /// 添加所有视频到下载列表事件 + /// + private void ExecuteAddAllToDownloadCommand() + { + AddToDownload(false); + } + + #endregion + + /// + /// 添加到下载 + /// + /// + private async void AddToDownload(bool isOnlySelected) + { + // 收藏夹里只有视频 + AddToDownloadService addToDownloadService = new AddToDownloadService(PlayStreamType.VIDEO); + + // 选择文件夹 + string directory = await addToDownloadService.SetDirectory(dialogService); + + // 视频计数 + int i = 0; + await Task.Run(() => + { + // 为了避免执行其他操作时, + // Medias变化导致的异常 + var list = Medias.ToList(); + + // 添加到下载 + foreach (var media in list) + { + // 只下载选中项,跳过未选中项 + if (isOnlySelected && !media.IsSelected) + { + continue; + } + + /// 有分P的就下载全部 + + // 开启服务 + VideoInfoService videoInfoService = new VideoInfoService(media.Bvid); + + addToDownloadService.SetVideoInfoService(videoInfoService); + addToDownloadService.GetVideo(); + addToDownloadService.ParseVideo(videoInfoService); + // 下载 + i += addToDownloadService.AddToDownload(eventAggregator, directory); + } + }); + + if (directory == null) + { + return; + } + + // 通知用户添加到下载列表的结果 + if (i <= 0) + { + eventAggregator.GetEvent().Publish(DictionaryResource.GetString("TipAddDownloadingZero")); + } + else + { + eventAggregator.GetEvent() + .Publish( + $"{DictionaryResource.GetString("TipAddDownloadingFinished1")}{i}{DictionaryResource.GetString("TipAddDownloadingFinished2")}"); + } + } + + private void OnCountChanged_Pager(int count) + { + } + + private bool OnCurrentChanged_Pager(int old, int current) + { + if (!IsEnabled) + { + //Pager.Current = old; + return false; + } + + Medias.Clear(); + IsSelectAll = false; + LoadingVisibility = true; + NoDataVisibility = false; + + UpdatePublication(current); + + return true; + } + + private async void UpdatePublication(int current) + { + // 是否正在获取数据 + // 在所有的退出分支中都需要设为true + IsEnabled = false; + + var tab = TabHeaders[SelectTabId]; + + await Task.Run(() => + { + CancellationToken cancellationToken = tokenSource.Token; + + var publications = Core.BiliApi.Users.UserSpace.GetPublication(mid, current, VideoNumberInPage, tab.Id); + if (publications == null) + { + // 没有数据,UI提示 + LoadingVisibility = false; + NoDataVisibility = true; + return; + } + + var videos = publications.Vlist; + if (videos == null) + { + // 没有数据,UI提示 + LoadingVisibility = false; + NoDataVisibility = true; + return; + } + + foreach (var video in videos) + { + // 查询、保存封面 + string coverUrl = video.Pic; + Bitmap cover; + if (coverUrl == null || coverUrl == "") + { + cover = null; // new BitmapImage(new Uri($"pack://application:,,,/Resources/video-placeholder.png")); + } + else + { + if (!coverUrl.ToLower().StartsWith("http")) + { + coverUrl = $"https:{video.Pic}"; + } + + StorageCover storageCover = new StorageCover(); + cover = storageCover.GetCoverThumbnail(video.Aid, video.Bvid, -1, coverUrl, 200, 125); + } + + // 播放数 + string play = string.Empty; + if (video.Play > 0) + { + play = Format.FormatNumber(video.Play); + } + else + { + play = "--"; + } + + DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1)); // 当地时区 + DateTime dateCTime = startTime.AddSeconds(video.Created); + string ctime = dateCTime.ToString("yyyy-MM-dd"); + + App.PropertyChangeAsync(() => + { + PublicationMedia media = new PublicationMedia(eventAggregator) + { + Avid = video.Aid, + Bvid = video.Bvid, + Cover = cover ?? + ImageHelper.LoadFromResource( + new Uri("avares://DownKyi/Resources/video-placeholder.png")), + Duration = video.Length, + Title = video.Title, + PlayNumber = play, + CreateTime = ctime + }; + medias.Add(media); + + LoadingVisibility = false; + NoDataVisibility = false; + }); + + // 判断是否该结束线程,若为true,跳出循环 + if (cancellationToken.IsCancellationRequested) + { + break; + } + } + }, (tokenSource = new CancellationTokenSource()).Token); + IsEnabled = true; + } + + /// + /// 初始化页面数据 + /// + private void InitView() + { + ArrowBack.Fill = DictionaryResource.GetColor("ColorTextDark"); + + DownloadManage = ButtonIcon.Instance().DownloadManage; + DownloadManage.Height = 24; + DownloadManage.Width = 24; + DownloadManage.Fill = DictionaryResource.GetColor("ColorPrimary"); + + TabHeaders.Clear(); + Medias.Clear(); + SelectTabId = -1; + IsSelectAll = false; + } + + /// + /// 导航到页面时执行 + /// + /// + public override void OnNavigatedTo(NavigationContext navigationContext) + { + base.OnNavigatedTo(navigationContext); + + // 根据传入参数不同执行不同任务 + var parameter = navigationContext.Parameters.GetValue>("Parameter"); + if (parameter == null) + { + return; + } + + InitView(); + + mid = (long)parameter["mid"]; + int tid = (int)parameter["tid"]; + List zones = (List)parameter["list"]; + + foreach (var item in zones) + { + TabHeaders.Add(new TabHeader + { + Id = item.Tid, + Title = item.Name, + SubTitle = item.Count.ToString() + }); + } + + // 初始选中项 + var selectTab = TabHeaders.FirstOrDefault(item => item.Id == tid); + SelectTabId = TabHeaders.IndexOf(selectTab); + + // 页面选择 + Pager = new CustomPagerViewModel(1, + (int)Math.Ceiling(double.Parse(selectTab.SubTitle) / VideoNumberInPage)); + Pager.CurrentChanged += OnCurrentChanged_Pager; + Pager.CountChanged += OnCountChanged_Pager; + Pager.Current = 1; + } + } +} \ No newline at end of file diff --git a/DownKyi/ViewModels/ViewSeasonsSeriesViewModel.cs b/DownKyi/ViewModels/ViewSeasonsSeriesViewModel.cs new file mode 100644 index 0000000..7adf883 --- /dev/null +++ b/DownKyi/ViewModels/ViewSeasonsSeriesViewModel.cs @@ -0,0 +1,712 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Avalonia.Media.Imaging; +using DownKyi.Core.BiliApi.VideoStream; +using DownKyi.Core.Storage; +using DownKyi.Core.Utils; +using DownKyi.CustomControl; +using DownKyi.Events; +using DownKyi.Images; +using DownKyi.Services; +using DownKyi.Services.Download; +using DownKyi.Utils; +using DownKyi.ViewModels.PageViewModels; +using Prism.Commands; +using Prism.Events; +using Prism.Regions; +using Prism.Services.Dialogs; + +namespace DownKyi.ViewModels; + +public class ViewSeasonsSeriesViewModel : ViewModelBase +{ + public const string Tag = "PageSeasonsSeries"; + + private CancellationTokenSource tokenSource; + + private long mid = -1; + private long id = -1; + private int type = 0; + + // 每页视频数量,暂时在此写死,以后在设置中增加选项 + private readonly int VideoNumberInPage = 30; + + #region 页面属性申明 + + private string pageName = Tag; + + public string PageName + { + get => pageName; + set => SetProperty(ref pageName, value); + } + + private bool loading; + public bool Loading + { + get => loading; + set => SetProperty(ref loading, value); + } + + private bool loadingVisibility; + + public bool LoadingVisibility + { + get => loadingVisibility; + set => SetProperty(ref loadingVisibility, value); + } + + private bool noDataVisibility; + + public bool NoDataVisibility + { + get => noDataVisibility; + set => SetProperty(ref noDataVisibility, value); + } + + private VectorImage arrowBack; + + public VectorImage ArrowBack + { + get => arrowBack; + set => SetProperty(ref arrowBack, value); + } + + private VectorImage downloadManage; + + public VectorImage DownloadManage + { + get => downloadManage; + set => SetProperty(ref downloadManage, value); + } + + private string title; + + public string Title + { + get => title; + set => SetProperty(ref title, value); + } + + private bool isEnabled = true; + + public bool IsEnabled + { + get => isEnabled; + set => SetProperty(ref isEnabled, value); + } + + private CustomPagerViewModel pager; + + public CustomPagerViewModel Pager + { + get => pager; + set => SetProperty(ref pager, value); + } + + private ObservableCollection medias; + + public ObservableCollection Medias + { + get => medias; + set => SetProperty(ref medias, value); + } + + private bool isSelectAll; + + public bool IsSelectAll + { + get => isSelectAll; + set => SetProperty(ref isSelectAll, value); + } + + #endregion + + public ViewSeasonsSeriesViewModel(IEventAggregator eventAggregator, IDialogService dialogService) : base( + eventAggregator) + { + this.dialogService = dialogService; + + #region 属性初始化 + + // 初始化loading + Loading = true; + LoadingVisibility = false; + NoDataVisibility = false; + + ArrowBack = NavigationIcon.Instance().ArrowBack; + ArrowBack.Fill = DictionaryResource.GetColor("ColorTextDark"); + + // 下载管理按钮 + DownloadManage = ButtonIcon.Instance().DownloadManage; + DownloadManage.Height = 24; + DownloadManage.Width = 24; + DownloadManage.Fill = DictionaryResource.GetColor("ColorPrimary"); + + Medias = new ObservableCollection(); + + #endregion + } + + #region 命令申明 + + // 返回事件 + private DelegateCommand backSpaceCommand; + + public DelegateCommand BackSpaceCommand => + backSpaceCommand ?? (backSpaceCommand = new DelegateCommand(ExecuteBackSpace)); + + /// + /// 返回事件 + /// + private void ExecuteBackSpace() + { + ArrowBack.Fill = DictionaryResource.GetColor("ColorText"); + + // 结束任务 + tokenSource?.Cancel(); + + NavigationParam parameter = new NavigationParam + { + ViewName = ParentView, + ParentViewName = null, + Parameter = null + }; + eventAggregator.GetEvent().Publish(parameter); + } + + // 前往下载管理页面 + private DelegateCommand downloadManagerCommand; + + public DelegateCommand DownloadManagerCommand => downloadManagerCommand ?? + (downloadManagerCommand = + new DelegateCommand(ExecuteDownloadManagerCommand)); + + /// + /// 前往下载管理页面 + /// + private void ExecuteDownloadManagerCommand() + { + NavigationParam parameter = new NavigationParam + { + ViewName = ViewDownloadManagerViewModel.Tag, + ParentViewName = Tag, + Parameter = null + }; + eventAggregator.GetEvent().Publish(parameter); + } + + // 全选按钮点击事件 + private DelegateCommand selectAllCommand; + + public DelegateCommand SelectAllCommand => selectAllCommand ?? + (selectAllCommand = + new DelegateCommand(ExecuteSelectAllCommand)); + + /// + /// 全选按钮点击事件 + /// + /// + private void ExecuteSelectAllCommand(object parameter) + { + if (IsSelectAll) + { + foreach (var item in Medias) + { + item.IsSelected = true; + } + } + else + { + foreach (var item in Medias) + { + item.IsSelected = false; + } + } + } + + // 列表选择事件 + private DelegateCommand mediasCommand; + + public DelegateCommand MediasCommand => + mediasCommand ?? (mediasCommand = new DelegateCommand(ExecuteMediasCommand)); + + /// + /// 列表选择事件 + /// + /// + private void ExecuteMediasCommand(object parameter) + { + if (!(parameter is IList selectedMedia)) + { + return; + } + + if (selectedMedia.Count == Medias.Count) + { + IsSelectAll = true; + } + else + { + IsSelectAll = false; + } + } + + // 添加选中项到下载列表事件 + private DelegateCommand addToDownloadCommand; + + public DelegateCommand AddToDownloadCommand => addToDownloadCommand ?? + (addToDownloadCommand = + new DelegateCommand(ExecuteAddToDownloadCommand)); + + /// + /// 添加选中项到下载列表事件 + /// + private void ExecuteAddToDownloadCommand() + { + AddToDownload(true); + } + + // 添加所有视频到下载列表事件 + private DelegateCommand addAllToDownloadCommand; + + public DelegateCommand AddAllToDownloadCommand => addAllToDownloadCommand ?? + (addAllToDownloadCommand = + new DelegateCommand(ExecuteAddAllToDownloadCommand)); + + /// + /// 添加所有视频到下载列表事件 + /// + private void ExecuteAddAllToDownloadCommand() + { + AddToDownload(false); + } + + #endregion + + /// + /// 添加到下载 + /// + /// + private async void AddToDownload(bool isOnlySelected) + { + // 频道里只有视频 + AddToDownloadService addToDownloadService = new AddToDownloadService(PlayStreamType.VIDEO); + + // 选择文件夹 + string directory = await addToDownloadService.SetDirectory(dialogService); + + // 视频计数 + int i = 0; + await Task.Run(() => + { + // 为了避免执行其他操作时, + // Medias变化导致的异常 + var list = Medias.ToList(); + + // 添加到下载 + foreach (var media in list) + { + // 只下载选中项,跳过未选中项 + if (isOnlySelected && !media.IsSelected) + { + continue; + } + + /// 有分P的就下载全部 + + // 开启服务 + VideoInfoService videoInfoService = new VideoInfoService(media.Bvid); + + addToDownloadService.SetVideoInfoService(videoInfoService); + addToDownloadService.GetVideo(); + addToDownloadService.ParseVideo(videoInfoService); + // 下载 + i += addToDownloadService.AddToDownload(eventAggregator, directory); + } + }); + + if (directory == null) + { + return; + } + + // 通知用户添加到下载列表的结果 + if (i <= 0) + { + eventAggregator.GetEvent().Publish(DictionaryResource.GetString("TipAddDownloadingZero")); + } + else + { + eventAggregator.GetEvent() + .Publish( + $"{DictionaryResource.GetString("TipAddDownloadingFinished1")}{i}{DictionaryResource.GetString("TipAddDownloadingFinished2")}"); + } + } + + private void OnCountChanged_Pager(int count) + { + } + + private bool OnCurrentChanged_Pager(int old, int current) + { + if (!IsEnabled) + { + //Pager.Current = old; + return false; + } + + Medias.Clear(); + IsSelectAll = false; + LoadingVisibility = true; + NoDataVisibility = false; + + //UpdateChannel(current); + + if (type == 1) + { + UpdateSeasons(current); + } + + if (type == 2) + { + UpdateSeries(current); + } + + return true; + } + + //private async void UpdateChannel(int current) + //{ + // // 是否正在获取数据 + // // 在所有的退出分支中都需要设为true + // IsEnabled = false; + + // await Task.Run(() => + // { + // CancellationToken cancellationToken = tokenSource.Token; + + // var channels = Core.BiliApi.Users.UserSpace.GetChannelVideoList(mid, cid, current, VideoNumberInPage); + // if (channels == null || channels.Count == 0) + // { + // // 没有数据,UI提示 + // LoadingVisibility = Visibility.Collapsed; + // NoDataVisibility = Visibility.Visible; + // return; + // } + + // foreach (var video in channels) + // { + // if (video.Cid == 0) + // { + // continue; + // } + + // // 查询、保存封面 + // string coverUrl = video.Pic; + // BitmapImage cover; + // if (coverUrl == null || coverUrl == "") + // { + // cover = null; // new BitmapImage(new Uri($"pack://application:,,,/Resources/video-placeholder.png")); + // } + // else + // { + // if (!coverUrl.ToLower().StartsWith("http")) + // { + // coverUrl = $"https:{video.Pic}"; + // } + + // StorageCover storageCover = new StorageCover(); + // cover = storageCover.GetCoverThumbnail(video.Aid, video.Bvid, -1, coverUrl, 200, 125); + // } + + // // 播放数 + // string play = string.Empty; + // if (video.Stat != null) + // { + // if (video.Stat.View > 0) + // { + // play = Format.FormatNumber(video.Stat.View); + // } + // else + // { + // play = "--"; + // } + // } + // else + // { + // play = "--"; + // } + + // DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1)); // 当地时区 + // DateTime dateCTime = startTime.AddSeconds(video.Ctime); + // string ctime = dateCTime.ToString("yyyy-MM-dd"); + + // App.PropertyChangeAsync(new Action(() => + // { + // ChannelMedia media = new ChannelMedia(eventAggregator) + // { + // Avid = video.Aid, + // Bvid = video.Bvid, + // Cover = cover ?? new BitmapImage(new Uri($"pack://application:,,,/Resources/video-placeholder.png")), + // Duration = Format.FormatDuration3(video.Duration), + // Title = video.Title, + // PlayNumber = play, + // CreateTime = ctime + // }; + // Medias.Add(media); + + // LoadingVisibility = Visibility.Collapsed; + // NoDataVisibility = Visibility.Collapsed; + // })); + + // // 判断是否该结束线程,若为true,跳出循环 + // if (cancellationToken.IsCancellationRequested) + // { + // break; + // } + // } + + // }, (tokenSource = new CancellationTokenSource()).Token); + + // IsEnabled = true; + //} + + private async void UpdateSeasons(int current) + { + // 是否正在获取数据 + // 在所有的退出分支中都需要设为true + IsEnabled = false; + + await Task.Run(() => + { + CancellationToken cancellationToken = tokenSource.Token; + + var seasons = Core.BiliApi.Users.UserSpace.GetSeasonsDetail(mid, id, current, VideoNumberInPage); + if (seasons == null || seasons.Meta.Total == 0) + { + // 没有数据,UI提示 + LoadingVisibility = false; + NoDataVisibility = true; + return; + } + + foreach (var video in seasons.Archives) + { + //if (video.Cid == 0) + //{ + // continue; + //} + + // 查询、保存封面 + string coverUrl = video.Pic; + Bitmap cover; + if (coverUrl == null || coverUrl == "") + { + cover = null; // new BitmapImage(new Uri($"pack://application:,,,/Resources/video-placeholder.png")); + } + else + { + if (!coverUrl.ToLower().StartsWith("http")) + { + coverUrl = $"https:{video.Pic}"; + } + + StorageCover storageCover = new StorageCover(); + cover = storageCover.GetCoverThumbnail(video.Aid, video.Bvid, -1, coverUrl, 200, 125); + } + + // 播放数 + string play = string.Empty; + if (video.Stat != null) + { + if (video.Stat.View > 0) + { + play = Format.FormatNumber(video.Stat.View); + } + else + { + play = "--"; + } + } + else + { + play = "--"; + } + + DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1)); // 当地时区 + DateTime dateCTime = startTime.AddSeconds(video.Ctime); + string ctime = dateCTime.ToString("yyyy-MM-dd"); + + App.PropertyChangeAsync(new Action(() => + { + ChannelMedia media = new ChannelMedia(eventAggregator) + { + Avid = video.Aid, + Bvid = video.Bvid, + Cover = cover ?? + ImageHelper.LoadFromResource( + new Uri($"avares://DownKyi/Resources/video-placeholder.png")), + Duration = Format.FormatDuration3(video.Duration), + Title = video.Title, + PlayNumber = play, + CreateTime = ctime + }; + Medias.Add(media); + + LoadingVisibility = false; + NoDataVisibility = false; + })); + + // 判断是否该结束线程,若为true,跳出循环 + if (cancellationToken.IsCancellationRequested) + { + break; + } + } + }, (tokenSource = new CancellationTokenSource()).Token); + + IsEnabled = true; + } + + private async void UpdateSeries(int current) + { + // 是否正在获取数据 + // 在所有的退出分支中都需要设为true + IsEnabled = false; + + await Task.Run(() => + { + CancellationToken cancellationToken = tokenSource.Token; + + var meta = Core.BiliApi.Users.UserSpace.GetSeriesMeta(id); + var series = Core.BiliApi.Users.UserSpace.GetSeriesDetail(mid, id, current, VideoNumberInPage); + if (series == null || meta.Meta.Total == 0) + { + // 没有数据,UI提示 + LoadingVisibility = false; + NoDataVisibility = true; + return; + } + + foreach (var video in series.Archives) + { + //if (video.Cid == 0) + //{ + // continue; + //} + + // 查询、保存封面 + string coverUrl = video.Pic; + Bitmap cover; + if (coverUrl == null || coverUrl == "") + { + cover = null; // new BitmapImage(new Uri($"pack://application:,,,/Resources/video-placeholder.png")); + } + else + { + if (!coverUrl.ToLower().StartsWith("http")) + { + coverUrl = $"https:{video.Pic}"; + } + + StorageCover storageCover = new StorageCover(); + cover = storageCover.GetCoverThumbnail(video.Aid, video.Bvid, -1, coverUrl, 200, 125); + } + + // 播放数 + string play = string.Empty; + if (video.Stat != null) + { + if (video.Stat.View > 0) + { + play = Format.FormatNumber(video.Stat.View); + } + else + { + play = "--"; + } + } + else + { + play = "--"; + } + + DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1)); // 当地时区 + DateTime dateCTime = startTime.AddSeconds(video.Ctime); + string ctime = dateCTime.ToString("yyyy-MM-dd"); + + App.PropertyChangeAsync(new Action(() => + { + ChannelMedia media = new ChannelMedia(eventAggregator) + { + Avid = video.Aid, + Bvid = video.Bvid, + Cover = cover ?? + ImageHelper.LoadFromResource( + new Uri("avares://DownKyi/Resources/video-placeholder.png")), + Duration = Format.FormatDuration3(video.Duration), + Title = video.Title, + PlayNumber = play, + CreateTime = ctime + }; + Medias.Add(media); + + LoadingVisibility = false; + NoDataVisibility = false; + })); + + // 判断是否该结束线程,若为true,跳出循环 + if (cancellationToken.IsCancellationRequested) + { + break; + } + } + }, (tokenSource = new CancellationTokenSource()).Token); + + IsEnabled = true; + } + + /// + /// 导航到VideoDetail页面时执行 + /// + /// + public override void OnNavigatedTo(NavigationContext navigationContext) + { + base.OnNavigatedTo(navigationContext); + + ArrowBack.Fill = DictionaryResource.GetColor("ColorTextDark"); + + DownloadManage = ButtonIcon.Instance().DownloadManage; + DownloadManage.Height = 24; + DownloadManage.Width = 24; + DownloadManage.Fill = DictionaryResource.GetColor("ColorPrimary"); + + // 根据传入参数不同执行不同任务 + var parameter = navigationContext.Parameters.GetValue>("Parameter"); + if (parameter == null) + { + return; + } + + Medias.Clear(); + IsSelectAll = false; + + mid = (long)parameter["mid"]; + id = (long)parameter["id"]; + type = (int)parameter["type"]; + Title = (string)parameter["name"]; + int count = (int)parameter["count"]; + + // 页面选择 + Pager = new CustomPagerViewModel(1, (int)Math.Ceiling((double)count / VideoNumberInPage)); + Pager.CurrentChanged += OnCurrentChanged_Pager; + Pager.CountChanged += OnCountChanged_Pager; + Pager.Current = 1; + } +} \ No newline at end of file diff --git a/DownKyi/ViewModels/ViewSettingsViewModel.cs b/DownKyi/ViewModels/ViewSettingsViewModel.cs new file mode 100644 index 0000000..f0599f8 --- /dev/null +++ b/DownKyi/ViewModels/ViewSettingsViewModel.cs @@ -0,0 +1,167 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using DownKyi.Events; +using DownKyi.Images; +using DownKyi.Utils; +using DownKyi.ViewModels.PageViewModels; +using DownKyi.ViewModels.Settings; +using Prism.Commands; +using Prism.Events; +using Prism.Regions; +using ReactiveUI; + +namespace DownKyi.ViewModels; + +public class ViewSettingsViewModel : ViewModelBase +{ + public const string Tag = "PageSettings"; + + private readonly IRegionManager regionManager; + + #region 页面属性申明 + + private VectorImage arrowBack; + + public VectorImage ArrowBack + { + get => arrowBack; + set => SetProperty(ref arrowBack, value); + } + + private List tabHeaders; + + public List TabHeaders + { + get => tabHeaders; + set => SetProperty(ref tabHeaders, value); + } + + private int selectTabId; + + public int SelectTabId + { + get => selectTabId; + set => SetProperty(ref selectTabId, value); + } + + #endregion + + public ViewSettingsViewModel(IRegionManager regionManager, IEventAggregator eventAggregator) : base(eventAggregator) + { + this.regionManager = regionManager; + + #region 属性初始化 + + ArrowBack = NavigationIcon.Instance().ArrowBack; + ArrowBack.Fill = DictionaryResource.GetColor("ColorTextDark"); + + TabHeaders = new List + { + new() { Id = 0, Title = DictionaryResource.GetString("Basic") }, + new() { Id = 1, Title = DictionaryResource.GetString("Network") }, + new() { Id = 2, Title = DictionaryResource.GetString("Video") }, + new() { Id = 3, Title = DictionaryResource.GetString("SettingDanmaku") }, + new() { Id = 4, Title = DictionaryResource.GetString("About") } + }; + + #endregion + } + + #region 命令申明 + + // 返回事件 + private DelegateCommand backSpaceCommand; + + public DelegateCommand BackSpaceCommand => + backSpaceCommand ?? (backSpaceCommand = new DelegateCommand(ExecuteBackSpace)); + + /// + /// 返回事件 + /// + private void ExecuteBackSpace() + { + NavigationParam parameter = new NavigationParam + { + ViewName = ParentView, + ParentViewName = null, + Parameter = null + }; + eventAggregator.GetEvent().Publish(parameter); + } + + // 左侧tab点击事件 + private DelegateCommand leftTabHeadersCommand; + + public DelegateCommand LeftTabHeadersCommand => leftTabHeadersCommand ?? + (leftTabHeadersCommand = + new DelegateCommand( + ExecuteLeftTabHeadersCommand)); + + /// + /// 左侧tab点击事件 + /// + /// + private void ExecuteLeftTabHeadersCommand(object parameter) + { + if (!(parameter is TabHeader tabHeader)) + { + return; + } + + NavigationParameters param = new NavigationParameters(); + + switch (tabHeader.Id) + { + case 0: + regionManager.RequestNavigate("SettingsContentRegion", ViewBasicViewModel.Tag, param); + break; + case 1: + regionManager.RequestNavigate("SettingsContentRegion", ViewNetworkViewModel.Tag, param); + break; + case 2: + regionManager.RequestNavigate("SettingsContentRegion", ViewVideoViewModel.Tag, param); + break; + case 3: + regionManager.RequestNavigate("SettingsContentRegion", ViewDanmakuViewModel.Tag, param); + break; + case 4: + regionManager.RequestNavigate("SettingsContentRegion", ViewAboutViewModel.Tag, param); + break; + } + } + + private DelegateCommand loadedCommand; + + public DelegateCommand LoadedCommand => + loadedCommand ?? (loadedCommand = new DelegateCommand(ExecuteLoadedCommand)); + + /// + /// region加载完成事件 + /// + private void ExecuteLoadedCommand() + { + regionManager.RequestNavigate("SettingsContentRegion", ViewBasicViewModel.Tag, new NavigationParameters()); + } + + #endregion + + /// + /// 导航到页面时执行 + /// + /// + public override void OnNavigatedTo(NavigationContext navigationContext) + { + base.OnNavigatedTo(navigationContext); + + // 进入设置页面时显示的设置项 + SelectTabId = 0; + + PropertyChangeAsync(() => + { + regionManager.RequestNavigate("SettingsContentRegion", ViewBasicViewModel.Tag, new NavigationParameters()); + }); + + ArrowBack.Fill = DictionaryResource.GetColor("ColorTextDark"); + } +} \ No newline at end of file diff --git a/DownKyi/ViewModels/ViewToolboxViewModel.cs b/DownKyi/ViewModels/ViewToolboxViewModel.cs new file mode 100644 index 0000000..c0251c9 --- /dev/null +++ b/DownKyi/ViewModels/ViewToolboxViewModel.cs @@ -0,0 +1,145 @@ +using System.Collections.Generic; +using DownKyi.Events; +using DownKyi.Images; +using DownKyi.Utils; +using DownKyi.ViewModels.PageViewModels; +using DownKyi.ViewModels.Toolbox; +using Prism.Commands; +using Prism.Events; +using Prism.Regions; + +namespace DownKyi.ViewModels +{ + public class ViewToolboxViewModel : ViewModelBase + { + public const string Tag = "PageToolbox"; + + private readonly IRegionManager regionManager; + + #region 页面属性申明 + + private VectorImage arrowBack; + + public VectorImage ArrowBack + { + get => arrowBack; + set => SetProperty(ref arrowBack, value); + } + + private List tabHeaders; + + public List TabHeaders + { + get => tabHeaders; + set => SetProperty(ref tabHeaders, value); + } + + private int selectTabId; + + public int SelectTabId + { + get => selectTabId; + set => SetProperty(ref selectTabId, value); + } + + #endregion + + public ViewToolboxViewModel(IRegionManager regionManager, IEventAggregator eventAggregator) : base( + eventAggregator) + { + this.regionManager = regionManager; + + #region 属性初始化 + + ArrowBack = NavigationIcon.Instance().ArrowBack; + ArrowBack.Fill = DictionaryResource.GetColor("ColorTextDark"); + + TabHeaders = new List + { + new() { Id = 0, Title = DictionaryResource.GetString("BiliHelper") }, + new() { Id = 1, Title = DictionaryResource.GetString("Delogo") }, + new() { Id = 2, Title = DictionaryResource.GetString("ExtractMedia") } + }; + + #endregion + } + + #region 命令申明 + + // 返回事件 + private DelegateCommand backSpaceCommand; + + public DelegateCommand BackSpaceCommand => + backSpaceCommand ?? (backSpaceCommand = new DelegateCommand(ExecuteBackSpace)); + + /// + /// 返回事件 + /// + private void ExecuteBackSpace() + { + NavigationParam parameter = new NavigationParam + { + ViewName = ParentView, + ParentViewName = null, + Parameter = null + }; + eventAggregator.GetEvent().Publish(parameter); + } + + // 左侧tab点击事件 + private DelegateCommand leftTabHeadersCommand; + + public DelegateCommand LeftTabHeadersCommand => leftTabHeadersCommand ?? + (leftTabHeadersCommand = + new DelegateCommand( + ExecuteLeftTabHeadersCommand)); + + /// + /// 左侧tab点击事件 + /// + /// + private void ExecuteLeftTabHeadersCommand(object parameter) + { + if (!(parameter is TabHeader tabHeader)) + { + return; + } + + NavigationParameters param = new NavigationParameters(); + + switch (tabHeader.Id) + { + case 0: + regionManager.RequestNavigate("ToolboxContentRegion", ViewBiliHelperViewModel.Tag, param); + break; + case 1: + regionManager.RequestNavigate("ToolboxContentRegion", ViewDelogoViewModel.Tag, param); + break; + case 2: + regionManager.RequestNavigate("ToolboxContentRegion", ViewExtractMediaViewModel.Tag, param); + break; + } + } + + #endregion + + /// + /// 导航到页面时执行 + /// + /// + public override void OnNavigatedTo(NavigationContext navigationContext) + { + base.OnNavigatedTo(navigationContext); + + // 进入设置页面时显示的设置项 + SelectTabId = 0; + PropertyChangeAsync(() => + { + regionManager.RequestNavigate("ToolboxContentRegion", ViewBiliHelperViewModel.Tag, + new NavigationParameters()); + }); + + ArrowBack.Fill = DictionaryResource.GetColor("ColorTextDark"); + } + } +} \ No newline at end of file diff --git a/DownKyi/ViewModels/ViewUserSpaceViewModel.cs b/DownKyi/ViewModels/ViewUserSpaceViewModel.cs new file mode 100644 index 0000000..9c80ef5 --- /dev/null +++ b/DownKyi/ViewModels/ViewUserSpaceViewModel.cs @@ -0,0 +1,607 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Threading.Tasks; +using Avalonia.Media.Imaging; +using DownKyi.Core.BiliApi.Users; +using DownKyi.Core.BiliApi.Users.Models; +using DownKyi.Core.Storage; +using DownKyi.Core.Utils; +using DownKyi.Events; +using DownKyi.Images; +using DownKyi.Utils; +using DownKyi.ViewModels.UserSpace; +using Prism.Commands; +using Prism.Events; +using Prism.Regions; + +namespace DownKyi.ViewModels; + +public class ViewUserSpaceViewModel : ViewModelBase +{ + public const string Tag = "PageUserSpace"; + + private readonly IRegionManager regionManager; + + // mid + private long mid = -1; + + #region 页面属性申明 + + private VectorImage arrowBack; + + public VectorImage ArrowBack + { + get => arrowBack; + set => SetProperty(ref arrowBack, value); + } + + private bool loading; + public bool Loading + { + get => loading; + set => SetProperty(ref loading, value); + } + + private bool noDataVisibility; + + public bool NoDataVisibility + { + get => noDataVisibility; + set => SetProperty(ref noDataVisibility, value); + } + + private bool loadingVisibility; + + public bool LoadingVisibility + { + get => loadingVisibility; + set => SetProperty(ref loadingVisibility, value); + } + + private bool viewVisibility; + + public bool ViewVisibility + { + get => viewVisibility; + set => SetProperty(ref viewVisibility, value); + } + + private bool contentVisibility; + + public bool ContentVisibility + { + get => contentVisibility; + set => SetProperty(ref contentVisibility, value); + } + + private string topNavigationBg; + + public string TopNavigationBg + { + get => topNavigationBg; + set => SetProperty(ref topNavigationBg, value); + } + + private Bitmap background; + + public Bitmap Background + { + get => background; + set => SetProperty(ref background, value); + } + + private Bitmap header; + + public Bitmap Header + { + get => header; + set => SetProperty(ref header, value); + } + + private string userName; + + public string UserName + { + get => userName; + set => SetProperty(ref userName, value); + } + + private Bitmap sex; + + public Bitmap Sex + { + get => sex; + set => SetProperty(ref sex, value); + } + + private Bitmap level; + + public Bitmap Level + { + get => level; + set => SetProperty(ref level, value); + } + + private bool vipTypeVisibility; + + public bool VipTypeVisibility + { + get => vipTypeVisibility; + set => SetProperty(ref vipTypeVisibility, value); + } + + private string vipType; + + public string VipType + { + get => vipType; + set => SetProperty(ref vipType, value); + } + + private string sign; + + public string Sign + { + get => sign; + set => SetProperty(ref sign, value); + } + + private string isFollowed; + + public string IsFollowed + { + get => isFollowed; + set => SetProperty(ref isFollowed, value); + } + + private ObservableCollection tabLeftBanners; + + public ObservableCollection TabLeftBanners + { + get => tabLeftBanners; + set => SetProperty(ref tabLeftBanners, value); + } + + private ObservableCollection tabRightBanners; + + public ObservableCollection TabRightBanners + { + get => tabRightBanners; + set => SetProperty(ref tabRightBanners, value); + } + + private int selectedRightBanner; + + public int SelectedRightBanner + { + get => selectedRightBanner; + set => SetProperty(ref selectedRightBanner, value); + } + + #endregion + + public ViewUserSpaceViewModel(IRegionManager regionManager, IEventAggregator eventAggregator) : base( + eventAggregator) + { + this.regionManager = regionManager; + + #region 属性初始化 + + // 返回按钮 + ArrowBack = NavigationIcon.Instance().ArrowBack; + ArrowBack.Fill = DictionaryResource.GetColor("ColorTextDark"); + + // 初始化loading + Loading = true; + + TopNavigationBg = "#00FFFFFF"; // 透明 + + TabLeftBanners = new ObservableCollection(); + TabRightBanners = new ObservableCollection(); + + #endregion + } + + #region 命令申明 + + // 返回事件 + private DelegateCommand backSpaceCommand; + + public DelegateCommand BackSpaceCommand => + backSpaceCommand ?? (backSpaceCommand = new DelegateCommand(ExecuteBackSpace)); + + /// + /// 返回事件 + /// + private void ExecuteBackSpace() + { + NavigationParam parameter = new NavigationParam + { + ViewName = ParentView, + ParentViewName = null, + Parameter = null + }; + eventAggregator.GetEvent().Publish(parameter); + } + + // 左侧tab点击事件 + private DelegateCommand tabLeftBannersCommand; + + public DelegateCommand TabLeftBannersCommand => tabLeftBannersCommand ?? + (tabLeftBannersCommand = + new DelegateCommand( + ExecuteTabLeftBannersCommand)); + + /// + /// 左侧tab点击事件 + /// + /// + private void ExecuteTabLeftBannersCommand(object parameter) + { + if (!(parameter is TabLeftBanner banner)) + { + return; + } + + NavigationParameters param = new NavigationParameters() + { + { "object", banner.Object }, + { "mid", mid }, + }; + + switch (banner.Id) + { + case 0: // 投稿 + regionManager.RequestNavigate("UserSpaceContentRegion", ViewArchiveViewModel.Tag, param); + break; + case 1: // 频道(弃用) + regionManager.RequestNavigate("UserSpaceContentRegion", ViewChannelViewModel.Tag, param); + break; + case 2: // 合集和列表 + regionManager.RequestNavigate("UserSpaceContentRegion", UserSpace.ViewSeasonsSeriesViewModel.Tag, + param); + break; + } + } + + // 右侧tab点击事件 + private DelegateCommand tabRightBannersCommand; + + public DelegateCommand TabRightBannersCommand => tabRightBannersCommand ?? + (tabRightBannersCommand = + new DelegateCommand( + ExecuteTabRightBannersCommand)); + + /// + /// 右侧tab点击事件 + /// + private void ExecuteTabRightBannersCommand(object parameter) + { + if (!(parameter is TabRightBanner banner)) + { + return; + } + + Dictionary data = new Dictionary + { + { "mid", mid }, + { "friendId", 0 } + }; + + string parentViewName; + if (ParentView == ViewFriendsViewModel.Tag) + { + parentViewName = ViewIndexViewModel.Tag; + } + else + { + parentViewName = Tag; + } + + switch (banner.Id) + { + case 0: + data["friendId"] = 0; + NavigateToView.NavigationView(eventAggregator, ViewFriendsViewModel.Tag, parentViewName, data); + break; + case 1: + data["friendId"] = 1; + NavigateToView.NavigationView(eventAggregator, ViewFriendsViewModel.Tag, parentViewName, data); + break; + } + + SelectedRightBanner = -1; + } + + #endregion + + /// + /// 初始化页面 + /// + private void InitView() + { + TopNavigationBg = "#00FFFFFF"; // 透明 + ArrowBack.Fill = DictionaryResource.GetColor("ColorTextDark"); + Background = null; + + Header = null; + UserName = ""; + Sex = null; + Level = null; + VipTypeVisibility = false; + VipType = ""; + Sign = ""; + + TabLeftBanners.Clear(); + TabRightBanners.Clear(); + + SelectedRightBanner = -1; + + // 将内容置空,使其不指向任何页面 + regionManager.RequestNavigate("UserSpaceContentRegion", ""); + + ContentVisibility = false; + ViewVisibility = false; + LoadingVisibility = true; + NoDataVisibility = false; + } + + /// + /// 更新用户信息 + /// + private async void UpdateSpaceInfo() + { + bool isNoData = true; + Uri toutuUri = null; + string headerUri = null; + Uri sexUri = null; + Uri levelUri = null; + + await Task.Run(() => + { + // 背景图片 + SpaceSettings spaceSettings = Core.BiliApi.Users.UserSpace.GetSpaceSettings(mid); + if (spaceSettings != null) + { + StorageCover storageCover = new StorageCover(); + string toutu = storageCover.GetCover($"https://i0.hdslb.com/{spaceSettings.Toutu.Limg}"); + toutuUri = new Uri(toutu); + } + else + { + toutuUri = new Uri("avares://DownKyi/Resources/backgound/9-绿荫秘境.png"); + } + + // 用户信息 + UserInfoForSpace userInfo = UserInfo.GetUserInfoForSpace(mid); + if (userInfo != null) + { + isNoData = false; + + // 头像 + StorageHeader storageHeader = new StorageHeader(); + headerUri = storageHeader.GetHeader(mid, userInfo.Name, userInfo.Face); + // 用户名 + UserName = userInfo.Name; + // 性别 + if (userInfo.Sex == "男") + { + sexUri = new Uri("avares://DownKyi/Resources/sex/male.png"); + } + else if (userInfo.Sex == "女") + { + sexUri = new Uri("avares://DownKyi/Resources/sex/female.png"); + } + + // 显示vip信息 + if (userInfo.Vip.Label.Text == null || userInfo.Vip.Label.Text == "") + { + VipTypeVisibility = false; + } + else + { + VipTypeVisibility = true; + VipType = userInfo.Vip.Label.Text; + } + + // 等级 + levelUri = new Uri($"avares://DownKyi/Resources/level/lv{userInfo.Level}.png"); + // 签名 + Sign = userInfo.Sign; + + // 是否关注此UP + PropertyChangeAsync(() => + { + IsFollowed = userInfo.IsFollowed + ? DictionaryResource.GetString("Followed") + : DictionaryResource.GetString("NotFollowed"); + }); + } + else + { + // 没有数据 + isNoData = true; + } + }); + + // 是否获取到数据 + if (isNoData) + { + TopNavigationBg = "#00FFFFFF"; // 透明 + ArrowBack.Fill = DictionaryResource.GetColor("ColorTextDark"); + Background = null; + + ViewVisibility = false; + LoadingVisibility = false; + NoDataVisibility = true; + return; + } + else + { + // 头像 + StorageHeader storageHeader = new StorageHeader(); + Header = storageHeader.GetHeaderThumbnail(headerUri, 64, 64); + // 性别 + Sex = sexUri == null ? null : ImageHelper.LoadFromResource(sexUri); + // 等级 + Level = levelUri == null ? null : ImageHelper.LoadFromResource(levelUri); + + ArrowBack.Fill = DictionaryResource.GetColor("ColorText"); + TopNavigationBg = DictionaryResource.GetColor("ColorMask100"); + Background = ImageHelper.LoadFromResource(toutuUri); + + ViewVisibility = true; + LoadingVisibility = false; + NoDataVisibility = false; + } + + ContentVisibility = true; + + // 投稿视频 + List publicationTypes = null; + await Task.Run(() => { publicationTypes = Core.BiliApi.Users.UserSpace.GetPublicationType(mid); }); + if (publicationTypes != null && publicationTypes.Count > 0) + { + TabLeftBanners.Add(new TabLeftBanner + { + Object = publicationTypes, + Id = 0, + Icon = NormalIcon.Instance().VideoUp, + IconColor = "#FF02B5DA", + Title = DictionaryResource.GetString("Publication"), + IsSelected = true + }); + } + + // 频道 + //List channelList = null; + //await Task.Run(() => + //{ + // channelList = Core.BiliApi.Users.UserSpace.GetChannelList(mid); + //}); + //if (channelList != null && channelList.Count > 0) + //{ + // TabLeftBanners.Add(new TabLeftBanner + // { + // Object = channelList, + // Id = 1, + // Icon = NormalIcon.Instance().Channel, + // IconColor = "#FF23C9ED", + // Title = DictionaryResource.GetString("Channel") + // }); + //} + + // 合集和列表 + SpaceSeasonsSeries seasonsSeries = null; + await Task.Run(() => { seasonsSeries = Core.BiliApi.Users.UserSpace.GetSeasonsSeries(mid, 1, 20); }); + if (seasonsSeries != null && seasonsSeries.Page.Total > 0) + { + TabLeftBanners.Add(new TabLeftBanner + { + Object = seasonsSeries, + Id = 2, + Icon = NormalIcon.Instance().Channel, + IconColor = "#FF23C9ED", + Title = DictionaryResource.GetString("SeasonsSeries") + }); + } + + // 收藏夹 + // 订阅 + + // 关系状态数 + UserRelationStat relationStat = null; + await Task.Run(() => { relationStat = UserStatus.GetUserRelationStat(mid); }); + if (relationStat != null) + { + TabRightBanners.Add(new TabRightBanner + { + Id = 0, + IsEnabled = true, + LabelColor = DictionaryResource.GetColor("ColorPrimary"), + CountColor = DictionaryResource.GetColor("ColorPrimary"), + Label = DictionaryResource.GetString("FollowingCount"), + Count = Format.FormatNumber(relationStat.Following) + }); + TabRightBanners.Add(new TabRightBanner + { + Id = 1, + IsEnabled = true, + LabelColor = DictionaryResource.GetColor("ColorPrimary"), + CountColor = DictionaryResource.GetColor("ColorPrimary"), + Label = DictionaryResource.GetString("FollowerCount"), + Count = Format.FormatNumber(relationStat.Follower) + }); + } + + // UP主状态数,需要任意用户登录,否则不会返回任何数据 + UpStat upStat = null; + await Task.Run(() => { upStat = UserStatus.GetUpStat(mid); }); + if (upStat != null && upStat.Archive != null && upStat.Article != null) + { + TabRightBanners.Add(new TabRightBanner + { + Id = 2, + IsEnabled = false, + LabelColor = DictionaryResource.GetColor("ColorTextGrey"), + CountColor = DictionaryResource.GetColor("ColorTextDark"), + Label = DictionaryResource.GetString("LikesCount"), + Count = Format.FormatNumber(upStat.Likes) + }); + + long archiveView = 0; + if (upStat.Archive != null) + { + archiveView = upStat.Archive.View; + } + + TabRightBanners.Add(new TabRightBanner + { + Id = 3, + IsEnabled = false, + LabelColor = DictionaryResource.GetColor("ColorTextGrey"), + CountColor = DictionaryResource.GetColor("ColorTextDark"), + Label = DictionaryResource.GetString("ArchiveViewCount"), + Count = Format.FormatNumber(archiveView) + }); + + long articleView = 0; + if (upStat.Article != null) + { + articleView = upStat.Article.View; + } + + TabRightBanners.Add(new TabRightBanner + { + Id = 4, + IsEnabled = false, + LabelColor = DictionaryResource.GetColor("ColorTextGrey"), + CountColor = DictionaryResource.GetColor("ColorTextDark"), + Label = DictionaryResource.GetString("ArticleViewCount"), + Count = Format.FormatNumber(articleView) + }); + } + } + + /// + /// 接收mid参数 + /// + /// + public override void OnNavigatedTo(NavigationContext navigationContext) + { + base.OnNavigatedTo(navigationContext); + + // 根据传入参数不同执行不同任务 + long parameter = navigationContext.Parameters.GetValue("Parameter"); + if (parameter == 0) + { + return; + } + + mid = parameter; + + InitView(); + UpdateSpaceInfo(); + } +} \ No newline at end of file diff --git a/DownKyi/ViewModels/ViewVideoDetailViewModel.cs b/DownKyi/ViewModels/ViewVideoDetailViewModel.cs new file mode 100644 index 0000000..880c488 --- /dev/null +++ b/DownKyi/ViewModels/ViewVideoDetailViewModel.cs @@ -0,0 +1,790 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using DownKyi.Core.BiliApi.BiliUtils; +using DownKyi.Core.BiliApi.VideoStream; +using DownKyi.Core.Logging; +using DownKyi.Core.Settings; +using DownKyi.Events; +using DownKyi.Images; +using DownKyi.Services; +using DownKyi.Services.Download; +using DownKyi.Utils; +using DownKyi.ViewModels.Dialogs; +using DownKyi.ViewModels.PageViewModels; +using Newtonsoft.Json; +using Prism.Commands; +using Prism.Events; +using Prism.Regions; +using Prism.Services.Dialogs; +using Console = DownKyi.Core.Utils.Debugging.Console; + +namespace DownKyi.ViewModels; + +public class ViewVideoDetailViewModel : ViewModelBase +{ + public const string Tag = "PageVideoDetail"; + + // 保存输入字符串,避免被用户修改 + private string input = null; + + #region 页面属性申明 + + private VectorImage arrowBack; + + public VectorImage ArrowBack + { + get => arrowBack; + set => SetProperty(ref arrowBack, value); + } + + private string inputText; + + public string InputText + { + get => inputText; + set => SetProperty(ref inputText, value); + } + + private string inputSearchText; + + public string InputSearchText + { + get => inputSearchText; + set => SetProperty(ref inputSearchText, value); + } + + private bool loading; + public bool Loading + { + get => loading; + set => SetProperty(ref loading, value); + } + + + + private bool loadingVisibility; + + public bool LoadingVisibility + { + get => loadingVisibility; + set => SetProperty(ref loadingVisibility, value); + } + + private VectorImage downloadManage; + + public VectorImage DownloadManage + { + get => downloadManage; + set => SetProperty(ref downloadManage, value); + } + + private VideoInfoView videoInfoView; + + public VideoInfoView VideoInfoView + { + get => videoInfoView; + set => SetProperty(ref videoInfoView, value); + } + + private ObservableCollection videoSections; + + public ObservableCollection VideoSections + { + get => videoSections; + set => SetProperty(ref videoSections, value); + } + + public ObservableCollection CaCheVideoSections { get; set; } + + public List selectedVideoPages { get; set; } = new(); + + private bool isSelectAll; + + public bool IsSelectAll + { + get => isSelectAll; + set => SetProperty(ref isSelectAll, value); + } + + private bool contentVisibility; + + public bool ContentVisibility + { + get => contentVisibility; + set => SetProperty(ref contentVisibility, value); + } + + private bool noDataVisibility; + + public bool NoDataVisibility + { + get => noDataVisibility; + set => SetProperty(ref noDataVisibility, value); + } + + #endregion + + public ViewVideoDetailViewModel(IEventAggregator eventAggregator, IDialogService dialogService) : base( + eventAggregator, dialogService) + { + // 初始化loading + Loading = true; + LoadingVisibility = false; + + // 返回按钮 + ArrowBack = NavigationIcon.Instance().ArrowBack; + ArrowBack.Fill = DictionaryResource.GetColor("ColorTextDark"); + + // 下载管理按钮 + DownloadManage = ButtonIcon.Instance().DownloadManage; + DownloadManage.Height = 24; + DownloadManage.Width = 24; + DownloadManage.Fill = DictionaryResource.GetColor("ColorPrimary"); + + VideoSections = new ObservableCollection(); + CaCheVideoSections = new ObservableCollection(); + } + + #region 命令申明 + +// 返回 + private DelegateCommand backSpaceCommand; + + public DelegateCommand BackSpaceCommand => + backSpaceCommand ?? (backSpaceCommand = new DelegateCommand(ExecuteBackSpace)); + + /// + /// 返回 + /// + private void ExecuteBackSpace() + { + NavigationParam parameter = new NavigationParam + { + ViewName = ParentView, + ParentViewName = null, + Parameter = null + }; + eventAggregator.GetEvent().Publish(parameter); + } + + // 前往下载管理页面 + private DelegateCommand downloadManagerCommand; + + public DelegateCommand DownloadManagerCommand => downloadManagerCommand ?? + (downloadManagerCommand = + new DelegateCommand(ExecuteDownloadManagerCommand)); + + /// + /// 前往下载管理页面 + /// + private void ExecuteDownloadManagerCommand() + { + NavigationParam parameter = new NavigationParam + { + ViewName = ViewDownloadManagerViewModel.Tag, + ParentViewName = Tag, + Parameter = null + }; + eventAggregator.GetEvent().Publish(parameter); + } + + // 输入确认事件 + private DelegateCommand inputCommand; + + public DelegateCommand InputCommand => + inputCommand ?? (inputCommand = new DelegateCommand(ExecuteInputCommand, CanExecuteInputCommand)); + + + private DelegateCommand inputSearchCommand; + + public DelegateCommand InputSearchCommand => + inputSearchCommand ?? (inputSearchCommand = new DelegateCommand(ExcuteInputSearchCommand)); + + /// + /// 搜索视频输入事件 + /// + private async void ExcuteInputSearchCommand() + { + await Task.Run(() => + { + if (InputSearchText == null || InputSearchText == string.Empty) + { + foreach (VideoSection section in VideoSections) + { + var cache = CaCheVideoSections.FirstOrDefault(e => e.Id == section.Id); + if (cache != null) + { + section.VideoPages = cache.VideoPages; + } + } + } + else + { + foreach (VideoSection section in VideoSections) + { + var cache = CaCheVideoSections.FirstOrDefault(e => e.Id == section.Id); + if (cache != null) + { + var pages = cache.VideoPages.Where(e => e.Name.Contains(InputSearchText)).ToList(); + section.VideoPages = pages; + } + } + } + }); + } + + /// + /// 处理输入事件 + /// + private async void ExecuteInputCommand() + { + InitView(); + try + { + await Task.Run(() => + { + if (InputText == null || InputText == string.Empty) + { + return; + } + + LogManager.Debug(Tag, $"InputText: {InputText}"); + InputText = Regex.Replace(InputText, @"[【]*[^【]*[^】]*[】 ]", ""); + input = InputText; + + // 更新页面 + UnityUpdateView(UpdateView, input, null); + + // 是否自动解析视频 + if (SettingsManager.GetInstance().IsAutoParseVideo() == AllowStatus.YES) + { + PropertyChangeAsync(ExecuteParseAllVideoCommand); + } + }); + } + catch (Exception e) + { + Console.PrintLine("InputCommand()发生异常: {0}", e); + LogManager.Error(Tag, e); + + LoadingVisibility = false; + ContentVisibility = false; + NoDataVisibility = true; + } + } + + /// + /// 输入事件是否允许执行 + /// + /// + private bool CanExecuteInputCommand() + { + return LoadingVisibility != true; + } + + // 复制封面事件 + private DelegateCommand? copyCoverCommand; + + public DelegateCommand CopyCoverCommand => + copyCoverCommand ??= new DelegateCommand(ExecuteCopyCoverCommand); + + /// + /// 复制封面事件 + /// + private void ExecuteCopyCoverCommand() + { + // 复制封面图片到剪贴板 + // Clipboard.SetImage(VideoInfoView.Cover); + LogManager.Info(Tag, "复制封面图片到剪贴板"); + } + + // 复制封面URL事件 + private DelegateCommand? copyCoverUrlCommand; + + public DelegateCommand CopyCoverUrlCommand => + copyCoverUrlCommand ??= new DelegateCommand(ExecuteCopyCoverUrlCommand); + + /// + /// 复制封面URL事件 + /// + private void ExecuteCopyCoverUrlCommand() + { + // 复制封面url到剪贴板 + // Clipboard.SetText(VideoInfoView.CoverUrl); + LogManager.Info(Tag, "复制封面url到剪贴板"); + } + + // 前往UP主页事件 + private DelegateCommand? upperCommand; + public DelegateCommand UpperCommand => upperCommand ??= new DelegateCommand(ExecuteUpperCommand); + + /// + /// 前往UP主页事件 + /// + private void ExecuteUpperCommand() + { + NavigateToView.NavigateToViewUserSpace(eventAggregator, Tag, VideoInfoView.UpperMid); + } + +// 视频章节选择事件 + private DelegateCommand? videoSectionsCommand; + + public DelegateCommand VideoSectionsCommand => + videoSectionsCommand ??= new DelegateCommand(ExecuteVideoSectionsCommand); + + /// + /// 视频章节选择事件 + /// + /// + private void ExecuteVideoSectionsCommand(object parameter) + { + if (!(parameter is VideoSection section)) + { + return; + } + + bool isSelectAll = true; + foreach (VideoPage page in section.VideoPages) + { + if (!page.IsSelected) + { + isSelectAll = false; + break; + } + } + + IsSelectAll = section.VideoPages.Count != 0 && isSelectAll; + } + +// 视频page选择事件 + private DelegateCommand videoPagesCommand; + + public DelegateCommand VideoPagesCommand => videoPagesCommand ?? + (videoPagesCommand = + new DelegateCommand(ExecuteVideoPagesCommand)); + + /// + /// 视频page选择事件 + /// + /// + private void ExecuteVideoPagesCommand(IList parameter) + { + if (!(parameter is IList videoPages)) + { + return; + } + + VideoSection section = VideoSections.FirstOrDefault(item => item.IsSelected); + + if (section == null) + { + return; + } + + selectedVideoPages.Clear(); + foreach (var page in videoPages) + { + selectedVideoPages.Add((VideoPage)page); + } + + IsSelectAll = section.VideoPages.Count == videoPages.Count && section.VideoPages.Count != 0; + } + + // Ctrl+A 全选事件 + private DelegateCommand keySelectAllCommand; + + public DelegateCommand KeySelectAllCommand => keySelectAllCommand ?? + (keySelectAllCommand = + new DelegateCommand(ExecuteKeySelectAllCommand)); + + /// + /// Ctrl+A 全选事件 + /// + private void ExecuteKeySelectAllCommand(object parameter) + { + if (!(parameter is VideoSection section)) + { + return; + } + + foreach (VideoPage page in section.VideoPages) + { + page.IsSelected = true; + } + } + + // 解析所有视频流事件 + private DelegateCommand parseAllVideoCommand; + + public DelegateCommand ParseAllVideoCommand => parseAllVideoCommand ?? (parseAllVideoCommand = + new DelegateCommand(ExecuteParseAllVideoCommand, CanExecuteParseAllVideoCommand)); + + /// + /// 解析所有视频流事件 + /// + private async void ExecuteParseAllVideoCommand() + { + LoadingVisibility = true; + + // 解析范围 + ParseScope parseScope = SettingsManager.GetInstance().GetParseScope(); + + // 是否选择了解析范围 + if (parseScope == ParseScope.NONE) + { + //打开解析选择器 + dialogService.ShowDialog(ViewParsingSelectorViewModel.Tag, null, async result => + { + if (result.Result == ButtonResult.OK) + { + // 选择的解析范围 + parseScope = result.Parameters.GetValue("parseScope"); + await ExecuteParse(parseScope); + } + else + { + loadingVisibility = false; + } + }); + } + else + { + await ExecuteParse(parseScope); + } + } + + /// + /// 解析所有视频流事件是否允许执行 + /// + /// + private bool CanExecuteParseAllVideoCommand() + { + return LoadingVisibility != true; + } + + private async Task ExecuteParse(ParseScope parseScope) + { + try + { + await Task.Run(() => + { + LogManager.Debug(Tag, "Parse video"); + + switch (parseScope) + { + case ParseScope.NONE: + break; + case ParseScope.SELECTED_ITEM: + foreach (VideoSection section in VideoSections) + { + foreach (VideoPage page in section.VideoPages) + { + if (selectedVideoPages.Find(v => v.Order == page.Order) != null) + { + UnityUpdateView(ParseVideo, input, page); + } + /*if (page.IsSelected) + { + // 执行解析任务 + UnityUpdateView(ParseVideo, input, page); + }*/ + } + } + + break; + case ParseScope.CURRENT_SECTION: + foreach (VideoSection section in VideoSections) + { + if (section.IsSelected) + { + foreach (VideoPage page in section.VideoPages) + { + // 执行解析任务 + UnityUpdateView(ParseVideo, input, page); + } + } + } + + break; + case ParseScope.ALL: + foreach (VideoSection section in VideoSections) + { + foreach (VideoPage page in section.VideoPages) + { + // 执行解析任务 + UnityUpdateView(ParseVideo, input, page); + } + } + + break; + default: + break; + } + }); + } + catch (Exception e) + { + Console.PrintLine("ParseCommand()发生异常: {0}", e); + LogManager.Error(Tag, e); + + LoadingVisibility = false; + } + + LoadingVisibility = false; + + // 解析后是否自动下载解析视频 + AllowStatus isAutoDownloadAll = SettingsManager.GetInstance().IsAutoDownloadAll(); + if (parseScope != ParseScope.NONE && isAutoDownloadAll == AllowStatus.YES) + { + AddToDownload(true); + } + + LogManager.Debug(Tag, $"ParseScope: {parseScope:G}"); + } + + // 添加到下载列表事件 + private DelegateCommand addToDownloadCommand; + + public DelegateCommand AddToDownloadCommand => addToDownloadCommand ?? (addToDownloadCommand = + new DelegateCommand(ExecuteAddToDownloadCommand, CanExecuteAddToDownloadCommand)); + + /// + /// 添加到下载列表事件 + /// + private void ExecuteAddToDownloadCommand() + { + AddToDownload(false); + } + + private bool CanExecuteAddToDownloadCommand() + { + return LoadingVisibility != true; + } + + #endregion + + #region 业务逻辑 + + /// + /// 初始化页面元素 + /// + private void InitView() + { + LogManager.Debug(Tag, "初始化页面元素"); + + LoadingVisibility = true; + ContentVisibility = false; + NoDataVisibility = false; + + VideoSections.Clear(); + CaCheVideoSections.Clear(); + } + + /// + /// 更新页面的统一方法 + /// + /// + /// + /// + private void UnityUpdateView(Action action, string input, VideoPage page) + { + // 视频 + if (ParseEntrance.IsAvUrl(input) || ParseEntrance.IsBvUrl(input)) + { + action(new VideoInfoService(input), page); + } + + // 番剧(电影、电视剧) + if (ParseEntrance.IsBangumiSeasonUrl(input) || ParseEntrance.IsBangumiEpisodeUrl(input) || + ParseEntrance.IsBangumiMediaUrl(input)) + { + action(new BangumiInfoService(input), page); + } + + // 课程 + if (ParseEntrance.IsCheeseSeasonUrl(input) || ParseEntrance.IsCheeseEpisodeUrl(input)) + { + action(new CheeseInfoService(input), page); + } + } + + /// + /// 更新页面 + /// + /// + private void UpdateView(IInfoService videoInfoService, VideoPage param) + { + // 获取视频详情 + VideoInfoView = videoInfoService.GetVideoView(); + if (VideoInfoView == null) + { + LogManager.Debug(Tag, "VideoInfoView is null."); + + LoadingVisibility = false; + ContentVisibility = false; + NoDataVisibility = true; + return; + } + else + { + LoadingVisibility = false; + ContentVisibility = true; + NoDataVisibility = false; + } + + // 获取视频列表 + List videoSections = videoInfoService.GetVideoSections(false); + + // 清空以前的数据 + PropertyChangeAsync(() => + { + VideoSections.Clear(); + CaCheVideoSections.Clear(); + }); + + // 添加新数据 + if (videoSections == null) + { + LogManager.Debug(Tag, "videoSections is not exist."); + + List pages = videoInfoService.GetVideoPages(); + + PropertyChangeAsync(() => + { + VideoSections.Add(new VideoSection + { + Id = 0, + Title = "default", + IsSelected = true, + VideoPages = pages + }); + CaCheVideoSections.Add(new VideoSection + { + Id = 0, + Title = "default", + IsSelected = true, + VideoPages = pages + }); + }); + } + else + { + //这里如果浅拷贝会导致用于查询的CaCheVideoSections数据变化,所以这样处理 + var videoSectionsStr = JsonConvert.SerializeObject(videoSections); + var videoSectionsData = JsonConvert.DeserializeObject>(videoSectionsStr); + PropertyChangeAsync(() => + { + VideoSections.AddRange(videoSections); + CaCheVideoSections.AddRange(videoSectionsData); + }); + } + } + + /// + /// 解析视频流 + /// + /// + private void ParseVideo(IInfoService videoInfoService, VideoPage videoPage) + { + videoInfoService.GetVideoStream(videoPage); + } + + /// + /// 添加到下载列表事件 + /// + /// 是否下载所有,包括未选中项 + private async void AddToDownload(bool isAll) + { + AddToDownloadService addToDownloadService = null; + // 视频 + if (ParseEntrance.IsAvUrl(input) || ParseEntrance.IsBvUrl(input)) + { + addToDownloadService = new AddToDownloadService(PlayStreamType.VIDEO); + } + // 番剧(电影、电视剧) + else if (ParseEntrance.IsBangumiSeasonUrl(input) || ParseEntrance.IsBangumiEpisodeUrl(input) || + ParseEntrance.IsBangumiMediaUrl(input)) + { + addToDownloadService = new AddToDownloadService(PlayStreamType.BANGUMI); + } + // 课程 + else if (ParseEntrance.IsCheeseSeasonUrl(input) || ParseEntrance.IsCheeseEpisodeUrl(input)) + { + addToDownloadService = new AddToDownloadService(PlayStreamType.CHEESE); + } + else + { + return; + } + + // 选择文件夹 + string directory = await addToDownloadService.SetDirectory(dialogService); + + // 视频计数 + int i = 0; + await Task.Run(() => + { + // 传递video对象 + addToDownloadService.GetVideo(VideoInfoView, VideoSections.ToList(), + selectedVideoPages.Select(video => video.Order).ToList()); + // 下载 + i = addToDownloadService.AddToDownload(eventAggregator, directory, isAll); + }); + + if (directory == null) + { + return; + } + + // 通知用户添加到下载列表的结果 + if (i <= 0) + { + eventAggregator.GetEvent().Publish(DictionaryResource.GetString("TipAddDownloadingZero")); + } + else + { + eventAggregator.GetEvent() + .Publish( + $"{DictionaryResource.GetString("TipAddDownloadingFinished1")}{i}{DictionaryResource.GetString("TipAddDownloadingFinished2")}"); + } + } + + #endregion + + public override void OnNavigatedTo(NavigationContext navigationContext) + { + ArrowBack.Fill = DictionaryResource.GetColor("ColorTextDark"); + + DownloadManage = ButtonIcon.Instance().DownloadManage; + DownloadManage.Height = 24; + DownloadManage.Width = 24; + DownloadManage.Fill = DictionaryResource.GetColor("ColorPrimary"); + // Parent参数为null时,表示是从下一个页面返回到本页面,不需要执行任务 + if (navigationContext.Parameters.GetValue("Parent") != null) + { + string param = navigationContext.Parameters.GetValue("Parameter"); + // 移除剪贴板id + string input = param.Replace(AppConstant.ClipboardId, ""); + + // 检测是否从剪贴板传入 + if (InputText == input && param.EndsWith(AppConstant.ClipboardId)) + { + return; + } + + // 正在执行任务时不开启新任务 + if (LoadingVisibility != true) + { + InputText = input; + PropertyChangeAsync(ExecuteInputCommand); + } + } + + base.OnNavigatedTo(navigationContext); + } +} \ No newline at end of file diff --git a/DownKyi/Views/Dialogs/ViewAlertDialog.axaml b/DownKyi/Views/Dialogs/ViewAlertDialog.axaml new file mode 100644 index 0000000..a6ec635 --- /dev/null +++ b/DownKyi/Views/Dialogs/ViewAlertDialog.axaml @@ -0,0 +1,106 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/DownKyi/Views/ViewDownloadManager.axaml.cs b/DownKyi/Views/ViewDownloadManager.axaml.cs new file mode 100644 index 0000000..9a29eb5 --- /dev/null +++ b/DownKyi/Views/ViewDownloadManager.axaml.cs @@ -0,0 +1,13 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; + +namespace DownKyi.Views; + +public partial class ViewDownloadManager : UserControl +{ + public ViewDownloadManager() + { + InitializeComponent(); + } +} \ No newline at end of file diff --git a/DownKyi/Views/ViewFriends.axaml b/DownKyi/Views/ViewFriends.axaml new file mode 100644 index 0000000..c3f911e --- /dev/null +++ b/DownKyi/Views/ViewFriends.axaml @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/DownKyi/Views/ViewFriends.axaml.cs b/DownKyi/Views/ViewFriends.axaml.cs new file mode 100644 index 0000000..7d93418 --- /dev/null +++ b/DownKyi/Views/ViewFriends.axaml.cs @@ -0,0 +1,13 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; + +namespace DownKyi.Views; + +public partial class ViewFriends : UserControl +{ + public ViewFriends() + { + InitializeComponent(); + } +} \ No newline at end of file diff --git a/DownKyi/Views/ViewIndex.axaml b/DownKyi/Views/ViewIndex.axaml new file mode 100644 index 0000000..ce03cb9 --- /dev/null +++ b/DownKyi/Views/ViewIndex.axaml @@ -0,0 +1,216 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/DownKyi/Views/ViewIndex.axaml.cs b/DownKyi/Views/ViewIndex.axaml.cs new file mode 100644 index 0000000..2191d5b --- /dev/null +++ b/DownKyi/Views/ViewIndex.axaml.cs @@ -0,0 +1,13 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; + +namespace DownKyi.Views; + +public partial class ViewIndex : UserControl +{ + public ViewIndex() + { + InitializeComponent(); + } +} \ No newline at end of file diff --git a/DownKyi/Views/ViewLogin.axaml b/DownKyi/Views/ViewLogin.axaml new file mode 100644 index 0000000..7dcfbab --- /dev/null +++ b/DownKyi/Views/ViewLogin.axaml @@ -0,0 +1,130 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/DownKyi/Views/ViewLogin.axaml.cs b/DownKyi/Views/ViewLogin.axaml.cs new file mode 100644 index 0000000..75fc91b --- /dev/null +++ b/DownKyi/Views/ViewLogin.axaml.cs @@ -0,0 +1,13 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; + +namespace DownKyi.Views; + +public partial class ViewLogin : UserControl +{ + public ViewLogin() + { + InitializeComponent(); + } +} \ No newline at end of file diff --git a/DownKyi/Views/ViewMyBangumiFollow.axaml b/DownKyi/Views/ViewMyBangumiFollow.axaml new file mode 100644 index 0000000..5e6735a --- /dev/null +++ b/DownKyi/Views/ViewMyBangumiFollow.axaml @@ -0,0 +1,372 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/DownKyi/Views/ViewMySpace.axaml.cs b/DownKyi/Views/ViewMySpace.axaml.cs new file mode 100644 index 0000000..3d99b84 --- /dev/null +++ b/DownKyi/Views/ViewMySpace.axaml.cs @@ -0,0 +1,13 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; + +namespace DownKyi.Views; + +public partial class ViewMySpace : UserControl +{ + public ViewMySpace() + { + InitializeComponent(); + } +} \ No newline at end of file diff --git a/DownKyi/Views/ViewMyToViewVideo.axaml b/DownKyi/Views/ViewMyToViewVideo.axaml new file mode 100644 index 0000000..e64f6bd --- /dev/null +++ b/DownKyi/Views/ViewMyToViewVideo.axaml @@ -0,0 +1,295 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/DownKyi/Views/ViewSettings.axaml.cs b/DownKyi/Views/ViewSettings.axaml.cs new file mode 100644 index 0000000..30d3f0c --- /dev/null +++ b/DownKyi/Views/ViewSettings.axaml.cs @@ -0,0 +1,13 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; + +namespace DownKyi.Views; + +public partial class ViewSettings : UserControl +{ + public ViewSettings() + { + InitializeComponent(); + } +} \ No newline at end of file diff --git a/DownKyi/Views/ViewToolbox.axaml b/DownKyi/Views/ViewToolbox.axaml new file mode 100644 index 0000000..bfd59ca --- /dev/null +++ b/DownKyi/Views/ViewToolbox.axaml @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/DownKyi/Views/ViewToolbox.axaml.cs b/DownKyi/Views/ViewToolbox.axaml.cs new file mode 100644 index 0000000..f3cd10d --- /dev/null +++ b/DownKyi/Views/ViewToolbox.axaml.cs @@ -0,0 +1,13 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; + +namespace DownKyi.Views; + +public partial class ViewToolbox : UserControl +{ + public ViewToolbox() + { + InitializeComponent(); + } +} \ No newline at end of file diff --git a/DownKyi/Views/ViewUserSpace.axaml b/DownKyi/Views/ViewUserSpace.axaml new file mode 100644 index 0000000..0ec73a0 --- /dev/null +++ b/DownKyi/Views/ViewUserSpace.axaml @@ -0,0 +1,328 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/DownKyi/Views/ViewUserSpace.axaml.cs b/DownKyi/Views/ViewUserSpace.axaml.cs new file mode 100644 index 0000000..ffeef6a --- /dev/null +++ b/DownKyi/Views/ViewUserSpace.axaml.cs @@ -0,0 +1,13 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; + +namespace DownKyi.Views; + +public partial class ViewUserSpace : UserControl +{ + public ViewUserSpace() + { + InitializeComponent(); + } +} \ No newline at end of file diff --git a/DownKyi/Views/ViewVideoDetail.axaml b/DownKyi/Views/ViewVideoDetail.axaml new file mode 100644 index 0000000..49241e7 --- /dev/null +++ b/DownKyi/Views/ViewVideoDetail.axaml @@ -0,0 +1,423 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +