feat: 首次完成测试

This commit is contained in:
姚彪
2023-11-25 21:59:48 +08:00
commit face3bfa69
432 changed files with 61025 additions and 0 deletions

9
.gitignore vendored Normal file
View File

@@ -0,0 +1,9 @@
.idea/
.vs/
.vs_code/
**/.DS_Store
*/**/obj
*/**/bin
DownKyi.sln.DotSettings.user

View File

@@ -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
{
/// <summary>
/// 剧集基本信息mediaId方式
/// </summary>
/// <param name="mediaId"></param>
/// <returns></returns>
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<BangumiMediaOrigin>(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;
}
}
/// <summary>
/// 获取剧集明细web端seasonId/episodeId方式
/// </summary>
/// <param name="seasonId"></param>
/// <param name="episodeId"></param>
/// <returns></returns>
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<BangumiSeasonOrigin>(response);
if (bangumiSeason != null)
{
return bangumiSeason.Result;
}
else
{
return null;
}
}
catch (Exception e)
{
Console.PrintLine("BangumiSeasonInfo()发生异常: {0}", e);
LogManager.Error("BangumiInfo", e);
return null;
}
}
}

View File

@@ -0,0 +1,32 @@
namespace DownKyi.Core.BiliApi.Bangumi;
public static class BangumiType
{
public static Dictionary<int, string> Type = new Dictionary<int, string>()
{
{ 1, "Anime" },
{ 2, "Movie" },
{ 3, "Documentary" },
{ 4, "Guochuang" },
{ 5, "TV" },
{ 6, "Unknown" },
{ 7, "Entertainment" },
{ 8, "Unknown" },
{ 9, "Unknown" },
{ 10, "Unknown" }
};
public static Dictionary<int, int> TypeId = new Dictionary<int, int>()
{
{ 1, 13 },
{ 2, 23 },
{ 3, 177 },
{ 4, 167 },
{ 5, 11 },
{ 6, -1 },
{ 7, -1 },
{ 8, -1 },
{ 9, -1 },
{ 10, -1 }
};
}

View File

@@ -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; }
}

View File

@@ -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; }
}

View File

@@ -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<BangumiArea> 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; }
}

View File

@@ -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; }
}

View File

@@ -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<BangumiArea> Areas { get; set; }
[JsonProperty("bkg_cover")] public string BkgCover { get; set; }
[JsonProperty("cover")] public string Cover { get; set; }
[JsonProperty("episodes")] public List<BangumiEpisode> 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<BangumiSeasonInfo> Seasons { get; set; }
[JsonProperty("section")] public List<BangumiSection> 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; }
}

View File

@@ -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
}

View File

@@ -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<BangumiEpisode> Episodes { get; set; }
[JsonProperty("id")] public long Id { get; set; }
[JsonProperty("title")] public string Title { get; set; }
[JsonProperty("type")] public int Type { get; set; }
}

View File

@@ -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; }
}

View File

@@ -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
}

View File

@@ -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;
}
/// <summary>
/// bvid转avid
/// </summary>
/// <param name="bvid"></param>
/// <returns></returns>
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;
}
/// <summary>
/// avid转bvid
/// </summary>
/// <param name="av"></param>
/// <returns></returns>
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;
}
}

View File

@@ -0,0 +1,74 @@
namespace DownKyi.Core.BiliApi.BiliUtils;
public static class Constant
{
private static readonly List<Quality> resolutions = new List<Quality>
{
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<Quality> codecIds = new List<Quality>
{
new() { Name = "H.264/AVC", Id = 7 },
new() { Name = "H.265/HEVC", Id = 12 },
new() { Name = "AV1", Id = 13 },
};
private static readonly List<Quality> qualities = new List<Quality>
{
//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 },
};
/// <summary>
/// 获取支持的视频画质
/// </summary>
/// <returns></returns>
public static List<Quality> GetResolutions()
{
// 使用深复制,
// 保证外部修改list后
// 不会影响其他调用处
return new List<Quality>(resolutions);
}
/// <summary>
/// 获取视频编码代码
/// </summary>
/// <returns></returns>
public static List<Quality> GetCodecIds()
{
// 使用深复制,
// 保证外部修改list后
// 不会影响其他调用处
return new List<Quality>(codecIds);
}
/// <summary>
/// 获取支持的视频音质
/// </summary>
/// <returns></returns>
public static List<Quality> GetAudioQualities()
{
// 使用深复制,
// 保证外部修改list后
// 不会影响其他调用处
return new List<Quality>(qualities);
}
}

View File

@@ -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;
}
/// <summary>
/// 查询弹幕发送者
/// </summary>
/// <param name="userId"></param>
/// <returns></returns>
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]}";
}
}

