提交已重构的部分

pull/252/head
flyself 3 years ago
parent 2c13369532
commit 8f7b9df8f9

@ -1,440 +0,0 @@
using System;
using System.Text.RegularExpressions;
namespace Core
{
public static class Common
{
// 配置文件所在路径
public static readonly string ConfigPath = "./Config/";
// 日志、历史等文件所在路径
public static readonly string RecordPath = "./Config/";
/// <summary>
/// 判断字符串是否以http或https开头且域名为bilibili.com
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public static bool IsUrl(string input)
{
if (input.StartsWith("http://") || input.StartsWith("https://"))
{
if (input.Contains("www.bilibili.com")) { return true; }
else { return false; }
}
else { return false; }
}
/// <summary>
/// 判断是否为avid
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public static bool IsAvid(string input)
{
if (input.StartsWith("av"))
{
bool isInt = Regex.IsMatch(input.Remove(0, 2), @"^\d+$");
return isInt;
}
return false;
}
/// <summary>
/// 判断是否为bvid
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public static bool IsBvid(string input)
{
if (input.StartsWith("BV") && input.Length == 12)
{
return true;
}
return false;
}
/// <summary>
/// 判断是否是用户空间的url
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public static bool IsUserSpaceUrl(string input)
{
if (input.StartsWith("http://") || input.StartsWith("https://"))
{
if (input.Contains("space.bilibili.com"))
{
return true;
}
else { return false; }
}
else { return false; }
}
/// <summary>
/// 判断是否是用户id
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public static bool IsUserId(string input)
{
string inputLower = input.ToLower();
if (inputLower.StartsWith("uid:"))
{
string uid = inputLower.TrimStart(new char[] { 'u', 'i', 'd', ':' });
return IsInt(uid);
}
else if (inputLower.StartsWith("uid"))
{
string uid = inputLower.TrimStart(new char[] { 'u', 'i', 'd' });
return IsInt(uid);
}
else { return false; }
}
/// <summary>
/// 获取用户id
/// </summary>
/// <param name="url"></param>
/// <returns></returns>
public static long GetUserId(string url)
{
string[] strList = url.Split('?');
string baseUrl = strList[0];
var match = Regex.Match(baseUrl, @"\d+");
if (match.Success)
{
return GetInt(match.Value);
}
else
{
return -1;
}
}
/// <summary>
/// 从url中解析id包括bvid和番剧的id
/// </summary>
/// <param name="url"></param>
/// <returns></returns>
public static string GetVideoId(string url)
{
string[] strList = url.Split('?');
string baseUrl = strList[0];
string[] str2List = baseUrl.Split('/');
string id = str2List[str2List.Length - 1];
if (id == "")
{
// 字符串末尾
return str2List[str2List.Length - 2];
}
return id;
}
/// <summary>
/// 判断是视频还是番剧
/// </summary>
/// <param name="url"></param>
/// <returns></returns>
public static VideoType GetVideoType(string url)
{
if (url.ToLower().Contains("/video/bv"))
{
return VideoType.VIDEO;
}
if (url.ToLower().Contains("/video/av"))
{
return VideoType.VIDEO_AV;
}
if (url.ToLower().Contains("/bangumi/play/ss"))
{
return VideoType.BANGUMI_SEASON;
}
if (url.ToLower().Contains("/bangumi/play/ep"))
{
return VideoType.BANGUMI_EPISODE;
}
if (url.ToLower().Contains("/bangumi/media/md"))
{
return VideoType.BANGUMI_MEDIA;
}
if (url.ToLower().Contains("/cheese/play/ss"))
{
return VideoType.CHEESE_SEASON;
}
if (url.ToLower().Contains("/cheese/play/ep"))
{
return VideoType.CHEESE_EPISODE;
}
return VideoType.NONE;
}
/// <summary>
/// 格式化Duration时间
/// </summary>
/// <param name="duration"></param>
/// <returns></returns>
public static string FormatDuration(long duration)
{
string formatDuration;
if (duration / 60 > 0)
{
long dur = duration / 60;
if (dur / 60 > 0)
{
formatDuration = $"{dur / 60}h{dur % 60}m{duration % 60}s";
}
else
{
formatDuration = $"{duration / 60}m{duration % 60}s";
}
}
else
{
formatDuration = $"{duration}s";
}
return formatDuration;
}
/// <summary>
/// 格式化Duration时间格式为00:00:00
/// </summary>
/// <param name="duration"></param>
/// <returns></returns>
public static string FormatDuration2(long duration)
{
string formatDuration;
if (duration / 60 > 0)
{
long dur = duration / 60;
if (dur / 60 > 0)
{
formatDuration = string.Format("{0:D2}", dur / 60) + ":" + string.Format("{0:D2}", dur % 60) + ":" + string.Format("{0:D2}", duration % 60);
}
else
{
formatDuration = "00:" + string.Format("{0:D2}", duration / 60) + ":" + string.Format("{0:D2}", duration % 60);
}
}
else
{
formatDuration = "00:00:" + string.Format("{0:D2}", duration);
}
return formatDuration;
}
/// <summary>
/// 格式化Duration时间格式为00:00
/// </summary>
/// <param name="duration"></param>
/// <returns></returns>
public static string FormatDuration3(long duration)
{
string formatDuration;
if (duration / 60 > 0)
{
long dur = duration / 60;
if (dur / 60 > 0)
{
formatDuration = string.Format("{0:D2}", dur / 60) + ":" + string.Format("{0:D2}", dur % 60) + ":" + string.Format("{0:D2}", duration % 60);
}
else
{
formatDuration = string.Format("{0:D2}", duration / 60) + ":" + string.Format("{0:D2}", duration % 60);
}
}
else
{
formatDuration = "00:" + string.Format("{0:D2}", duration);
}
return formatDuration;
}
/// <summary>
/// 格式化数字超过10000的数字将单位改为万超过100000000的数字将单位改为亿并保留1位小数
/// </summary>
/// <param name="number"></param>
/// <returns></returns>
public static string FormatNumber(long number)
{
if (number > 99999999)
{
return (number / 100000000.0f).ToString("F1") + "亿";
}
if (number > 9999)
{
return (number / 10000.0f).ToString("F1") + "万";
}
else
{
return number.ToString();
}
}
/// <summary>
/// 去除非法字符
/// </summary>
/// <param name="originName"></param>
/// <returns></returns>
public static string FormatFileName(string originName)
{
string destName = originName;
// Windows中不能作为文件名的字符
destName = destName.Replace("\\", " ");
destName = destName.Replace("/", " ");
destName = destName.Replace(":", " ");
destName = destName.Replace("*", " ");
destName = destName.Replace("?", " ");
destName = destName.Replace("\"", " ");
destName = destName.Replace("<", " ");
destName = destName.Replace(">", " ");
destName = destName.Replace("|", " ");
// 转义字符
destName = destName.Replace("\a", "");
destName = destName.Replace("\b", "");
destName = destName.Replace("\f", "");
destName = destName.Replace("\n", "");
destName = destName.Replace("\r", "");
destName = destName.Replace("\t", "");
destName = destName.Replace("\v", "");
// 控制字符
destName = Regex.Replace(destName, @"\p{C}+", string.Empty);
return destName.Trim();
}
/// <summary>
/// 格式化网速
/// </summary>
/// <param name="speed"></param>
/// <returns></returns>
public static string FormatSpeed(float speed)
{
string formatSpeed;
if (speed <= 0)
{
formatSpeed = "0B/s";
}
else if (speed < 1024)
{
formatSpeed = speed.ToString("#.##") + "B/s";
}
else if (speed < 1024 * 1024)
{
formatSpeed = (speed / 1024).ToString("#.##") + "KB/s";
}
else
{
formatSpeed = (speed / 1024 / 1024).ToString("#.##") + "MB/s";
}
return formatSpeed;
}
/// <summary>
/// 格式化字节大小,可用于文件大小的显示
/// </summary>
/// <param name="fileSize"></param>
/// <returns></returns>
public static string FormatFileSize(long fileSize)
{
string formatFileSize;
if (fileSize <= 0)
{
formatFileSize = "0B";
}
else if (fileSize < 1024)
{
formatFileSize = fileSize.ToString() + "B";
}
else if (fileSize < 1024 * 1024)
{
formatFileSize = (fileSize / 1024.0).ToString("#.##") + "KB";
}
else if (fileSize < 1024 * 1024 * 1024)
{
formatFileSize = (fileSize / 1024.0 / 1024.0).ToString("#.##") + "MB";
}
else
{
formatFileSize = (fileSize / 1024.0 / 1024.0 / 1024.0).ToString("#.##") + "GB";
}
return formatFileSize;
}
private static long GetInt(string value)
{
if (IsInt(value))
{
return long.Parse(value);
}
else
{
return -1;
}
}
private static bool IsInt(string value)
{
return Regex.IsMatch(value, @"^\d+$");
}
}
/// <summary>
/// 支持的视频类型
/// </summary>
public enum VideoType
{
NONE,
VIDEO, // 对应 /video/BV
VIDEO_AV, // 对应 /video/av
// BANGUMI, // BANGUMI细分为以下三个部分
BANGUMI_SEASON, // 对应 /bangumi/play/ss
BANGUMI_EPISODE, // 对应 /bangumi/play/ep
BANGUMI_MEDIA, // 对应 /bangumi/media/md
CHEESE_SEASON, // 对应 /cheese/play/ss
CHEESE_EPISODE // 对应 /cheese/play/ep
}
/// <summary>
/// 线程
/// </summary>
public enum ThreadStatus
{
MAIN_UI, // 主线程
START_PARSE, // 开始解析url
ADD_ALL_TO_DOWNLOAD,
START_DOWNLOAD
}
/// <summary>
/// 视频的编码格式flv也视为编码放这里
/// </summary>
[Serializable]
public enum VideoCodec
{
NONE = 1,
AVC,
HEVC,
FLV
}
}

@ -1,534 +0,0 @@
using Core.entity;
using Core.settings;
using Newtonsoft.Json;
using System;
using System.Net;
using System.Text.RegularExpressions;
namespace Core
{
public static class Downloader
{
/// <summary>
/// 获得远程文件的大小
/// </summary>
/// <param name="url"></param>
/// <param name="referer"></param>
/// <returns></returns>
public static long GetRemoteFileSize(string url, string referer)
{
try
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "GET";
request.Timeout = 30 * 1000;
request.UserAgent = Utils.GetUserAgent();
//request.ContentType = "text/html;charset=UTF-8";
request.Headers["accept-language"] = "zh-CN,zh;q=0.9,en;q=0.8";
request.Referer = referer;
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
return response.ContentLength;
}
catch (Exception e)
{
Console.WriteLine("GetRemoteFileSize()发生异常: {0}", e);
return 0;
}
}
/// <summary>
/// 获得视频详情及播放列表
/// </summary>
/// <param name="bvid"></param>
/// <returns></returns>
public static VideoViewData GetVideoInfo(string bvid, long aid, string referer, bool isBackup = false)
{
string url;
if (bvid != null)
{
url = $"https://api.bilibili.com/x/web-interface/view?bvid={bvid}";
}
else if (aid >= 0)
{
url = $"https://api.bilibili.com/x/web-interface/view?aid={aid}";
}
else
{ return null; }
// 采用备用的api只能获取cid
if (isBackup)
{
string backupUrl = $"https://api.bilibili.com/x/player/pagelist?bvid={bvid}&jsonp=jsonp";
url = backupUrl;
}
string response = Utils.RequestWeb(url, referer);
try
{
VideoView videoView;
if (isBackup)
{
Pagelist pagelist = JsonConvert.DeserializeObject<Pagelist>(response);
videoView = new VideoView
{
code = pagelist.code,
message = pagelist.message,
ttl = pagelist.ttl
};
videoView.data.pages = pagelist.data;
}
else
{
videoView = JsonConvert.DeserializeObject<VideoView>(response);
}
if (videoView != null)
{
if (videoView.data != null)
{
return videoView.data;
}
else
{
return null;
// 进入备选的url中
//return GetVideoInfo(bvid, referer, true);
}
}
else
{
return null;
}
}
catch (JsonReaderException e)
{
Console.WriteLine("GetVideoInfo()发生JsonReader异常: {0}", e);
return null;
}
catch (Exception e)
{
Console.WriteLine("GetVideoInfo()发生异常: {0}", e);
return null;
}
}
/// <summary>
/// 通过seasonId获得番剧的剧集详情
/// </summary>
/// <param name="seasonId"></param>
/// <returns></returns>
public static BangumiSeasonResult GetBangumiSeason(long seasonId, string referer)
{
string url = $"https://api.bilibili.com/pgc/view/web/season?season_id={seasonId}";
string response = Utils.RequestWeb(url, referer);
try
{
BangumiSeason bangumiSeason = JsonConvert.DeserializeObject<BangumiSeason>(response);
if (bangumiSeason != null) { return bangumiSeason.result; }
else { return null; }
}
catch (JsonReaderException e)
{
Console.WriteLine("GetBangumiSeason()发生JsonReader异常: {0}", e);
return null;
}
catch (Exception e)
{
Console.WriteLine("GetBangumiSeason()发生异常: {0}", e);
return null;
}
}
public static long GetBangumiSeasonIdByMedia(long mediaId, string referer)
{
string url = $"https://api.bilibili.com/pgc/review/user?media_id={mediaId}";
string response = Utils.RequestWeb(url, referer);
try
{
BangumiMedia bangumiMedia = JsonConvert.DeserializeObject<BangumiMedia>(response);
if (bangumiMedia.result.media != null) { return bangumiMedia.result.media.season_id; }
else { return 0; }
}
catch (JsonReaderException e)
{
Console.WriteLine("GetBangumiSeasonIdByMedia()发生JsonReader异常: {0}", e);
return 0;
}
catch (Exception e)
{
Console.WriteLine("GetBangumiSeasonIdByMedia()发生异常: {0}", e);
return 0;
}
}
public static long GetBangumiSeasonIdByEpisode(long episode, string referer)
{
string url = $"https://www.bilibili.com/bangumi/play/ep{episode}";
string response = Utils.RequestWeb(url, referer);
// "ssId": 28324,
string pattern = "\"ssId\":\\s?\\d+,";
Regex regex = new Regex(pattern);
Match match = regex.Match(response);
// 删除多余的字符
string ssId = match.Value.Replace("ssId", "");
ssId = ssId.Replace("\"", "");
ssId = ssId.Replace(":", "");
ssId = ssId.Replace(" ", "");
ssId = ssId.Replace(",", "");
long seasonId;
try
{
seasonId = long.Parse(ssId);
}
catch (FormatException e)
{
Console.WriteLine("GetBangumiSeasonIdByEpisode()发生异常: {0}", e);
return 0;
}
return seasonId;
}
/// <summary>
/// 通过ep_id获得课程的信息
/// </summary>
/// <param name="episode"></param>
/// <param name="referer"></param>
/// <returns></returns>
public static CheeseSeasonData GetCheeseSeason(long seasonId, long episode, string referer)
{
string url = $"https://api.bilibili.com/pugv/view/web/season?";
if (seasonId != 0)
{
url += $"season_id={seasonId}";
}
else if (episode != 0)
{
url += $"ep_id={episode}";
}
string response = Utils.RequestWeb(url, referer);
try
{
CheeseSeason cheeseSeason = JsonConvert.DeserializeObject<CheeseSeason>(response);
if (cheeseSeason != null) { return cheeseSeason.data; }
else { return null; }
}
catch (JsonReaderException e)
{
Console.WriteLine("GetCheeseSeason()发生JsonReader异常: {0}", e);
return null;
}
catch (Exception e)
{
Console.WriteLine("GetCheeseSeason()发生异常: {0}", e);
return null;
}
}
//public static long GetCheeseEpisodeIdBySeasonId(long seasonId, string referer)
//{
// string url = $"https://api.bilibili.com/pugv/view/web/ep/list?season_id={seasonId}&pn=1";
// string response = Utils.RequestWeb(url, referer);
// try
// {
// CheeseList cheeseList = JsonConvert.DeserializeObject<CheeseList>(response);
// if (cheeseList.data.items != null && cheeseList.data.items.Count > 0)
// {
// return cheeseList.data.items[0].id;
// }
// else { return 0; }
// }
// catch (JsonReaderException e)
// {
// Console.WriteLine("发生异常: {0}", e);
// return 0;
// }
//}
/// <summary>
/// 获得音视频流链接
/// </summary>
/// <param name="bvid">视频的bvid</param>
/// <param name="cid">视频的cid</param>
public static PlayUrlData GetStreamInfo(string bvid, long avid, long cid, long episodeId, int quality, string referer, bool isProxy = false, int proxy = 0)
{
string baseUrlVideo = "https://api.bilibili.com/x/player/playurl";
string baseUrlSeason = "https://api.bilibili.com/pgc/player/web/playurl";
string baseUrlCheese = "https://api.bilibili.com/pugv/player/web/playurl";
string baseUrl;
VideoType videoType = Common.GetVideoType(referer);
switch (videoType)
{
case VideoType.VIDEO:
baseUrl = baseUrlVideo;
break;
case VideoType.VIDEO_AV:
baseUrl = baseUrlVideo;
break;
case VideoType.BANGUMI_SEASON:
baseUrl = baseUrlSeason;
break;
case VideoType.BANGUMI_EPISODE:
baseUrl = baseUrlSeason;
break;
case VideoType.BANGUMI_MEDIA:
baseUrl = baseUrlSeason;
break;
case VideoType.CHEESE_SEASON:
baseUrl = baseUrlCheese;
break;
case VideoType.CHEESE_EPISODE:
baseUrl = baseUrlCheese;
break;
default:
baseUrl = baseUrlVideo;
break;
}
// TODO 没有的参数不加入url
//string url = $"{baseUrl}?cid={cid}&bvid={bvid}&avid={avid}&ep_id={episodeId}&qn={quality}&otype=json&fourk=1&fnver=0&fnval=16";
string url = $"{baseUrl}?cid={cid}&qn={quality}&otype=json&fourk=1&fnver=0&fnval=16";
if (bvid != null)
{
url += $"&bvid={bvid}";
}
if (avid != 0)
{
url += $"&avid={avid}";
}
if (episodeId != 0)
{
url += $"&ep_id={episodeId}";
}
// 代理网址
//https://www.biliplus.com/BPplayurl.php?cid=180873425&qn=116&type=&otype=json&fourk=1&bvid=BV1pV411o7yD&ep_id=317925&fnver=0&fnval=16&module=pgc
if (isProxy && proxy == 1)
{
string proxyUrl1 = "https://www.biliplus.com/BPplayurl.php";
url = $"{proxyUrl1}?cid={cid}&bvid={bvid}&qn={quality}&otype=json&fourk=1&fnver=0&fnval=16&module=pgc";
}
else if (isProxy && proxy == 2)
{
string proxyUrl2 = "https://biliplus.ipcjs.top/BPplayurl.php";
url = $"{proxyUrl2}?cid={cid}&bvid={bvid}&qn={quality}&otype=json&fourk=1&fnver=0&fnval=16&module=pgc";
}
string response = Utils.RequestWeb(url, referer);
//Console.WriteLine(response);
try
{
PlayUrl playUrl;
if (isProxy)
{
PlayUrlData playUrlData = JsonConvert.DeserializeObject<PlayUrlData>(response);
playUrl = new PlayUrl
{
result = playUrlData
};
}
else
{
playUrl = JsonConvert.DeserializeObject<PlayUrl>(response);
}
if (playUrl != null)
{
if (playUrl.data != null) { return playUrl.data; }
if (playUrl.result != null) { return playUrl.result; }
// 无法从B站获取数据进入代理网站
if (Settings.GetInstance().IsLiftingOfRegion() == ALLOW_STATUS.YES)
{
switch (proxy)
{
case 0:
return GetStreamInfo(bvid, avid, cid, episodeId, quality, referer, true, 1);
case 1:
return GetStreamInfo(bvid, avid, cid, episodeId, quality, referer, true, 2);
case 2:
return null;
}
}
return null;
}
else { return null; }
}
catch (JsonReaderException e)
{
Console.WriteLine("GetStreamInfo()发生JsonReader异常: {0}", e);
return null;
}
catch (Exception e)
{
Console.WriteLine("GetStreamInfo()发生异常: {0}", e);
return null;
}
}
//public static List<Danmaku> GetAllDanmaku(long cid, long publishTime, string referer)
//{
// List<Danmaku> danmakus = new List<Danmaku>();
// // 设置视频发布日期
// DateTime publishDate = new DateTime(1970, 1, 1);
// publishDate = publishDate.AddSeconds(publishTime);
// // 获得有弹幕的日期date
// List<string> danmakuDateList = new List<string>();
// while (true)
// {
// string month = publishDate.ToString("yyyy-MM");
// string url = $"https://api.bilibili.com/x/v2/dm/history/index?type=1&oid={cid}&month={month}";
// string response = Utils.RequestWeb(url, referer);
// DanmuDate danmakuDate;
// try
// {
// danmakuDate = JsonConvert.DeserializeObject<DanmuDate>(response);
// }
// catch (Exception e)
// {
// Console.WriteLine("GetAllDanmaku()发生异常: {0}", e);
// continue;
// }
// if (danmakuDate != null || danmakuDate.data != null) { danmakuDateList.AddRange(danmakuDate.data); }
// if (publishDate.CompareTo(DateTime.Now) > 0) { break; }
// publishDate = publishDate.AddMonths(1);
// Thread.Sleep(100);
// }
// // 获取弹幕
// foreach (var date in danmakuDateList)
// {
// Console.WriteLine(date);
// List<Danmaku> danmakusOfOneDay = GetDanmaku(cid, date);
// foreach (Danmaku danmaku in danmakusOfOneDay)
// {
// if (danmakus.Find(it => it.DanmuId == danmaku.DanmuId) == null)
// {
// danmakus.Add(danmaku);
// }
// }
// }
// // 按弹幕发布时间排序
// danmakus = danmakus.OrderBy(it => it.Timestamp).ToList();
// return danmakus;
//}
//public static List<Danmaku> GetDanmaku(long cid, string date, string referer)
//{
// string url = $"https://api.bilibili.com/x/v2/dm/history?type=1&oid={cid}&date={date}";
// string response = Utils.RequestWeb(url, referer);
// // <?xml version="1.0" encoding="UTF-8"?>
// // {"code":-101,"message":"账号未登录","ttl":1}
// if (response.Contains("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"))
// {
// List<Danmaku> danmakus = new List<Danmaku>();
// XmlDocument doc = new XmlDocument();
// doc.LoadXml(response);
// // 取得节点名为d的XmlNode集合
// XmlNodeList danmuList = doc.GetElementsByTagName("d");
// foreach (XmlNode node in danmuList)
// {
// // 返回的是文字内容
// string nodeText = node.InnerText;
// // 节点p属性值
// string childValue = node.Attributes["p"].Value;
// // 拆分属性
// string[] attrs = childValue.Split(',');
// Danmaku danmaku = new Danmaku
// {
// Text = nodeText,
// Time = float.Parse(attrs[0]),
// Type = int.Parse(attrs[1]),
// Fontsize = int.Parse(attrs[2]),
// Color = long.Parse(attrs[3]),
// Timestamp = long.Parse(attrs[4]),
// Pool = int.Parse(attrs[5]),
// UserId = attrs[6],
// DanmuId = attrs[7]
// };
// danmakus.Add(danmaku);
// }
// return danmakus;
// }
// else
// {
// DanmuFromWeb danmu = JsonConvert.DeserializeObject<DanmuFromWeb>(response);
// if (danmu != null) { Console.WriteLine(danmu.message); }
// return null;
// }
//}
///// <summary>
///// 获取弹幕不需要登录信息只能获取3000条弹幕
///// </summary>
///// <param name="cid"></param>
///// <returns></returns>
//public static List<Danmaku> GetDanmaku(long cid, string referer)
//{
// string url = $"https://api.bilibili.com/x/v1/dm/list.so?oid={cid}";
// string response = Utils.RequestWeb(url, referer);
// if (response.Contains("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"))
// {
// List<Danmaku> danmakus = new List<Danmaku>();
// XmlDocument doc = new XmlDocument();
// doc.LoadXml(response);
// // 取得节点名为d的XmlNode集合
// XmlNodeList danmuList = doc.GetElementsByTagName("d");
// foreach (XmlNode node in danmuList)
// {
// // 返回的是文字内容
// string nodeText = node.InnerText;
// // 节点p属性值
// string childValue = node.Attributes["p"].Value;
// // 拆分属性
// string[] attrs = childValue.Split(',');
// Danmaku danmaku = new Danmaku
// {
// Text = nodeText,
// Time = float.Parse(attrs[0]),
// Type = int.Parse(attrs[1]),
// Fontsize = int.Parse(attrs[2]),
// Color = long.Parse(attrs[3]),
// Timestamp = long.Parse(attrs[4]),
// Pool = int.Parse(attrs[5]),
// UserId = attrs[6],
// DanmuId = attrs[7]
// };
// danmakus.Add(danmaku);
// }
// return danmakus;
// }
// return null;
//}
}
}

@ -1,254 +0,0 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Windows;
using System.Windows.Controls;
namespace Core
{
public static class FFmpegHelper
{
/// <summary>
/// 合并音频和视频
/// </summary>
/// <param name="video1"></param>
/// <param name="video2"></param>
/// <param name="destVideo"></param>
public static bool MergeVideo(string video1, string video2, string destVideo)
{
string param = $"-i \"{video1}\" -i \"{video2}\" -acodec copy -vcodec copy -f mp4 \"{destVideo}\"";
if (video1 == null || !File.Exists(video1))
{
param = $"-i \"{video2}\" -acodec copy -vcodec copy -f mp4 \"{destVideo}\"";
}
if (video2 == null || !File.Exists(video2))
{
param = $"-i \"{video1}\" -acodec copy -vcodec copy -f mp4 \"{destVideo}\"";
}
if (!File.Exists(video1) && !File.Exists(video2)) { return false; }
// 如果存在
try { File.Delete(destVideo); }
catch (IOException e)
{
Console.WriteLine("MergeVideo()发生IO异常: {0}", e);
return false;
}
ExcuteProcess("ffmpeg.exe", param, null, (s, e) => Console.WriteLine(e.Data));
try
{
if (video1 != null) { File.Delete(video1); }
if (video2 != null) { File.Delete(video2); }
}
catch (IOException e)
{
Console.WriteLine("MergeVideo()发生IO异常: {0}", e);
}
return true;
}
/// <summary>
/// 拼接多个视频
/// </summary>
/// <param name="workingDirectory"></param>
/// <param name="flvFiles"></param>
/// <param name="destVideo"></param>
/// <returns></returns>
public static bool ConcatVideo(string workingDirectory, List<string> flvFiles, string destVideo)
{
// contact的文件名不包含路径
string concatFileName = Guid.NewGuid().ToString("N") + "_concat.txt";
try
{
string contact = "";
foreach (string flv in flvFiles)
{
contact += $"file '{flv}'\n";
}
FileStream fileStream = new FileStream(workingDirectory + "/" + concatFileName, FileMode.Create);
StreamWriter streamWriter = new StreamWriter(fileStream);
//开始写入
streamWriter.Write(contact);
//清空缓冲区
streamWriter.Flush();
//关闭流
streamWriter.Close();
fileStream.Close();
}
catch (Exception e)
{
Console.WriteLine("ConcatVideo()发生异常: {0}", e);
return false;
}
// ffmpeg -f concat -safe 0 -i filelist.txt -c copy output.mkv
// 加上-y表示如果有同名文件则默认覆盖
string param = $"-f concat -safe 0 -i {concatFileName} -c copy \"{destVideo}\" -y";
ExcuteProcess("ffmpeg.exe", param, workingDirectory, (s, e) => Console.WriteLine(e.Data));
// 删除临时文件
try
{
// 删除concat文件
File.Delete(workingDirectory + "/" + concatFileName);
foreach (string flv in flvFiles)
{
File.Delete(flv);
}
}
catch (Exception e)
{
Console.WriteLine("ConcatVideo()发生异常: {0}", e);
}
return true;
}
/// <summary>
/// 去水印非常消耗cpu资源
/// </summary>
/// <param name="video"></param>
/// <param name="destVideo"></param>
/// <param name="x"></param>
/// <param name="y"></param>
/// <param name="width"></param>
/// <param name="height"></param>
/// <param name="output"></param>
/// <param name="window"></param>
public static void Delogo(string video, string destVideo, int x, int y, int width, int height, TextBox output = null, Window window = null)
{
// ffmpeg -i "video.mp4" -vf delogo=x=1670:y=50:w=180:h=70:show=1 "delogo.mp4"
string param = $"-i \"{video}\" -vf delogo=x={x}:y={y}:w={width}:h={height} \"{destVideo}\" -hide_banner";
ExcuteProcess("ffmpeg.exe", param,
null, (s, e) =>
{
Console.WriteLine(e.Data);
if (output != null && window != null)
{
window.Dispatcher.Invoke(new Action(() =>
{
output.Text += e.Data + "\n";
output.ScrollToEnd();
}));
}
});
}
/// <summary>
/// 从一个视频中仅提取音频
/// </summary>
/// <param name="video">源视频</param>
/// <param name="audio">目标音频</param>
/// <param name="output">输出信息</param>
/// <param name="window"></param>
public static void ExtractAudio(string video, string audio, TextBox output = null, Window window = null)
{
// 抽取音频命令
// ffmpeg -i 3.mp4 -vn -y -acodec copy 3.aac
// ffmpeg -i 3.mp4 -vn -y -acodec copy 3.m4a
string param = $"-i \"{video}\" -vn -y -acodec copy \"{audio}\" -hide_banner";
ExcuteProcess("ffmpeg.exe", param,
null, (s, e) =>
{
Console.WriteLine(e.Data);
if (output != null && window != null)
{
window.Dispatcher.Invoke(new Action(() =>
{
output.Text += e.Data + "\n";
output.ScrollToEnd();
}));
}
});
}
/// <summary>
/// 从一个视频中仅提取视频
/// </summary>
/// <param name="video">源视频</param>
/// <param name="destVideo">目标视频</param>
/// <param name="output">输出信息</param>
/// <param name="window"></param>
public static void ExtractVideo(string video, string destVideo, TextBox output = null, Window window = null)
{
// 提取视频 Extract Video
// ffmpeg -i Life.of.Pi.has.subtitles.mkv -vcodec copy an videoNoAudioSubtitle.mp4
string param = $"-i \"{video}\" -y -vcodec copy -an \"{destVideo}\" -hide_banner";
ExcuteProcess("ffmpeg.exe", param,
null, (s, e) =>
{
Console.WriteLine(e.Data);
if (output != null && window != null)
{
window.Dispatcher.Invoke(new Action(() =>
{
output.Text += e.Data + "\n";
output.ScrollToEnd();
}));
}
});
}
/// <summary>
/// 提取视频的帧,输出为图片
/// </summary>
/// <param name="video"></param>
/// <param name="image"></param>
/// <param name="number"></param>
public static void ExtractFrame(string video, string image, uint number)
{
// 提取帧
// ffmpeg -i caiyilin.wmv -vframes 1 wm.bmp
string param = $"-i \"{video}\" -y -vframes {number} \"{image}\"";
ExcuteProcess("ffmpeg.exe", param, null, (s, e) => Console.WriteLine(e.Data));
}
/// <summary>
/// 执行一个控制台程序
/// </summary>
/// <param name="exe">程序名称</param>
/// <param name="arg">参数</param>
/// <param name="workingDirectory">工作路径</param>
/// <param name="output">输出重定向</param>
private static void ExcuteProcess(string exe, string arg, string workingDirectory, DataReceivedEventHandler output)
{
using (var p = new Process())
{
p.StartInfo.FileName = exe;
p.StartInfo.Arguments = arg;
// 工作目录
if (workingDirectory != null)
{
p.StartInfo.WorkingDirectory = workingDirectory;
}
p.StartInfo.UseShellExecute = false; //输出信息重定向
p.StartInfo.CreateNoWindow = true;
p.StartInfo.RedirectStandardError = true;
p.StartInfo.RedirectStandardOutput = true;
// 将 StandardErrorEncoding 改为 UTF-8 才不会出现中文乱码
p.StartInfo.StandardOutputEncoding = System.Text.Encoding.UTF8;
p.StartInfo.StandardErrorEncoding = System.Text.Encoding.UTF8;
p.OutputDataReceived += output;
p.ErrorDataReceived += output;
p.Start(); //启动线程
p.BeginOutputReadLine();
p.BeginErrorReadLine();
p.WaitForExit(); //等待进程结束
}
}
}
}