View File

@@ -0,0 +1,575 @@
using DownKyi.Core.Utils.Validator;
using System.Text.RegularExpressions;
namespace DownKyi.Core.BiliApi.BiliUtils;
/// <summary>
/// 解析输入的字符串<para/>
/// 支持的格式有:<para/>
/// av号av170001, AV170001, https://www.bilibili.com/video/av170001 <para/>
/// BV号BV17x411w7KC, https://www.bilibili.com/video/BV17x411w7KC, https://b23.tv/BV17x411w7KC <para/>
/// 番剧电影、电视剧ss号ss32982, SS32982, https://www.bilibili.com/bangumi/play/ss32982 <para/>
/// 番剧电影、电视剧ep号ep317925, EP317925, https://www.bilibili.com/bangumi/play/ep317925 <para/>
/// 番剧电影、电视剧md号md28228367, MD28228367, https://www.bilibili.com/bangumi/media/md28228367 <para/>
/// 课程ss号https://www.bilibili.com/cheese/play/ss205 <para/>
/// 课程ep号https://www.bilibili.com/cheese/play/ep3489 <para/>
/// 收藏夹ml1329019876, ML1329019876, https://www.bilibili.com/medialist/detail/ml1329019876, https://www.bilibili.com/medialist/play/ml1329019876/ <para/>
/// 用户空间uid928123, UID928123, uid:928123, UID:928123, https://space.bilibili.com/928123
/// </summary>
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
/// <summary>
/// 是否为av id
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public static bool IsAvId(string input)
{
return IsIntId(input, "av");
}
/// <summary>
/// 是否为av url
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public static bool IsAvUrl(string input)
{
string id = GetVideoId(input);
return IsAvId(id);
}
/// <summary>
/// 获取av id
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
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;
}
}
/// <summary>
/// 是否为bv id
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public static bool IsBvId(string input)
{
return input.StartsWith("BV") && input.Length == 12;
}
/// <summary>
/// 是否为bv url
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public static bool IsBvUrl(string input)
{
string id = GetVideoId(input);
return IsBvId(id);
}
/// <summary>
/// 获取bv id
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public static string GetBvId(string input)
{
if (IsBvId(input))
{
return input;
}
else if (IsBvUrl(input))
{
return GetVideoId(input);
}
else
{
return "";
}
}
#endregion
#region
/// <summary>
/// 是否为番剧season id
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public static bool IsBangumiSeasonId(string input)
{
return IsIntId(input, "ss");
}
/// <summary>
/// 是否为番剧season url
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public static bool IsBangumiSeasonUrl(string input)
{
string id = GetBangumiId(input);
return IsBangumiSeasonId(id);
}
/// <summary>
/// 获取番剧season id
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
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;
}
}
/// <summary>
/// 是否为番剧episode id
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public static bool IsBangumiEpisodeId(string input)
{
return IsIntId(input, "ep");
}
/// <summary>
/// 是否为番剧episode url
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public static bool IsBangumiEpisodeUrl(string input)
{
string id = GetBangumiId(input);
return IsBangumiEpisodeId(id);
}
/// <summary>
/// 获取番剧episode id
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
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;
}
}
/// <summary>
/// 是否为番剧media id
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public static bool IsBangumiMediaId(string input)
{
return IsIntId(input, "md");
}
/// <summary>
/// 是否为番剧media url
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public static bool IsBangumiMediaUrl(string input)
{
string id = GetBangumiId(input);
return IsBangumiMediaId(id);
}
/// <summary>
/// 获取番剧media id
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
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
/// <summary>
/// 是否为课程season url
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public static bool IsCheeseSeasonUrl(string input)
{
string id = GetCheeseId(input);
return IsIntId(id, "ss");
}
/// <summary>
/// 获取课程season id
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public static long GetCheeseSeasonId(string input)
{
return IsCheeseSeasonUrl(input) ? Number.GetInt(GetCheeseId(input).Remove(0, 2)) : -1;
}
/// <summary>
/// 是否为课程episode url
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public static bool IsCheeseEpisodeUrl(string input)
{
string id = GetCheeseId(input);
return IsIntId(id, "ep");
}
/// <summary>
/// 获取课程episode id
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public static long GetCheeseEpisodeId(string input)
{
return IsCheeseEpisodeUrl(input) ? Number.GetInt(GetCheeseId(input).Remove(0, 2)) : -1;
}
#endregion
#region
/// <summary>
/// 是否为收藏夹id
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public static bool IsFavoritesId(string input)
{
return IsIntId(input, "ml");
}
/// <summary>
/// 是否为收藏夹url
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public static bool IsFavoritesUrl(string input)
{
return IsFavoritesUrl1(input) || IsFavoritesUrl2(input);
}
/// <summary>
/// 是否为收藏夹url1
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
private static bool IsFavoritesUrl1(string input)
{
string favoritesId = GetId(input, FavoritesUrl1);
return IsFavoritesId(favoritesId);
}
/// <summary>
/// 是否为收藏夹ur2
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
private static bool IsFavoritesUrl2(string input)
{
string favoritesId = GetId(input, FavoritesUrl2);
return IsFavoritesId(favoritesId.Split('/')[0]);
}
/// <summary>
/// 获取收藏夹id
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
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
/// <summary>
/// 是否为用户id
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
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;
}
}
/// <summary>
/// 是否为用户空间url
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public static bool IsUserUrl(string input)
{
if (!IsUrl(input))
{
return false;
}
if (input.Contains("space.bilibili.com"))
{
return true;
}
else
{
return false;
}
}
/// <summary>
/// 获取用户mid
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
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
/// <summary>
/// 是否为网址
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
private static bool IsUrl(string input)
{
return input.StartsWith("http://") || input.StartsWith("https://");
}
/// <summary>
/// 将http转为https
/// </summary>
/// <returns></returns>
private static string EnableHttps(string url)
{
if (!IsUrl(url))
{
return null;
}
return url.Replace("http://", "https://");
}
/// <summary>
/// 去除url中的参数
/// </summary>
/// <param name="url"></param>
/// <returns></returns>
private static string DeleteUrlParam(string url)
{
string[] strList = url.Split('?');
return strList[0].EndsWith("/") ? strList[0].TrimEnd('/') : strList[0];
}
/// <summary>
/// 从url中获取视频idavid/bvid
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
private static string GetVideoId(string input)
{
return GetId(input, VideoUrl);
}
/// <summary>
/// 从url中获取番剧idss/ep/md
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
private static string GetBangumiId(string input)
{
string id = GetId(input, BangumiUrl);
if (id != "")
{
return id;
}
return GetId(input, BangumiMediaUrl);
}
/// <summary>
/// 从url中获取课程idss/ep
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
private static string GetCheeseId(string input)
{
return GetId(input, CheeseUrl);
}
/// <summary>
/// 是否为数字型id
/// </summary>
/// <param name="input"></param>
/// <param name="prefix"></param>
/// <returns></returns>
private static bool IsIntId(string input, string prefix)
{
if (input.ToLower().StartsWith(prefix))
{
return Regex.IsMatch(input.Remove(0, 2), @"^\d+$");
}
return false;
}
/// <summary>
/// 从url中获取id
/// </summary>
/// <param name="input"></param>
/// <param name="baseUrl"></param>
/// <returns></returns>
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, "");
}
}

View File

@@ -0,0 +1,8 @@
namespace DownKyi.Core.BiliApi.BiliUtils;
[Serializable]
public class Quality
{
public string Name { get; set; }
public int Id { get; set; }
}

File diff suppressed because one or more lines are too long

View File

@@ -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
{
/// <summary>
/// 获取课程基本信息
/// </summary>
/// <param name="seasonId"></param>
/// <param name="episodeId"></param>
/// <returns></returns>
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<CheeseViewOrigin>(response);
if (cheese != null)
{
return cheese.Data;
}
else
{
return null;
}
}
catch (Exception e)
{
Console.PrintLine("CheeseViewInfo()发生异常: {0}", e);
LogManager.Error("CheeseInfo", e);
return null;
}
}
/// <summary>
/// 获取课程分集列表
/// </summary>
/// <param name="seasonId"></param>
/// <param name="ps"></param>
/// <param name="pn"></param>
/// <returns></returns>
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<CheeseEpisodeListOrigin>(response);
if (cheese != null)
{
return cheese.Data;
}
else
{
return null;
}
}
catch (Exception e)
{
Console.PrintLine("CheeseEpisodeList()发生异常: {0}", e);
LogManager.Error("CheeseInfo", e);
return null;
}
}
}

View File

@@ -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<CheeseImg> Img { get; set; }
[JsonProperty("title")] public string Title { get; set; }
[JsonProperty("type")] public int Type { get; set; }
}