@ -1,198 +0,0 @@
using System;
using System.IO;
using System.Net;
namespace Core
{
// from https://www.jianshu.com/p/f31910ed8435
public class FileDownloadUtil
{
private string url; //文件下载网络地址
private string referer; //访问url的referer
private string path; //文件下载位置如d:/download
private string filename; //文件名如test.jpg
private string fileId; //文件ID文件唯一标识一般为UUID
private System.Threading.Timer FileTimer; // 定时器
private readonly int SPD_INTERVAL_SEC = 1; // 每隔多少秒计算一次速度
private long FileTemp = 0; // 临时储存长度
private float FileSpeed = 0; // //SPD_INTERVAL_SEC秒下载字节数
// 下载进度回调
public delegate void ProgressChangedHandler(int progress, string fileId);
public event ProgressChangedHandler ProgressChanged;
protected virtual void OnProgressChanged(int progress, string fileId)
{
ProgressChanged?.Invoke(progress, fileId);
}
public delegate void ProgressChanged2Handler(long totalBytes, long totalDownloadedByte, float speed, string fileId);
public event ProgressChanged2Handler ProgressChanged2;
protected virtual void OnProgressChanged2(long totalBytes, long totalDownloadedByte, float speed, string fileId)
{
ProgressChanged2?.Invoke(totalBytes, totalDownloadedByte, speed, fileId);
}
// 下载结果回调
public delegate void DownloadFinishHandler(bool isSuccess, string downloadPath, string fileId, string msg = null);
public event DownloadFinishHandler DownloadFinish;
protected virtual void OnDownloadFinish(bool isSuccess, string downloadPath, string fileId, string msg = null)
{
DownloadFinish?.Invoke(isSuccess, downloadPath, fileId, msg);
}
//通过网络链接直接下载任意文件
public FileDownloadUtil Init(string url, string referer, string path, string filename, string fileId)
{
this.url = url;
this.referer = referer;
this.path = path;
this.filename = filename;
this.fileId = fileId;
return this;
}
public void Download()
{
Download(url, path, filename, fileId);
}
private void Download(string url, string path, string filename, string fileId)
{
if (!Directory.Exists(path)) //判断文件夹是否存在
Directory.CreateDirectory(path);
path = path + "\\" + filename;
// 临时文件 "bilidownkyi\\"
string tempFile = Path.GetTempPath() + "downkyi." + Guid.NewGuid().ToString("N");
//string tempFile = path + ".temp";
try
{
if (File.Exists(tempFile))
{
File.Delete(tempFile); //存在则删除
}
if (File.Exists(path))
{
File.Delete(path); //存在则删除
}
}
catch (IOException e)
{
Console.WriteLine("Download()发生IO异常: {0}", e);
}
FileStream fs = null;
HttpWebRequest request = null;
HttpWebResponse response = null;
Stream responseStream = null;
try
{
//创建临时文件
fs = new FileStream(tempFile, FileMode.Append, FileAccess.Write, FileShare.ReadWrite);
request = WebRequest.Create(url) as HttpWebRequest;
request.Method = "GET";
request.Timeout = 60 * 1000;
request.UserAgent = Utils.GetUserAgent();
//request.ContentType = "text/html;charset=UTF-8";
request.Headers["accept-language"] = "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7";
//request.Headers["accept-encoding"] = "gzip, deflate, br";
request.Headers["origin"] = "https://www.bilibili.com";
request.Referer = referer;
// 构造cookie
// web端请求视频链接时没有加入cookie
//if (!url.Contains("getLogin"))
//{
// CookieContainer cookies = Login.GetLoginInfoCookies();
// if (cookies != null)
// {
// request.CookieContainer = cookies;
// }
//}
//发送请求并获取相应回应数据
response = request.GetResponse() as HttpWebResponse;
//直到request.GetResponse()程序才开始向目标网页发送Post请求
responseStream = response.GetResponseStream();
byte[] bArr = new byte[1024];
long totalBytes = response.ContentLength; //通过响应头获取文件大小,前提是响应头有文件大小
int size = responseStream.Read(bArr, 0, (int)bArr.Length); //读取响应流到bArr读取大小
float percent = 0; //用来保存计算好的百分比
long totalDownloadedByte = 0; //总共下载字节数
FileTimer = new System.Threading.Timer(SpeedTimer, null, 0, SPD_INTERVAL_SEC * 1000);
while (size > 0) //while (totalBytes > totalDownloadedByte) //while循环读取响应流
{
fs.Write(bArr, 0, size); //写到临时文件
// 定期刷新数据到磁盘,影响下载速度
//fs.Flush(true);
totalDownloadedByte += size;
FileTemp += size;
size = responseStream.Read(bArr, 0, (int)bArr.Length);
percent = (float)totalDownloadedByte / (float)totalBytes * 100;
// 下载进度回调
OnProgressChanged((int)percent, fileId);
OnProgressChanged2(totalBytes, totalDownloadedByte, FileSpeed, fileId);
}
try
{
if (File.Exists(path))
{
File.Delete(path); //存在则删除
}
}
catch (IOException e)
{
Console.WriteLine("Download()发生IO异常: {0}", e);
}
if (fs != null)
fs.Close();
File.Move(tempFile, path); //重命名为正式文件
OnDownloadFinish(true, path, fileId, null); //下载完成,成功回调
}
catch (Exception ex)
{
Console.WriteLine("Download()发生异常: {0}", ex);
OnDownloadFinish(false, null, fileId, ex.Message); //下载完成,失败回调
}
finally
{
if (fs != null)
fs.Close();
if (request != null)
request.Abort();
if (response != null)
response.Close();
if (responseStream != null)
responseStream.Close();
try
{
if (File.Exists(tempFile))
{
File.Delete(tempFile); //存在则删除
}
}
catch (IOException e)
{
Console.WriteLine("Download()发生IO异常: {0}", e);
}
}
}
private void SpeedTimer(object state)
{
FileSpeed = FileTemp / SPD_INTERVAL_SEC; //SPD_INTERVAL_SEC秒下载字节数,
FileTemp = 0; //清空临时储存
}
}
}

@ -1,148 +0,0 @@
using Core.entity;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
namespace Core
{
public static class UserSpaceOld
{
/// <summary>
/// 获取我创建的收藏夹
/// </summary>
/// <param name="mid"></param>
/// <returns></returns>
public static FavFolderData GetCreatedFavFolder(long mid)
{
string url = $"https://api.bilibili.com/x/v3/fav/folder/created/list?up_mid={mid}&ps=50";
return GetAllFavFolder(url);
}
/// <summary>
/// 获取我收藏的收藏夹
/// </summary>
/// <param name="mid"></param>
/// <returns></returns>
public static FavFolderData GetCollectedFavFolder(long mid)
{
string url = $"https://api.bilibili.com/x/v3/fav/folder/collected/list?up_mid={mid}&ps=50";
return GetAllFavFolder(url);
}
private static FavFolderData GetAllFavFolder(string baseUrl)
{
FavFolderData userFavoriteData = new FavFolderData
{
count = 0,
list = new List<FavFolderDataList>()
};
int i = 0;
while (true)
{
i++;
string url = baseUrl + $"&pn={i}";
var data = GetFavFolder(url);
if (data == null)
{ break; }
if (data.count == 0 || data.list == null)
{ break; }
userFavoriteData.list.AddRange(data.list);
}
userFavoriteData.count = userFavoriteData.list.Count;
return userFavoriteData;
}
private static FavFolderData GetFavFolder(string url)
{
string referer = "https://www.bilibili.com";
string response = Utils.RequestWeb(url, referer);
try
{
FavFolder favFolder = JsonConvert.DeserializeObject<FavFolder>(response);
if (favFolder == null || favFolder.data == null) { return null; }
return favFolder.data;
}
catch (Exception e)
{
Console.WriteLine("GetFavFolder()发生异常: {0}", e);
return null;
}
}
/// <summary>
/// 获得某个收藏夹的内容
/// </summary>
/// <param name="mediaId"></param>
/// <returns></returns>
public static List<FavResourceDataMedia> GetAllFavResource(long mediaId)
{
string baseUrl = $"https://api.bilibili.com/x/v3/fav/resource/list?media_id={mediaId}&ps=20";
List<FavResourceDataMedia> medias = new List<FavResourceDataMedia>();
int i = 0;
while (true)
{
i++;
string url = baseUrl + $"&pn={i}";
var data = GetFavResource(url);
if (data == null || data.Count == 0)
{ break; }
medias.AddRange(data);
}
return medias;
}
private static List<FavResourceDataMedia> GetFavResource(string url)
{
string referer = "https://www.bilibili.com";
string response = Utils.RequestWeb(url, referer);
try
{
FavResource favResource = JsonConvert.DeserializeObject<FavResource>(response);
if (favResource == null || favResource.data == null) { return null; }
return favResource.data.medias;
}
catch (Exception e)
{
Console.WriteLine("GetFavResource()发生异常: {0}", e);
return null;
}
}
/// <summary>
/// 获取订阅番剧的数量
/// 废弃
/// </summary>
/// <param name="mid"></param>
/// <returns></returns>
//public static int GetBangumiFollowList(long mid)
//{
// string url = $"https://space.bilibili.com/ajax/Bangumi/getList?mid={mid}";
// string referer = "https://www.bilibili.com";
// string response = Utils.RequestWeb(url, referer);
// try
// {
// BangumiList bangumiList = JsonConvert.DeserializeObject<BangumiList>(response);
// if (bangumiList == null || bangumiList.data == null) { return -1; }
// return bangumiList.data.count;
// }
// catch (Exception e)
// {
// Console.WriteLine("发生异常: {0}", e);
// return 0;
// }
//}
}
}

@ -1,430 +0,0 @@
using Brotli;
using Core.api.login;
using Core.history;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
namespace Core
{
public static class Utils
{
/// <summary>
/// 随机的UserAgent
/// </summary>
/// <returns>userAgent</returns>
public static string GetUserAgent()
{
string[] userAgents = {
// Chrome
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.182 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.77 Safari/537.36",
// 新版Edge
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36 Edg/83.0.478.58",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36 Edg/90.0.818.66",
// IE 11
"Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 10.0; WOW64; Trident/7.0; .NET4.0C; .NET4.0E; .NET CLR 2.0.50727; .NET CLR 3.0.30729; .NET CLR 3.5.30729)",
// 火狐
"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:69.0) Gecko/20100101 Firefox/69.0",
// Opera
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36 OPR/63.0.3368.43",
// MacOS Chrome
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.106 Safari/537.36",
// MacOS Safari
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_5) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.1.1 Safari/605.1.15"
};
var time = DateTime.Now;
Random random = new Random(time.GetHashCode());
int number = random.Next(0, userAgents.Length - 1);
return userAgents[number];
}
/// <summary>
/// 发送get或post请求
/// </summary>
/// <param name="url"></param>
/// <param name="referer"></param>
/// <param name="method"></param>
/// <param name="parameters"></param>
/// <returns></returns>
public static string RequestWeb(string url, string referer = null, string method = "GET", Dictionary<string, string> parameters = null, int retry = 3)
{
// 重试次数
if (retry <= 0) { return ""; }
// post请求发送参数
if (method == "POST" && parameters != null)
{
StringBuilder builder = new StringBuilder();
int i = 0;
foreach (var item in parameters)
{
if (i > 0) builder.Append("&");
builder.AppendFormat("{0}={1}", item.Key, item.Value);
i++;
}
url += "?" + builder.ToString();
}
try
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Method = method;
request.Timeout = 30 * 1000;
request.UserAgent = GetUserAgent();
//request.ContentType = "application/json,text/html,application/xhtml+xml,application/xml;charset=UTF-8";
request.Headers["accept-language"] = "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7";
request.Headers["accept-encoding"] = "gzip, deflate, br";
//request.Headers["sec-fetch-dest"] = "empty";
//request.Headers["sec-fetch-mode"] = "cors";
//request.Headers["sec-fetch-site"] = "same-site";
// referer
if (referer != null)
{
request.Referer = referer;
}
// 构造cookie
if (!url.Contains("getLogin"))
{
request.Headers["origin"] = "https://www.bilibili.com";
CookieContainer cookies = LoginHelper.GetInstance().GetLoginInfoCookies();
if (cookies != null)
{
request.CookieContainer = cookies;
}
}
//// post请求发送参数
//if (method == "POST" && parameters != null)
//{
// StringBuilder builder = new StringBuilder();
// int i = 0;
// foreach (var item in parameters)
// {
// if (i > 0) builder.Append("&");
// builder.AppendFormat("{0}={1}", item.Key, item.Value);
// i++;
// }
// byte[] data = Encoding.UTF8.GetBytes(builder.ToString());
// request.ContentLength = data.Length;
// Stream reqStream = request.GetRequestStream();
// reqStream.Write(data, 0, data.Length);
// reqStream.Close();
// Console.WriteLine("\n" + builder.ToString() + "\t" + data.Length + "\n");
//}
//HttpWebResponse response = (HttpWebResponse)request.GetResponse();
//Stream responseStream = response.GetResponseStream();
//StreamReader streamReader = new StreamReader(responseStream, Encoding.UTF8);
//string str = streamReader.ReadToEnd();
//streamReader.Close();
//responseStream.Close();
string html = string.Empty;
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
{
if (response.ContentEncoding.ToLower().Contains("gzip"))
{
using (GZipStream stream = new GZipStream(response.GetResponseStream(), CompressionMode.Decompress))
{
using (StreamReader reader = new StreamReader(stream, Encoding.UTF8))
{
html = reader.ReadToEnd();
}
}
}
else if (response.ContentEncoding.ToLower().Contains("deflate"))
{
using (DeflateStream stream = new DeflateStream(response.GetResponseStream(), CompressionMode.Decompress))
{
using (StreamReader reader = new StreamReader(stream, Encoding.UTF8))
{
html = reader.ReadToEnd();
}
}
}
else if (response.ContentEncoding.ToLower().Contains("br"))
{
using (BrotliStream stream = new BrotliStream(response.GetResponseStream(), CompressionMode.Decompress))
{
using (StreamReader reader = new StreamReader(stream, Encoding.UTF8))
{
html = reader.ReadToEnd();
}
}
}
else
{
using (Stream stream = response.GetResponseStream())
{
using (StreamReader reader = new StreamReader(stream, Encoding.UTF8))
{
html = reader.ReadToEnd();
}
}
}
}
return html;
}
catch (WebException e)
{
Console.WriteLine("RequestWeb()发生Web异常: {0}", e);
return RequestWeb(url, referer, method, parameters, retry - 1);
}
catch (IOException e)
{
Console.WriteLine("RequestWeb()发生IO异常: {0}", e);
return RequestWeb(url, referer, method, parameters, retry - 1);
}
catch (Exception e)
{
Console.WriteLine("RequestWeb()发生其他异常: {0}", e);
return RequestWeb(url, referer, method, parameters, retry - 1);
}
}
/// <summary>
/// 解析二维码登录返回的url用于设置cookie
/// </summary>
/// <param name="url"></param>
/// <returns></returns>
public static CookieContainer ParseCookie(string url)
{
CookieContainer cookieContainer = new CookieContainer();
if (url == null || url == "") { return cookieContainer; }
string[] strList = url.Split('?');
if (strList.Count() < 2) { return cookieContainer; }
string[] strList2 = strList[1].Split('&');
if (strList2.Count() == 0) { return cookieContainer; }
// 获取expires
string expires = strList2.FirstOrDefault(it => it.Contains("Expires")).Split('=')[1];
DateTime dateTime = DateTime.Now;
dateTime = dateTime.AddSeconds(int.Parse(expires));
foreach (var item in strList2)
{
string[] strList3 = item.Split('=');
if (strList3.Count() < 2) { continue; }
string name = strList3[0];
string value = strList3[1];
// 不需要
if (name == "Expires" || name == "gourl") { continue; }
// 添加cookie
cookieContainer.Add(new Cookie(name, value, "/", ".bilibili.com") { Expires = dateTime });
#if DEBUG
Console.WriteLine(name + ": " + value + "\t" + cookieContainer.Count);
#endif
}
return cookieContainer;
}
/// <summary>
/// 将CookieContainer中的所有的Cookie读出来
/// </summary>
/// <param name="cc"></param>
/// <returns></returns>
public static List<Cookie> GetAllCookies(CookieContainer cc)
{
List<Cookie> lstCookies = new List<Cookie>();
Hashtable table = (Hashtable)cc.GetType().InvokeMember("m_domainTable",
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.GetField |
System.Reflection.BindingFlags.Instance, null, cc, new object[] { });
foreach (object pathList in table.Values)
{
SortedList lstCookieCol = (SortedList)pathList.GetType().InvokeMember("m_list",
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.GetField
| System.Reflection.BindingFlags.Instance, null, pathList, new object[] { });
foreach (CookieCollection colCookies in lstCookieCol.Values)
foreach (Cookie c in colCookies) lstCookies.Add(c);
}
return lstCookies;
}
/// <summary>
/// 写入cookies到磁盘
/// </summary>
/// <param name="file"></param>
/// <param name="cookieJar"></param>
/// <returns></returns>
public static bool WriteCookiesToDisk(string file, CookieContainer cookieJar)
{
return WriteObjectToDisk(file, cookieJar);
}
/// <summary>
/// 从磁盘读取cookie
/// </summary>
/// <param name="file"></param>
/// <returns></returns>
public static CookieContainer ReadCookiesFromDisk(string file)
{
return (CookieContainer)ReadObjectFromDisk(file);
}
/// <summary>
/// 写入历史数据到磁盘
/// </summary>
/// <param name="file"></param>
/// <param name="history"></param>
/// <returns></returns>
public static bool WriteHistoryToDisk(string file, HistoryEntity history)
{
return WriteObjectToDisk(file, history);
}
/// <summary>
/// 从磁盘读取历史数据
/// </summary>
/// <param name="file"></param>
/// <returns></returns>
public static HistoryEntity ReadHistoryFromDisk(string file)
{
return (HistoryEntity)ReadObjectFromDisk(file);
}
/// <summary>
/// 写入序列化对象到磁盘
/// </summary>
/// <param name="file"></param>
/// <param name="obj"></param>
/// <returns></returns>
public static bool WriteObjectToDisk(string file, object obj)
{
try
{
using (Stream stream = File.Create(file))
{
#if DEBUG
Console.Out.Write("Writing object to disk... ");
#endif
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(stream, obj);
#if DEBUG
Console.Out.WriteLine("Done.");
#endif
return true;
}
}
catch (IOException e)
{
Console.WriteLine("WriteObjectToDisk()发生IO异常: {0}", e);
return false;
}
catch (Exception e)
{
//Console.Out.WriteLine("Problem writing object to disk: " + e.GetType());
Console.WriteLine("WriteObjectToDisk()发生异常: {0}", e);
return false;
}
}
/// <summary>
/// 从磁盘读取序列化对象
/// </summary>
/// <param name="file"></param>
/// <returns></returns>
public static object ReadObjectFromDisk(string file)
{
try
{
using (Stream stream = File.Open(file, FileMode.Open))
{
#if DEBUG
Console.Out.Write("Reading object from disk... ");
#endif
BinaryFormatter formatter = new BinaryFormatter();
#if DEBUG
Console.Out.WriteLine("Done.");
#endif
return formatter.Deserialize(stream);
}
}
catch (IOException e)
{
Console.WriteLine("ReadObjectFromDisk()发生IO异常: {0}", e);
return null;
}
catch (Exception e)
{
//Console.Out.WriteLine("Problem reading object from disk: " + e.GetType());
Console.WriteLine("ReadObjectFromDisk()发生异常: {0}", e);
return null;
}
}
/// <summary>
/// 生成二维码
/// </summary>
/// <param name="msg">信息</param>
/// <param name="version">版本 1 ~ 40</param>
/// <param name="pixel">像素点大小</param>
/// <param name="icon_path">图标路径</param>
/// <param name="icon_size">图标尺寸</param>
/// <param name="icon_border">图标边框厚度</param>
/// <param name="white_edge">二维码白边</param>
/// <returns>位图</returns>
public static Bitmap EncodeQRCode(string msg, int version, int pixel, string icon_path, int icon_size, int icon_border, bool white_edge)
{
QRCoder.QRCodeGenerator code_generator = new QRCoder.QRCodeGenerator();
QRCoder.QRCodeData code_data = code_generator.CreateQrCode(msg, QRCoder.QRCodeGenerator.ECCLevel.H/* 这里设置容错率的一个级别 */, true, false, QRCoder.QRCodeGenerator.EciMode.Utf8, version);
QRCoder.QRCode code = new QRCoder.QRCode(code_data);
Bitmap icon;
if (icon_path == null || icon_path == "")
{
icon = null;
}
else
{
icon = new Bitmap(icon_path);
}
Bitmap bmp = code.GetGraphic(pixel, Color.Black, Color.White, icon, icon_size, icon_border, white_edge);
return bmp;
}
}
}

@ -1,36 +0,0 @@
namespace Core.api.danmaku.entity
{
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()
{
//return base.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}";
}
}
}

@ -1,115 +0,0 @@
using Core.api.danmaku.entity;
using System;
using System.Collections.Generic;
using System.IO;
namespace Core.api.danmaku
{
/// <summary>
/// protobuf弹幕
/// </summary>
public class DanmakuProtobuf
{
private static DanmakuProtobuf instance;
/// <summary>
/// 获取DanmakuProtobuf实例
/// </summary>
/// <returns></returns>
public static DanmakuProtobuf GetInstance()
{
if (instance == null)
{
instance = new DanmakuProtobuf();
}
return instance;
}
/// <summary>
/// 隐藏DanmakuProtobuf()方法,必须使用单例模式
/// </summary>
private DanmakuProtobuf() { }
/// <summary>
/// 下载6分钟内的弹幕返回弹幕列表
/// </summary>
/// <param name="avid">稿件avID</param>
/// <param name="cid">视频CID</param>
/// <param name="segmentIndex">分包每6分钟一包</param>
/// <returns></returns>
public 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";
FileDownloadUtil fileDownload = new FileDownloadUtil();
fileDownload.Init(url, referer, Path.GetTempPath() + "downkyi/danmaku", $"{cid}-{segmentIndex}.proto", "DanmakuProtobuf");
fileDownload.Download();
var danmakuList = new List<BiliDanmaku>();
DmSegMobileReply danmakus;
try
{
using (var input = File.OpenRead(Path.GetTempPath() + $"downkyi/danmaku/{cid}-{segmentIndex}.proto"))
{
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)
{
#if DEBUG
Console.WriteLine("发生异常: {0}", e);
#endif
return null;
}
return danmakuList;
}
/// <summary>
/// 下载所有弹幕,返回弹幕列表
/// </summary>
/// <param name="avid">稿件avID</param>
/// <param name="cid">视频CID</param>
/// <returns></returns>
public 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;
}
}
}