View File

@@ -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; }
}

View File

@@ -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<CheeseEpisode> Items { get; set; }
[JsonProperty("page")] public CheeseEpisodePage Page { get; set; }
}

View File

@@ -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; }
}

View File

@@ -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; }
}

View File

@@ -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; }
}

View File

@@ -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; }
}

View File

@@ -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<CheeseEpisode> 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
}

View File

@@ -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
{
/// <summary>
/// 下载6分钟内的弹幕返回弹幕列表
/// </summary>
/// <param name="avid">稿件avID</param>
/// <param name="cid">视频CID</param>
/// <param name="segmentIndex">分包每6分钟一包</param>
/// <returns></returns>
public static List<BiliDanmaku> 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<BiliDanmaku>();
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;
}
/// <summary>
/// 下载所有弹幕,返回弹幕列表
/// </summary>
/// <param name="avid">稿件avID</param>
/// <param name="cid">视频CID</param>
/// <returns></returns>
public static List<BiliDanmaku> GetAllDanmakuProto(long avid, long cid)
{
var danmakuList = new List<BiliDanmaku>();
int segmentIndex = 0;
while (true)
{
segmentIndex += 1;
var danmakus = GetDanmakuProto(avid, cid, segmentIndex);
if (danmakus == null)
{
break;
}
danmakuList.AddRange(danmakus);
}
return danmakuList;
}
}

View File

@@ -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}";
}
}

View File

@@ -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
{
/// <summary>
/// 获取收藏夹元数据
/// </summary>
/// <param name="mediaId"></param>
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<FavoritesMetaInfoOrigin>(response);
if (info != null)
{
return info.Data;
}
else
{
return null;
}
}
catch (Exception e)
{
Console.PrintLine("GetFavoritesInfo()发生异常: {0}", e);
LogManager.Error("FavoritesInfo", e);
return null;
}
}
/// <summary>
/// 查询用户创建的视频收藏夹
/// </summary>
/// <param name="mid">目标用户UID</param>
/// <param name="pn">页码</param>
/// <param name="ps">每页项数</param>
/// <returns></returns>
public static List<FavoritesMetaInfo> 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<FavoritesListOrigin>(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;
}
}
/// <summary>
/// 查询所有的用户创建的视频收藏夹
/// </summary>
/// <param name="mid">目标用户UID</param>
/// <returns></returns>
public static List<FavoritesMetaInfo> GetAllCreatedFavorites(long mid)
{
List<FavoritesMetaInfo> result = new List<FavoritesMetaInfo>();
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;
}
/// <summary>
/// 查询用户收藏的视频收藏夹
/// </summary>
/// <param name="mid">目标用户UID</param>
/// <param name="pn">页码</param>
/// <param name="ps">每页项数</param>
/// <returns></returns>
public static List<FavoritesMetaInfo> 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<FavoritesListOrigin>(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;
}
}
/// <summary>
/// 查询所有的用户收藏的视频收藏夹
/// </summary>
/// <param name="mid">目标用户UID</param>
/// <returns></returns>
public static List<FavoritesMetaInfo> GetAllCollectedFavorites(long mid)
{
List<FavoritesMetaInfo> result = new List<FavoritesMetaInfo>();
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;
}
}

View File

@@ -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
{
/// <summary>
/// 获取收藏夹内容明细列表
/// </summary>
/// <param name="mediaId">收藏夹ID</param>
/// <param name="pn">页码</param>
/// <param name="ps">每页项数</param>
/// <returns></returns>
public static List<FavoritesMedia> 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<FavoritesMediaResourceOrigin>(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;
}
}
/// <summary>
/// 获取收藏夹内容明细列表(全部)
/// </summary>
/// <param name="mediaId">收藏夹ID</param>
/// <returns></returns>
public static List<FavoritesMedia> GetAllFavoritesMedia(long mediaId)
{
List<FavoritesMedia> result = new List<FavoritesMedia>();
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;
}
/// <summary>
/// 获取收藏夹全部内容id
/// </summary>
/// <param name="mediaId"></param>
/// <returns></returns>
public static List<FavoritesMediaId> 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<FavoritesMediaIdOrigin>(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;
}
}
}

View File

@@ -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; }
}

View File

@@ -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
}

View File

@@ -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<FavoritesMetaInfo> List { get; set; }
//[JsonProperty("has_more")]
//public bool HasMore { get; set; }
}

View File

@@ -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
}

View File

@@ -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<FavoritesMediaId> 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; }
}

View File

@@ -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<FavoritesMedia> Medias { get; set; }
[JsonProperty("has_more")] public bool HasMore { get; set; }
}

View File

@@ -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; }
}

View File

@@ -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; }
}

View File

@@ -0,0 +1,63 @@
using DownKyi.Core.BiliApi.History.Models;
using DownKyi.Core.Logging;
using Newtonsoft.Json;
using System;
namespace DownKyi.Core.BiliApi.History
{
/// <summary>
/// 历史记录
/// </summary>
public static class History
{
/// <summary>
/// 获取历史记录列表(视频、直播、专栏)
/// startId和startTime必须同时使用才有效分别对应结果中的max和view_at默认为0
/// </summary>
/// <param name="startId">历史记录开始目标ID</param>
/// <param name="startTime">历史记录开始时间</param>
/// <param name="ps">每页项数</param>
/// <param name="business">历史记录ID类型</param>
/// <returns></returns>
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<HistoryOrigin>(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;
}
}
}
}

View File

@@ -0,0 +1,11 @@
namespace DownKyi.Core.BiliApi.History.Models
{
public enum HistoryBusiness
{
ARCHIVE = 1, // 稿件
PGC, // 番剧(影视)
LIVE, // 直播
ARTICLE_LIST, // 文集
ARTICLE, // 文章
}
}

View File

@@ -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; }
}
}

View File

@@ -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<HistoryDataTab> tab { get; set; }
[JsonProperty("list")]
public List<HistoryList> List { get; set; }
}
}

View File

@@ -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
}
}

View File

@@ -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; }
}
}

View File

@@ -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<ToViewList> List { get; set; }
}
}

View File

@@ -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
}
}

View File

@@ -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
{
/// <summary>
/// 稍后再看
/// </summary>
public static class ToView
{
/// <summary>
/// 获取稍后再看视频列表
/// </summary>
/// <returns></returns>
public static List<ToViewList> 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<ToViewOrigin>(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;
}
}
}
}