@ -1,814 +0,0 @@
// <auto-generated>
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: Danmaku.proto
// </auto-generated>
#pragma warning disable 1591, 0612, 3021
#region Designer generated code
using pb = global::Google.Protobuf;
using pbc = global::Google.Protobuf.Collections;
using pbr = global::Google.Protobuf.Reflection;
using scg = global::System.Collections.Generic;
/// <summary>Holder for reflection information generated from Danmaku.proto</summary>
public static partial class DanmakuReflection {
#region Descriptor
/// <summary>File descriptor for Danmaku.proto</summary>
public static pbr::FileDescriptor Descriptor {
get { return descriptor; }
}
private static pbr::FileDescriptor descriptor;
static DanmakuReflection() {
byte[] descriptorData = global::System.Convert.FromBase64String(
string.Concat(
"Cg1EYW5tYWt1LnByb3RvIsgBCgtEYW5tYWt1RWxlbRIKCgJpZBgBIAEoAxIQ",
"Cghwcm9ncmVzcxgCIAEoBRIMCgRtb2RlGAMgASgFEhAKCGZvbnRzaXplGAQg",
"ASgFEg0KBWNvbG9yGAUgASgNEg8KB21pZEhhc2gYBiABKAkSDwoHY29udGVu",
"dBgHIAEoCRINCgVjdGltZRgIIAEoAxIOCgZ3ZWlnaHQYCSABKAUSDgoGYWN0",
"aW9uGAogASgJEgwKBHBvb2wYCyABKAUSDQoFaWRTdHIYDCABKAkiLwoQRG1T",
"ZWdNb2JpbGVSZXBseRIbCgVlbGVtcxgBIAMoCzIMLkRhbm1ha3VFbGVtYgZw",
"cm90bzM="));
descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
new pbr::FileDescriptor[] { },
new pbr::GeneratedClrTypeInfo(null, null, new pbr::GeneratedClrTypeInfo[] {
new pbr::GeneratedClrTypeInfo(typeof(global::DanmakuElem), global::DanmakuElem.Parser, new[]{ "Id", "Progress", "Mode", "Fontsize", "Color", "MidHash", "Content", "Ctime", "Weight", "Action", "Pool", "IdStr" }, null, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::DmSegMobileReply), global::DmSegMobileReply.Parser, new[]{ "Elems" }, null, null, null, null)
}));
}
#endregion
}
#region Messages
public sealed partial class DanmakuElem : pb::IMessage<DanmakuElem>
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
, pb::IBufferMessage
#endif
{
private static readonly pb::MessageParser<DanmakuElem> _parser = new pb::MessageParser<DanmakuElem>(() => new DanmakuElem());
private pb::UnknownFieldSet _unknownFields;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pb::MessageParser<DanmakuElem> Parser { get { return _parser; } }
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pbr::MessageDescriptor Descriptor {
get { return global::DanmakuReflection.Descriptor.MessageTypes[0]; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
pbr::MessageDescriptor pb::IMessage.Descriptor {
get { return Descriptor; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public DanmakuElem() {
OnConstruction();
}
partial void OnConstruction();
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public DanmakuElem(DanmakuElem other) : this() {
id_ = other.id_;
progress_ = other.progress_;
mode_ = other.mode_;
fontsize_ = other.fontsize_;
color_ = other.color_;
midHash_ = other.midHash_;
content_ = other.content_;
ctime_ = other.ctime_;
weight_ = other.weight_;
action_ = other.action_;
pool_ = other.pool_;
idStr_ = other.idStr_;
_unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public DanmakuElem Clone() {
return new DanmakuElem(this);
}
/// <summary>Field number for the "id" field.</summary>
public const int IdFieldNumber = 1;
private long id_;
/// <summary>
///弹幕dmID
/// </summary>
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public long Id {
get { return id_; }
set {
id_ = value;
}
}
/// <summary>Field number for the "progress" field.</summary>
public const int ProgressFieldNumber = 2;
private int progress_;
/// <summary>
///出现时间
/// </summary>
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public int Progress {
get { return progress_; }
set {
progress_ = value;
}
}
/// <summary>Field number for the "mode" field.</summary>
public const int ModeFieldNumber = 3;
private int mode_;
/// <summary>
///弹幕类型
/// </summary>
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public int Mode {
get { return mode_; }
set {
mode_ = value;
}
}
/// <summary>Field number for the "fontsize" field.</summary>
public const int FontsizeFieldNumber = 4;
private int fontsize_;
/// <summary>
///文字大小
/// </summary>
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public int Fontsize {
get { return fontsize_; }
set {
fontsize_ = value;
}
}
/// <summary>Field number for the "color" field.</summary>
public const int ColorFieldNumber = 5;
private uint color_;
/// <summary>
///弹幕颜色
/// </summary>
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public uint Color {
get { return color_; }
set {
color_ = value;
}
}
/// <summary>Field number for the "midHash" field.</summary>
public const int MidHashFieldNumber = 6;
private string midHash_ = "";
/// <summary>
///发送者UID的HASH
/// </summary>
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public string MidHash {
get { return midHash_; }
set {
midHash_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
}
}
/// <summary>Field number for the "content" field.</summary>
public const int ContentFieldNumber = 7;
private string content_ = "";
/// <summary>
///弹幕内容
/// </summary>
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public string Content {
get { return content_; }
set {
content_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
}
}
/// <summary>Field number for the "ctime" field.</summary>
public const int CtimeFieldNumber = 8;
private long ctime_;
/// <summary>
///发送时间
/// </summary>
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public long Ctime {
get { return ctime_; }
set {
ctime_ = value;
}
}
/// <summary>Field number for the "weight" field.</summary>
public const int WeightFieldNumber = 9;
private int weight_;
/// <summary>
///权重
/// </summary>
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public int Weight {
get { return weight_; }
set {
weight_ = value;
}
}
/// <summary>Field number for the "action" field.</summary>
public const int ActionFieldNumber = 10;
private string action_ = "";
/// <summary>
///动作?
/// </summary>
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public string Action {
get { return action_; }
set {
action_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
}
}
/// <summary>Field number for the "pool" field.</summary>
public const int PoolFieldNumber = 11;
private int pool_;
/// <summary>
///弹幕池
/// </summary>
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public int Pool {
get { return pool_; }
set {
pool_ = value;
}
}
/// <summary>Field number for the "idStr" field.</summary>
public const int IdStrFieldNumber = 12;
private string idStr_ = "";
/// <summary>
///弹幕dmID字串形式
/// </summary>
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public string IdStr {
get { return idStr_; }
set {
idStr_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
}
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override bool Equals(object other) {
return Equals(other as DanmakuElem);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public bool Equals(DanmakuElem other) {
if (ReferenceEquals(other, null)) {
return false;
}
if (ReferenceEquals(other, this)) {
return true;
}
if (Id != other.Id) return false;
if (Progress != other.Progress) return false;
if (Mode != other.Mode) return false;
if (Fontsize != other.Fontsize) return false;
if (Color != other.Color) return false;
if (MidHash != other.MidHash) return false;
if (Content != other.Content) return false;
if (Ctime != other.Ctime) return false;
if (Weight != other.Weight) return false;
if (Action != other.Action) return false;
if (Pool != other.Pool) return false;
if (IdStr != other.IdStr) return false;
return Equals(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override int GetHashCode() {
int hash = 1;
if (Id != 0L) hash ^= Id.GetHashCode();
if (Progress != 0) hash ^= Progress.GetHashCode();
if (Mode != 0) hash ^= Mode.GetHashCode();
if (Fontsize != 0) hash ^= Fontsize.GetHashCode();
if (Color != 0) hash ^= Color.GetHashCode();
if (MidHash.Length != 0) hash ^= MidHash.GetHashCode();
if (Content.Length != 0) hash ^= Content.GetHashCode();
if (Ctime != 0L) hash ^= Ctime.GetHashCode();
if (Weight != 0) hash ^= Weight.GetHashCode();
if (Action.Length != 0) hash ^= Action.GetHashCode();
if (Pool != 0) hash ^= Pool.GetHashCode();
if (IdStr.Length != 0) hash ^= IdStr.GetHashCode();
if (_unknownFields != null) {
hash ^= _unknownFields.GetHashCode();
}
return hash;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override string ToString() {
return pb::JsonFormatter.ToDiagnosticString(this);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void WriteTo(pb::CodedOutputStream output) {
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
output.WriteRawMessage(this);
#else
if (Id != 0L) {
output.WriteRawTag(8);
output.WriteInt64(Id);
}
if (Progress != 0) {
output.WriteRawTag(16);
output.WriteInt32(Progress);
}
if (Mode != 0) {
output.WriteRawTag(24);
output.WriteInt32(Mode);
}
if (Fontsize != 0) {
output.WriteRawTag(32);
output.WriteInt32(Fontsize);
}
if (Color != 0) {
output.WriteRawTag(40);
output.WriteUInt32(Color);
}
if (MidHash.Length != 0) {
output.WriteRawTag(50);
output.WriteString(MidHash);
}
if (Content.Length != 0) {
output.WriteRawTag(58);
output.WriteString(Content);
}
if (Ctime != 0L) {
output.WriteRawTag(64);
output.WriteInt64(Ctime);
}
if (Weight != 0) {
output.WriteRawTag(72);
output.WriteInt32(Weight);
}
if (Action.Length != 0) {
output.WriteRawTag(82);
output.WriteString(Action);
}
if (Pool != 0) {
output.WriteRawTag(88);
output.WriteInt32(Pool);
}
if (IdStr.Length != 0) {
output.WriteRawTag(98);
output.WriteString(IdStr);
}
if (_unknownFields != null) {
_unknownFields.WriteTo(output);
}
#endif
}
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) {
if (Id != 0L) {
output.WriteRawTag(8);
output.WriteInt64(Id);
}
if (Progress != 0) {
output.WriteRawTag(16);
output.WriteInt32(Progress);
}
if (Mode != 0) {
output.WriteRawTag(24);
output.WriteInt32(Mode);
}
if (Fontsize != 0) {
output.WriteRawTag(32);
output.WriteInt32(Fontsize);
}
if (Color != 0) {
output.WriteRawTag(40);
output.WriteUInt32(Color);
}
if (MidHash.Length != 0) {
output.WriteRawTag(50);
output.WriteString(MidHash);
}
if (Content.Length != 0) {
output.WriteRawTag(58);
output.WriteString(Content);
}
if (Ctime != 0L) {
output.WriteRawTag(64);
output.WriteInt64(Ctime);
}
if (Weight != 0) {
output.WriteRawTag(72);
output.WriteInt32(Weight);
}
if (Action.Length != 0) {
output.WriteRawTag(82);
output.WriteString(Action);
}
if (Pool != 0) {
output.WriteRawTag(88);
output.WriteInt32(Pool);
}
if (IdStr.Length != 0) {
output.WriteRawTag(98);
output.WriteString(IdStr);
}
if (_unknownFields != null) {
_unknownFields.WriteTo(ref output);
}
}
#endif
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public int CalculateSize() {
int size = 0;
if (Id != 0L) {
size += 1 + pb::CodedOutputStream.ComputeInt64Size(Id);
}
if (Progress != 0) {
size += 1 + pb::CodedOutputStream.ComputeInt32Size(Progress);
}
if (Mode != 0) {
size += 1 + pb::CodedOutputStream.ComputeInt32Size(Mode);
}
if (Fontsize != 0) {
size += 1 + pb::CodedOutputStream.ComputeInt32Size(Fontsize);
}
if (Color != 0) {
size += 1 + pb::CodedOutputStream.ComputeUInt32Size(Color);
}
if (MidHash.Length != 0) {
size += 1 + pb::CodedOutputStream.ComputeStringSize(MidHash);
}
if (Content.Length != 0) {
size += 1 + pb::CodedOutputStream.ComputeStringSize(Content);
}
if (Ctime != 0L) {
size += 1 + pb::CodedOutputStream.ComputeInt64Size(Ctime);
}
if (Weight != 0) {
size += 1 + pb::CodedOutputStream.ComputeInt32Size(Weight);
}
if (Action.Length != 0) {
size += 1 + pb::CodedOutputStream.ComputeStringSize(Action);
}
if (Pool != 0) {
size += 1 + pb::CodedOutputStream.ComputeInt32Size(Pool);
}
if (IdStr.Length != 0) {
size += 1 + pb::CodedOutputStream.ComputeStringSize(IdStr);
}
if (_unknownFields != null) {
size += _unknownFields.CalculateSize();
}
return size;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(DanmakuElem other) {
if (other == null) {
return;
}
if (other.Id != 0L) {
Id = other.Id;
}
if (other.Progress != 0) {
Progress = other.Progress;
}
if (other.Mode != 0) {
Mode = other.Mode;
}
if (other.Fontsize != 0) {
Fontsize = other.Fontsize;
}
if (other.Color != 0) {
Color = other.Color;
}
if (other.MidHash.Length != 0) {
MidHash = other.MidHash;
}
if (other.Content.Length != 0) {
Content = other.Content;
}
if (other.Ctime != 0L) {
Ctime = other.Ctime;
}
if (other.Weight != 0) {
Weight = other.Weight;
}
if (other.Action.Length != 0) {
Action = other.Action;
}
if (other.Pool != 0) {
Pool = other.Pool;
}
if (other.IdStr.Length != 0) {
IdStr = other.IdStr;
}
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(pb::CodedInputStream input) {
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
input.ReadRawMessage(this);
#else
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
break;
case 8: {
Id = input.ReadInt64();
break;
}
case 16: {
Progress = input.ReadInt32();
break;
}
case 24: {
Mode = input.ReadInt32();
break;
}
case 32: {
Fontsize = input.ReadInt32();
break;
}
case 40: {
Color = input.ReadUInt32();
break;
}
case 50: {
MidHash = input.ReadString();
break;
}
case 58: {
Content = input.ReadString();
break;
}
case 64: {
Ctime = input.ReadInt64();
break;
}
case 72: {
Weight = input.ReadInt32();
break;
}
case 82: {
Action = input.ReadString();
break;
}
case 88: {
Pool = input.ReadInt32();
break;
}
case 98: {
IdStr = input.ReadString();
break;
}
}
}
#endif
}
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) {
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input);
break;
case 8: {
Id = input.ReadInt64();
break;
}
case 16: {
Progress = input.ReadInt32();
break;
}
case 24: {
Mode = input.ReadInt32();
break;
}
case 32: {
Fontsize = input.ReadInt32();
break;
}
case 40: {
Color = input.ReadUInt32();
break;
}
case 50: {
MidHash = input.ReadString();
break;
}
case 58: {
Content = input.ReadString();
break;
}
case 64: {
Ctime = input.ReadInt64();
break;
}
case 72: {
Weight = input.ReadInt32();
break;
}
case 82: {
Action = input.ReadString();
break;
}
case 88: {
Pool = input.ReadInt32();
break;
}
case 98: {
IdStr = input.ReadString();
break;
}
}
}
}
#endif
}
public sealed partial class DmSegMobileReply : pb::IMessage<DmSegMobileReply>
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
, pb::IBufferMessage
#endif
{
private static readonly pb::MessageParser<DmSegMobileReply> _parser = new pb::MessageParser<DmSegMobileReply>(() => new DmSegMobileReply());
private pb::UnknownFieldSet _unknownFields;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pb::MessageParser<DmSegMobileReply> Parser { get { return _parser; } }
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pbr::MessageDescriptor Descriptor {
get { return global::DanmakuReflection.Descriptor.MessageTypes[1]; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
pbr::MessageDescriptor pb::IMessage.Descriptor {
get { return Descriptor; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public DmSegMobileReply() {
OnConstruction();
}
partial void OnConstruction();
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public DmSegMobileReply(DmSegMobileReply other) : this() {
elems_ = other.elems_.Clone();
_unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public DmSegMobileReply Clone() {
return new DmSegMobileReply(this);
}
/// <summary>Field number for the "elems" field.</summary>
public const int ElemsFieldNumber = 1;
private static readonly pb::FieldCodec<global::DanmakuElem> _repeated_elems_codec
= pb::FieldCodec.ForMessage(10, global::DanmakuElem.Parser);
private readonly pbc::RepeatedField<global::DanmakuElem> elems_ = new pbc::RepeatedField<global::DanmakuElem>();
/// <summary>
///弹幕条目
/// </summary>
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public pbc::RepeatedField<global::DanmakuElem> Elems {
get { return elems_; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override bool Equals(object other) {
return Equals(other as DmSegMobileReply);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public bool Equals(DmSegMobileReply other) {
if (ReferenceEquals(other, null)) {
return false;
}
if (ReferenceEquals(other, this)) {
return true;
}
if(!elems_.Equals(other.elems_)) return false;
return Equals(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override int GetHashCode() {
int hash = 1;
hash ^= elems_.GetHashCode();
if (_unknownFields != null) {
hash ^= _unknownFields.GetHashCode();
}
return hash;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override string ToString() {
return pb::JsonFormatter.ToDiagnosticString(this);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void WriteTo(pb::CodedOutputStream output) {
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
output.WriteRawMessage(this);
#else
elems_.WriteTo(output, _repeated_elems_codec);
if (_unknownFields != null) {
_unknownFields.WriteTo(output);
}
#endif
}
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) {
elems_.WriteTo(ref output, _repeated_elems_codec);
if (_unknownFields != null) {
_unknownFields.WriteTo(ref output);
}
}
#endif
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public int CalculateSize() {
int size = 0;
size += elems_.CalculateSize(_repeated_elems_codec);
if (_unknownFields != null) {
size += _unknownFields.CalculateSize();
}
return size;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(DmSegMobileReply other) {
if (other == null) {
return;
}
elems_.Add(other.elems_);
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(pb::CodedInputStream input) {
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
input.ReadRawMessage(this);
#else
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
break;
case 10: {
elems_.AddEntriesFrom(input, _repeated_elems_codec);
break;
}
}
}
#endif
}
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) {
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input);
break;
case 10: {
elems_.AddEntriesFrom(ref input, _repeated_elems_codec);
break;
}
}
}
}
#endif
}
#endregion
#endregion Designer generated code

@ -1,20 +0,0 @@
syntax = "proto3";
message DanmakuElem {
int64 id = 1; //dmID
int32 progress = 2; //
int32 mode = 3; //
int32 fontsize = 4; //
uint32 color = 5; //
string midHash = 6; //UIDHASH
string content = 7; //
int64 ctime = 8; //
int32 weight = 9; //
string action = 10; //
int32 pool = 11; //
string idStr = 12; //dmID
}
message DmSegMobileReply {
repeated DanmakuElem elems = 1; //
}

@ -1,42 +0,0 @@
using System;
using System.Collections.Generic;
namespace Core.api.fileDownload
{
[Serializable]
internal class FileDownloadConfig
{
public long DownloadSize { get; set; }
public long TotalSize { get; set; }
public Queue<ThreadDownloadInfo> DownloadQueue { get; set; }
/// <summary>
/// 保存文件下载的配置信息,包括总字节数、已下载字节数、下载队列信息
/// </summary>
/// <param name="configFile"></param>
/// <param name="downloadSize"></param>
/// <param name="totalSize"></param>
/// <param name="downloadQueue"></param>
public static void SaveConfig(string configFile, long downloadSize, long totalSize, Queue<ThreadDownloadInfo> downloadQueue)
{
var config = new FileDownloadConfig()
{
DownloadSize = downloadSize,
TotalSize = totalSize,
DownloadQueue = downloadQueue
};
Utils.WriteObjectToDisk(configFile, config);
}
/// <summary>
/// 读取文件下载的配置信息,包括总字节数、已下载字节数、下载队列信息
/// </summary>
/// <param name="configFile"></param>
/// <returns></returns>
public static FileDownloadConfig ReadConfig(string configFile)
{
return (FileDownloadConfig)Utils.ReadObjectFromDisk(configFile);
}
}
}

@ -1,24 +0,0 @@
namespace Core.api.fileDownload
{
public class FileDownloadEvent
{
//private long _downloadSize;
//private long _totalSize;
public FileDownloadEvent() { }
// 每秒下载的速度 B/s
public float Speed { get; set; }
public float Percent
{
get { return DownloadSize * 100.0f / TotalSize; }
}
public long DownloadSize { get; set; }
public long TotalSize { get; set; }
}
}

@ -1,317 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
namespace Core.api.fileDownload
{
public class FileDownloadHelper
{
private const int DOWNLOAD_BUFFER_SIZE = 102400; //每次下载量 100KB
private const int THREAD_BUFFER_SIZE = 10485760; //每个线程每次最大下载大小 设为10MB 不能太小 否则会创建太多的request对象
public delegate void ErrorMakedEventHandler(string errorstring);
public event ErrorMakedEventHandler ErrorMakedEvent;
public delegate void DownloadEventHandler(FileDownloadEvent e);
public event DownloadEventHandler DownloadEvent;
public delegate void StopEventHandler();
public event StopEventHandler StopEvent;
private object locker = new object();
private long downloadSize = 0; //已经下载的字节
private CancellationTokenSource cancelTokenSource = new CancellationTokenSource();
private ManualResetEvent mre = new ManualResetEvent(true); //初始化不等待
private AutoResetEvent eventFinished = new AutoResetEvent(false);
private void ThreadWork(string url, FileStream fs, Queue<ThreadDownloadInfo> downQueue)
{
mre.WaitOne();
if (cancelTokenSource.IsCancellationRequested)
{
return;
}
Monitor.Enter(downQueue);
if (downQueue.Count == 0)
{
return;
}
ThreadDownloadInfo downInfo = downQueue.Dequeue();
Monitor.Exit(downQueue);
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.AddRange(downInfo.StartLength); //设置Range值
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Stream ns = response.GetResponseStream();
byte[] nbytes = new byte[DOWNLOAD_BUFFER_SIZE];
int temp = 0;
int nReadSize = 0;
byte[] buffer = new byte[downInfo.Length]; //文件写入缓冲
nReadSize = ns.Read(nbytes, 0, Math.Min(DOWNLOAD_BUFFER_SIZE, downInfo.Length));
while (temp < downInfo.Length)
{
mre.WaitOne();
Buffer.BlockCopy(nbytes, 0, buffer, temp, nReadSize);
lock (locker)
{
downloadSize += nReadSize;
}
temp += nReadSize;
nReadSize = ns.Read(nbytes, 0, Math.Min(DOWNLOAD_BUFFER_SIZE, downInfo.Length - temp));
}
lock (locker)
{
fs.Seek(downInfo.StartLength, SeekOrigin.Begin);
fs.Write(buffer, 0, buffer.Length);
}
ns.Close();
ThreadWork(url, fs, downQueue);
}
public async void StartDownload(FileDownloadInfo info)
{
if (string.IsNullOrEmpty(info.DownLoadUrl))
{ throw new Exception("下载地址不能为空!"); }
if (!info.DownLoadUrl.ToLower().StartsWith("http://") || !info.DownLoadUrl.ToLower().StartsWith("https://"))
{ throw new Exception("非法的下载地址!"); }
downloadSize = 0;
await Task.Run(() =>
{
try
{
long totalSize = 0;
long threadInitedLength = 0; //分配线程任务的下载量
#region 获取文件信息
//打开网络连接
HttpWebRequest initRequest = (HttpWebRequest)WebRequest.Create(info.DownLoadUrl);
WebResponse initResponse = initRequest.GetResponse();
FileInfo fileMsg = FileInfo.GetFileMessage(initResponse);
totalSize = fileMsg.Length;
if ((!string.IsNullOrEmpty(fileMsg.FileName)) && info.LocalSaveFolder != null)
{
info.SavePath = Path.Combine(info.LocalSaveFolder, fileMsg.FileName);
}
//ReaderWriterLock readWriteLock = new ReaderWriterLock();
#endregion
#region 读取配置文件
string configPath = info.SavePath.Substring(0, info.SavePath.LastIndexOf(".")) + ".cfg";
FileDownloadConfig initInfo = null;
if (File.Exists(configPath) && (info.IsNew == false))
{
initInfo = FileDownloadConfig.ReadConfig(configPath);
downloadSize = (long)initInfo.DownloadSize;
totalSize = (long)initInfo.TotalSize;
}
#endregion
#region 计算速度
//Stopwatch MyStopWatch = new Stopwatch();
long lastDownloadSize = 0; //上次下载量
bool isSendCompleteEvent = false; //是否完成
Timer timer = new Timer(new TimerCallback((o) =>
{
if (!isSendCompleteEvent)
{
FileDownloadEvent e = new FileDownloadEvent();
e.DownloadSize = downloadSize;
e.TotalSize = totalSize;
if (totalSize > 0 && downloadSize == totalSize)
{
e.Speed = 0;
isSendCompleteEvent = true;
eventFinished.Set();
}
else
{
e.Speed = downloadSize - lastDownloadSize;
lastDownloadSize = downloadSize; //更新上次下载量
}
DownloadEvent(e);
}
}), null, 0, 1000);
#endregion
string tempPath = info.SavePath.Substring(0, info.SavePath.LastIndexOf(".")) + ".dat";
#region 多线程下载
//分配下载队列
Queue<ThreadDownloadInfo> downQueue = null;
if (initInfo == null || info.IsNew)
{
downQueue = new Queue<ThreadDownloadInfo>(); //下载信息队列
while (threadInitedLength < totalSize)
{
ThreadDownloadInfo downInfo = new ThreadDownloadInfo();
downInfo.StartLength = threadInitedLength;
downInfo.Length = (int)Math.Min(Math.Min(THREAD_BUFFER_SIZE, totalSize - threadInitedLength), totalSize / info.ThreadCount); //下载量
downQueue.Enqueue(downInfo);
threadInitedLength += downInfo.Length;
}
}
else
{
downQueue = initInfo.DownloadQueue;
}
FileStream fs = new FileStream(tempPath, FileMode.OpenOrCreate);
fs.SetLength(totalSize);
int threads = info.ThreadCount;
for (int i = 0; i < info.ThreadCount; i++)
{
ThreadPool.QueueUserWorkItem((state) =>
{
ThreadWork(info.DownLoadUrl, fs, downQueue);
if (Interlocked.Decrement(ref threads) == 0)
{
(state as AutoResetEvent).Set();
}
}, eventFinished);
}
//等待所有线程完成
eventFinished.WaitOne();
if (fs != null)
{
fs.Close();
}
fs = null;
if (File.Exists(info.SavePath))
{
File.Delete(info.SavePath);
}
if (downloadSize == totalSize)
{
File.Move(tempPath, info.SavePath);
File.Delete(configPath);
}
if (cancelTokenSource.IsCancellationRequested && StopEvent != null)
{
StopEvent();
//保存配置文件
FileDownloadConfig.SaveConfig(configPath, downloadSize, totalSize, downQueue);
}
#endregion
}
catch (Exception ex)
{
ErrorMakedEvent?.Invoke(ex.Message);
}
});
}
public void Stop()
{
cancelTokenSource.Cancel();
}
public void Suspend()
{
mre.Reset();
}
public void Resume()
{
mre.Set();
}
//#region 获取文件信息
//public class FileMessage
//{
// public long Length { get; set; }
// public string FileName { get; set; }
//}
//public FileMessage GetFileMessage(WebResponse response)
//{
// FileMessage info = new FileMessage();
// if (response.Headers["Content-Disposition"] != null)
// {
// Match match = Regex.Match(response.Headers["Content-Disposition"], "filename=(.*)");
// if (match.Success)
// {
// string fileName = match.Groups[1].Value;
// Encoding encoding = Encoding.UTF8;
// string str = (response as HttpWebResponse).CharacterSet;
// if (!string.IsNullOrEmpty(str))
// {
// encoding = Encoding.GetEncoding(str);
// }
// info.FileName = System.Web.HttpUtility.UrlDecode(fileName, encoding);
// }
// }
// if (response.Headers["Content-Length"] != null)
// {
// info.Length = long.Parse(response.Headers.Get("Content-Length"));
// }
// else
// {
// info.Length = response.ContentLength;
// }
// return info;
//}
//#endregion
//private void SaveConfig(string configPath, long downloadSize, long totalSize, Queue downQueue)
//{
// stringBuilder sb = new stringBuilder();
// sb.Append(downloadSize + ";" + totalSize + ";");
// foreach (ThreadDownloadInfo info in downQueue)
// {
// sb.Append("(" + info.startLength + ",");
// sb.Append(info.length + ");");
// }
// byte[] buffer = Encoding.UTF8.GetBytes(sb.Tostring());
// string str = Convert.ToBase64string(buffer);
// File.WriteAllText(configPath, str);
//}
//private List ReadConfig(string configPath)
//{
// List list = new List();
// string str = File.ReadAllText(configPath);
// byte[] buffer = Convert.FromBase64string(str);
// str =Encoding.UTF8.Getstring(buffer);
// lock (locker)
// {
// string[] split = str.Split(';');
// long downloadSize = Convert.ToInt64(split[0]);
// long totalSize = Convert.ToInt64(split[1]);
// Queue downQueue = new Queue(); //下载信息队列
// foreach (Match match in Regex.Matches(str, "\\((\\d+),(\\d+)\\);"))
// {
// ThreadDownloadInfo downInfo = new ThreadDownloadInfo();
// downInfo.startLength = Convert.ToInt64(match.Groups[1].Value);
// downInfo.length = Convert.ToInt32(match.Groups[2].Value);
// downQueue.Enqueue(downInfo);
// }
// list.Add(downloadSize);
// list.Add(totalSize);
// list.Add(downQueue);
// }
// return list;
//}
}
}

@ -1,77 +0,0 @@
using System;
using System.IO;
namespace Core.api.fileDownload
{
public class FileDownloadInfo
{
// 下载地址
public string DownLoadUrl { get; set; }
private string _localSaveFolder;
// 本地保存路径
public string LocalSaveFolder
{
get { return _localSaveFolder; }
set
{ _localSaveFolder = value; }
}
// 包含文件名的完整保存路径
private string _savePath;
public string SavePath
{
get
{
if (_savePath == null)
{
if (_localSaveFolder == null)
{
throw new Exception("本地保存路径不能为空");
}
_savePath = Path.Combine(_localSaveFolder, Path.GetFileName(DownLoadUrl));
if (File.Exists(_savePath))
{
if (IsNew)
{
if (IsOver)
{
File.Delete(_savePath);
}
else
{
_savePath = _savePath.Substring(0, _savePath.LastIndexOf(".")) + "(2)" + _savePath.Substring(_savePath.LastIndexOf("."));
}
}
}
}
return _savePath;
}
set
{
_savePath = value;
}
}
private int _threadCount = 1;
////// 线程数
public int ThreadCount
{
get { return _threadCount; }
set { _threadCount = value; }
}
////// 是否覆盖已存在的文件
public bool IsOver { get; set; }
////// 是否重新下载
public bool IsNew { get; set; }
}
}

@ -1,43 +0,0 @@
using System.Net;
using System.Text.RegularExpressions;
namespace Core.api.fileDownload
{
internal class FileInfo
{
public long Length { get; set; }
public string FileName { get; set; }
/// <summary>
/// 获取远程文件的信息
/// </summary>
/// <param name="response"></param>
/// <returns></returns>
public static FileInfo GetFileMessage(WebResponse response)
{
FileInfo info = new FileInfo();
if (response.Headers["Content-Disposition"] != null)
{
Match match = Regex.Match(response.Headers["Content-Disposition"], "filename=(.*)");
if (match.Success)
{
string fileName = match.Groups[1].Value;
info.FileName = WebUtility.UrlDecode(fileName);
}
}
if (response.Headers["Content-Length"] != null)
{
info.Length = long.Parse(response.Headers.Get("Content-Length"));
}
else
{
info.Length = response.ContentLength;
}
return info;
}
}
}

@ -1,11 +0,0 @@
namespace Core.api.fileDownload
{
internal class ThreadDownloadInfo
{
// 开始位置
public long StartLength { get; set; }
// 下载量
public int Length { get; set; }
}
}

@ -1,90 +0,0 @@
using Core.entity2.history;
using Newtonsoft.Json;
using System;
namespace Core.api.history
{
/// <summary>
/// 历史记录
/// </summary>
public class History
{
private static History instance;
/// <summary>
/// 获取UserInfo实例
/// </summary>
/// <returns></returns>
public static History GetInstance()
{
if (instance == null)
{
instance = new History();
}
return instance;
}
/// <summary>
/// History()方法,必须使用单例模式
/// </summary>
private 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 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 = Utils.RequestWeb(url, referer);
try
{
var history = JsonConvert.DeserializeObject<HistoryOrigin>(response);
if (history == null || history.Data == null) { return null; }
return history.Data;
}
catch (Exception e)
{
Console.WriteLine("GetHistory()发生异常: {0}", e);
return null;
}
}
}
public enum HistoryBusiness
{
ARCHIVE = 1, // 稿件
PGC, // 番剧(影视)
LIVE, // 直播
ARTICLE_LIST, // 文集
ARTICLE, // 文章
}
}

@ -1,58 +0,0 @@
using Core.entity2.history;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
namespace Core.api.history
{
/// <summary>
/// 获取稍后再看列表
/// </summary>
public class ToView
{
private static ToView instance;
/// <summary>
/// 获取ToView实例
/// </summary>
/// <returns></returns>
public static ToView GetInstance()
{
if (instance == null)
{
instance = new ToView();
}
return instance;
}
/// <summary>
/// 隐藏ToView()方法,必须使用单例模式
/// </summary>
private ToView() { }
/// <summary>
/// 获取稍后再看视频列表
/// </summary>
/// <returns></returns>
public List<ToViewDataList> GetHistoryToView()
{
string url = "https://api.bilibili.com/x/v2/history/toview/web";
string referer = "https://www.bilibili.com";
string response = Utils.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)
{
Console.WriteLine("GetHistoryToView()发生异常: {0}", e);
return null;
}
}
}
}

@ -1,231 +0,0 @@
using Core.settings;
using System;
using System.Drawing;
using System.IO;
using System.Net;
using System.Windows.Media.Imaging;
namespace Core.api.login
{
public class LoginHelper
{
private static LoginHelper instance;
/// <summary>
/// 获取LoginHelper实例
/// </summary>
/// <returns></returns>
public static LoginHelper GetInstance()
{
if (instance == null)
{
instance = new LoginHelper();
}
return instance;
}
/// <summary>
/// 隐藏LoginHelper()方法,必须使用单例模式
/// </summary>
private LoginHelper() { }
private static readonly string LOCAL_LOGIN_INFO = Common.ConfigPath + "Login";
private static readonly string SecretKey = "Ps*rB$TGaM#&JvOe"; // 16位密码ps:密码位数没有限制,可任意设置
/// <summary>
/// 获得登录二维码
/// </summary>
/// <returns></returns>
public BitmapImage GetLoginQRCode()
{
try
{
string loginUrl = Login.GetInstance().GetLoginUrl().Data.Url;
return GetLoginQRCode(loginUrl);
}
catch (Exception e)
{
Console.WriteLine("GetLoginQRCode()发生异常: {0}", e);
return null;
}
}
/// <summary>
/// 根据输入url生成二维码
/// </summary>
/// <param name="url"></param>
/// <returns></returns>
public BitmapImage GetLoginQRCode(string url)
{
// 设置的参数影响app能否成功扫码
Bitmap qrCode = Utils.EncodeQRCode(url, 10, 10, null, 0, 0, false);
MemoryStream ms = new MemoryStream();
qrCode.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp);
byte[] bytes = ms.GetBuffer();
ms.Close();
BitmapImage image = new BitmapImage();
image.BeginInit();
image.StreamSource = new MemoryStream(bytes);
image.EndInit();
return image;
}
/// <summary>
/// 保存登录的cookies到文件
/// </summary>
/// <param name="url"></param>
/// <returns></returns>
public bool SaveLoginInfoCookies(string url)
{
if (!Directory.Exists(Common.ConfigPath))
{
Directory.CreateDirectory(Common.ConfigPath);
}
string tempFile = LOCAL_LOGIN_INFO + "-" + Guid.NewGuid().ToString("N");
CookieContainer cookieContainer = Utils.ParseCookie(url);
bool isSucceed = Utils.WriteCookiesToDisk(tempFile, cookieContainer);
if (isSucceed)
{
// 加密密钥,增加机器码
string password = SecretKey + MachineCode.GetMachineCodeString();
try
{
Encryptor.EncryptFile(tempFile, LOCAL_LOGIN_INFO, password);
}
catch (Exception e)
{
Console.WriteLine("SaveLoginInfoCookies()发生异常: {0}", e);
return false;
}
}
if (File.Exists(tempFile))
{
File.Delete(tempFile);
}
return isSucceed;
}
/// <summary>
/// 获得登录的cookies
/// </summary>
/// <returns></returns>
public CookieContainer GetLoginInfoCookies()
{
string tempFile = LOCAL_LOGIN_INFO + "-" + Guid.NewGuid().ToString("N");
if (File.Exists(LOCAL_LOGIN_INFO))
{
try
{
// 加密密钥,增加机器码
string password = SecretKey + MachineCode.GetMachineCodeString();
Encryptor.DecryptFile(LOCAL_LOGIN_INFO, tempFile, password);
}
catch (CryptoHelpException e)
{
Console.WriteLine("GetLoginInfoCookies()发生异常: {0}", e);
if (File.Exists(tempFile))
{
File.Delete(tempFile);
}
return null;
}
catch (FileNotFoundException e)
{
Console.WriteLine("GetLoginInfoCookies()发生异常: {0}", e);
if (File.Exists(tempFile))
{
File.Delete(tempFile);
}
return null;
}
catch (DirectoryNotFoundException e)
{
Console.WriteLine("GetLoginInfoCookies()发生异常: {0}", e);
if (File.Exists(tempFile))
{
File.Delete(tempFile);
}
return null;
}
catch (Exception e)
{
Console.WriteLine("GetLoginInfoCookies()发生异常: {0}", e);
if (File.Exists(tempFile))
{
File.Delete(tempFile);
}
return null;
}
}
else { return null; }
CookieContainer cookies = Utils.ReadCookiesFromDisk(tempFile);
if (File.Exists(tempFile))
{
File.Delete(tempFile);
}
return cookies;
}
/// <summary>
/// 返回登录信息的cookies的字符串
/// </summary>
/// <returns></returns>
public string GetLoginInfoCookiesString()
{
var cookieContainer = GetLoginInfoCookies();
if (cookieContainer == null)
{
return "";
}
var cookies = Utils.GetAllCookies(cookieContainer);
string cookie = string.Empty;
foreach (var item in cookies)
{
cookie += item.ToString() + ";";
}
return cookie.TrimEnd(';');
}
/// <summary>
/// 注销登录
/// </summary>
/// <returns></returns>
public bool Logout()
{
if (File.Exists(LOCAL_LOGIN_INFO))
{
try
{
File.Delete(LOCAL_LOGIN_INFO);
Settings.GetInstance().SetUserInfo(new UserInfoForSetting
{
Mid = -1,
Name = "",
IsLogin = false,
IsVip = false
});
return true;
}
catch (IOException e)
{
Console.WriteLine("Logout()发生异常: {0}", e);
return false;
}
}
return false;
}
}
}

@ -1,81 +0,0 @@
using Core.entity2.users;
using Newtonsoft.Json;
using System;
namespace Core.api.users
{
/// <summary>
/// 用户基本信息
/// </summary>
public class UserInfo
{
private static UserInfo instance;
/// <summary>
/// 获取UserInfo实例
/// </summary>
/// <returns></returns>
public static UserInfo GetInstance()
{
if (instance == null)
{
instance = new UserInfo();
}
return instance;
}
/// <summary>
/// 隐藏UserInfo()方法,必须使用单例模式
/// </summary>
private UserInfo() { }
/// <summary>
/// 用户详细信息1 (用于空间)
/// </summary>
/// <param name="mid">目标用户UID</param>
/// <returns></returns>
public SpaceInfo GetInfoForSpace(long mid)
{
string url = $"https://api.bilibili.com/x/space/acc/info?mid={mid}";
string referer = "https://www.bilibili.com";
string response = Utils.RequestWeb(url, referer);
try
{
var spaceInfo = JsonConvert.DeserializeObject<SpaceInfoOrigin>(response);
if (spaceInfo == null || spaceInfo.Data == null) { return null; }
return spaceInfo.Data;
}
catch (Exception e)
{
Console.WriteLine("GetInfoForSpace()发生异常: {0}", e);
return null;
}
}
/// <summary>
/// 本用户详细信息
/// </summary>
/// <returns></returns>
public MyInfo GetMyInfo()
{
string url = "https://api.bilibili.com/x/space/myinfo";
string referer = "https://www.bilibili.com";
string response = Utils.RequestWeb(url, referer);
try
{
var myInfo = JsonConvert.DeserializeObject<MyInfoOrigin>(response);
if (myInfo == null || myInfo.Data == null) { return null; }
return myInfo.Data;
}
catch (Exception e)
{
Console.WriteLine("GetMyInfo()发生异常: {0}", e);
return null;
}
}
}
}

@ -1,290 +0,0 @@
using Core.entity2.users;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
namespace Core.api.users
{
/// <summary>
/// 用户关系相关
/// </summary>
public class UserRelation
{
private static UserRelation instance;
/// <summary>
/// 获取UserRelation实例
/// </summary>
/// <returns></returns>
public static UserRelation GetInstance()
{
if (instance == null)
{
instance = new UserRelation();
}
return instance;
}
/// <summary>
/// 隐藏UserRelation()方法,必须使用单例模式
/// </summary>
private UserRelation() { }
/// <summary>
/// 查询用户粉丝明细
/// </summary>
/// <param name="mid">目标用户UID</param>
/// <param name="pn">页码</param>
/// <param name="ps">每页项数</param>
/// <returns></returns>
public RelationFollow GetFollowers(long mid, int pn, int ps)
{
string url = $"https://api.bilibili.com/x/relation/followers?vmid={mid}&pn={pn}&ps={ps}";
string referer = "https://www.bilibili.com";
string response = Utils.RequestWeb(url, referer);
try
{
var relationFollower = JsonConvert.DeserializeObject<RelationFollowOrigin>(response);
if (relationFollower == null || relationFollower.Data == null) { return null; }
return relationFollower.Data;
}
catch (Exception e)
{
Console.WriteLine("GetFollowers()发生异常: {0}", e);
return null;
}
}
/// <summary>
/// 查询用户所有的粉丝明细
/// </summary>
/// <param name="mid">目标用户UID</param>
/// <returns></returns>
public List<RelationFollowInfo> GetAllFollowers(long mid)
{
List<RelationFollowInfo> result = new List<RelationFollowInfo>();
int i = 0;
while (true)
{
i++;
int ps = 50;
var data = GetFollowers(mid, i, ps);
//if (data == null) { continue; }
if (data == null || data.List == null || data.List.Count == 0)
{ break; }
result.AddRange(data.List);
}
return result;
}
/// <summary>
/// 查询用户关注明细
/// </summary>
/// <param name="mid">目标用户UID</param>
/// <param name="pn">页码</param>
/// <param name="ps">每页项数</param>
/// <param name="order">排序方式</param>
/// <returns></returns>
public RelationFollow GetFollowings(long mid, int pn, int ps, FollowingOrder order = FollowingOrder.DEFAULT)
{
string orderType = "";
if (order == FollowingOrder.ATTENTION)
{
orderType = "attention";
}
string url = $"https://api.bilibili.com/x/relation/followings?vmid={mid}&pn={pn}&ps={ps}&order_type={orderType}";
string referer = "https://www.bilibili.com";
string response = Utils.RequestWeb(url, referer);
try
{
var relationFollower = JsonConvert.DeserializeObject<RelationFollowOrigin>(response);
if (relationFollower == null || relationFollower.Data == null) { return null; }
return relationFollower.Data;
}
catch (Exception e)
{
Console.WriteLine("GetFollowings()发生异常: {0}", e);
return null;
}
}
/// <summary>
/// 查询用户所有的关注明细
/// </summary>
/// <param name="mid">目标用户UID</param>
/// <param name="order">排序方式</param>
/// <returns></returns>
public List<RelationFollowInfo> GetAllFollowings(long mid, FollowingOrder order = FollowingOrder.DEFAULT)
{
List<RelationFollowInfo> result = new List<RelationFollowInfo>();
int i = 0;
while (true)
{
i++;
int ps = 50;
var data = GetFollowings(mid, i, ps, order);
//if (data == null) { continue; }
if (data == null || data.List == null || data.List.Count == 0)
{ break; }
result.AddRange(data.List);
}
return result;
}
/// <summary>
/// 查询悄悄关注明细
/// </summary>
/// <param name="pn">页码</param>
/// <param name="ps">每页项数</param>
/// <returns></returns>
public List<RelationWhisper> GetWhispers(int pn, int ps)
{
string url = $"https://api.bilibili.com/x/relation/whispers?pn={pn}&ps={ps}";
string referer = "https://www.bilibili.com";
string response = Utils.RequestWeb(url, referer);
try
{
var relationWhisper = JsonConvert.DeserializeObject<RelationWhisperOrigin>(response);
if (relationWhisper == null || relationWhisper.Data == null) { return null; }
return relationWhisper.Data;
}
catch (Exception e)
{
Console.WriteLine("GetWhispers()发生异常: {0}", e);
return null;
}
}
/// <summary>
/// 查询黑名单明细
/// </summary>
/// <param name="pn">页码</param>
/// <param name="ps">每页项数</param>
/// <returns></returns>
public List<RelationBlack> GetBlacks(int pn, int ps)
{
string url = $"https://api.bilibili.com/x/relation/blacks?pn={pn}&ps={ps}";
string referer = "https://www.bilibili.com";
string response = Utils.RequestWeb(url, referer);
try
{
var relationBlack = JsonConvert.DeserializeObject<RelationBlackOrigin>(response);
if (relationBlack == null || relationBlack.Data == null) { return null; }
return relationBlack.Data;
}
catch (Exception e)
{
Console.WriteLine("GetBlacks()发生异常: {0}", e);
return null;
}
}
// 关注分组相关,只能查询当前登录账户的信息
/// <summary>
/// 查询关注分组列表
/// </summary>
/// <returns></returns>
public List<FollowingGroup> GetFollowingGroup()
{
string url = $"https://api.bilibili.com/x/relation/tags";
string referer = "https://www.bilibili.com";
string response = Utils.RequestWeb(url, referer);
try
{
var followingGroup = JsonConvert.DeserializeObject<FollowingGroupOrigin>(response);
if (followingGroup == null || followingGroup.Data == null) { return null; }
return followingGroup.Data;
}
catch (Exception e)
{
Console.WriteLine("GetFollowingGroup()发生异常: {0}", e);
return null;
}
}
/// <summary>
/// 查询关注分组明细
/// </summary>
/// <param name="tagId">分组ID</param>
/// <param name="pn">页数</param>
/// <param name="ps">每页项数</param>
/// <param name="order">排序方式</param>
/// <returns></returns>
public List<FollowingGroupContent> GetFollowingGroupContent(int tagId, int pn, int ps, FollowingOrder order = FollowingOrder.DEFAULT)
{
string orderType = "";
if (order == FollowingOrder.ATTENTION)
{
orderType = "attention";
}
string url = $"https://api.bilibili.com/x/relation/tag?tagid={tagId}&pn={pn}&ps={ps}&order_type={orderType}";
string referer = "https://www.bilibili.com";
string response = Utils.RequestWeb(url, referer);
try
{
var content = JsonConvert.DeserializeObject<FollowingGroupContentOrigin>(response);
if (content == null || content.Data == null) { return null; }
return content.Data;
}
catch (Exception e)
{
Console.WriteLine("GetFollowingGroupContent()发生异常: {0}", e);
return null;
}
}
/// <summary>
/// 查询所有的关注分组明细
/// </summary>
/// <param name="tagId">分组ID</param>
/// <param name="order">排序方式</param>
/// <returns></returns>
public List<FollowingGroupContent> GetAllFollowingGroupContent(int tagId, FollowingOrder order = FollowingOrder.DEFAULT)
{
List<FollowingGroupContent> result = new List<FollowingGroupContent>();
int i = 0;
while (true)
{
i++;
int ps = 50;
var data = GetFollowingGroupContent(tagId, i, ps, order);
if (data == null || data.Count == 0)
{ break; }
result.AddRange(data);
}
return result;
}
}
public enum FollowingOrder
{
DEFAULT = 1, // 按照关注顺序排列,默认
ATTENTION // 按照最常访问排列
}
}

@ -1,520 +0,0 @@
using Core.entity2.users;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Core.api.users
{
/// <summary>
/// 用户空间信息
/// </summary>
public class UserSpace
{
private static UserSpace instance;
/// <summary>
/// 获取UserSpace实例
/// </summary>
/// <returns></returns>
public static UserSpace GetInstance()
{
if (instance == null)
{
instance = new UserSpace();
}
return instance;
}
/// <summary>
/// 隐藏UserSpace()方法,必须使用单例模式
/// </summary>
private UserSpace() { }
/// <summary>
/// 查询空间设置
/// </summary>
/// <param name="mid"></param>
/// <returns></returns>
public SpaceSettings GetSpaceSettings(long mid)
{
string url = $"https://space.bilibili.com/ajax/settings/getSettings?mid={mid}";
string referer = "https://www.bilibili.com";
string response = Utils.RequestWeb(url, referer);
try
{
var settings = JsonConvert.DeserializeObject<SpaceSettingsOrigin>(response);
if (settings == null || settings.Data == null || !settings.Status) { return null; }
return settings.Data;
}
catch (Exception e)
{
Console.WriteLine("GetSpaceSettings()发生异常: {0}", e);
return null;
}
}
/// <summary>
/// 获取用户投稿视频的所有分区
/// </summary>
/// <param name="mid">用户id</param>
/// <returns></returns>
public List<SpacePublicationListTypeVideoZone> GetPublicationType(long mid)
{
int pn = 1;
int ps = 1;
var publication = GetPublication(mid, pn, ps);
return GetPublicationType(publication);
}
/// <summary>
/// 获取用户投稿视频的所有分区
/// </summary>
/// <param name="mid">用户id</param>
/// <returns></returns>
public List<SpacePublicationListTypeVideoZone> GetPublicationType(SpacePublicationList publication)
{
if (publication == null || publication.Tlist == null)
{
return null;
}
List<SpacePublicationListTypeVideoZone> result = new List<SpacePublicationListTypeVideoZone>();
JObject typeList = JObject.Parse(publication.Tlist.ToString("N"));
foreach (var item in typeList)
{
var value = JsonConvert.DeserializeObject<SpacePublicationListTypeVideoZone>(item.Value.ToString());
result.Add(value);
}
return result;
}
/// <summary>
/// 查询用户所有的投稿视频明细
/// </summary>
/// <param name="mid">用户id</param>
/// <param name="order">排序</param>
/// <param name="tid">视频分区</param>
/// <param name="keyword">搜索关键词</param>
/// <returns></returns>
public async Task<List<SpacePublicationListVideo>> GetAllPublication(long mid, int tid = 0, PublicationOrder order = PublicationOrder.PUBDATE, string keyword = "")
{
List<SpacePublicationListVideo> result = new List<SpacePublicationListVideo>();
await Task.Run(() =>
{
int i = 0;
while (true)
{
i++;
int ps = 100;
var data = GetPublication(mid, i, ps, tid, order, keyword);
//if (data == null) { continue; }
if (data == null || data.Vlist == null || data.Vlist.Count == 0)
{ break; }
result.AddRange(data.Vlist);
}
});
return result;
}
/// <summary>
/// 查询用户投稿视频明细
/// </summary>
/// <param name="mid">用户id</param>
/// <param name="pn">页码</param>
/// <param name="ps">每页的视频数</param>
/// <param name="order">排序</param>
/// <param name="tid">视频分区</param>
/// <param name="keyword">搜索关键词</param>
/// <returns></returns>
public SpacePublicationList GetPublication(long mid, int pn, int ps, int tid = 0, PublicationOrder order = PublicationOrder.PUBDATE, string keyword = "")
{
string url = $"https://api.bilibili.com/x/space/arc/search?mid={mid}&pn={pn}&ps={ps}&order={order.ToString("G").ToLower()}&tid={tid}&keyword={keyword}";
string referer = "https://www.bilibili.com";
string response = Utils.RequestWeb(url, referer);
try
{
// 忽略play的值为“--”时的类型错误
var settings = new JsonSerializerSettings
{
Error = (sender, args) =>
{
if (Equals(args.ErrorContext.Member, "play") &&
args.ErrorContext.OriginalObject.GetType() == typeof(SpacePublicationListVideo))
{
args.ErrorContext.Handled = true;
}
}
};
var spacePublication = JsonConvert.DeserializeObject<SpacePublicationOrigin>(response, settings);
if (spacePublication == null || spacePublication.Data == null) { return null; }
return spacePublication.Data.List;
}
catch (Exception e)
{
Console.WriteLine("GetPublication()发生异常: {0}", e);
return null;
}
}
/// <summary>
/// 查询用户频道列表
/// </summary>
/// <param name="mid">用户id</param>
/// <returns></returns>
public List<SpaceChannelList> GetChannelList(long mid)
{
string url = $"https://api.bilibili.com/x/space/channel/list?mid={mid}";
string referer = "https://www.bilibili.com";
string response = Utils.RequestWeb(url, referer);
try
{
var spaceChannel = JsonConvert.DeserializeObject<SpaceChannelOrigin>(response);
if (spaceChannel == null || spaceChannel.Data == null) { return null; }
return spaceChannel.Data.List;
}
catch (Exception e)
{
Console.WriteLine("GetChannelList()发生异常: {0}", e);
return null;
}
}
/// <summary>
/// 查询用户频道中的所有视频
/// </summary>
/// <param name="mid"></param>
/// <param name="cid"></param>
/// <returns></returns>
public List<SpaceChannelVideoArchive> GetAllChannelVideoList(long mid, long cid)
{
List<SpaceChannelVideoArchive> result = new List<SpaceChannelVideoArchive>();
int i = 0;
while (true)
{
i++;
int ps = 100;
var data = GetChannelVideoList(mid, cid, i, ps);
if (data == null || data.Count == 0)
{ break; }
result.AddRange(data);
}
return result;
}
/// <summary>
/// 查询用户频道中的视频
/// </summary>
/// <param name="mid"></param>
/// <param name="cid"></param>
/// <param name="pn"></param>
/// <param name="ps"></param>
/// <returns></returns>
public List<SpaceChannelVideoArchive> GetChannelVideoList(long mid, long cid, int pn, int ps)
{
string url = $"https://api.bilibili.com/x/space/channel/video?mid={mid}&cid={cid}&pn={pn}&ps={ps}";
string referer = "https://www.bilibili.com";
string response = Utils.RequestWeb(url, referer);
try
{
var spaceChannelVideo = JsonConvert.DeserializeObject<SpaceChannelVideoOrigin>(response);
if (spaceChannelVideo == null || spaceChannelVideo.Data == null || spaceChannelVideo.Data.List == null)
{ return null; }
return spaceChannelVideo.Data.List.Archives;
}
catch (Exception e)
{
Console.WriteLine("GetChannelVideoList()发生异常: {0}", e);
return null;
}
}
/// <summary>
/// 查询用户创建的视频收藏夹
/// </summary>
/// <param name="mid">目标用户UID</param>
/// <param name="pn">页码</param>
/// <param name="ps">每页项数</param>
/// <returns></returns>
public List<SpaceFavoriteFolderList> GetCreatedFavoriteFolder(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 = Utils.RequestWeb(url, referer);
try
{
var favoriteFolder = JsonConvert.DeserializeObject<SpaceFavoriteFolderOrigin>(response);
if (favoriteFolder == null || favoriteFolder.Data == null || favoriteFolder.Data.List == null)
{ return null; }
return favoriteFolder.Data.List;
}
catch (Exception e)
{
Console.WriteLine("GetCreatedFavoriteFolder()发生异常: {0}", e);
return null;
}
}
/// <summary>
/// 查询所有的用户创建的视频收藏夹
/// </summary>
/// <param name="mid">目标用户UID</param>
/// <returns></returns>
public List<SpaceFavoriteFolderList> GetAllCreatedFavoriteFolder(long mid)
{
List<SpaceFavoriteFolderList> result = new List<SpaceFavoriteFolderList>();
int i = 0;
while (true)
{
i++;
int ps = 50;
var data = GetCreatedFavoriteFolder(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 List<SpaceFavoriteFolderList> GetCollectedFavoriteFolder(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 = Utils.RequestWeb(url, referer);
try
{
var favoriteFolder = JsonConvert.DeserializeObject<SpaceFavoriteFolderOrigin>(response);
if (favoriteFolder == null || favoriteFolder.Data == null || favoriteFolder.Data.List == null)
{ return null; }
return favoriteFolder.Data.List;
}
catch (Exception e)
{
Console.WriteLine("GetCollectedFavoriteFolder()发生异常: {0}", e);
return null;
}
}
/// <summary>
/// 查询所有的用户收藏的视频收藏夹
/// </summary>
/// <param name="mid">目标用户UID</param>
/// <returns></returns>
public List<SpaceFavoriteFolderList> GetAllCollectedFavoriteFolder(long mid)
{
List<SpaceFavoriteFolderList> result = new List<SpaceFavoriteFolderList>();
int i = 0;
while (true)
{
i++;
int ps = 50;
var data = GetCollectedFavoriteFolder(mid, i, ps);
if (data == null || data.Count == 0)
{ break; }
result.AddRange(data);
}
return result;
}
/// <summary>
/// 查询视频收藏夹的内容
/// </summary>
/// <param name="mediaId">收藏夹ID</param>
/// <param name="pn">页码</param>
/// <param name="ps">每页项数</param>
/// <returns></returns>
public List<SpaceFavoriteFolderMedia> GetFavoriteFolderResource(long mediaId, int pn, int ps)
{
string url = $"https://api.bilibili.com/x/v3/fav/resource/list?media_id={mediaId}&pn={pn}&ps={ps}";
string referer = "https://www.bilibili.com";
string response = Utils.RequestWeb(url, referer);
try
{
var resource = JsonConvert.DeserializeObject<SpaceFavoriteFolderResourceOrigin>(response);
if (resource == null || resource.Data == null || resource.Data.Medias == null)
{ return null; }
return resource.Data.Medias;
}
catch (Exception e)
{
Console.WriteLine("GetFavoriteFolderResource()发生异常: {0}", e);
return null;
}
}
/// <summary>
/// 查询视频收藏夹的所有内容
/// </summary>
/// <param name="mediaId">收藏夹ID</param>
/// <returns></returns>
public List<SpaceFavoriteFolderMedia> GetAllFavoriteFolderResource(long mediaId)
{
List<SpaceFavoriteFolderMedia> result = new List<SpaceFavoriteFolderMedia>();
int i = 0;
while (true)
{
i++;
int ps = 20;
var data = GetFavoriteFolderResource(mediaId, 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 List<SpaceCheese> GetCheese(long mid, int pn, int ps)
{
string url = $"https://api.bilibili.com/pugv/app/web/season/page?mid={mid}&pn={pn}&ps={ps}";
string referer = "https://www.bilibili.com";
string response = Utils.RequestWeb(url, referer);
try
{
var cheese = JsonConvert.DeserializeObject<SpaceCheeseOrigin>(response);
if (cheese == null || cheese.Data == null || cheese.Data.Items == null)
{ return null; }
return cheese.Data.Items;
}
catch (Exception e)
{
Console.WriteLine("GetCheese()发生异常: {0}", e);
return null;
}
}
/// <summary>
/// 查询用户发布的所有课程列表
/// </summary>
/// <param name="mid">目标用户UID</param>
/// <returns></returns>
public List<SpaceCheese> GetAllCheese(long mid)
{
List<SpaceCheese> result = new List<SpaceCheese>();
int i = 0;
while (true)
{
i++;
int ps = 50;
var data = GetCheese(mid, i, ps);
if (data == null || data.Count == 0)
{ break; }
result.AddRange(data);
}
return result;
}
/// <summary>
/// 查询用户追番(追剧)明细
/// </summary>
/// <param name="mid">目标用户UID</param>
/// <param name="type">查询类型</param>
/// <param name="pn">页码</param>
/// <param name="ps">每页项数</param>
/// <returns></returns>
public BangumiFollowData GetBangumiFollow(long mid, BangumiType type, int pn, int ps)
{
string url = $"https://api.bilibili.com/x/space/bangumi/follow/list?vmid={mid}&type={type:D}&pn={pn}&ps={ps}";
string referer = "https://www.bilibili.com";
string response = Utils.RequestWeb(url, referer);
try
{
var bangumiFollow = JsonConvert.DeserializeObject<BangumiFollowOrigin>(response);
if (bangumiFollow == null || bangumiFollow.Data == null)
{ return null; }
return bangumiFollow.Data;
}
catch (Exception e)
{
Console.WriteLine("GetBangumiFollow()发生异常: {0}", e);
return null;
}
}
/// <summary>
/// 查询用户所有的追番(追剧)明细
/// </summary>
/// <param name="mid">目标用户UID</param>
/// <param name="type">查询类型</param>
/// <returns></returns>
public List<BangumiFollow> GetAllBangumiFollow(long mid, BangumiType type)
{
List<BangumiFollow> result = new List<BangumiFollow>();
int i = 0;
while (true)
{
i++;
int ps = 30;
var data = GetBangumiFollow(mid, type, i, ps);
if (data == null || data.List == null || data.List.Count == 0)
{ break; }
result.AddRange(data.List);
}
return result;
}
}
public enum PublicationOrder
{
PUBDATE = 1, // 最新发布,默认
CLICK, // 最多播放
STOW // 最多收藏
}
public enum BangumiType
{
ANIME = 1, // 番剧
EPISODE = 2 // 剧集、电影
}
}

@ -1,83 +0,0 @@
using Core.entity2.users;
using Newtonsoft.Json;
using System;
namespace Core.api.users
{
/// <summary>
/// 用户状态数
/// </summary>
public class UserStatus
{
private static UserStatus instance;
/// <summary>
/// 获取UserStatus实例
/// </summary>
/// <returns></returns>
public static UserStatus GetInstance()
{
if (instance == null)
{
instance = new UserStatus();
}
return instance;
}
/// <summary>
/// 隐藏UserStatus()方法,必须使用单例模式
/// </summary>
private UserStatus() { }
/// <summary>
/// 关系状态数
/// </summary>
/// <param name="mid"></param>
/// <returns></returns>
public UserRelationStat GetUserRelationStat(long mid)
{
string url = $"https://api.bilibili.com/x/relation/stat?vmid={mid}";
string referer = "https://www.bilibili.com";
string response = Utils.RequestWeb(url, referer);
try
{
var userRelationStat = JsonConvert.DeserializeObject<UserRelationStatOrigin>(response);
if (userRelationStat == null || userRelationStat.Data == null) { return null; }
return userRelationStat.Data;
}
catch (Exception e)
{
Console.WriteLine("GetUserRelationStat()发生异常: {0}", e);
return null;
}
}
/// <summary>
/// UP主状态数
///
/// 注:该接口需要任意用户登录,否则不会返回任何数据
/// </summary>
/// <param name="mid"></param>
/// <returns></returns>
public UpStat GetUpStat(long mid)
{
string url = $"https://api.bilibili.com/x/space/upstat?mid={mid}";
string referer = "https://www.bilibili.com";
string response = Utils.RequestWeb(url, referer);
try
{
var upStat = JsonConvert.DeserializeObject<UpStatOrigin>(response);
if (upStat == null || upStat.Data == null) { return null; }
return upStat.Data;
}
catch (Exception e)
{
Console.WriteLine("GetUpStat()发生异常: {0}", e);
return null;
}
}
}
}

@ -1,433 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
// 代码来源
// https://blog.csdn.net/haibin258/article/details/87905628
// Aria2详细信息请看
// https://aria2.github.io/manual/en/html/aria2c.html#rpc-interface
// 废弃
namespace Core.aria2cNet
{
//定义一个类用于转码成JSON字符串发送给Aria2 json-rpc接口
public class JsonClass
{
public string Jsonrpc { get; set; }
public string Id { get; set; }
public string Method { get; set; }
public List<string> Params { get; set; }
}
public class Aria2
{
public static ClientWebSocket webSocket; // 用于连接到Aria2Rpc的客户端
public static CancellationToken cancellationToken; // 传播有关应取消操作的通知
/// <summary>
/// 连接Aria2Rpc服务器
/// </summary>
/// <param name="uri"></param>
/// <returns></returns>
public static async Task<bool> ConnectServer(string uri)
{
webSocket = new ClientWebSocket(); // 用于连接到Aria2Rpc的客户端
cancellationToken = new CancellationToken(); // 传播有关应取消操作的通知
bool status = false; //储存连接状态
try
{
//连接服务器
await webSocket.ConnectAsync(new Uri(uri), cancellationToken);
}
catch
{
status = false;
}
//检查连接是否成功
if (webSocket.State == WebSocketState.Open)
{
status = true;
}
return status;
}
/// <summary>
/// JsonClass类转为json格式
/// </summary>
/// <param name="json"></param>
/// <returns></returns>
private static string ToJson(JsonClass json)
{
string str = "{" + "\"jsonrpc\":\"" + json.Jsonrpc + "\",\"id\":\"" + json.Id + "\",\"method\":\"" + json.Method + "\",\"params\":[";
for (int i = 0; i < json.Params.Count; i++)
{
if (json.Method == "aria2.addUri")
{
str += "[\"" + json.Params[i] + "\"]";
}
else if (json.Method == "aria2.tellStatus")
{
if (i == 0)
{
str += "\"" + json.Params[i] + "\"";
}
else
{
str += "[\"" + json.Params[i] + "\"]";
}
}
else
{
str += "\"" + json.Params[i] + "\"";
}
if (json.Params.Count - 1 > i)
{
str += ",";
}
}
str += "]}";
//最后得到类似
//{"jsonrpc":"2.0","id":"qwer","method":"aria2.addUri","params:"[["http://www.baidu.com"]]}
return str;
}
/// <summary>
/// 发送json并返回json消息
/// </summary>
/// <param name="json"></param>
/// <returns></returns>
private static async Task<string> SendAndReceive(JsonClass json)
{
string str = ToJson(json);
try
{
//发送json数据
await webSocket.SendAsync(new ArraySegment<byte>(Encoding.UTF8.GetBytes(str)), WebSocketMessageType.Text, true, cancellationToken);
var result = new byte[1024];
//接收数据
await webSocket.ReceiveAsync(new ArraySegment<byte>(result), new CancellationToken());
str += "\r\n" + Encoding.UTF8.GetString(result, 0, result.Length) + "\r\n";
}
catch
{
str = "连接错误";
}
return str;
}
/// <summary>
/// 添加新的下载
/// </summary>
/// <param name="uri"></param>
/// <returns></returns>
public static async Task<string> AddUri(string uri)
{
var json = new JsonClass
{
Jsonrpc = "2.0",
Id = "qwer",
Method = "aria2.addUri"
};
List<string> paramslist = new List<string>();
//添加下载地址
paramslist.Add(uri);
json.Params = paramslist;
string str = await SendAndReceive(json);
return str;
}
/// <summary>
/// 上传“.torrent”文件添加BitTorrent下载
/// </summary>
/// <param name="file"></param>
/// <returns></returns>
public static async Task<string> AddTorrent(string path)
{
string str = "";
string fsbase64 = "";
byte[] fs = File.ReadAllBytes(path);
fsbase64 = Convert.ToBase64String(fs); //转为Base64编码
var json = new JsonClass();
json.Jsonrpc = "2.0";
json.Id = "qwer";
json.Method = "aria2.addTorrent";
List<string> paramslist = new List<string>();
//添加“.torrent”文件本地地址
paramslist.Add(fsbase64);
json.Params = paramslist;
str = await SendAndReceive(json);
return str;
}
/// <summary>
/// 删除已经停止的任务强制删除请使用ForceRemove方法
/// </summary>
/// <param name="gid"></param>
/// <returns></returns>
public static async Task<string> Remove(string gid)
{
string str = "";
var json = new JsonClass
{
Jsonrpc = "2.0",
Id = "qwer",
Method = "aria2.remove"
};
List<string> paramslist = new List<string>();
//添加下载地址
paramslist.Add(gid);
json.Params = paramslist;
str = await SendAndReceive(json);
return str;
}
/// <summary>
/// 强制删除
/// </summary>
/// <param name="gid"></param>
/// <returns></returns>
public static async Task<string> ForceRemove(string gid)
{
string str = "";
var json = new JsonClass
{
Jsonrpc = "2.0",
Id = "qwer",
Method = "aria2.forceRemove"
};
List<string> paramslist = new List<string>();
//添加下载地址
paramslist.Add(gid);
json.Params = paramslist;
str = await SendAndReceive(json);
return str;
}
/// <summary>
/// 暂停下载,强制暂停请使用ForcePause方法
/// </summary>
/// <param name="gid"></param>
/// <returns></returns>
public static async Task<string> Pause(string gid)
{
string str = "";
var json = new JsonClass
{
Jsonrpc = "2.0",
Id = "qwer",
Method = "aria2.pause"
};
List<string> paramslist = new List<string>();
//添加下载地址
paramslist.Add(gid);
json.Params = paramslist;
str = await SendAndReceive(json);
return str;
}
/// <summary>
/// 暂停全部任务
/// </summary>
/// <param name="gid"></param>
/// <returns></returns>
public static async Task<string> PauseAll()
{
string str = "";
var json = new JsonClass();
json.Jsonrpc = "2.0";
json.Id = "qwer";
json.Method = "aria2.pauseAll";
List<string> paramslist = new List<string>();
//添加下载地址
paramslist.Add("");
json.Params = paramslist;
str = await Aria2.SendAndReceive(json);
return str;
}
/// <summary>
/// 强制暂停下载
/// </summary>
/// <param name="gid"></param>
/// <returns></returns>
public static async Task<string> ForcePause(string gid)
{
string str = "";
var json = new JsonClass();
json.Jsonrpc = "2.0";
json.Id = "qwer";
json.Method = "aria2.forcePause";
List<string> paramslist = new List<string>();
//添加下载地址
paramslist.Add(gid);
json.Params = paramslist;
str = await Aria2.SendAndReceive(json);
return str;
}
/// <summary>
/// 强制暂停全部下载
/// </summary>
/// <param name="gid"></param>
/// <returns></returns>
public static async Task<string> ForcePauseAll()
{
string str = "";
var json = new JsonClass();
json.Jsonrpc = "2.0";
json.Id = "qwer";
json.Method = "aria2.forcePauseAll";
List<string> paramslist = new List<string>();
//添加下载地址
paramslist.Add("");
json.Params = paramslist;
str = await Aria2.SendAndReceive(json);
return str;
}
/// <summary>
/// 把正在下载的任务状态改为等待下载
/// </summary>
/// <param name="gid"></param>
/// <returns></returns>
public static async Task<string> PauseToWaiting(string gid)
{
string str = "";
var json = new JsonClass();
json.Jsonrpc = "2.0";
json.Id = "qwer";
json.Method = "aria2.unpause";
List<string> paramslist = new List<string>();
//添加下载地址
paramslist.Add(gid);
json.Params = paramslist;
str = await Aria2.SendAndReceive(json);
return str;
}
/// <summary>
/// 把全部在下载的任务状态改为等待下载
/// </summary>
/// <param name="gid"></param>
/// <returns></returns>
public static async Task<string> PauseToWaitingAll()
{
string str = "";
var json = new JsonClass();
json.Jsonrpc = "2.0";
json.Id = "qwer";
json.Method = "aria2.unpauseAll";
List<string> paramslist = new List<string>();
//添加下载地址
paramslist.Add("");
json.Params = paramslist;
str = await Aria2.SendAndReceive(json);
return str;
}
/// <summary>
/// 返回下载进度
/// </summary>
/// <param name="gid"></param>
/// <returns></returns>
public static async Task<string> TellStatus(string gid)
{
string str = "";
var json = new JsonClass();
json.Jsonrpc = "2.0";
json.Id = "qwer";
json.Method = "aria2.tellStatus";
List<string> paramslist = new List<string>();
//添加下载地址
paramslist.Add(gid);
paramslist.Add("completedLength\", \"totalLength\",\"downloadSpeed");
json.Params = paramslist;
str = await Aria2.SendAndReceive(json);
return str;
}
/// <summary>
/// 返回全局统计信息,例如整体下载和上载速度
/// </summary>
/// <param name="gid"></param>
/// <returns></returns>
public static async Task<string> GetGlobalStat(string gid)
{
string str = "";
var json = new JsonClass();
json.Jsonrpc = "2.0";
json.Id = "qwer";
json.Method = "aria2.getGlobalStat";
List<string> paramslist = new List<string>();
//添加下载地址
paramslist.Add(gid);
json.Params = paramslist;
str = await Aria2.SendAndReceive(json);
return str;
}
/// <summary>
/// 返回由gid字符串表示的下载中使用的URI 。响应是一个结构数组
/// </summary>
/// <param name="gid"></param>
/// <returns></returns>
public static async Task<string> GetUris(string gid)
{
string str = "";
var json = new JsonClass();
json.Jsonrpc = "2.0";
json.Id = "qwer";
json.Method = "aria2.getUris";
List<string> paramslist = new List<string>();
//添加下载地址
paramslist.Add(gid);
json.Params = paramslist;
str = await Aria2.SendAndReceive(json);
return str;
}
/// <summary>
/// 返回由gid字符串表示的下载文件列表
/// </summary>
/// <param name="gid"></param>
/// <returns></returns>
public static async Task<string> GetFiles(string gid)
{
string str = "";
var json = new JsonClass();
json.Jsonrpc = "2.0";
json.Id = "qwer";
json.Method = "aria2.getFiles";
List<string> paramslist = new List<string>();
//添加下载地址
paramslist.Add(gid);
json.Params = paramslist;
str = await Aria2.SendAndReceive(json);
return str;
}
}
}

@ -1,111 +0,0 @@
using Core.aria2cNet.client.entity;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Core.aria2cNet.client
{
public class AriaClientWebSocket
{
private static readonly string JSONRPC = "2.0";
private static readonly string TOKEN = "downkyi";
public static ClientWebSocket webSocket; // 用于连接到Aria2Rpc的客户端
public static CancellationToken cancellationToken; // 传播有关应取消操作的通知
public static bool Status; // 储存连接状态
/// <summary>
/// 连接Aria2Rpc服务器
/// </summary>
/// <param name="uri"></param>
/// <returns></returns>
public static async Task<bool> ConnectServerAsync(string uri)
{
webSocket = new ClientWebSocket(); // 用于连接到Aria2Rpc的客户端
cancellationToken = new CancellationToken(); // 传播有关应取消操作的通知
Status = false; // 储存连接状态
try
{
//连接服务器
await webSocket.ConnectAsync(new Uri(uri), cancellationToken);
}
catch
{
Status = false;
}
//检查连接是否成功
if (webSocket.State == WebSocketState.Open)
{
Status = true;
}
return Status;
}
/// <summary>
/// add
/// </summary>
/// <param name="uris"></param>
/// <returns></returns>
public static async Task<string> AddUriAsync(List<string> uris)
{
AriaSendOption option = new AriaSendOption
{
Out = "index测试.html",
Dir = "home/"
};
List<object> ariaParams = new List<object>
{
"token:" + TOKEN,
uris,
option
};
AriaSendData ariaSend = new AriaSendData
{
Id = Guid.NewGuid().ToString("N"),
Jsonrpc = JSONRPC,
Method = "aria2.addUri",
Params = ariaParams
};
string sendJson = JsonConvert.SerializeObject(ariaSend);
string result = await SendAndReceiveAsync(sendJson);
return result;
}
/// <summary>
/// 发送并接受数据
/// </summary>
/// <param name="sendJson"></param>
/// <returns></returns>
private static async Task<string> SendAndReceiveAsync(string sendJson)
{
string result;
try
{
//发送json数据
await webSocket.SendAsync(new ArraySegment<byte>(Encoding.UTF8.GetBytes(sendJson)), WebSocketMessageType.Text, true, cancellationToken);
byte[] receive = new byte[1024];
//接收数据
await webSocket.ReceiveAsync(new ArraySegment<byte>(receive), new CancellationToken());
result = Encoding.UTF8.GetString(receive).TrimEnd('\0');
}
catch
{
result = "{\"id\":null,\"jsonrpc\":\"2.0\",\"error\":{\"code\":-2020,\"message\":\"连接错误\"}}";
}
return result;
}
}
}

@ -1,163 +0,0 @@
using Core.api.danmaku;
using System.Collections.Generic;
namespace Core.danmaku2ass
{
public class Bilibili
{
private static Bilibili instance;
private Dictionary<string, bool> config = new Dictionary<string, bool>
{
{ "top_filter", false },
{ "bottom_filter", false },
{ "scroll_filter", false }
};
private readonly Dictionary<int, string> mapping = new Dictionary<int, string>
{
{ 1, "scroll" },
{ 2, "scroll" },
{ 3, "scroll" },
{ 4, "bottom" },
{ 5, "top" },
{ 6, "scroll" }, // 逆向滚动弹幕,还是当滚动处理
{ 7, "none" }, // 高级弹幕,暂时不要考虑
{ 8, "none" }, // 代码弹幕,暂时不要考虑
{ 9, "none" } // BAS弹幕暂时不要考虑
};
// 弹幕标准字体大小
private readonly int normalFontSize = 25;
/// <summary>
/// 获取Bilibili实例
/// </summary>
/// <returns></returns>
public static Bilibili GetInstance()
{
if (instance == null)
{
instance = new Bilibili();
}
return instance;
}
/// <summary>
/// 隐藏Bilibili()方法,必须使用单例模式
/// </summary>
private Bilibili() { }
/// <summary>
/// 是否屏蔽顶部弹幕
/// </summary>
/// <param name="isFilter"></param>
/// <returns></returns>
public Bilibili SetTopFilter(bool isFilter)
{
config["top_filter"] = isFilter;
return this;
}
/// <summary>
/// 是否屏蔽底部弹幕
/// </summary>
/// <param name="isFilter"></param>
/// <returns></returns>
public Bilibili SetBottomFilter(bool isFilter)
{
config["bottom_filter"] = isFilter;
return this;
}
/// <summary>
/// 是否屏蔽滚动弹幕
/// </summary>
/// <param name="isFilter"></param>
/// <returns></returns>
public Bilibili SetScrollFilter(bool isFilter)
{
config["scroll_filter"] = isFilter;
return this;
}
public void Create(long avid, long cid, Config subtitleConfig, string assFile)
{
// 弹幕转换
var biliDanmakus = DanmakuProtobuf.GetInstance().GetAllDanmakuProto(avid, cid);
// 按弹幕出现顺序排序
biliDanmakus.Sort((x, y) => { return x.Progress.CompareTo(y.Progress); });
var danmakus = new List<Danmaku>();
foreach (var biliDanmaku in biliDanmakus)
{
var danmaku = new Danmaku
{
// biliDanmaku.Progress单位是毫秒所以除以1000单位变为秒
Start = biliDanmaku.Progress / 1000.0f,
Style = mapping[biliDanmaku.Mode],
Color = (int)biliDanmaku.Color,
Commenter = biliDanmaku.MidHash,
Content = biliDanmaku.Content,
SizeRatio = 1.0f * biliDanmaku.Fontsize / normalFontSize
};
danmakus.Add(danmaku);
}
// 弹幕预处理
Producer producer = new Producer(config, danmakus);
producer.StartHandle();
// 字幕生成
var keepedDanmakus = producer.KeepedDanmakus;
var studio = new Studio(subtitleConfig, keepedDanmakus);
studio.StartHandle();
studio.CreateAssFile(assFile);
}
public Dictionary<string, int> GetResolution(int quality)
{
var resolution = new Dictionary<string, int>
{
{ "width", 0 },
{ "height", 0 }
};
switch (quality)
{
// 240P 极速仅mp4方式
case 6:
break;
// 360P 流畅
case 16:
break;
// 480P 清晰
case 32:
break;
// 720P 高清(登录)
case 64:
break;
// 720P60 高清(大会员)
case 74:
break;
// 1080P 高清(登录)
case 80:
break;
// 1080P+ 高清(大会员)
case 112:
break;
// 1080P60 高清(大会员)
case 116:
break;
// 4K 超清大会员需要fourk=1
case 120:
break;
}
return resolution;
}
}
}

@ -1,61 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace Core.danmaku2ass
{
/// <summary>
/// 碰撞处理
/// </summary>
public class Collision
{
private readonly int lineCount;
private readonly List<int> leaves;
public Collision(int lineCount)
{
this.lineCount = lineCount;
leaves = Leaves();
}
private List<int> Leaves()
{
var ret = new List<int>(lineCount);
for (int i = 0; i < lineCount; i++) ret.Add(0);
return ret;
}
/// <summary>
/// 碰撞检测
/// 返回行号和时间偏移
/// </summary>
/// <param name="display"></param>
/// <returns></returns>
public Tuple<int, float> Detect(Display display)
{
List<float> beyonds = new List<float>();
for (int i = 0; i < leaves.Count; i++)
{
float beyond = display.Danmaku.Start - leaves[i];
// 某一行有足够空间,直接返回行号和 0 偏移
if (beyond >= 0)
{
return Tuple.Create(i, 0f);
}
beyonds.Add(beyond);
}
// 所有行都没有空间了,那么找出哪一行能在最短时间内让出空间
float soon = beyonds.Max();
int lineIndex = beyonds.IndexOf(soon);
float offset = -soon;
return Tuple.Create(lineIndex, offset);
}
public void Update(float leave, int lineIndex, float offset)
{
leaves[lineIndex] = Utils.IntCeiling(leave + offset);
}
}
}

@ -1,55 +0,0 @@
using System;
namespace Core.danmaku2ass
{
public class Config
{
public string Title = "Downkyi";
public int ScreenWidth = 1920;
public int ScreenHeight = 1080;
public string FontName = "黑体";
public int BaseFontSize; // 字体大小,像素
// 限制行数
private int lineCount;
public int LineCount
{
get { return lineCount; }
set
{
if (value == 0)
{
lineCount = (int)Math.Floor(ScreenHeight / BaseFontSize * 1.0);
}
else
{
lineCount = value;
}
}
}
public string LayoutAlgorithm; // 布局算法async/sync
public int TuneDuration; // 微调时长
public int DropOffset; // 丢弃偏移
public int BottomMargin; // 底部边距
public int CustomOffset; // 自定义偏移
public string HeaderTemplate = @"[Script Info]
; Script generated by Downkyi Danmaku Converter
; https://github.com/FlySelfLog/downkyi
Title: {title}
ScriptType: v4.00+
Collisions: Normal
PlayResX: {width}
PlayResY: {height}
Timer: 10.0000
WrapStyle: 2
ScaledBorderAndShadow: no
[V4+ Styles]
Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding
Style: Default,{fontname},54,&H00FFFFFF,&H00FFFFFF,&H00000000,&H00000000,0,0,0,0,100,100,0.00,0.00,1,2.00,0.00,2,30,30,120,0
Style: Alternate,{fontname},36,&H00FFFFFF,&H00FFFFFF,&H00000000,&H00000000,0,0,0,0,100,100,0.00,0.00,1,2.00,0.00,2,30,30,84,0
Style: Danmaku,{fontname},{fontsize},&H00FFFFFF,&H00FFFFFF,&H00000000,&H00000000,0,0,0,0,100,100,0.00,0.00,1,1.00,0.00,2,30,30,30,0
[Events]
Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text";
}
}

@ -1,88 +0,0 @@
using System.Collections.Generic;
namespace Core.danmaku2ass
{
/// <summary>
/// 创建器
/// </summary>
public class Creater
{
public Config Config;
public List<Danmaku> Danmakus;
public List<Subtitle> Subtitles;
public string Text;
public Creater(Config config, List<Danmaku> danmakus)
{
Config = config;
Danmakus = danmakus;
Subtitles = SetSubtitles();
Text = SetText();
}
protected List<Subtitle> SetSubtitles()
{
var scroll = new Collision(Config.LineCount);
var stayed = new Collision(Config.LineCount);
Dictionary<string, Collision> collisions = new Dictionary<string, Collision>
{
{ "scroll", scroll },
{ "top", stayed },
{ "bottom", stayed }
};
List<Subtitle> subtitles = new List<Subtitle>();
foreach (var danmaku in Danmakus)
{
// 丢弃不支持的
if (danmaku.Style == "none")
{
continue;
}
// 创建显示方式对象
var display = Display.Factory(Config, danmaku);
var collision = collisions[danmaku.Style];
var detect = collision.Detect(display);
int lineIndex = detect.Item1;
float waitingOffset = detect.Item2;
// 超过容忍的偏移量,丢弃掉此条弹幕
if (waitingOffset > Config.DropOffset)
{
continue;
}
// 接受偏移,更新碰撞信息
display.Relayout(lineIndex);
collision.Update(display.Leave, lineIndex, waitingOffset);
// 再加上自定义偏移
float offset = waitingOffset + Config.CustomOffset;
Subtitle subtitle = new Subtitle(danmaku, display, offset);
subtitles.Add(subtitle);
}
return subtitles;
}
protected string SetText()
{
string header = Config.HeaderTemplate
.Replace("{title}", Config.Title)
.Replace("{width}", Config.ScreenWidth.ToString())
.Replace("{height}", Config.ScreenHeight.ToString())
.Replace("{fontname}", Config.FontName)
.Replace("{fontsize}", Config.BaseFontSize.ToString());
string events = string.Empty;
foreach (var subtitle in Subtitles)
{
events += "\n" + subtitle.Text;
}
return header + events;
}
}
}

@ -1,12 +0,0 @@
namespace Core.danmaku2ass
{
public class Danmaku
{
public float Start { get; set; }
public string Style { get; set; }
public int Color { get; set; }
public string Commenter { get; set; }
public string Content { get; set; }
public float SizeRatio { get; set; }
}
}

@ -1,6 +0,0 @@
namespace Core.danmaku2ass
{
public class Dictionary<T>
{
}
}

@ -1,406 +0,0 @@
using System;
using System.Collections.Generic;
using System.Reflection;
namespace Core.danmaku2ass
{
/// <summary>
/// 显示方式
/// </summary>
public class Display
{
public Config Config;
public Danmaku Danmaku;
public int LineIndex;
public int FontSize;
public bool IsScaled;
public int MaxLength;
public int Width;
public int Height;
public Tuple<int, int> Horizontal;
public Tuple<int, int> Vertical;
public int Duration;
public int Leave;
protected Display() { }
public Display(Config config, Danmaku danmaku)
{
Config = config;
Danmaku = danmaku;
LineIndex = 0;
IsScaled = SetIsScaled();
FontSize = SetFontSize();
MaxLength = SetMaxLength();
Width = SetWidth();
Height = SetHeight();
Horizontal = SetHorizontal();
Vertical = SetVertical();
Duration = SetDuration();
Leave = SetLeave();
}
/// <summary>
/// 根据弹幕样式自动创建对应的 Display 类
/// </summary>
/// <returns></returns>
public static Display Factory(Config config, Danmaku danmaku)
{
Dictionary<string, Display> dict = new Dictionary<string, Display>
{
{ "scroll", new ScrollDisplay(config, danmaku) },
{ "top", new TopDisplay(config, danmaku) },
{ "bottom", new BottomDisplay(config, danmaku) }
};
return dict[danmaku.Style];
}
/// <summary>
/// 字体大小
/// 按用户自定义的字体大小来缩放
/// </summary>
/// <returns></returns>
protected int SetFontSize()
{
if (IsScaled)
{
Console.WriteLine($"{Danmaku.SizeRatio}");
}
return Utils.IntCeiling(Config.BaseFontSize * Danmaku.SizeRatio);
}
/// <summary>
/// 字体是否被缩放过
/// </summary>
/// <returns></returns>
protected bool SetIsScaled()
{
return !Math.Round(Danmaku.SizeRatio, 2).Equals(1.0);
//return Danmaku.SizeRatio.Equals(1.0f);
}
/// <summary>
/// 最长的行字符数
/// </summary>
/// <returns></returns>
protected int SetMaxLength()
{
string[] lines = Danmaku.Content.Split('\n');
int maxLength = 0;
foreach (string line in lines)
{
int length = Utils.DisplayLength(line);
if (maxLength < length)
{
maxLength = length;
}
}
return maxLength;
}
/// <summary>
/// 整条字幕宽度
/// </summary>
/// <returns></returns>
protected int SetWidth()
{
float charCount = MaxLength;// / 2;
return Utils.IntCeiling(FontSize * charCount);
}
/// <summary>
/// 整条字幕高度
/// </summary>
/// <returns></returns>
protected int SetHeight()
{
int lineCount = Danmaku.Content.Split('\n').Length;
return lineCount * FontSize;
}
/// <summary>
/// 出现和消失的水平坐标位置
/// 默认在屏幕中间
/// </summary>
/// <returns></returns>
protected virtual Tuple<int, int> SetHorizontal()
{
int x = (int)Math.Floor(Config.ScreenWidth / 2.0);
return Tuple.Create(x, x);
}
/// <summary>
/// 出现和消失的垂直坐标位置
/// 默认在屏幕中间
/// </summary>
/// <returns></returns>
protected virtual Tuple<int, int> SetVertical()
{
int y = (int)Math.Floor(Config.ScreenHeight / 2.0);
return Tuple.Create(y, y);
}
/// <summary>
/// 整条字幕的显示时间
/// </summary>
/// <returns></returns>
protected virtual int SetDuration()
{
int baseDuration = 3 + Config.TuneDuration;
if (baseDuration <= 0)
{
baseDuration = 0;
}
float charCount = MaxLength / 2;
int value;
if (charCount < 6)
{
value = baseDuration + 1;
}
else if (charCount < 12)
{
value = baseDuration + 2;
}
else
{
value = baseDuration + 3;
}
return value;
}
/// <summary>
/// 离开碰撞时间
/// </summary>
/// <returns></returns>
protected virtual int SetLeave()
{
return (int)(Danmaku.Start + Duration);
}
/// <summary>
/// 按照新的行号重新布局
/// </summary>
/// <param name="lineIndex"></param>
public void Relayout(int lineIndex)
{
LineIndex = lineIndex;
Horizontal = SetHorizontal();
Vertical = SetVertical();
}
}
/// <summary>
/// 顶部
/// </summary>
public class TopDisplay : Display
{
public TopDisplay(Config config, Danmaku danmaku) : base(config, danmaku)
{
Console.WriteLine("TopDisplay constructor.");
}
/// <summary>
///
/// </summary>
/// <returns></returns>
protected override Tuple<int, int> SetVertical()
{
// 这里 y 坐标为 0 就是最顶行了
int y = LineIndex * Config.BaseFontSize;
return Tuple.Create(y, y);
}
}
/// <summary>
/// 底部
/// </summary>
public class BottomDisplay : Display
{
public BottomDisplay(Config config, Danmaku danmaku) : base(config, danmaku)
{
Console.WriteLine("BottomDisplay constructor.");
}
/// <summary>
///
/// </summary>
/// <returns></returns>
protected override Tuple<int, int> SetVertical()
{
// 要让字幕不超出底部,减去高度
int y = Config.ScreenHeight - (LineIndex * Config.BaseFontSize) - Height;
// 再减去自定义的底部边距
y -= Config.BottomMargin;
return Tuple.Create(y, y);
}
}
/// <summary>
/// 滚动
/// </summary>
public class ScrollDisplay : Display
{
public int Distance;
public int Speed;
public ScrollDisplay(Config config, Danmaku danmaku) : base()
{
Console.WriteLine("ScrollDisplay constructor.");
Config = config;
Danmaku = danmaku;
LineIndex = 0;
IsScaled = SetIsScaled();
FontSize = SetFontSize();
MaxLength = SetMaxLength();
Width = SetWidth();
Height = SetHeight();
Horizontal = SetHorizontal();
Vertical = SetVertical();
Distance = SetDistance();
Speed = SetSpeed();
Duration = SetDuration();
Leave = SetLeave();
}
/// <summary>
/// ASS 的水平位置参考点是整条字幕文本的中点
/// </summary>
/// <returns></returns>
protected override Tuple<int, int> SetHorizontal()
{
int x1 = Config.ScreenWidth + (int)Math.Floor(Width / 2.0);
int x2 = 0 - (int)Math.Floor(Width / 2.0);
return Tuple.Create(x1, x2);
}
protected override Tuple<int, int> SetVertical()
{
int baseFontSize = Config.BaseFontSize;
// 垂直位置,按基准字体大小算每一行的高度
int y = (LineIndex + 1) * baseFontSize;
// 个别弹幕可能字体比基准要大,所以最上的一行还要避免挤出顶部屏幕
// 坐标不能小于字体大小
if (y < FontSize)
{
y = FontSize;
}
return Tuple.Create(y, y);
}
/// <summary>
/// 字幕坐标点的移动距离
/// </summary>
/// <returns></returns>
protected int SetDistance()
{
Tuple<int, int> x = Horizontal;
return x.Item1 - x.Item2;
}
/// <summary>
/// 字幕每个字的移动的速度
/// </summary>
/// <returns></returns>
protected int SetSpeed()
{
// 基准时间,就是每个字的移动时间
// 12 秒加上用户自定义的微调
int baseDuration = 12 + Config.TuneDuration;
if (baseDuration <= 0)
{
baseDuration = 1;
}
return Utils.IntCeiling(Config.ScreenWidth / baseDuration);
}
/// <summary>
/// 计算每条弹幕的显示时长,同步方式
/// 每个弹幕的滚动速度都一样,辨认度好,适合观看剧集类视频。
/// </summary>
/// <returns></returns>
public int SyncDuration()
{
return Distance / Speed;
}
/// <summary>
/// 计算每条弹幕的显示时长,异步方式
/// 每个弹幕的滚动速度都不一样,动态调整,辨认度低,适合观看 MTV 类视频。
/// </summary>
/// <returns></returns>
public int AsyncDuration()
{
int baseDuration = 6 + Config.TuneDuration;
if (baseDuration <= 0)
{
baseDuration = 0;
}
float charCount = MaxLength / 2;
int value;
if (charCount < 6)
{
value = (int)(baseDuration + charCount);
}
else if (charCount < 12)
{
value = baseDuration + (int)(charCount / 2);
}
else if (charCount < 24)
{
value = baseDuration + (int)(charCount / 3);
}
else
{
value = baseDuration + 10;
}
return value;
}
/// <summary>
/// 整条字幕的移动时间
/// </summary>
/// <returns></returns>
protected override int SetDuration()
{
string methodName = Config.LayoutAlgorithm.Substring(0, 1).ToUpper() + Config.LayoutAlgorithm.Substring(1);
methodName += "Duration";
MethodInfo method = typeof(ScrollDisplay).GetMethod(methodName);
if (method != null)
{
return (int)method.Invoke(this, null);
}
return 0;
}
/// <summary>
/// 离开碰撞时间
/// </summary>
/// <returns></returns>
protected override int SetLeave()
{
// 对于滚动样式弹幕来说,就是最后一个字符离开最右边缘的时间
// 坐标是字幕中点,在屏幕外和内各有半个字幕宽度
// 也就是跑过一个字幕宽度的路程
float duration = Width / Speed;
return (int)(Danmaku.Start + duration);
}
}
}

@ -1,89 +0,0 @@
using System;
using System.Collections.Generic;
namespace Core.danmaku2ass
{
/// <summary>
/// 过滤器基类
/// </summary>
public class Filter
{
public virtual List<Danmaku> DoFilter(List<Danmaku> danmakus)
{
throw new NotImplementedException("使用了过滤器的未实现的方法。");
}
}
/// <summary>
/// 顶部样式过滤器
/// </summary>
public class TopFilter : Filter
{
public override List<Danmaku> DoFilter(List<Danmaku> danmakus)
{
List<Danmaku> keep = new List<Danmaku>();
foreach (var danmaku in danmakus)
{
if (danmaku.Style == "top")
{
continue;
}
keep.Add(danmaku);
}
return keep;
}
}
/// <summary>
/// 底部样式过滤器
/// </summary>
public class BottomFilter : Filter
{
public override List<Danmaku> DoFilter(List<Danmaku> danmakus)
{
List<Danmaku> keep = new List<Danmaku>();
foreach (var danmaku in danmakus)
{
if (danmaku.Style == "bottom")
{
continue;
}
keep.Add(danmaku);
}
return keep;
}
}
/// <summary>
/// 滚动样式过滤器
/// </summary>
public class ScrollFilter : Filter
{
public override List<Danmaku> DoFilter(List<Danmaku> danmakus)
{
List<Danmaku> keep = new List<Danmaku>();
foreach (var danmaku in danmakus)
{
if (danmaku.Style == "scroll")
{
continue;
}
keep.Add(danmaku);
}
return keep;
}
}
/// <summary>
/// 自定义过滤器
/// </summary>
public class CustomFilter : Filter
{
public override List<Danmaku> DoFilter(List<Danmaku> danmakus)
{
// TODO
return base.DoFilter(danmakus);
}
}
}

@ -1,105 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace Core.danmaku2ass
{
public class Producer
{
public Dictionary<string, bool> Config;
public Dictionary<string, Filter> Filters;
public List<Danmaku> Danmakus;
public List<Danmaku> KeepedDanmakus;
public Dictionary<string, int> FilterDetail;
public Producer(Dictionary<string, bool> config, List<Danmaku> danmakus)
{
Config = config;
Danmakus = danmakus;
}
public void StartHandle()
{
LoadFilter();
ApplyFilter();
}
public void LoadFilter()
{
Filters = new Dictionary<string, Filter>();
if (Config["top_filter"])
{
Filters.Add("top_filter", new TopFilter());
}
if (Config["bottom_filter"])
{
Filters.Add("bottom_filter", new BottomFilter());
}
if (Config["scroll_filter"])
{
Filters.Add("scroll_filter", new ScrollFilter());
}
//if (Config["custom_filter"])
//{
// Filters.Add("custom_filter", new CustomFilter());
//}
}
public void ApplyFilter()
{
Dictionary<string, int> filterDetail = new Dictionary<string, int>() {
{ "top_filter",0},
{ "bottom_filter",0},
{ "scroll_filter",0},
//{ "custom_filter",0}
};
List<Danmaku> danmakus = Danmakus;
//string[] orders = { "top_filter", "bottom_filter", "scroll_filter", "custom_filter" };
string[] orders = { "top_filter", "bottom_filter", "scroll_filter" };
foreach (var name in orders)
{
Filter filter;
try
{
filter = Filters[name];
}
catch (Exception e)
{
Console.WriteLine("ApplyFilter()发生异常: {0}", e);
continue;
}
int count = danmakus.Count;
danmakus = filter.DoFilter(danmakus);
filterDetail[name] = count - danmakus.Count;
}
KeepedDanmakus = danmakus;
FilterDetail = filterDetail;
}
public Dictionary<string, int> Report()
{
int blockedCount = 0;
foreach (int count in FilterDetail.Values)
{
blockedCount += count;
}
int passedCount = KeepedDanmakus.Count;
int totalCount = blockedCount + passedCount;
Dictionary<string, int> ret = new Dictionary<string, int>
{
{ "blocked", blockedCount },
{ "passed", passedCount },
{ "total", totalCount }
};
return (Dictionary<string, int>)ret.Concat(FilterDetail);
}
}
}

@ -1,84 +0,0 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace Core.danmaku2ass
{
/// <summary>
/// 字幕工程类
/// </summary>
public class Studio
{
public Config Config;
public List<Danmaku> Danmakus;
public Creater Creater;
public int KeepedCount;
public int DropedCount;
public Studio(Config config, List<Danmaku> danmakus)
{
Config = config;
Danmakus = danmakus;
}
public void StartHandle()
{
Creater = SetCreater();
KeepedCount = SetKeepedCount();
DropedCount = SetDropedCount();
}
/// <summary>
/// ass 创建器
/// </summary>
/// <returns></returns>
protected Creater SetCreater()
{
return new Creater(Config, Danmakus);
}
/// <summary>
/// 保留条数
/// </summary>
/// <returns></returns>
protected int SetKeepedCount()
{
return Creater.Subtitles.Count();
}
/// <summary>
/// 丢弃条数
/// </summary>
/// <returns></returns>
protected int SetDropedCount()
{
return Danmakus.Count - KeepedCount;
}
/// <summary>
/// 创建 ass 字幕
/// </summary>
/// <param name="fileName"></param>
public void CreateAssFile(string fileName)
{
CreateFile(fileName, Creater.Text);
}
public void CreateFile(string fileName, string text)
{
File.WriteAllText(fileName, text);
}
public Dictionary<string, int> Report()
{
return new Dictionary<string, int>()
{
{"total", Danmakus.Count},
{"droped", DropedCount},
{"keeped", KeepedCount},
};
}
}
}

@ -1,155 +0,0 @@
using System;
using System.Collections.Generic;
namespace Core.danmaku2ass
{
/// <summary>
/// 字幕
/// </summary>
public class Subtitle
{
public Danmaku Danmaku;
public Display Display;
public float Offset;
public float Start;
public float End;
public string Color;
public Dictionary<string, int> Position;
public string StartMarkup;
public string EndMarkup;
public string ColorMarkup;
public string BorderMarkup;
public string FontSizeMarkup;
public string StyleMarkup;
public string LayerMarkup;
public string ContentMarkup;
public string Text;
public Subtitle(Danmaku danmaku, Display display, float offset = 0)
{
Danmaku = danmaku;
Display = display;
Offset = offset;
Start = SetStart();
End = SetEnd();
Color = SetColor();
Position = SetPosition();
StartMarkup = SetStartMarkup();
EndMarkup = SetEndMarkup();
ColorMarkup = SetColorMarkup();
BorderMarkup = SetBorderMarkup();
FontSizeMarkup = SetFontSizeMarkup();
StyleMarkup = SetStyleMarkup();
LayerMarkup = SetLayerMarkup();
ContentMarkup = SetContentMarkup();
Text = SetText();
}
protected float SetStart()
{
return Danmaku.Start + Offset;
}
protected float SetEnd()
{
return Start + Display.Duration;
}
protected string SetColor()
{
return Utils.Int2bgr(Danmaku.Color);
}
protected Dictionary<string, int> SetPosition()
{
Tuple<int, int> x = Display.Horizontal;
Tuple<int, int> y = Display.Vertical;
Dictionary<string, int> value = new Dictionary<string, int>
{
{ "x1", x.Item1 },
{ "x2", x.Item2 },
{ "y1", y.Item1 },
{ "y2", y.Item2 }
};
return value;
}
protected string SetStartMarkup()
{
return Utils.Second2hms(Start);
}
protected string SetEndMarkup()
{
return Utils.Second2hms(End);
}
protected string SetColorMarkup()
{
// 白色不需要加特别标记
if (Color == "FFFFFF")
{
return "";
}
return "\\c&H" + Color;
}
protected string SetBorderMarkup()
{
// 暗色加个亮色边框,方便阅读
if (Utils.IsDark(Danmaku.Color))
{
//return "\\3c&HFFFFFF";
return "\\3c&H000000";
}
else
{
return "\\3c&H000000";
}
//return "";
}
protected string SetFontSizeMarkup()
{
if (Display.IsScaled)
{
return $"\\fs{Display.FontSize}";
}
return "";
}
protected string SetStyleMarkup()
{
if (Danmaku.Style == "scroll")
{
return $"\\move({Position["x1"]}, {Position["y1"]}, {Position["x2"]}, {Position["y2"]})";
}
return $"\\a6\\pos({Position["x1"]}, {Position["y1"]})";
}
protected string SetLayerMarkup()
{
if (Danmaku.Style != "scroll")
{
return "-2";
}
return "-1";
}
protected string SetContentMarkup()
{
string markup = StyleMarkup + ColorMarkup + BorderMarkup + FontSizeMarkup;
string content = Utils.CorrectTypos(Danmaku.Content);
return $"{{{markup}}}{content}";
}
protected string SetText()
{
return $"Dialogue: {LayerMarkup},{StartMarkup},{EndMarkup},Danmaku,,0000,0000,0000,,{ContentMarkup}";
}
}
}

@ -1,228 +0,0 @@
using System;
using System.Linq;
using System.Text;
namespace Core.danmaku2ass
{
internal static class Utils
{
/// <summary>
/// 向上取整返回int类型
/// </summary>
/// <param name="number"></param>
/// <returns></returns>
public static int IntCeiling(float number)
{
return (int)Math.Ceiling(number);
}
/// <summary>
/// 字符长度1个汉字当2个英文
/// </summary>
/// <param name="text"></param>
/// <returns></returns>
public static int DisplayLength(string text)
{
return Encoding.Default.GetBytes(text).Length;
}
/// <summary>
/// 修正一些评论者的拼写错误
/// </summary>
/// <param name="text"></param>
/// <returns></returns>
public static string CorrectTypos(string text)
{
text = text.Replace("/n", "\\N");
text = text.Replace("&gt;", ">");
text = text.Replace("&lt;", "<");
return text;
}
/// <summary>
/// 秒数转 时:分:秒 格式
/// </summary>
/// <param name="seconds"></param>
/// <returns></returns>
public static string Second2hms(float seconds)
{
if (seconds < 0)
{
return "0:00:00.00";
}
int i = (int)Math.Floor(seconds / 1.0);
int dec = (int)(Math.Round(seconds % 1.0f, 2) * 100);
if (dec >= 100)
{
dec = 99;
}
int min = (int)Math.Floor(i / 60.0);
int second = (int)(i % 60.0f);
int hour = (int)Math.Floor(min / 60.0);
return $"{hour:D}:{min:D2}:{second:D2}.{dec:D2}";
}
/// <summary>
/// 时:分:秒 格式转 秒数
/// </summary>
/// <param name="hms"></param>
/// <returns></returns>
public static float Hms2second(string hms)
{
string[] numbers = hms.Split(':');
float seconds = 0;
for (int i = 0; i < numbers.Length; i++)
{
seconds += (float)(float.Parse(numbers[numbers.Length - i - 1]) * Math.Pow(60, i));
}
return seconds;
}
/// <summary>
/// 同Hms2second(string hms),不过可以用 +/- 符号来连接多个
/// 即 3:00-2:30 相当于 30 秒
/// </summary>
/// <param name="xhms"></param>
/// <returns></returns>
public static float Xhms2second(string xhms)
{
string[] args = xhms.Replace("+", " +").Replace("-", " -").Split(' ');
float result = 0;
foreach (string hms in args)
{
result += Hms2second(hms);
}
return result;
}
/// <summary>
/// 颜色值,整型转 RGB
/// </summary>
/// <param name="integer"></param>
/// <returns></returns>
public static string Int2rgb(int integer)
{
return integer.ToString("X").PadLeft(6, '0'); ;
}
/// <summary>
/// 颜色值,整型转 BGR
/// </summary>
/// <param name="integer"></param>
/// <returns></returns>
public static string Int2bgr(int integer)
{
string rgb = Int2rgb(integer);
string bgr = rgb.Substring(4, 2) + rgb.Substring(2, 2) + rgb.Substring(0, 2);
return bgr;
}
/// <summary>
/// 颜色值,整型转 HLS
/// </summary>
/// <param name="integer"></param>
/// <returns></returns>
public static float[] Int2hls(int integer)
{
string rgb = Int2rgb(integer);
int[] rgb_decimals = { 0, 0, 0 };
rgb_decimals[0] = int.Parse(rgb.Substring(0, 2), System.Globalization.NumberStyles.HexNumber);
rgb_decimals[1] = int.Parse(rgb.Substring(2, 2), System.Globalization.NumberStyles.HexNumber);
rgb_decimals[2] = int.Parse(rgb.Substring(4, 2), System.Globalization.NumberStyles.HexNumber);
int[] rgb_coordinates = { 0, 0, 0 };
rgb_coordinates[0] = (int)Math.Floor(rgb_decimals[0] / 255.0);
rgb_coordinates[1] = (int)Math.Floor(rgb_decimals[1] / 255.0);
rgb_coordinates[2] = (int)Math.Floor(rgb_decimals[2] / 255.0);
float[] hls_corrdinates = Rgb2hls(rgb_coordinates);
float[] hls = { 0, 0, 0 };
hls[0] = hls_corrdinates[0] * 360;
hls[1] = hls_corrdinates[1] * 100;
hls[2] = hls_corrdinates[2] * 100;
return hls;
}
/// <summary>
/// HLS: Hue, Luminance, Saturation
/// H: position in the spectrum
/// L: color lightness
/// S: color saturation
/// </summary>
/// <param name="rgb"></param>
/// <returns></returns>
private static float[] Rgb2hls(int[] rgb)
{
float[] hls = { 0, 0, 0 };
int maxc = rgb.Max();
int minc = rgb.Min();
hls[1] = (minc + maxc) / 2.0f;
if (minc == maxc)
{
return hls;
}
if (hls[1] <= 0.5)
{
hls[2] = (maxc - minc) / (maxc + minc);
}
else
{
hls[2] = (maxc - minc) / (2.0f - maxc - minc);
}
float rc = (maxc - rgb[0]) / (maxc - minc);
float gc = (maxc - rgb[1]) / (maxc - minc);
float bc = (maxc - rgb[2]) / (maxc - minc);
if (rgb[0] == maxc)
{
hls[0] = bc - gc;
}
else if (rgb[1] == maxc)
{
hls[0] = 2.0f + rc - bc;
}
else
{
hls[0] = 4.0f + gc - rc;
}
hls[0] = (hls[0] / 6.0f) % 1.0f;
return hls;
}
/// <summary>
/// 是否属于暗色
/// </summary>
/// <param name="integer"></param>
/// <returns></returns>
public static bool IsDark(int integer)
{
if (integer == 0)
{
return true;
}
float[] hls = Int2hls(integer);
float hue = hls[0];
float lightness = hls[1];
// HSL 色轮见
// http://zh.wikipedia.org/zh-cn/HSL和HSV色彩空间
// 以下的数值都是我的主观判断认为是暗色
if ((hue > 30 && hue < 210) && lightness < 33)
{
return true;
}
if ((hue < 30 || hue > 210) && lightness < 66)
{
return true;
}
return false;
}
}
}

@ -1,35 +0,0 @@
// 注释掉未使用的属性
namespace Core.entity
{
// https://api.bilibili.com/pgc/review/user?media_id=28228367
class BangumiMedia
{
//public int code { get; set; }
//public string message { get; set; }
public BangumiMediaData result { get; set; }
}
public class BangumiMediaData
{
public BangumiMediaDataMedia media { get; set; }
//public BangumiMediaDataReview review { get; set; }
}
public class BangumiMediaDataMedia
{
// TODO 暂时只实现部分字段
//public long media_id { get; set; }
public long season_id { get; set; }
//public string share_url { get; set; }
//public string title { get; set; }
//public string type_name { get; set; }
}
//public class BangumiMediaDataReview
//{
// public int is_coin { get; set; }
// public int is_open { get; set; }
//}
}

@ -1,199 +0,0 @@
using System.Collections.Generic;
// 注释掉未使用的属性
namespace Core.entity
{
//https://api.bilibili.com/pgc/view/web/season?season_id=28324
public class BangumiSeason
{
//public int code { get; set; }
//public string message { get; set; }
public BangumiSeasonResult result { get; set; }
}
public class BangumiSeasonResult
{
//public BangumiSeasonResultActivity activity { get; set; }
//public string alias { get; set; }
//public string bkg_cover { get; set; }
public string cover { get; set; }
public List<BangumiSeasonResultEpisodes> episodes { get; set; }
public string evaluate { get; set; }
//public string jp_title { get; set; }
//public string link { get; set; }
//public long media_id { get; set; }
//public int mode { get; set; }
//public BangumiSeasonResultNewEp new_ep { get; set; }
//public BangumiSeasonResultPositive positive { get; set; }
//public BangumiSeasonResultPublish publish { get; set; }
//public BangumiSeasonResultRating rating { get; set; }
//public string record { get; set; }
//public BangumiSeasonResultRights rights { get; set; }
//public long season_id { get; set; }
//public string season_title { get; set; }
//public List<BangumiSeasonResultSeasons> seasons { get; set; }
//public BangumiSeasonResultSeries series { get; set; }
//public string share_copy { get; set; }
//public string share_sub_title { get; set; }
//public string share_url { get; set; }
//public BangumiSeasonResultShow show { get; set; }
//public string square_cover { get; set; }
public BangumiSeasonResultStat stat { get; set; }
//public int status { get; set; }
//public string subtitle { get; set; }
public string title { get; set; }
//public int total { get; set; }
public int type { get; set; }
}
//public class BangumiSeasonResultActivity
//{
// public string head_bg_url { get; set; }
// public long id { get; set; }
// public string title { get; set; }
//}
public class BangumiSeasonResultEpisodes
{
public long aid { get; set; }
//public string badge { get; set; }
//public BangumiSeasonResultBadgeInfo badge_info { get; set; }
//public int badge_type { get; set; }
public string bvid { get; set; }
public long cid { get; set; }
//public string cover { get; set; }
public BangumiSeasonResultEpisodesDimension dimension { get; set; }
//public string from { get; set; }
//public long id { get; set; }
//public string link { get; set; }
//public string long_title { get; set; }
//public long pub_time { get; set; }
//public string release_date { get; set; }
//public BangumiSeasonResultEpisodesRights rights { get; set; }
public string share_copy { get; set; }
//public string share_url { get; set; }
//public string short_link { get; set; }
//public int status { get; set; }
//public string subtitle { get; set; }
public string title { get; set; }
//public string vid { get; set; }
}
//public class BangumiSeasonResultBadgeInfo
//{
// public string bg_color { get; set; }
// public string bg_color_night { get; set; }
// public string text { get; set; }
//}
public class BangumiSeasonResultEpisodesDimension
{
public int width { get; set; }
public int height { get; set; }
//public int rotate { get; set; }
}
//public class BangumiSeasonResultEpisodesRights
//{
// public int allow_dm { get; set; }
//}
//public class BangumiSeasonResultNewEp
//{
// public string desc { get; set; }
// public long id { get; set; }
// public int is_new { get; set; }
// public string title { get; set; }
//}
//public class BangumiSeasonResultPositive
//{
// public long id { get; set; }
// public string title { get; set; }
//}
//public class BangumiSeasonResultPublish
//{
// public int is_finish { get; set; }
// public int is_started { get; set; }
// public string pub_time { get; set; }
// public string pub_time_show { get; set; }
// public int unknow_pub_date { get; set; }
// public int weekday { get; set; }
//}
//public class BangumiSeasonResultRating
//{
// public long count { get; set; }
// public float score { get; set; }
//}
//public class BangumiSeasonResultRights
//{
// public int allow_bp { get; set; }
// public int allow_bp_rank { get; set; }
// public int allow_download { get; set; }
// public int allow_review { get; set; }
// public int area_limit { get; set; }
// public int ban_area_show { get; set; }
// public int can_watch { get; set; }
// public string copyright { get; set; }
// public int forbid_pre { get; set; }
// public int is_cover_show { get; set; }
// public int is_preview { get; set; }
// public int only_vip_download { get; set; }
// public string resource { get; set; }
// public int watch_platform { get; set; }
//}
//public class BangumiSeasonResultSeasons
//{
// public string badge { get; set; }
// public BangumiSeasonResultBadgeInfo badge_info { get; set; }
// public int badge_type { get; set; }
// public string cover { get; set; }
// public long media_id { get; set; }
// public BangumiSeasonResultSeasonsNewEp new_ep { get; set; }
// public long season_id { get; set; }
// public string season_title { get; set; }
// public int season_type { get; set; }
// public BangumiSeasonResultSeasonsStat stat { get; set; }
//}
//public class BangumiSeasonResultSeasonsNewEp
//{
// public string cover { get; set; }
// public long id { get; set; }
// public string index_show { get; set; }
//}
//public class BangumiSeasonResultSeasonsStat
//{
// public long favorites { get; set; }
// public long series_follow { get; set; }
// public long views { get; set; }
//}
//public class BangumiSeasonResultSeries
//{
// public long series_id { get; set; }
// public string series_title { get; set; }
//}
//public class BangumiSeasonResultShow
//{
// public int wide_screen { get; set; }
//}
public class BangumiSeasonResultStat
{
public long coins { get; set; }
public long danmakus { get; set; }
public long favorites { get; set; }
public long likes { get; set; }
public long reply { get; set; }
public long share { get; set; }
public long views { get; set; }
}
}

@ -1,44 +0,0 @@
using System.Collections.Generic;
namespace Core.entity
{
// https://api.bilibili.com/pugv/view/web/ep/list?season_id=112&pn=1
public class CheeseList
{
public int code { get; set; }
public CheeseListData data { get; set; }
public string message { get; set; }
}
public class CheeseListData
{
public List<CheeseListDataItem> items { get; set; }
public CheeseListDataPage page { get; set; }
}
public class CheeseListDataItem
{
public long aid { get; set; }
public long cid { get; set; }
public long duration { get; set; }
public string from { get; set; }
public long id { get; set; } // ep_id
public int index { get; set; }
public int page { get; set; }
public long play { get; set; }
public long release_date { get; set; }
public int status { get; set; }
public string title { get; set; }
public bool watched { get; set; }
public int watchedHistory { get; set; }
}
public class CheeseListDataPage
{
public bool next { get; set; } // 是否还有下一页
public int num { get; set; } // 当前页
public int size { get; set; } // list大小
public int total { get; set; } // 总的视频数量
}
}

@ -1,52 +0,0 @@
using System.Collections.Generic;
namespace Core.entity
{
// https://api.bilibili.com/pugv/view/web/season?ep_id=2126
class CheeseSeason
{
//public int code { get; set; }
public CheeseSeasonData data { get; set; }
//public string message { get; set; }
}
public class CheeseSeasonData
{
public string cover { get; set; }
public List<CheeseSeasonDataEpisode> episodes { get; set; }
public long season_id { get; set; }
public CheeseSeasonDataStat stat { get; set; }
public string subtitle { get; set; }
public string title { get; set; }
}
public class CheeseSeasonDataEpisode
{
public long aid { get; set; }
public long cid { get; set; }
public long duration { get; set; }
public string from { get; set; }
public long id { get; set; } // ep_id
public int index { get; set; }
public int page { get; set; }
public long play { get; set; }
public long release_date { get; set; }
public int status { get; set; }
public string title { get; set; }
public bool watched { get; set; }
public int watchedHistory { get; set; }
}
public class CheeseSeasonDataStat
{
public long play { get; set; }
public string play_desc { get; set; }
}
}

@ -1,25 +0,0 @@
using System.Collections.Generic;
// 注释掉未使用的属性
namespace Core.entity
{
public class DanmuDate
{
//{"code":0,"message":"0","ttl":1,"data":["2020-07-01","2020-07-02","2020-07-03","2020-07-04","2020-07-05","2020-07-06","2020-07-07","2020-07-08"]}
//public int code { get; set; }
//public string message { get; set; }
//public int ttl { get; set; }
public List<string> data { get; set; }
}
public class DanmuFromWeb
{
//public int code { get; set; }
public string message { get; set; }
//public int ttl { get; set; }
}
}

@ -1,49 +0,0 @@
using System.Collections.Generic;
namespace Core.entity
{
/// <summary>
/// https://api.bilibili.com/x/v3/fav/folder/created/list?pn=1&ps=10&up_mid=42018135
/// https://api.bilibili.com/x/v3/fav/folder/collected/list?pn=1&ps=20&up_mid=42018135
/// 上述两个网址都使用同一个class解析
/// </summary>
public class FavFolder
{
//public int code { get; set; }
public FavFolderData data { get; set; }
//public string message { get; set; }
//public int ttl { get; set; }
}
public class FavFolderData
{
public int count { get; set; }
public List<FavFolderDataList> list { get; set; }
}
public class FavFolderDataList
{
public int attr { get; set; }
public string cover { get; set; }
public int cover_type { get; set; }
public long ctime { get; set; }
public int fav_state { get; set; }
public long fid { get; set; }
public long id { get; set; }
public string intro { get; set; }
public int media_count { get; set; }
public long mid { get; set; }
public long mtime { get; set; }
public int state { get; set; }
public string title { get; set; }
public FavFolderDataUpper upper { get; set; }
}
public class FavFolderDataUpper
{
public string face { get; set; }
public long mid { get; set; }
public string name { get; set; }
}
}

@ -1,54 +0,0 @@
using System.Collections.Generic;
namespace Core.entity
{
// https://api.bilibili.com/x/v3/fav/resource/list?media_id=94341835&pn=1&ps=20
public class FavResource
{
//public int code { get; set; }
public FavResourceData data { get; set; }
//public string message { get; set; }
//public int ttl { get; set; }
}
public class FavResourceData
{
//public FavResourceDataInfo info{get;set;}
public List<FavResourceDataMedia> medias { get; set; }
}
public class FavResourceDataMedia
{
public int attr { get; set; }
public string bv_id { get; set; }
public string bvid { get; set; }
public FavResourceDataMediaCnt_info cnt_info { get; set; }
public string cover { get; set; }
public long ctime { get; set; }
public long duration { get; set; }
public long fav_time { get; set; }
public long id { get; set; }
public string intro { get; set; }
public string link { get; set; }
public int page { get; set; }
public long pubtime { get; set; }
public string title { get; set; }
public int type { get; set; }
public FavResourceDataMediaUpper upper { get; set; }
}
public class FavResourceDataMediaCnt_info
{
public long collect { get; set; }
public long danmaku { get; set; }
public long play { get; set; }
}
public class FavResourceDataMediaUpper
{
public string face { get; set; }
public long mid { get; set; }
public string name { get; set; }
}
}

@ -1,50 +0,0 @@
// 注释掉未使用的属性
namespace Core.entity
{
public class LoginUrl
{
//public int code { get; set; }
public LoginData data { get; set; }
public bool status { get; set; }
//public long ts { get; set; }
}
public class LoginData
{
public string oauthKey { get; set; }
public string url { get; set; }
}
public class LoginInfo
{
public int code { get; set; }
public bool status { get; set; }
public string message { get; set; }
public string url { get; set; }
}
public class LoginInfoScanning
{
public bool status { get; set; }
public int data { get; set; }
public string message { get; set; }
}
public class LoginInfoReady
{
// {"code":0,"status":true,"ts":1594131179,"data":{"url":"https://passport.biligame.com/crossDomain?DedeUserID=42018135&DedeUserID__ckMd5=44e22fa30fe34ac4&Expires=15551000&SESSDATA=92334e44%2C1609683179%2C54db1%2A71&bili_jct=979b94fb3879c68574f02800d8a39484&gourl=https%3A%2F%2Fwww.bilibili.com"}}
public int code { get; set; }
public bool status { get; set; }
//public long ts { get; set; }
public LoginInfoData data { get; set; }
}
public class LoginInfoData
{
public string url { get; set; }
}
}

@ -1,96 +0,0 @@
namespace Core.entity
{
// https://api.bilibili.com/x/space/myinfo
public class MyInfo
{
//public int code { get; set; }
public MyInfoData data { get; set; }
public string message { get; set; }
//public int ttl { get; set; }
}
public class MyInfoData
{
public long birthday { get; set; }
public float coins { get; set; }
public int email_status { get; set; }
public string face { get; set; }
public int follower { get; set; }
public int following { get; set; }
public int identification { get; set; }
public int is_deleted { get; set; }
public int is_fake_account { get; set; }
public int is_tourist { get; set; }
public int jointime { get; set; }
public int level { get; set; }
public MyInfoDataLevelExp level_exp { get; set; }
public long mid { get; set; }
public int moral { get; set; }
public string name { get; set; }
public MyInfoDataNamePlate nameplate { get; set; }
public MyInfoDataOfficial official { get; set; }
public MyInfoDataPendant pendant { get; set; }
public int pin_prompting { get; set; }
public int rank { get; set; }
public string sex { get; set; }
public string sign { get; set; }
public int silence { get; set; }
public int tel_status { get; set; }
public MyInfoDataVip vip { get; set; }
}
public class MyInfoDataLevelExp
{
public int current_exp { get; set; }
public int current_level { get; set; }
public int current_min { get; set; }
public int next_exp { get; set; }
}
public class MyInfoDataNamePlate
{
public string condition { get; set; }
public string image { get; set; }
public string image_small { get; set; }
public string level { get; set; }
public string name { get; set; }
public int nid { get; set; }
}
public class MyInfoDataOfficial
{
public string desc { get; set; }
public int role { get; set; }
public string title { get; set; }
public int type { get; set; }
}
public class MyInfoDataPendant
{
public int expire { get; set; }
public string image { get; set; }
public string image_enhance { get; set; }
public string name { get; set; }
public int pid { get; set; }
}
public class MyInfoDataVip
{
public int avatar_subscript { get; set; }
public long due_date { get; set; }
public MyInfoDataVipLabel label { get; set; }
public string nickname_color { get; set; }
public int status { get; set; }
public int theme_type { get; set; }
public int type { get; set; }
public int vip_pay_type { get; set; }
}
public class MyInfoDataVipLabel
{
public string label_theme { get; set; }
public string path { get; set; }
public string text { get; set; }
}
}

@ -1,88 +0,0 @@
// 注释掉未使用的属性
namespace Core.entity
{
public class Nav
{
//public int code { get; set; }
public NavData data { get; set; }
public string message { get; set; }
//public int ttl { get; set; }
}
public class NavData
{
//public int allowance_count { get; set; }
//public int answer_status { get; set; }
//public int email_verified { get; set; }
public string face { get; set; }
//public bool has_shop { get; set; }
public bool isLogin { get; set; }
//public NavDataLevelInfo level_info { get; set; }
public long mid { get; set; }
//public int mobile_verified { get; set; }
public float money { get; set; }
//public int moral { get; set; }
//public NavDataOfficial official { get; set; }
//public NavDataOfficialVerify officialVerify { get; set; }
//public NavDataPendant pendant { get; set; }
//public int scores { get; set; }
//public string shop_url { get; set; }
public string uname { get; set; }
//public long vipDueDate { get; set; }
public int vipStatus { get; set; }
//public int vipType { get; set; }
//public int vip_avatar_subscript { get; set; }
//public NavDataVipLabel vip_label { get; set; }
//public string vip_nickname_color { get; set; }
//public int vip_pay_type { get; set; }
//public int vip_theme_type { get; set; }
public NavDataWallet wallet { get; set; }
}
public class NavDataLevelInfo
{
public int current_exp { get; set; }
public int current_level { get; set; }
public int current_min { get; set; }
//public int next_exp { get; set; } // 当等级为6时next_exp为string类型值为"--"
}
//public class NavDataOfficial
//{
// public string desc { get; set; }
// public int role { get; set; }
// public string title { get; set; }
// public int type { get; set; }
//}
//public class NavDataOfficialVerify
//{
// public string desc { get; set; }
// public int type { get; set; }
//}
//public class NavDataPendant
//{
// public int expire { get; set; }
// public string image { get; set; }
// public string image_enhance { get; set; }
// public string name { get; set; }
// public int pid { get; set; }
//}
//public class NavDataVipLabel
//{
// public string label_theme { get; set; }
// public string path { get; set; }
// public string text { get; set; }
//}
public class NavDataWallet
{
public float bcoin_balance { get; set; }
public float coupon_balance { get; set; }
public long coupon_due_time { get; set; }
public long mid { get; set; }
}
}

@ -1,89 +0,0 @@
using System.Collections.Generic;
// 注释掉未使用的属性
namespace Core.entity
{
public class PlayUrl
{
//public int code { get; set; }
public PlayUrlData data { get; set; }
public PlayUrlData result { get; set; }
//public string message { get; set; }
//public int ttl { get; set; }
}
public class PlayUrlData
{
public List<string> accept_description { get; set; }
//public string accept_format { get; set; }
public List<int> accept_quality { get; set; }
public PlayUrlDataDash dash { get; set; }
//public string format { get; set; }
//public string from { get; set; }
//public string message { get; set; }
public int quality { get; set; }
//public string result { get; set; }
//public string seek_param { get; set; }
//public string seek_type { get; set; }
//public string timelength { get; set; }
//public int video_codecid { get; set; }
public List<PlayUrlDUrl> durl { get; set; }
}
public class PlayUrlDataDash
{
public List<PlayUrlDataDashVideo> audio { get; set; }
public long duration { get; set; }
//public float minBufferTime { get; set; }
//public float min_buffer_time { get; set; }
public List<PlayUrlDataDashVideo> video { get; set; }
}
public class PlayUrlDataDashVideo
{
//public PlayUrlDataDashSegmentBaseCls SegmentBase { get; set; }
public List<string> backupUrl { get; set; }
public List<string> backup_url { get; set; }
//public long bandwidth { get; set; }
public string baseUrl { get; set; }
public string base_url { get; set; }
//public int codecid { get; set; }
public string codecs { get; set; }
public string frameRate { get; set; }
//public string frame_rate { get; set; }
public int height { get; set; }
public int id { get; set; }
public string mimeType { get; set; }
//public string mime_type { get; set; }
//public string sar { get; set; }
//public PlayUrlDataDashSegmentBaseCls2 segment_base { get; set; }
//public int startWithSap { get; set; }
//public int start_with_sap { get; set; }
public int width { get; set; }
}
//public class PlayUrlDataDashSegmentBaseCls
//{
// public string Initialization { get; set; }
// public string indexRange { get; set; }
//}
//public class PlayUrlDataDashSegmentBaseCls2
//{
// public string initialization { get; set; }
// public string index_range { get; set; }
//}
public class PlayUrlDUrl
{
//public int order { get; set; }
public long length { get; set; }
public long size { get; set; }
//public string ahead { get; set; }
//public string vhead { get; set; }
public string url { get; set; }
public List<string> backup_url { get; set; }
}
}

@ -1,21 +0,0 @@
namespace Core.entity
{
// https://api.bilibili.com/x/relation/stat?vmid=42018135
public class Stat
{
//public int code { get; set; }
public StatData data { get; set; }
//public string message { get; set; }
//public int ttl { get; set; }
}
public class StatData
{
public int black { get; set; } // 黑名单
public int follower { get; set; } // 粉丝数
public int following { get; set; } // 关注数
public long mid { get; set; } // 用户id
public int whisper { get; set; } // 悄悄关注数
}
}

@ -1,31 +0,0 @@
namespace Core.entity
{
// https://space.bilibili.com/ajax/settings/getSettings?mid=42018135
public class UserSettings
{
public UserSettingsData data { get; set; }
public bool status { get; set; }
}
public class UserSettingsData
{
// ……
public UserSettingsDataToutu toutu { get; set; }
}
public class UserSettingsDataToutu
{
public string android_img { get; set; }
public long expire { get; set; }
public string ipad_img { get; set; }
public string iphone_img { get; set; }
public string l_img { get; set; }
public int platform { get; set; }
public string s_img { get; set; }
public int sid { get; set; }
public string thumbnail_img { get; set; }
}
}

@ -1,28 +0,0 @@
namespace Core.entity
{
// https://api.bilibili.com/x/web-interface/view/detail?bvid=BV1TJ411h7E6
public class VideoDetail
{
//public int code { get; set; }
public VideoDetailData data { get; set; }
//public string message { get; set; }
//public int ttl { get; set; }
}
public class VideoDetailData
{
//public VideoDetailDataCard Card { get; set; }
//public VideoDetailDataRelated Related { get; set; }
//public VideoDetailDataReply Reply { get; set; }
//public VideoDetailDataTags Tags { get; set; }
public VideoDetailDataView View { get; set; }
}
public class VideoDetailDataView
{
// ...
public string redirect_url { get; set; }
// ...
}
}

@ -1,207 +0,0 @@
using System.Collections.Generic;
// 注释掉未使用的属性
namespace Core.entity
{
public class VideoView
{
public int code { get; set; }
public VideoViewData data { get; set; }
public string message { get; set; }
public int ttl { get; set; }
}
public class VideoViewData
{
public long aid { get; set; }
//public long attribute { get; set; }
public string bvid { get; set; }
//public long cid { get; set; }
//public int copyright { get; set; }
public long ctime { get; set; }
public string desc { get; set; }
//public VideoViewDataDimension dimension { get; set; }
//public long duration { get; set; }
//public string dynamic { get; set; }
//public VideoViewDataLabel label { get; set; }
//public long mission_id { get; set; }
//public bool no_cache { get; set; }
public VideoViewDataOwner owner { get; set; }
public List<VideoViewDataPages> pages { get; set; }
public string pic { get; set; }
public long pubdate { get; set; }
//public VideoViewDataRights rights { get; set; }
//public long season_id { get; set; }
public VideoViewDataStat stat { get; set; }
//public int state { get; set; }
//public VideoViewDataSubtitle subtitle { get; set; }
public long tid { get; set; }
public string title { get; set; }
public string tname { get; set; }
//public VideoViewDataUgcSeason ugc_season { get; set; }
//public int videos { get; set; }
}
public class VideoViewDataDimension
{
public int width { get; set; }
public int height { get; set; }
//public int rotate { get; set; }
}
//public class VideoViewDataLabel
//{
// public int type { get; set; }
//}
public class VideoViewDataOwner
{
public string face { get; set; }
public long mid { get; set; }
public string name { get; set; }
}
public class VideoViewDataPages
{
public long cid { get; set; }
public VideoViewDataDimension dimension { get; set; }
public long duration { get; set; }
//public string from { get; set; }
public int page { get; set; }
public string part { get; set; }
//public string vid { get; set; }
//public string weblink { get; set; }
}
//public class VideoViewDataRights
//{
// public int autoplay { get; set; }
// public int bp { get; set; }
// public int download { get; set; }
// public int elec { get; set; }
// public int hd5 { get; set; }
// public int is_cooperation { get; set; }
// public int movie { get; set; }
// public int no_background { get; set; }
// public int no_reprint { get; set; }
// public int pay { get; set; }
// public int ugc_pay { get; set; }
// public int ugc_pay_preview { get; set; }
//}
public class VideoViewDataStat
{
public long aid { get; set; }
public long coin { get; set; }
public long danmaku { get; set; }
public long dislike { get; set; }
public string evaluation { get; set; }
public long favorite { get; set; }
public long his_rank { get; set; }
public long like { get; set; }
public long now_rank { get; set; }
public long reply { get; set; }
public long share { get; set; }
public long view { get; set; }
}
//public class VideoViewDataSubtitle
//{
// public bool allow_submit { get; set; }
// //public List<string> list { get; set; }
//}
//public class VideoViewDataUgcSeason
//{
// public int attribute { get; set; }
// public string cover { get; set; }
// public int ep_count { get; set; }
// public long id { get; set; }
// public string intro { get; set; }
// public long mid { get; set; }
// public List<VideoViewDataUgcSeasonSections> sections { get; set; }
// public int sign_state { get; set; }
// public VideoViewDataStat stat { get; set; }
// public string title { get; set; }
//}
//public class VideoViewDataUgcSeasonSections
//{
// public List<VideoViewDataUgcSeasonSectionsEpisodes> episodes { get; set; }
// public long id { get; set; }
// public long season_id { get; set; }
// public string title { get; set; }
// public int type { get; set; }
//}
//public class VideoViewDataUgcSeasonStat
//{
// public long coin { get; set; }
// public long danmaku { get; set; }
// public long favorite { get; set; }
// public long his_rank { get; set; }
// public long like { get; set; }
// public long now_rank { get; set; }
// public long reply { get; set; }
// public long season_id { get; set; }
// public long share { get; set; }
// public long view { get; set; }
//}
//public class VideoViewDataUgcSeasonSectionsEpisodes
//{
// public long aid { get; set; }
// public VideoViewDataUgcSeasonSectionsEpisodesArc arc { get; set; }
// public int attribute { get; set; }
// public long cid { get; set; }
// public long id { get; set; }
// public VideoViewDataUgcSeasonSectionsEpisodesPage page { get; set; }
// public long season_id { get; set; }
// public long section_id { get; set; }
// public string title { get; set; }
//}
//public class VideoViewDataUgcSeasonSectionsEpisodesArc
//{
// public long aid { get; set; }
// public int copyright { get; set; }
// public long ctime { get; set; }
// public string desc { get; set; }
// public VideoViewDataDimension dimension { get; set; }
// public long duration { get; set; }
// public string dynamic { get; set; }
// public VideoViewDataOwner owner { get; set; }
// public string pic { get; set; }
// public long pubdate { get; set; }
// public VideoViewDataRights rights { get; set; }
// public VideoViewDataStat stat { get; set; }
// public int state { get; set; }
// public long tid { get; set; }
// public string title { get; set; }
// public string tname { get; set; }
// public int videos { get; set; }
//}
//public class VideoViewDataUgcSeasonSectionsEpisodesPage
//{
// public long cid { get; set; }
// public VideoViewDataDimension dimension { get; set; }
// public long duration { get; set; }
// public string from { get; set; }
// public int page { get; set; }
// public string part { get; set; }
// public string vid { get; set; }
// public string weblink { get; set; }
//}
// https://api.bilibili.com/x/player/pagelist?bvid={bvid}&jsonp=jsonp
public class Pagelist
{
public int code { get; set; }
public List<VideoViewDataPages> data { get; set; }
public string message { get; set; }
public int ttl { get; set; }
}
}

@ -1,101 +0,0 @@
using Newtonsoft.Json;
using System.Collections.Generic;
namespace Core.entity2.history
{
// https://api.bilibili.com/x/web-interface/history/cursor?max={startId}&view_at={startTime}&ps={ps}&business={businessStr}
[JsonObject]
public class HistoryOrigin : BaseEntity
{
//[JsonProperty("code")]
//public int Code { get; set; }
[JsonProperty("data")]
public HistoryData Data { get; set; }
//[JsonProperty("message")]
//public string Message { get; set; }
//[JsonProperty("ttl")]
//public int Ttl { get; set; }
}
[JsonObject]
public class HistoryData : BaseEntity
{
[JsonProperty("cursor")]
public HistoryDataCursor Cursor { get; set; }
[JsonProperty("list")]
public List<HistoryDataList> List { get; set; }
//public List<HistoryDataTab> tab { get; set; }
}
[JsonObject]
public class HistoryDataCursor : BaseEntity
{
[JsonProperty("business")]
public string Business { get; set; }
[JsonProperty("max")]
public long Max { get; set; }
[JsonProperty("ps")]
public int Ps { get; set; }
[JsonProperty("view_at")]
public long ViewAt { get; set; }
}
[JsonObject]
public class HistoryDataList : BaseEntity
{
[JsonProperty("author_face")]
public string AuthorFace { get; set; }
[JsonProperty("author_mid")]
public long AuthorMid { get; set; }
[JsonProperty("author_name")]
public string AuthorName { get; set; }
// ...
[JsonProperty("cover")]
public string Cover { get; set; }
// ...
[JsonProperty("duration")]
public long Duration { get; set; }
[JsonProperty("history")]
public HistoryDataListHistory History { get; set; }
// ...
[JsonProperty("new_desc")]
public string NewDesc { get; set; }
[JsonProperty("progress")]
public long Progress { get; set; }
[JsonProperty("show_title")]
public string ShowTitle { get; set; }
[JsonProperty("tag_name")]
public string TagName { get; set; }
[JsonProperty("title")]
public string Title { get; set; }
// ...
[JsonProperty("uri")]
public string Uri { get; set; }
[JsonProperty("videos")]
public int Videos { get; set; }
[JsonProperty("view_at")]
public long ViewAt { get; set; }
}
[JsonObject]
public class HistoryDataListHistory : BaseEntity
{
[JsonProperty("business")]
public string Business { get; set; }
[JsonProperty("bvid")]
public string Bvid { get; set; }
[JsonProperty("cid")]
public long Cid { get; set; }
[JsonProperty("dt")]
public int Dt { get; set; }
[JsonProperty("epid")]
public long Epid { get; set; }
[JsonProperty("oid")]
public long Oid { get; set; }
[JsonProperty("page")]
public int Page { get; set; }
[JsonProperty("part")]
public string Part { get; set; }
}
}

@ -1,60 +0,0 @@
using Newtonsoft.Json;
using System.Collections.Generic;
namespace Core.entity2.history
{
// https://api.bilibili.com/x/v2/history/toview/web
[JsonObject]
public class ToViewOrigin : BaseEntity
{
//public int code { get; set; }
[JsonProperty("data")]
public ToViewData Data { get; set; }
//public string message { get; set; }
//public int ttl { get; set; }
}
[JsonObject]
public class ToViewData : BaseEntity
{
[JsonProperty("count")]
public int Count { get; set; }
[JsonProperty("list")]
public List<ToViewDataList> List { get; set; }
}
[JsonObject]
public class ToViewDataList : BaseEntity
{
[JsonProperty("add_at")]
public long AddAt { get; set; }
[JsonProperty("aid")]
public long Aid { get; set; }
//public long attribute { get; set; }
[JsonProperty("bvid")]
public string Bvid { get; set; }
[JsonProperty("cid")]
public long Cid { get; set; }
// ...
[JsonProperty("owner")]
public ToViewDataListOwner Owner { get; set; }
// ...
[JsonProperty("pic")]
public string Cover { get; set; }
// ...
[JsonProperty("title")]
public string Title { get; set; }
}
[JsonObject]
public class ToViewDataListOwner : BaseEntity
{
[JsonProperty("face")]
public string Face { get; set; }
[JsonProperty("mid")]
public long Mid { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
}
}

@ -1,103 +0,0 @@
using Newtonsoft.Json;
using System.Collections.Generic;
namespace Core.entity2.users
{
// https://api.bilibili.com/x/space/bangumi/follow/list?vmid={mid}&type={type}&pn={pn}&ps={ps}
[JsonObject]
public class BangumiFollowOrigin : BaseEntity
{
//[JsonProperty("code")]
//public int Code { get; set; }
[JsonProperty("data")]
public BangumiFollowData Data { get; set; }
//[JsonProperty("message")]
//public string Message { get; set; }
//[JsonProperty("ttl")]
//public int Ttl { get; set; }
}
[JsonObject]
public class BangumiFollowData : BaseEntity
{
[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; }
}
[JsonObject]
public class BangumiFollow : BaseEntity
{
[JsonProperty("areas")]
public List<BangumiFollowAreas> Areas { get; set; }
[JsonProperty("badge")]
public string Badge { get; set; }
[JsonProperty("badge_ep")]
public string BadgeEp { get; set; }
// ...
[JsonProperty("cover")]
public string Cover { get; set; }
[JsonProperty("evaluate")]
public string Evaluate { get; set; }
// ...
[JsonProperty("media_id")]
public long MediaId { get; set; }
// ...
[JsonProperty("new_ep")]
public BangumiFollowNewEp NewEp { get; set; }
[JsonProperty("progress")]
public string Progress { get; set; }
// ...
[JsonProperty("season_id")]
public long SeasonId { get; set; }
[JsonProperty("season_status")]
public int SeasonStatus { get; set; }
[JsonProperty("season_title")]
public string SeasonTitle { 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("total_count")]
public int TotalCount { get; set; }
[JsonProperty("url")]
public string Url { get; set; }
}
[JsonObject]
public class BangumiFollowAreas : BaseEntity
{
[JsonProperty("id")]
public int Id { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
}
[JsonObject]
public class BangumiFollowNewEp : BaseEntity
{
[JsonProperty("cover")]
public string Cover { get; set; }
[JsonProperty("duration")]
public long Duration { get; set; }
[JsonProperty("id")]
public long Id { get; set; }
[JsonProperty("index_show")]
public string IndexShow { get; set; }
[JsonProperty("long_title")]
public string LongTitle { get; set; }
[JsonProperty("pub_time")]
public string PubTime { get; set; }
[JsonProperty("title")]
public string Title { get; set; }
}
}

@ -1,33 +0,0 @@
using Newtonsoft.Json;
using System.Collections.Generic;
namespace Core.entity2.users
{
// https://api.bilibili.com/x/relation/tags
[JsonObject]
public class FollowingGroupOrigin : BaseEntity
{
//[JsonProperty("code")]
//public int Code { get; set; }
[JsonProperty("data")]
public List<FollowingGroup> Data { get; set; }
//[JsonProperty("message")]
//public string Message { get; set; }
//[JsonProperty("ttl")]
//public int Ttl { get; set; }
}
[JsonObject]
public class FollowingGroup : BaseEntity
{
[JsonProperty("count")]
public int Count { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("tagid")]
public int TagId { get; set; }
[JsonProperty("tip")]
public string Tip { get; set; }
}
}

@ -1,42 +0,0 @@
using Newtonsoft.Json;
using System.Collections.Generic;
namespace Core.entity2.users
{
// https://api.bilibili.com/x/relation/tag?tagid={tagId}&pn={pn}&ps={ps}&order_type={orderType}
[JsonObject]
public class FollowingGroupContentOrigin : BaseEntity
{
//[JsonProperty("code")]
//public int Code { get; set; }
[JsonProperty("data")]
public List<FollowingGroupContent> Data { get; set; }
//[JsonProperty("message")]
//public string Message { get; set; }
//[JsonProperty("ttl")]
//public int Ttl { get; set; }
}
[JsonObject]
public class FollowingGroupContent : BaseEntity
{
[JsonProperty("attribute")]
public int Attribute { get; set; }
// ...
[JsonProperty("face")]
public string Face { get; set; }
[JsonProperty("mid")]
public long Mid { get; set; }
// ...
[JsonProperty("sign")]
public string Sign { get; set; }
[JsonProperty("special")]
public int Special { get; set; }
[JsonProperty("tag")]
public List<long> Tag { get; set; }
[JsonProperty("uname")]
public string Name { get; set; }
// ...
}
}

@ -1,166 +0,0 @@
using Newtonsoft.Json;
namespace Core.entity2.users
{
// https://api.bilibili.com/x/space/myinfo
[JsonObject]
public class MyInfoOrigin : BaseEntity
{
//[JsonProperty("code")]
//public int Code { get; set; }
[JsonProperty("data")]
public MyInfo Data { get; set; }
//[JsonProperty("message")]
//public string Message { get; set; }
//[JsonProperty("ttl")]
//public int Ttl { get; set; }
}
[JsonObject]
public class MyInfo : BaseEntity
{
[JsonProperty("birthday")]
public long Birthday { get; set; }
[JsonProperty("coins")]
public float Coins { get; set; }
[JsonProperty("email_status")]
public int EmailStatus { get; set; }
[JsonProperty("face")]
public string Face { get; set; }
[JsonProperty("follower")]
public int Follower { get; set; }
[JsonProperty("following")]
public int Following { get; set; }
[JsonProperty("identification")]
public int Identification { get; set; }
[JsonProperty("is_deleted")]
public int IsDeleted { get; set; }
[JsonProperty("is_fake_account")]
public int IsFakeAccount { get; set; }
[JsonProperty("is_tourist")]
public int IsTourist { get; set; }
[JsonProperty("jointime")]
public int Jointime { get; set; }
[JsonProperty("level")]
public int Level { get; set; }
[JsonProperty("level_exp")]
public MyInfoLevelExp LevelExp { get; set; }
[JsonProperty("mid")]
public long Mid { get; set; }
[JsonProperty("moral")]
public int Moral { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("nameplate")]
public MyInfoNamePlate Nameplate { get; set; }
[JsonProperty("official")]
public MyInfoOfficial Official { get; set; }
[JsonProperty("pendant")]
public MyInfoPendant Pendant { get; set; }
[JsonProperty("pin_prompting")]
public int PinPrompting { get; set; }
[JsonProperty("rank")]
public int Rank { get; set; }
[JsonProperty("sex")]
public string Sex { get; set; }
[JsonProperty("sign")]
public string Sign { get; set; }
[JsonProperty("silence")]
public int Silence { get; set; }
[JsonProperty("tel_status")]
public int TelStatus { get; set; }
[JsonProperty("vip")]
public MyInfoVip Vip { get; set; }
}
[JsonObject]
public class MyInfoLevelExp : BaseEntity
{
[JsonProperty("current_exp")]
public int CurrentExp { get; set; }
[JsonProperty("current_level")]
public int CurrentLevel { get; set; }
[JsonProperty("current_min")]
public int CurrentMin { get; set; }
[JsonProperty("next_exp")]
public int NextExp { get; set; }
}
[JsonObject]
public class MyInfoNamePlate : BaseEntity
{
[JsonProperty("condition")]
public string Condition { get; set; }
[JsonProperty("image")]
public string Image { get; set; }
[JsonProperty("image_small")]
public string ImageSmall { get; set; }
[JsonProperty("level")]
public string Level { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("nid")]
public int Nid { get; set; }
}
[JsonObject]
public class MyInfoOfficial : BaseEntity
{
[JsonProperty("desc")]
public string Desc { get; set; }
[JsonProperty("role")]
public int Role { get; set; }
[JsonProperty("title")]
public string Title { get; set; }
[JsonProperty("type")]
public int Type { get; set; }
}
[JsonObject]
public class MyInfoPendant : BaseEntity
{
[JsonProperty("expire")]
public int Expire { get; set; }
[JsonProperty("image")]
public string Image { get; set; }
[JsonProperty("image_enhance")]
public string ImageEnhance { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("pid")]
public int Pid { get; set; }
}
[JsonObject]
public class MyInfoVip : BaseEntity
{
[JsonProperty("avatar_subscript")]
public int AvatarSubscript { get; set; }
[JsonProperty("due_date")]
public long DueDate { get; set; }
[JsonProperty("label")]
public MyInfoDataVipLabel Label { get; set; }
[JsonProperty("nickname_color")]
public string NicknameColor { get; set; }
[JsonProperty("status")]
public int Status { get; set; }
[JsonProperty("theme_type")]
public int ThemeType { get; set; }
[JsonProperty("type")]
public int Type { get; set; }
[JsonProperty("vip_pay_type")]
public int VipPayType { get; set; }
}
[JsonObject]
public class MyInfoDataVipLabel : BaseEntity
{
[JsonProperty("label_theme")]
public string LabelTheme { get; set; }
[JsonProperty("path")]
public string Path { get; set; }
[JsonProperty("text")]
public string Text { get; set; }
}
}

@ -1,43 +0,0 @@
using Newtonsoft.Json;
using System.Collections.Generic;
namespace Core.entity2.users
{
// https://api.bilibili.com/x/relation/blacks?pn={pn}&ps={ps}
[JsonObject]
public class RelationBlackOrigin : BaseEntity
{
//[JsonProperty("code")]
//public int Code { get; set; }
[JsonProperty("data")]
public List<RelationBlack> Data { get; set; }
//[JsonProperty("message")]
//public string Message { get; set; }
//[JsonProperty("ttl")]
//public int Ttl { get; set; }
}
public class RelationBlack : BaseEntity
{
[JsonProperty("attribute")]
public int Attribute { get; set; }
// ...
[JsonProperty("face")]
public string Face { get; set; }
[JsonProperty("mid")]
public long Mid { get; set; }
[JsonProperty("mtime")]
public long Mtime { get; set; }
// ...
[JsonProperty("sign")]
public string Sign { get; set; }
[JsonProperty("special")]
public int Special { get; set; }
[JsonProperty("tag")]
public List<long> Tag { get; set; }
[JsonProperty("uname")]
public string Name { get; set; }
// ...
}
}

@ -1,56 +0,0 @@
using Newtonsoft.Json;
using System.Collections.Generic;
namespace Core.entity2.users
{
// 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}
[JsonObject]
public class RelationFollowOrigin : BaseEntity
{
//[JsonProperty("code")]
//public int Code { get; set; }
[JsonProperty("data")]
public RelationFollow Data { get; set; }
//[JsonProperty("message")]
//public string Message { get; set; }
//[JsonProperty("ttl")]
//public int Ttl { get; set; }
}
[JsonObject]
public class RelationFollow : BaseEntity
{
[JsonProperty("list")]
public List<RelationFollowInfo> List { get; set; }
//[JsonProperty("re_version")]
//public long reVersion { get; set; }
[JsonProperty("total")]
public int Total { get; set; }
}
[JsonObject]
public class RelationFollowInfo : BaseEntity
{
[JsonProperty("attribute")]
public int Attribute { get; set; }
// ...
[JsonProperty("face")]
public string Face { get; set; }
[JsonProperty("mid")]
public long Mid { get; set; }
[JsonProperty("mtime")]
public long Mtime { get; set; }
// ...
[JsonProperty("sign")]
public string Sign { get; set; }
[JsonProperty("special")]
public int Special { get; set; }
[JsonProperty("tag")]
public List<long> Tag { get; set; }
[JsonProperty("uname")]
public string Name { get; set; }
// ...
}
}

@ -1,43 +0,0 @@
using Newtonsoft.Json;
using System.Collections.Generic;
namespace Core.entity2.users
{
// https://api.bilibili.com/x/relation/whispers?pn={pn}&ps={ps}
[JsonObject]
public class RelationWhisperOrigin : BaseEntity
{
//[JsonProperty("code")]
//public int Code { get; set; }
[JsonProperty("data")]
public List<RelationWhisper> Data { get; set; }
//[JsonProperty("message")]
//public string Message { get; set; }
//[JsonProperty("ttl")]
//public int Ttl { get; set; }
}
public class RelationWhisper : BaseEntity
{
[JsonProperty("attribute")]
public int Attribute { get; set; }
// ...
[JsonProperty("face")]
public string Face { get; set; }
[JsonProperty("mid")]
public long Mid { get; set; }
[JsonProperty("mtime")]
public long Mtime { get; set; }
// ...
[JsonProperty("sign")]
public string Sign { get; set; }
[JsonProperty("special")]
public int Special { get; set; }
[JsonProperty("tag")]
public List<long> Tag { get; set; }
[JsonProperty("uname")]
public string Name { get; set; }
// ...
}
}

@ -1,48 +0,0 @@
using Newtonsoft.Json;
using System.Collections.Generic;
namespace Core.entity2.users
{
// https://api.bilibili.com/x/space/channel/list?mid=
[JsonObject]
public class SpaceChannelOrigin : BaseEntity
{
//[JsonProperty("code")]
//public int Code { get; set; }
[JsonProperty("data")]
public SpaceChannel Data { get; set; }
//[JsonProperty("message")]
//public string Message { get; set; }
//[JsonProperty("ttl")]
//public int Ttl { get; set; }
}
[JsonObject]
public class SpaceChannel : BaseEntity
{
[JsonProperty("count")]
public int Count { get; set; }
[JsonProperty("list")]
public List<SpaceChannelList> List { get; set; }
}
[JsonObject]
public class SpaceChannelList : BaseEntity
{
[JsonProperty("cid")]
public long Cid { get; set; }
[JsonProperty("count")]
public int Count { get; set; }
[JsonProperty("cover")]
public string Cover { get; set; }
[JsonProperty("intro")]
public string Intro { get; set; }
[JsonProperty("mid")]
public long Mid { get; set; }
[JsonProperty("mtime")]
public long Mtime { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
}
}

@ -1,103 +0,0 @@
using Newtonsoft.Json;
using System.Collections.Generic;
namespace Core.entity2.users
{
// https://api.bilibili.com/x/space/channel/video?mid={mid}&cid={cid}&pn={pn}&ps={ps}
[JsonObject]
public class SpaceChannelVideoOrigin : BaseEntity
{
//[JsonProperty("code")]
//public int Code { get; set; }
[JsonProperty("data")]
public SpaceChannelVideo Data { get; set; }
//[JsonProperty("message")]
//public string Message { get; set; }
//[JsonProperty("ttl")]
//public int Ttl { get; set; }
}
[JsonObject]
public class SpaceChannelVideo : BaseEntity
{
[JsonProperty("list")]
public SpaceChannelVideoList List { get; set; }
[JsonProperty("page")]
public SpaceChannelVideoPage Page { get; set; }
}
[JsonObject]
public class SpaceChannelVideoList : BaseEntity
{
[JsonProperty("archives")]
public List<SpaceChannelVideoArchive> Archives { get; set; }
[JsonProperty("cid")]
public long Cid { get; set; }
[JsonProperty("count")]
public int Count { get; set; }
[JsonProperty("cover")]
public string Cover { get; set; }
[JsonProperty("intro")]
public string Intro { get; set; }
[JsonProperty("mid")]
public long Mid { get; set; }
[JsonProperty("mtime")]
public long Mtime { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
}
[JsonObject]
public class SpaceChannelVideoPage : BaseEntity
{
[JsonProperty("count")]
public int Count { get; set; }
[JsonProperty("num")]
public int Num { get; set; }
[JsonProperty("size")]
public int Size { get; set; }
}
[JsonObject]
public class SpaceChannelVideoArchive : BaseEntity
{
[JsonProperty("aid")]
public long Aid { get; set; }
[JsonProperty("bvid")]
public string Bvid { get; set; }
[JsonProperty("cid")]
public long Cid { get; set; }
// ...
[JsonProperty("ctime")]
public long Ctime { get; set; }
[JsonProperty("desc")]
public string Desc { get; set; }
// ...
[JsonProperty("duration")]
public long Duration { get; set; }
// ...
[JsonProperty("pic")]
public string Pic { get; set; }
[JsonProperty("pubdate")]
public long Pubdate { get; set; }
// ...
[JsonProperty("stat")]
public SpaceChannelVideoArchiveStat Stat { get; set; }
// ...
[JsonProperty("tid")]
public int Tid { get; set; }
[JsonProperty("title")]
public string Title { get; set; }
[JsonProperty("tname")]
public string Tname { get; set; }
}
[JsonObject]
public class SpaceChannelVideoArchiveStat : BaseEntity
{
// ...
[JsonProperty("view")]
public long View { get; set; }
}
}

@ -1,65 +0,0 @@
using Newtonsoft.Json;
using System.Collections.Generic;
namespace Core.entity2.users
{
// https://api.bilibili.com/pugv/app/web/season/page?mid={mid}&pn={pn}&ps={ps}
[JsonObject]
public class SpaceCheeseOrigin : BaseEntity
{
//[JsonProperty("code")]
//public int Code { get; set; }
[JsonProperty("data")]
public SpaceCheeseList Data { get; set; }
//[JsonProperty("message")]
//public string Message { get; set; }
//[JsonProperty("ttl")]
//public int Ttl { get; set; }
}
[JsonObject]
public class SpaceCheeseList : BaseEntity
{
[JsonProperty("items")]
public List<SpaceCheese> Items { get; set; }
[JsonProperty("page")]
public SpaceCheesePage Page { get; set; }
}
[JsonObject]
public class SpaceCheese : BaseEntity
{
[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; }
}
[JsonObject]
public class SpaceCheesePage : BaseEntity
{
[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; }
}
}

@ -1,79 +0,0 @@
using Newtonsoft.Json;
using System.Collections.Generic;
namespace Core.entity2.users
{
// https://api.bilibili.com/x/v3/fav/folder/created/list?up_mid={mid}&pn={pn}&ps={ps}
// https://api.bilibili.com/x/v3/fav/folder/collected/list?up_mid={mid}&pn={pn}&ps={ps}
[JsonObject]
public class SpaceFavoriteFolderOrigin : BaseEntity
{
//[JsonProperty("code")]
//public int Code { get; set; }
[JsonProperty("data")]
public SpaceFavoriteFolder Data { get; set; }
//[JsonProperty("message")]
//public string Message { get; set; }
//[JsonProperty("ttl")]
//public int Ttl { get; set; }
}
[JsonObject]
public class SpaceFavoriteFolder : BaseEntity
{
[JsonProperty("count")]
public int Count { get; set; }
[JsonProperty("has_more")]
public int HasMore { get; set; }
[JsonProperty("list")]
public List<SpaceFavoriteFolderList> List { get; set; }
}
[JsonObject]
public class SpaceFavoriteFolderList : BaseEntity
{
[JsonProperty("attr")]
public int Attr { get; set; }
[JsonProperty("cover")]
public string Cover { get; set; }
[JsonProperty("cover_type")]
public int CoverType { get; set; }
[JsonProperty("ctime")]
public long Ctime { get; set; }
[JsonProperty("fav_state")]
public int FavState { get; set; }
[JsonProperty("fid")]
public long Fid { get; set; }
[JsonProperty("id")]
public long Id { get; set; }
[JsonProperty("intro")]
public string Intro { get; set; }
[JsonProperty("link")]
public string Link { get; set; }
[JsonProperty("media_count")]
public int MediaCount { get; set; }
[JsonProperty("mid")]
public long Mid { get; set; }
[JsonProperty("mtime")]
public long Mtime { get; set; }
[JsonProperty("state")]
public int State { get; set; }
[JsonProperty("title")]
public string Title { get; set; }
[JsonProperty("upper")]
public FavoriteFolderUpper Upper { get; set; }
// ...
}
[JsonObject]
public class FavoriteFolderUpper : BaseEntity
{
[JsonProperty("face")]
public string Face { get; set; }
[JsonProperty("mid")]
public long Mid { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
}
}

@ -1,89 +0,0 @@
using Newtonsoft.Json;
using System.Collections.Generic;
namespace Core.entity2.users
{
// https://api.bilibili.com/x/v3/fav/resource/list?media_id={mediaId}&pn={pn}&ps={ps}
[JsonObject]
public class SpaceFavoriteFolderResourceOrigin : BaseEntity
{
//[JsonProperty("code")]
//public int Code { get; set; }
[JsonProperty("data")]
public SpaceFavoriteFolderResource Data { get; set; }
//[JsonProperty("message")]
//public string Message { get; set; }
//[JsonProperty("ttl")]
//public int Ttl { get; set; }
}
[JsonObject]
public class SpaceFavoriteFolderResource : BaseEntity
{
[JsonProperty("has_more")]
public int HasMore { get; set; }
// ...
[JsonProperty("medias")]
public List<SpaceFavoriteFolderMedia> Medias { get; set; }
}
[JsonObject]
public class SpaceFavoriteFolderMedia : BaseEntity
{
[JsonProperty("attr")]
public int Attr { get; set; }
[JsonProperty("bv_id")]
public string BvId { get; set; }
[JsonProperty("bvid")]
public string Bvid { get; set; }
[JsonProperty("cnt_info")]
public SpaceFavoriteFolderMediaCntInfo CntInfo { get; set; }
[JsonProperty("cover")]
public string Cover { get; set; }
[JsonProperty("ctime")]
public long Ctime { get; set; }
[JsonProperty("duration")]
public long Duration { get; set; }
[JsonProperty("fav_time")]
public long FavTime { get; set; }
[JsonProperty("id")]
public long Id { get; set; }
[JsonProperty("intro")]
public string Intro { get; set; }
[JsonProperty("link")]
public string Link { get; set; }
[JsonProperty("page")]
public int Page { get; set; }
[JsonProperty("pubtime")]
public long Pubtime { get; set; }
[JsonProperty("title")]
public string Title { get; set; }
[JsonProperty("type")]
public int Type { get; set; }
[JsonProperty("upper")]
public SpaceFavoriteFolderMediaUpper Upper { get; set; }
}
[JsonObject]
public class SpaceFavoriteFolderMediaCntInfo : BaseEntity
{
[JsonProperty("collect")]
public long Collect { get; set; }
[JsonProperty("danmaku")]
public long Danmaku { get; set; }
[JsonProperty("play")]
public long Play { get; set; }
}
[JsonObject]
public class SpaceFavoriteFolderMediaUpper : BaseEntity
{
[JsonProperty("face")]
public string Face { get; set; }
[JsonProperty("mid")]
public long Mid { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
}
}

@ -1,77 +0,0 @@
using Newtonsoft.Json;
namespace Core.entity2.users
{
// https://api.bilibili.com/x/space/acc/info?mid={mid}
[JsonObject]
public class SpaceInfoOrigin : BaseEntity
{
//[JsonProperty("code")]
//public int Code { get; set; }
[JsonProperty("data")]
public SpaceInfo Data { get; set; }
//[JsonProperty("message")]
//public string Message { get; set; }
//[JsonProperty("ttl")]
//public int Ttl { get; set; }
}
[JsonObject]
public class SpaceInfo : BaseEntity
{
// ...
[JsonProperty("face")]
public string Face { get; set; }
[JsonProperty("fans_badge")]
public bool FansBadge { get; set; }
[JsonProperty("is_followed")]
public bool IsFollowed { get; set; }
// ...
[JsonProperty("level")]
public int Level { get; set; }
// ...
[JsonProperty("mid")]
public int Mid { get; set; }
// ...
[JsonProperty("name")]
public string Name { get; set; }
// ...
[JsonProperty("sex")]
public string Sex { get; set; }
// ...
[JsonProperty("sign")]
public string Sign { get; set; }
// ...
[JsonProperty("top_photo")]
public string TopPhoto { get; set; }
[JsonProperty("vip")]
public SpaceInfoVip Vip { get; set; }
}
public class SpaceInfoVip
{
[JsonProperty("avatar_subscript")]
public int AvatarSubscript { get; set; }
[JsonProperty("label")]
public SpaceInfoVipLabel Label { get; set; }
[JsonProperty("nickname_color")]
public string NicknameColor { get; set; }
[JsonProperty("status")]
public int Status { get; set; }
[JsonProperty("theme_type")]
public int ThemeType { get; set; }
[JsonProperty("type")]
public int Type { get; set; }
}
public class SpaceInfoVipLabel
{
[JsonProperty("label_theme")]
public string LabelTheme { get; set; }
[JsonProperty("path")]
public string Path { get; set; }
[JsonProperty("text")]
public string Text { get; set; }
}
}

@ -1,150 +0,0 @@
using Newtonsoft.Json;
using System.Collections.Generic;
namespace Core.entity2.users
{
// https://api.bilibili.com/x/space/arc/search
[JsonObject]
public class SpacePublicationOrigin : BaseEntity
{
//[JsonProperty("code")]
//public int Code { get; set; }
[JsonProperty("data")]
public SpacePublication Data { get; set; }
//[JsonProperty("message")]
//public string Message { get; set; }
//[JsonProperty("ttl")]
//public int Ttl { get; set; }
}
[JsonObject]
public class SpacePublication : BaseEntity
{
[JsonProperty("list")]
public SpacePublicationList List { get; set; }
[JsonProperty("page")]
public SpacePublicationPage Page { get; set; }
}
[JsonObject]
public class SpacePublicationList : BaseEntity
{
[JsonProperty("tlist")]
public SpacePublicationListType Tlist { get; set; }
[JsonProperty("vlist")]
public List<SpacePublicationListVideo> Vlist { get; set; }
}
[JsonObject]
public class SpacePublicationPage : BaseEntity
{
[JsonProperty("count")]
public int Count { get; set; }
[JsonProperty("pn")]
public int Pn { get; set; }
[JsonProperty("ps")]
public int Ps { get; set; }
}
[JsonObject]
public class SpacePublicationListType : BaseEntity
{
[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("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; }
}
[JsonObject]
public class SpacePublicationListVideo : BaseEntity
{
[JsonProperty("aid")]
public long Aid { get; set; }
//[JsonProperty("author")]
//public string Author { get; set; }
[JsonProperty("bvid")]
public string Bvid { get; set; }
//[JsonProperty("comment")]
//public int Comment { get; set; }
//[JsonProperty("copyright")]
//public string Copyright { get; set; }
[JsonProperty("created")]
public long Created { get; set; }
//[JsonProperty("description")]
//public string Description { get; set; }
//[JsonProperty("hide_click")]
//public bool HideClick { get; set; }
//[JsonProperty("is_pay")]
//public int IsPay { get; set; }
//[JsonProperty("is_steins_gate")]
//public int IsSteinsGate { get; set; }
//[JsonProperty("is_union_video")]
//public int IsUnionVideo { get; set; }
[JsonProperty("length")]
public string Length { get; set; }
[JsonProperty("mid")]
public long Mid { get; set; }
[JsonProperty("pic")]
public string Pic { get; set; }
[JsonProperty("play")]
public int Play { get; set; }
//[JsonProperty("review")]
//public int Review { get; set; }
//[JsonProperty("subtitle")]
//public string Subtitle { get; set; }
[JsonProperty("title")]
public string Title { get; set; }
[JsonProperty("typeid")]
public int Typeid { get; set; }
//[JsonProperty("video_review")]
//public int VideoReview { get; set; }
}
[JsonObject]
public class SpacePublicationListTypeVideoZone : BaseEntity
{
[JsonProperty("count")]
public int Count { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("tid")]
public int Tid { get; set; }
}
}

@ -1,46 +0,0 @@
using Newtonsoft.Json;
namespace Core.entity2.users
{
// https://space.bilibili.com/ajax/settings/getSettings?mid={mid}
[JsonObject]
public class SpaceSettingsOrigin : BaseEntity
{
[JsonProperty("data")]
public SpaceSettings Data { get; set; }
[JsonProperty("status")]
public bool Status { get; set; }
}
[JsonObject]
public class SpaceSettings : BaseEntity
{
// ...
[JsonProperty("toutu")]
public SpaceSettingsToutu Toutu { get; set; }
}
[JsonObject]
public class SpaceSettingsToutu : BaseEntity
{
[JsonProperty("android_img")]
public string AndroidImg { get; set; }
[JsonProperty("expire")]
public long Expire { get; set; }
[JsonProperty("ipad_img")]
public string IpadImg { get; set; }
[JsonProperty("iphone_img")]
public string IphoneImg { get; set; }
[JsonProperty("l_img")]
public string Limg { get; set; } // 完整url为http://i0.hdslb.com/+相对路径
[JsonProperty("platform")]
public int Platform { get; set; }
[JsonProperty("s_img")]
public string Simg { get; set; } // 完整url为http://i0.hdslb.com/+相对路径
[JsonProperty("sid")]
public int Sid { get; set; }
[JsonProperty("thumbnail_img")]
public string ThumbnailImg { get; set; }
}
}

@ -1,31 +0,0 @@
using Newtonsoft.Json;
namespace Core.entity2.users
{
// https://api.bilibili.com/x/space/upstat?mid={mid}
[JsonObject]
public class UpStatOrigin : BaseEntity
{
[JsonProperty("data")]
public UpStat Data { get; set; }
}
[JsonObject]
public class UpStat : BaseEntity
{
[JsonProperty("archive")]
public UpStatArchive Archive { get; set; }
[JsonProperty("article")]
public UpStatArchive Article { get; set; }
[JsonProperty("likes")]
public long Likes { get; set; }
}
[JsonObject]
public class UpStatArchive : BaseEntity
{
[JsonProperty("view")]
public long View { get; set; } // 视频播放量
}
}

@ -1,28 +0,0 @@
using Newtonsoft.Json;
namespace Core.entity2.users
{
// https://api.bilibili.com/x/relation/stat?vmid={mid}
[JsonObject]
public class UserRelationStatOrigin : BaseEntity
{
[JsonProperty("data")]
public UserRelationStat Data { get; set; }
}
[JsonObject]
public class UserRelationStat : BaseEntity
{
[JsonProperty("black")]
public long Black { get; set; }
[JsonProperty("follower")]
public long Follower { get; set; } // 粉丝数
[JsonProperty("following")]
public long Following { get; set; } // 关注数
[JsonProperty("mid")]
public long Mid { get; set; }
[JsonProperty("whisper")]
public long Whisper { get; set; }
}
}

@ -1,167 +0,0 @@
# 设置
Settings类位于`Core.settings`命名空间中采用单例模式调用。设置属性使用json格式保存并将加密后的字符串保存到文件。
| 文件名 | 内容 |
| ------------------- | -------------------------------------- |
| Settings.cs | Settings类的基本属性单例模式的代码等 |
| Settings.class.cs | SettingsEntity类等 |
| Settings.base.cs | `基本`设置的代码 |
| Settings.network.cs | `网络`设置的代码 |
| Settings.video.cs | `视频`设置的代码 |
| Settings.about.cs | `关于`设置的代码 |
## 基本
获取/设置下载完成后的操作。
```c#
public AfterDownloadOperation GetAfterDownloadOperation();
public bool SetAfterDownloadOperation(AfterDownloadOperation afterDownload);
```
## 网络
获取/设置是否解除地区限制。
```c#
public LiftingOfRegion IsLiftingOfRegion();
public bool IsLiftingOfRegion(LiftingOfRegion isLiftingOfRegion);
```
获取/设置Aria服务器的端口号。
```c#
public int GetAriaListenPort();
public bool SetAriaListenPort(int ariaListenPort);
```
获取/设置Aria日志等级。
```c#
public AriaConfigLogLevel GetAriaLogLevel();
public bool SetAriaLogLevel(AriaConfigLogLevel ariaLogLevel);
```
获取/设置Aria最大同时下载数(任务数)。
```c#
public int GetAriaMaxConcurrentDownloads();
public bool SetAriaMaxConcurrentDownloads(int ariaMaxConcurrentDownloads);
```
获取/设置Aria单文件最大线程数。
```c#
public int GetAriaSplit();
public bool SetAriaSplit(int ariaSplit);
```
获取/设置Aria下载速度限制。
```c#
public int GetAriaMaxOverallDownloadLimit();
public bool SetAriaMaxOverallDownloadLimit(int ariaMaxOverallDownloadLimit);
```
获取/设置Aria下载单文件速度限制。
```c#
public int GetAriaMaxDownloadLimit();
public bool SetAriaMaxDownloadLimit(int ariaMaxDownloadLimit);
```
获取/设置Aria文件预分配。
```c#
public AriaConfigFileAllocation GetAriaFileAllocation();
public bool SetAriaFileAllocation(AriaConfigFileAllocation ariaFileAllocation);
```
获取/设置是否开启Aria http代理。
```c#
public AriaHttpProxy IsAriaHttpProxy();
public bool IsAriaHttpProxy(AriaHttpProxy isAriaHttpProxy);
```
获取/设置Aria的http代理的地址。
```c#
public string GetAriaHttpProxy();
public bool SetAriaHttpProxy(string ariaHttpProxy);
```
获取/设置Aria的http代理的端口。
```c#
public int GetAriaHttpProxyListenPort();
public bool SetAriaHttpProxyListenPort(int ariaHttpProxyListenPort);
```
## 视频
获取/设置优先下载的视频编码。
```c#
public VideoCodecs GetVideoCodecs();
public bool SetVideoCodecs(VideoCodecs videoCodecs);
```
获取/设置优先下载画质。
```c#
public int GetQuality();
public bool SetQuality(int quality);
```
获取/设置是否给视频增加序号。
```c#
public AddOrder IsAddOrder();
public bool IsAddOrder(AddOrder isAddOrder);
```
获取/设置是否下载flv视频后转码为mp4。
```c#
public TranscodingFlvToMp4 IsTranscodingFlvToMp4();
public bool IsTranscodingFlvToMp4(TranscodingFlvToMp4 isTranscodingFlvToMp4);
```
获取/设置下载目录。
```c#
public string GetSaveVideoRootPath();
public bool SetSaveVideoRootPath(string path);
```
获取/设置是否使用默认下载目录。
```c#
public UseSaveVideoRootPath IsUseSaveVideoRootPath();
public bool IsUseSaveVideoRootPath(UseSaveVideoRootPath isUseSaveVideoRootPath);
```
获取/设置是否为不同视频分别创建文件夹。
```c#
public CreateFolderForMedia IsCreateFolderForMedia();
public bool IsCreateFolderForMedia(CreateFolderForMedia isCreateFolderForMedia);
```
## 关于
获取/设置是否接收测试版更新。
```c#
public ReceiveBetaVersion IsReceiveBetaVersion();
public bool IsReceiveBetaVersion(ReceiveBetaVersion isReceiveBetaVersion);
```
获取/设置是否允许启动时检查更新。
```c#
public AutoUpdateWhenLaunch GetAutoUpdateWhenLaunch();
public bool SetAutoUpdateWhenLaunch(AutoUpdateWhenLaunch autoUpdateWhenLaunch);
```

@ -1,90 +0,0 @@
using Core.aria2cNet.server;
namespace Core.settings
{
public class SettingsEntity
{
public UserInfoForSetting UserInfo { get; set; }
// 基本
public AfterDownloadOperation AfterDownload { get; set; }
public ALLOW_STATUS IsListenClipboard { get; set; }
public ALLOW_STATUS IsAutoParseVideo { get; set; }
public DownloadFinishedSort DownloadFinishedSort { get; set; }
// 网络
public ALLOW_STATUS IsLiftingOfRegion { get; set; }
public int AriaListenPort { get; set; }
public AriaConfigLogLevel AriaLogLevel { get; set; }
public int AriaMaxConcurrentDownloads { get; set; }
public int AriaSplit { get; set; }
public int AriaMaxOverallDownloadLimit { get; set; }
public int AriaMaxDownloadLimit { get; set; }
public AriaConfigFileAllocation AriaFileAllocation { get; set; }
public ALLOW_STATUS IsAriaHttpProxy { get; set; }
public string AriaHttpProxy { get; set; }
public int AriaHttpProxyListenPort { get; set; }
// 视频
public VideoCodecs VideoCodecs { get; set; }
public int Quality { get; set; }
public ALLOW_STATUS IsAddOrder { get; set; }
public ALLOW_STATUS IsTranscodingFlvToMp4 { get; set; }
public string SaveVideoRootPath { get; set; }
public ALLOW_STATUS IsUseSaveVideoRootPath { get; set; }
public ALLOW_STATUS IsCreateFolderForMedia { get; set; }
public ALLOW_STATUS IsDownloadDanmaku { get; set; }
public ALLOW_STATUS IsDownloadCover { get; set; }
// 弹幕
public ALLOW_STATUS DanmakuTopFilter { get; set; }
public ALLOW_STATUS DanmakuBottomFilter { get; set; }
public ALLOW_STATUS DanmakuScrollFilter { get; set; }
public ALLOW_STATUS IsCustomDanmakuResolution { get; set; }
public int DanmakuScreenWidth { get; set; }
public int DanmakuScreenHeight { get; set; }
public string DanmakuFontName { get; set; }
public int DanmakuFontSize { get; set; }
public int DanmakuLineCount { get; set; }
public DanmakuLayoutAlgorithm DanmakuLayoutAlgorithm { get; set; }
// 关于
public ALLOW_STATUS IsReceiveBetaVersion { get; set; }
public ALLOW_STATUS AutoUpdateWhenLaunch { get; set; }
}
public class UserInfoForSetting
{
public long Mid { get; set; }
public string Name { get; set; }
public bool IsLogin { get; set; } // 是否登录
public bool IsVip { get; set; } // 是否为大会员未登录时为false
}
public enum AfterDownloadOperation
{
NONE = 1, OPEN_FOLDER, CLOSE_APP, CLOSE_SYSTEM
}
public enum ALLOW_STATUS
{
NONE = 0, YES, NO
}
public enum DownloadFinishedSort
{
DOWNLOAD = 0, NUMBER
}
public enum VideoCodecs
{
NONE = 0, AVC, HEVC
}
public enum DanmakuLayoutAlgorithm
{
NONE = 0, ASYNC, SYNC
}
}

@ -1,132 +0,0 @@
using Newtonsoft.Json;
using System;
using System.IO;
namespace Core.settings
{
public partial class Settings
{
private static Settings instance;
/// <summary>
/// 获取Settings实例
/// </summary>
/// <returns></returns>
public static Settings GetInstance()
{
if (instance == null)
{
instance = new Settings();
}
return instance;
}
/// <summary>
/// 隐藏Settings()方法,必须使用单例模式
/// </summary>
private Settings()
{
settingsEntity = GetEntity();
}
// 内存中保存一份配置
private readonly SettingsEntity settingsEntity;
// 设置的配置文件
private readonly string settingsName = Common.ConfigPath + "Settings";
// 密钥
private readonly string password = "QA!M^gE@";
// 登录用户的mid
private readonly UserInfoForSetting userInfo = new UserInfoForSetting
{
Mid = -1,
Name = "",
IsLogin = false,
IsVip = false
};
private SettingsEntity GetEntity()
{
try
{
StreamReader streamReader = File.OpenText(settingsName);
string jsonWordTemplate = streamReader.ReadToEnd();
streamReader.Close();
// 解密字符串
jsonWordTemplate = Encryptor.DecryptString(jsonWordTemplate, password);
return JsonConvert.DeserializeObject<SettingsEntity>(jsonWordTemplate);
}
catch (FileNotFoundException e)
{
Console.WriteLine("GetEntity()发生异常: {0}", e);
return new SettingsEntity();
}
catch (DirectoryNotFoundException e)
{
Console.WriteLine("GetEntity()发生异常: {0}", e);
return new SettingsEntity();
}
catch (Exception e)
{
Console.WriteLine("GetEntity()发生异常: {0}", e);
return new SettingsEntity();
}
}
private bool SetEntity()
{
if (!Directory.Exists(Common.ConfigPath))
{
Directory.CreateDirectory(Common.ConfigPath);
}
string json = JsonConvert.SerializeObject(settingsEntity);
// 加密字符串
json = Encryptor.EncryptString(json, password);
try
{
File.WriteAllText(settingsName, json);
return true;
}
catch (IOException e)
{
Console.WriteLine("SetEntity()发生异常: {0}", e);
return false;
}
}
/// <summary>
/// 获取登录用户信息
/// </summary>
/// <returns></returns>
public UserInfoForSetting GetUserInfo()
{
if (settingsEntity.UserInfo == null)
{
// 第一次获取,先设置默认值
SetUserInfo(userInfo);
return userInfo;
}
return settingsEntity.UserInfo;
}
/// <summary>
/// 设置中保存登录用户的信息在index刷新用户状态时使用
/// </summary>
/// <param name="mid"></param>
/// <returns></returns>
public bool SetUserInfo(UserInfoForSetting userInfo)
{
settingsEntity.UserInfo = userInfo;
return SetEntity();
}
}
}

@ -1,8 +1,8 @@
using Core.aria2cNet.client;
using System;
using DownKyi.Core.Aria2cNet.Client;
using DownKyi.Core.Logging;
using System.Threading;
namespace Core.aria2cNet
namespace DownKyi.Core.Aria2cNet
{
public class AriaManager
{
@ -69,7 +69,8 @@ namespace Core.aria2cNet
}
if (status.Result.Result.ErrorCode != null && status.Result.Result.ErrorCode != "0")
{
Console.WriteLine("ErrorMessage: " + status.Result.Result.ErrorMessage);
Utils.Debug.Console.PrintLine("ErrorMessage: " + status.Result.Result.ErrorMessage);
LogManager.Error("AriaManager", status.Result.Result.ErrorMessage);
//// 如果返回状态码不是200则继续
//if (status.Result.Result.ErrorMessage.Contains("The response status is not successful"))
@ -80,7 +81,8 @@ namespace Core.aria2cNet
// aira中删除记录
var ariaRemove1 = AriaClient.RemoveDownloadResultAsync(gid);
Console.WriteLine(ariaRemove1);
Utils.Debug.Console.PrintLine(ariaRemove1);
LogManager.Debug("AriaManager", ariaRemove1.Result.Result);
// 返回回调信息,退出函数
OnDownloadFinish(false, null, gid, status.Result.Result.ErrorMessage);
@ -114,46 +116,5 @@ namespace Core.aria2cNet
}
}
//private async void Poll()
//{
// while (true)
// {
// // 查询全局status
// var globalStatus = await AriaClient.GetGlobalStatAsync();
// if (globalStatus == null || globalStatus.Result == null) { continue; }
// long globalSpeed = long.Parse(globalStatus.Result.DownloadSpeed);
// // 回调
// OnGetGlobalStatus(globalSpeed);
// // 查询gid对应的项目的status
// foreach (var gid in gidList)
// {
// var status = await AriaClient.TellStatus(gid);
// if (status == null || status.Result == null) { continue; }
// long totalLength = long.Parse(status.Result.TotalLength);
// long completedLength = long.Parse(status.Result.CompletedLength);
// long speed = long.Parse(status.Result.DownloadSpeed);
// // 回调
// OnTellStatus(totalLength, completedLength, speed, gid);
// }
// }
//}
}
/// <summary>
/// 下载状态
/// </summary>
public enum DownloadStatus
{
SUCCESS = 1,
FAILED,
ABORT
}
}

@ -1,4 +1,5 @@
using Core.aria2cNet.client.entity;
using DownKyi.Core.Aria2cNet.Client.Entity;
using DownKyi.Core.Logging;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
@ -7,9 +8,8 @@ using System.Net;
using System.Text;
using System.Threading.Tasks;
namespace Core.aria2cNet.client
namespace DownKyi.Core.Aria2cNet.Client
{
/// <summary>
/// http://aria2.github.io/manual/en/html/aria2c.html#methods
/// </summary>
@ -1093,7 +1093,8 @@ namespace Core.aria2cNet.client
}
catch (WebException e)
{
Console.WriteLine("Request()发生Web异常: {0}", e);
Utils.Debug.Console.PrintLine("Request()发生Web异常: {0}", e);
LogManager.Error("AriaClient", e);
//return Request(url, parameters, retry - 1);
string html = string.Empty;
@ -1106,34 +1107,24 @@ namespace Core.aria2cNet.client
html = reader.ReadToEnd();
}
}
#if DEBUG
Console.WriteLine($"本次请求使用的参数:{parameters}");
Console.WriteLine($"返回的web数据{html}");
#endif
return html;
}
catch (IOException e)
{
Console.WriteLine("Request()发生IO异常: {0}", e);
Utils.Debug.Console.PrintLine("Request()发生IO异常: {0}", e);
LogManager.Error("AriaClient", e);
return Request(url, parameters, retry - 1);
}
catch (Exception e)
{
Console.WriteLine("Request()发生其他异常: {0}", e);
Utils.Debug.Console.PrintLine("Request()发生其他异常: {0}", e);
LogManager.Error("AriaClient", e);
return Request(url, parameters, retry - 1);
}
}
}
/// <summary>
/// changePosition函数的how参数
/// </summary>
public enum HowChangePosition
{
POS_SET = 1,
POS_CUR,
POS_END
}
}

@ -1,6 +1,6 @@
using Newtonsoft.Json;
namespace Core.aria2cNet.client.entity
namespace DownKyi.Core.Aria2cNet.Client.Entity
{
[JsonObject]
public class AriaAddMetalink

@ -1,6 +1,6 @@
using Newtonsoft.Json;
namespace Core.aria2cNet.client.entity
namespace DownKyi.Core.Aria2cNet.Client.Entity
{
[JsonObject]
public class AriaAddTorrent

@ -1,6 +1,6 @@
using Newtonsoft.Json;
namespace Core.aria2cNet.client.entity
namespace DownKyi.Core.Aria2cNet.Client.Entity
{
//{
//"id": "downkyi",

@ -1,6 +1,6 @@
using Newtonsoft.Json;
namespace Core.aria2cNet.client.entity
namespace DownKyi.Core.Aria2cNet.Client.Entity
{
[JsonObject]
public class AriaChangeOption

@ -1,6 +1,6 @@
using Newtonsoft.Json;
namespace Core.aria2cNet.client.entity
namespace DownKyi.Core.Aria2cNet.Client.Entity
{
[JsonObject]
public class AriaChangePosition

@ -1,7 +1,7 @@
using Newtonsoft.Json;
using System.Collections.Generic;
namespace Core.aria2cNet.client.entity
namespace DownKyi.Core.Aria2cNet.Client.Entity
{
[JsonObject]
public class AriaChangeUri

@ -1,6 +1,6 @@
using Newtonsoft.Json;
namespace Core.aria2cNet.client.entity
namespace DownKyi.Core.Aria2cNet.Client.Entity
{
//"error": {
// "code": 1,

@ -1,7 +1,7 @@
using Newtonsoft.Json;
using System.Collections.Generic;
namespace Core.aria2cNet.client.entity
namespace DownKyi.Core.Aria2cNet.Client.Entity
{
[JsonObject]
public class AriaGetFiles
@ -50,5 +50,4 @@ namespace Core.aria2cNet.client.entity
return JsonConvert.SerializeObject(this);
}
}
}

@ -1,21 +1,21 @@
using Newtonsoft.Json;
namespace Core.aria2cNet.client.entity
namespace DownKyi.Core.Aria2cNet.Client.Entity
{
/*
{
"id": "qwer",
"jsonrpc": "2.0",
"result": {
"downloadSpeed": "0",
"numActive": "0",
"numStopped": "0",
"numStoppedTotal": "0",
"numWaiting": "0",
"uploadSpeed": "0"
}
}
*/
{
"id": "qwer",
"jsonrpc": "2.0",
"result": {
"downloadSpeed": "0",
"numActive": "0",
"numStopped": "0",
"numStoppedTotal": "0",
"numWaiting": "0",
"uploadSpeed": "0"
}
}
*/
[JsonObject]
public class AriaGetGlobalStat
{
@ -63,5 +63,4 @@ namespace Core.aria2cNet.client.entity
return JsonConvert.SerializeObject(this);
}
}
}

@ -1,6 +1,6 @@
using Newtonsoft.Json;
namespace Core.aria2cNet.client.entity
namespace DownKyi.Core.Aria2cNet.Client.Entity
{
[JsonObject]
public class AriaGetOption

@ -1,7 +1,7 @@
using Newtonsoft.Json;
using System.Collections.Generic;
namespace Core.aria2cNet.client.entity
namespace DownKyi.Core.Aria2cNet.Client.Entity
{
[JsonObject]
public class AriaGetPeers
@ -59,5 +59,4 @@ namespace Core.aria2cNet.client.entity
return JsonConvert.SerializeObject(this);
}
}
}

@ -1,7 +1,7 @@
using Newtonsoft.Json;
using System.Collections.Generic;
namespace Core.aria2cNet.client.entity
namespace DownKyi.Core.Aria2cNet.Client.Entity
{
[JsonObject]
public class AriaGetServers
@ -56,5 +56,4 @@ namespace Core.aria2cNet.client.entity
return JsonConvert.SerializeObject(this);
}
}
}

@ -1,6 +1,6 @@
using Newtonsoft.Json;
namespace Core.aria2cNet.client.entity
namespace DownKyi.Core.Aria2cNet.Client.Entity
{
[JsonObject]
public class AriaGetSessionInfo
@ -34,5 +34,4 @@ namespace Core.aria2cNet.client.entity
return JsonConvert.SerializeObject(this);
}
}
}

@ -1,7 +1,7 @@
using Newtonsoft.Json;
using System.Collections.Generic;
namespace Core.aria2cNet.client.entity
namespace DownKyi.Core.Aria2cNet.Client.Entity
{
[JsonObject]
public class AriaGetUris

@ -1,6 +1,6 @@
using Newtonsoft.Json;
namespace Core.aria2cNet.client.entity
namespace DownKyi.Core.Aria2cNet.Client.Entity
{
[JsonObject]
public class AriaOption

@ -1,6 +1,6 @@
using Newtonsoft.Json;
namespace Core.aria2cNet.client.entity
namespace DownKyi.Core.Aria2cNet.Client.Entity
{
[JsonObject]
public class AriaPause

@ -1,6 +1,6 @@
using Newtonsoft.Json;
namespace Core.aria2cNet.client.entity
namespace DownKyi.Core.Aria2cNet.Client.Entity
{
[JsonObject]
public class AriaRemove

@ -1,6 +1,6 @@
using Newtonsoft.Json;
namespace Core.aria2cNet.client.entity
namespace DownKyi.Core.Aria2cNet.Client.Entity
{
[JsonObject]
public class AriaSaveSession

@ -1,7 +1,7 @@
using Newtonsoft.Json;
using System.Collections.Generic;
namespace Core.aria2cNet.client.entity
namespace DownKyi.Core.Aria2cNet.Client.Entity
{
[JsonObject]
public class AriaSendData
@ -50,5 +50,4 @@ namespace Core.aria2cNet.client.entity
return JsonConvert.SerializeObject(this);
}
}
}

@ -1,6 +1,6 @@
using Newtonsoft.Json;
namespace Core.aria2cNet.client.entity
namespace DownKyi.Core.Aria2cNet.Client.Entity
{
[JsonObject]
public class AriaShutdown

@ -1,49 +1,8 @@
using Newtonsoft.Json;
using System.Collections.Generic;
namespace Core.aria2cNet.client.entity
namespace DownKyi.Core.Aria2cNet.Client.Entity
{
/*
{
"id": "qwer",
"jsonrpc": "2.0",
"result": {
"bitfield": "80",
"completedLength": "118188",
"connections": "0",
"dir": "D:\\home",
"downloadSpeed": "0",
"errorCode": "0",
"errorMessage": "",
"files": [
{
"completedLength": "118188",
"index": "1",
"length": "118188",
"path": "D:/home/ariaTest.html",
"selected": "true",
"uris": [
{
"status": "used",
"uri": "https://www.bilibili.com/"
},
{
"status": "waiting",
"uri": "https://www.bilibili.com/"
}
]
}
],
"gid": "4e7f671a6134b5ac",
"numPieces": "1",
"pieceLength": "1048576",
"status": "complete",
"totalLength": "118188",
"uploadLength": "0",
"uploadSpeed": "0"
}
}
*/
[JsonObject]
public class AriaTellStatus
{
@ -166,5 +125,4 @@ namespace Core.aria2cNet.client.entity
return JsonConvert.SerializeObject(this);
}
}
}

@ -1,6 +1,6 @@
using Newtonsoft.Json;
namespace Core.aria2cNet.client.entity
namespace DownKyi.Core.Aria2cNet.Client.Entity
{
[JsonObject]
public class AriaUri

@ -1,7 +1,7 @@
using Newtonsoft.Json;
using System.Collections.Generic;
namespace Core.aria2cNet.client.entity
namespace DownKyi.Core.Aria2cNet.Client.Entity
{
[JsonObject]
public class AriaVersion
@ -38,5 +38,4 @@ namespace Core.aria2cNet.client.entity
return JsonConvert.SerializeObject(this);
}
}
}

@ -1,7 +1,7 @@
using Newtonsoft.Json;
using System.Collections.Generic;
namespace Core.aria2cNet.client.entity
namespace DownKyi.Core.Aria2cNet.Client.Entity
{
[JsonObject]
public class SystemListMethods

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

Loading…
Cancel
Save