View File

@@ -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";
/// <summary>
/// 保存登录的cookies到文件
/// </summary>
/// <param name="url"></param>
/// <returns></returns>
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;
}
/// <summary>
/// 获得登录的cookies
/// </summary>
/// <returns></returns>
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;
}
/// <summary>
/// 返回登录信息的cookies的字符串
/// </summary>
/// <returns></returns>
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(';');
}
/// <summary>
/// 注销登录
/// </summary>
/// <returns></returns>
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;
}
}
}

View File

@@ -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
{
/// <summary>
/// 申请二维码URL及扫码密钥web端
/// </summary>
/// <returns></returns>
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<LoginUrlOrigin>(response);
}
catch (Exception e)
{
Utils.Debugging.Console.PrintLine("GetLoginUrl()发生异常: {0}", e);
LogManager.Error("LoginQR", e);
return null;
}
}
/// <summary>
/// 使用扫码登录web端
/// </summary>
/// <param name="qrcodeKey"></param>
/// <param name="goUrl"></param>
/// <returns></returns>
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<LoginStatus>(response);
}
catch (Exception e)
{
Utils.Debugging.Console.PrintLine("GetLoginInfo()发生异常: {0}", e);
LogManager.Error("LoginQR", e);
return null;
}
}
/// <summary>
/// 获得登录二维码
/// </summary>
/// <returns></returns>
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;
}
}
/// <summary>
/// 根据输入url生成二维码
/// </summary>
/// <param name="url"></param>
/// <returns></returns>
public static Bitmap GetLoginQRCode(string url)
{
// 设置的参数影响app能否成功扫码
Bitmap qrCode = QRCode.EncodeQRCode(url, 10, 10, null, 0, 0, false);
return qrCode;
}
}

View File

@@ -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; }
}
}

View File

@@ -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; }
}
}

View File

@@ -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();
}
}
}

View File

@@ -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; }
}

View File

@@ -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; }
}

View File

@@ -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; }
}

View File

@@ -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<Subtitle> Body { get; set; }
/// <summary>
/// srt格式字幕
/// </summary>
/// <returns></returns>
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;
}
/// <summary>
/// 秒数转 时:分:秒 格式
/// </summary>
/// <param name="seconds"></param>
/// <returns></returns>
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}";
}
}

View File

@@ -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; }
}

View File

@@ -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
{
/// <summary>
/// 打乱重排实时口令
/// </summary>
/// <param name="origin"></param>
/// <returns></returns>
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);
}
/// <summary>
/// 将字典参数转为字符串
/// </summary>
/// <param name="parameters"></param>
/// <returns></returns>
public static string ParametersToQuery(Dictionary<string, object> parameters)
{
var keys = parameters.Keys.ToList();
var queryList = new List<string>();
foreach (var item in keys)
{
var value = parameters[item];
queryList.Add($"{item}={value}");
}
return string.Join("&", queryList);
}
/// <summary>
/// Wbi签名返回所有参数字典
/// </summary>
/// <param name="parameters"></param>
/// <returns></returns>
public static Dictionary<string, object> EncodeWbi(Dictionary<string, object> parameters)
{
return EncodeWbi(parameters, GetKey().Item1, GetKey().Item2);
}
/// <summary>
/// Wbi签名返回所有参数字典
/// </summary>
/// <param name="parameters"></param>
/// <param name="imgKey"></param>
/// <param name="subKey"></param>
/// <returns></returns>
public static Dictionary<string, object> EncodeWbi(Dictionary<string, object> parameters, string imgKey,
string subKey)
{
var mixinKey = GetMixinKey(imgKey + subKey);
var chrFilter = new Regex("[!'()*]");
var newParameters = new Dictionary<string, object>
{
{ "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<string>();
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<string, string> GetKey()
{
var user = SettingsManager.GetInstance().GetUserInfo();
return new Tuple<string, string>(user.ImgKey, user.SubKey);
}
}

View File

@@ -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<BangumiFollowAreas> 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
}

View File

@@ -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; }
}

View File

@@ -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; }
}

View File

@@ -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<BangumiFollow> List { get; set; }
[JsonProperty("pn")] public int Pn { get; set; }
[JsonProperty("ps")] public int Ps { get; set; }
[JsonProperty("total")] public int Total { get; set; }
}

View File

@@ -0,0 +1,7 @@
namespace DownKyi.Core.BiliApi.Users.Models;
public enum BangumiType
{
ANIME = 1, // 番剧
EPISODE = 2 // 剧集、电影
}

View File

@@ -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<FollowingGroup> 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; }
}

View File

@@ -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<RelationFollowInfo> Data { get; set; }
}

View File

@@ -0,0 +1,7 @@
namespace DownKyi.Core.BiliApi.Users.Models;
public enum FollowingOrder
{
DEFAULT = 1, // 按照关注顺序排列,默认
ATTENTION // 按照最常访问排列
}

View File

@@ -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; }
}

View File

@@ -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; }
}

View File

@@ -0,0 +1,8 @@
namespace DownKyi.Core.BiliApi.Users.Models;
public enum PublicationOrder
{
PUBDATE = 1, // 最新发布,默认
CLICK, // 最多播放
STOW // 最多收藏
}

View File

@@ -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<RelationFollowInfo> Data { get; set; }
}

View File

@@ -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<RelationFollowInfo> List { get; set; }
//[JsonProperty("re_version")]
//public long reVersion { get; set; }
[JsonProperty("total")] public int Total { get; set; }
}

View File

@@ -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<long> 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
}

View File

@@ -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<RelationFollowInfo> List { get; set; }
// re_version
}

View File

@@ -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<SpaceChannelList> List { get; set; }
}

View File

@@ -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
}

View File

@@ -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; }
}

View File

@@ -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
}

View File

@@ -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; }
}

View File

@@ -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<SpaceChannelArchive> Archives { get; set; }
}

View File

@@ -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; }
}

View File

@@ -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; }
}

View File

@@ -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<SpaceCheese> Items { get; set; }
[JsonProperty("page")] public SpaceCheesePage Page { get; set; }
}

View File

@@ -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; }
}

View File

@@ -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; }
}

View File

@@ -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<SpacePublicationListVideo> Vlist { get; set; }
}

View File

@@ -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; }
}

View File

@@ -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; }
}

View File

@@ -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; }
}

View File

@@ -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; }
}

View File

@@ -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<long> Aids { get; set; }
[JsonProperty("archives")] public List<SpaceSeasonsSeriesArchives> Archives { get; set; }
[JsonProperty("meta")] public SpaceSeasonsMeta Meta { get; set; }
[JsonProperty("page")] public SpaceSeasonsSeriesPage Page { get; set; }
}

View File

@@ -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<SpaceSeasonsSeriesArchives> Archives { get; set; }
[JsonProperty("meta")] public SpaceSeasonsMeta Meta { get; set; }
[JsonProperty("recent_aids")] public List<long> RecentAids { get; set; }
}
public class SpaceSeries : BaseModel
{
[JsonProperty("archives")] public List<SpaceSeasonsSeriesArchives> Archives { get; set; }
[JsonProperty("meta")] public SpaceSeriesMeta Meta { get; set; }
[JsonProperty("recent_aids")] public List<long> RecentAids { get; set; }
}

View File

@@ -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
}

View File

@@ -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<string> 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; }
}

View File

@@ -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<SpaceSeasons> SeasonsList { get; set; }
[JsonProperty("series_list")] public List<SpaceSeries> SeriesList { get; set; }
}

View File

@@ -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;
}

View File

@@ -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; }
}

View File

@@ -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<long> Aids { get; set; }
// page
[JsonProperty("archives")] public List<SpaceSeasonsSeriesArchives> Archives { get; set; }
}

View File

@@ -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<long> RecentAids { get; set; }
}

View File

@@ -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; }
}

Some files were not shown because too many files have changed in this diff Show More