Compare commits

...
9 Commits
Author SHA1 Message Date
flyself b728db4ba5 v1.4.0 2021-06-12 23:02:57 +08:00
flyself 8ebfa17691 v1.3.8 2021-04-27 23:08:54 +08:00
flyself 3b0ed3e688 v1.3.7 2021-03-28 21:42:33 +08:00
flyself 332e288882 Update README.md 2021-03-06 10:12:04 +08:00
flyself 975b2a1969 v1.3.6 2021-03-04 19:53:55 +08:00
flyself 4b305230a4 v1.3.5 2021-02-21 16:20:11 +08:00
flyself 9046c63652 v1.3.4 2021-02-10 14:44:25 +08:00
flyself 666572ff1c 更新README 2021-02-09 11:57:04 +08:00
flyself 96e6afca41 Create LICENSE 2021-02-05 11:49:11 +08:00
96 changed files with 12320 additions and 22 deletions
+53
View File
@@ -1,5 +1,58 @@
# 更新日志
* `2021/06/12` v1.4.0
1. [修复] 视频无封面时崩溃的问题。
2. [优化] 视频分区代码与图标。
3. [优化] 屏蔽频道中的失效视频。
4. [优化] 二维码登录逻辑。
5. [新增] 弹幕下载(借鉴并重写于项目 [niconvert](https://github.com/muzuiget/niconvert))。
6. [新增] 弹幕样式设置。
7. [新增] 下载弹幕、下载封面的选项。
* `2021/04/27` v1.3.8
1. [修复] FLV视频只有1个分段时下载失败的问题。
2. [修复] UP主视频页面闪退的问题。
3. [修复] 电视剧图标丢失的问题。
4. [新增] UP主视频页面下载全部视频的按钮。
* `2021/03/28` v1.3.7
1. [修复] 播放数为空白的视频存在时,整页视频列表无法加载的问题。
2. [修复] 特殊字符(控制字符、末尾空格等)导致的下载失败。
3. [修复] 由于某些封面图片metadata损坏导致的程序崩溃。
4. [修复] 监听剪贴板数据异常报错的问题。
5. [优化] 部分界面显示。
6. [优化] 程序逻辑。
7. [新增] 监听剪贴板和自动解析的设置持久化。
8. [新增] 列表支持shift&ctrl多选。
9. [新增] 下载中列表重试按钮。
* `2021/03/04` v1.3.6
1. [修复] 下载FLV时失败的问题。
2. [修复] 主页的登录信息更新不及时的问题。
3. [优化] 主页下方按钮居中。
4. [优化] 首页搜索框添加搜索按钮,点击可进行搜索。
5. [新增] 监听剪贴板。
6. [新增] 已下载视频列表排序。
7. [新增] 下载管理页面增加全部暂停、全部开始、全部删除。
* `2021/02/21` v1.3.5
1. [修复] 分P标题相同时会下载失败的问题。
2. [修复] 个人空间中的头像可能显示不全的问题。
3. [优化] 订阅页面采用分页显示。
4. [优化] 增强程序健壮性。
5. [优化] 部分界面UI。
6. [优化] 视频详情页获取视频后不自动解析下载链接。
7. [新增] 视频详情页“自动解析”选项,“解析视频”按钮,列表右键菜单“解析”。
8. [新增] 视频详情页支持输入av号和BV号。
9. [新增] 视频详情页的UP主头像增加进入用户空间的入口。
10. [新增] 历史记录和稍后再看的up主头像增加进入用户空间的入口。
* `2021/02/10` v1.3.4
1. [修复] 修复在未登录时进入UP主用户空间,程序崩溃的问题。
2. [优化] 更新视频分区。
3. [优化] 视频数为0的频道不显示。
4. [优化] 部分界面UI。
* `2021/01/30` v1.3.3
1. [修复] 输入avid和bvid可能无法解析的问题。
2. [优化] 程序的一些显示。
+201
View File
@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2021 FlySelfLog
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
+16 -10
View File
@@ -9,7 +9,8 @@
- [x] 支持4K下载
- [x] 支持视频、番剧、剧集、电影、课程下载
- [x] **支持用户收藏夹、订阅、稍后再看、历史记录下载**
- [x] **支持港澳台番剧下载,解除地区限制**
- [x] ~~**支持港澳台番剧下载,解除地区限制**~~
- [x] 支持弹幕下载、样式设置
- [x] 支持封面下载
- [x] 支持断点续传
- [x] 支持Aria2c
@@ -38,6 +39,8 @@
哔哩下载姬支持多种复制于浏览器或APP的网址格式,在程序主页输入并按回车键即可开始检索。
- 检索只获取视频的基本信息,视频下载链接需点击解析。(v1.3.5)
- 监听剪贴板,复制即可开始检索。(v1.3.6)
- 视频详情页中,先选中视频再下载,如果该视频已经在下载队列或者已下载列表中,则不会被添加。
- 用户收藏夹、订阅、稍后再看、历史记录中,点击下载后,会默认下载选中视频的所有分P。
@@ -58,18 +61,21 @@
[全部更新日志](https://github.com/FlySelfLog/downkyi/blob/main/CHANGELOG.md)
* `2021/01/30` v1.3.3
1. [修复] 输入avid和bvid可能无法解析的问题。
2. [优化] 程序的一些显示。
3. [优化] 程序核心代码结构。
4. [新增] 访问用户空间。
5. [新增] UP主投稿视频列表展示。
6. [新增] UP主频道列表展示。
7. [新增] 意见反馈入口,将进入github的issue页。
* `2021/06/12` v1.4.0
1. [修复] 视频无封面时崩溃的问题。
2. [优化] 视频分区代码与图标。
3. [优化] 屏蔽频道中的失效视频。
4. [优化] 二维码登录逻辑。
5. [新增] 弹幕下载(借鉴并重写于项目 [niconvert](https://github.com/muzuiget/niconvert))。
6. [新增] 弹幕样式设置。
7. [新增] 下载弹幕、下载封面的选项。
## 下载
https://github.com/FlySelfLog/downkyi/releases
- [哔哩下载姬最新版](https://github.com/FlySelfLog/downkyi/releases/download/v1.3.7/DownKyi-1.3.7.zip)
- [下载页面](https://github.com/FlySelfLog/downkyi/releases)
## 赞助
+440
View File
@@ -0,0 +1,440 @@
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
}
}
+534
View File
@@ -0,0 +1,534 @@
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;
//}
}
}
+316
View File
@@ -0,0 +1,316 @@
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
namespace Core
{
public static class Encryptor
{
private const ulong FC_TAG = 0xFC010203040506CF;
private const int BUFFER_SIZE = 128 * 1024;
/// <summary>
/// 加密文件
/// </summary>
/// <param name="inFile">待加密文件</param>
/// <param name="outFile">加密后输入文件</param>
/// <param name="password">加密密码</param>
public static void EncryptFile(string inFile, string outFile, string password)
{
using (FileStream fin = File.OpenRead(inFile), fout = File.OpenWrite(outFile))
{
long lSize = fin.Length; // 输入文件长度
int size = (int)lSize;
byte[] bytes = new byte[BUFFER_SIZE]; // 缓存
int read = -1; // 输入文件读取数量
int value = 0;
// 获取IV和salt
byte[] IV = GenerateRandomBytes(16);
byte[] salt = GenerateRandomBytes(16);
// 创建加密对象
SymmetricAlgorithm sma = CreateRijndael(password, salt);
sma.IV = IV;
// 在输出文件开始部分写入IV和salt
fout.Write(IV, 0, IV.Length);
fout.Write(salt, 0, salt.Length);
// 创建散列加密
HashAlgorithm hasher = SHA256.Create();
using (CryptoStream cout = new CryptoStream(fout, sma.CreateEncryptor(), CryptoStreamMode.Write),
chash = new CryptoStream(Stream.Null, hasher, CryptoStreamMode.Write))
{
BinaryWriter bw = new BinaryWriter(cout);
bw.Write(lSize);
bw.Write(FC_TAG);
// 读写字节块到加密流缓冲区
while ((read = fin.Read(bytes, 0, bytes.Length)) != 0)
{
cout.Write(bytes, 0, read);
chash.Write(bytes, 0, read);
value += read;
}
// 关闭加密流
chash.Flush();
chash.Close();
// 读取散列
byte[] hash = hasher.Hash;
// 输入文件写入散列
cout.Write(hash, 0, hash.Length);
// 关闭文件流
cout.Flush();
cout.Close();
}
}
}
/// <summary>
/// 解密文件
/// </summary>
/// <param name="inFile">待解密文件</param>
/// <param name="outFile">解密后输出文件</param>
/// <param name="password">解密密码</param>
public static void DecryptFile(string inFile, string outFile, string password)
{
// 创建打开文件流
using (FileStream fin = File.OpenRead(inFile), fout = File.OpenWrite(outFile))
{
int size = (int)fin.Length;
byte[] bytes = new byte[BUFFER_SIZE];
int read = -1;
int value = 0;
int outValue = 0;
byte[] IV = new byte[16];
fin.Read(IV, 0, 16);
byte[] salt = new byte[16];
fin.Read(salt, 0, 16);
SymmetricAlgorithm sma = CreateRijndael(password, salt);
sma.IV = IV;
value = 32;
long lSize = -1;
// 创建散列对象, 校验文件
HashAlgorithm hasher = SHA256.Create();
try
{
using (CryptoStream cin = new CryptoStream(fin, sma.CreateDecryptor(), CryptoStreamMode.Read),
chash = new CryptoStream(Stream.Null, hasher, CryptoStreamMode.Write))
{
// 读取文件长度
BinaryReader br = new BinaryReader(cin);
lSize = br.ReadInt64();
ulong tag = br.ReadUInt64();
if (FC_TAG != tag)
throw new CryptoHelpException("文件被破坏");
long numReads = lSize / BUFFER_SIZE;
long slack = (long)lSize % BUFFER_SIZE;
for (int i = 0; i < numReads; ++i)
{
read = cin.Read(bytes, 0, bytes.Length);
fout.Write(bytes, 0, read);
chash.Write(bytes, 0, read);
value += read;
outValue += read;
}
if (slack > 0)
{
read = cin.Read(bytes, 0, (int)slack);
fout.Write(bytes, 0, read);
chash.Write(bytes, 0, read);
value += read;
outValue += read;
}
chash.Flush();
chash.Close();
fout.Flush();
fout.Close();
byte[] curHash = hasher.Hash;
// 获取比较和旧的散列对象
byte[] oldHash = new byte[hasher.HashSize / 8];
read = cin.Read(oldHash, 0, oldHash.Length);
if ((oldHash.Length != read) || (!CheckByteArrays(oldHash, curHash)))
throw new CryptoHelpException("文件被破坏");
}
}
catch (Exception e)
{
Console.WriteLine("DecryptFile()发生异常: {0}", e);
}
if (outValue != lSize)
throw new CryptoHelpException("文件大小不匹配");
}
}
/// <summary>
/// 检验两个Byte数组是否相同
/// </summary>
/// <param name="b1">Byte数组</param>
/// <param name="b2">Byte数组</param>
/// <returns>true-相等</returns>
private static bool CheckByteArrays(byte[] b1, byte[] b2)
{
if (b1.Length == b2.Length)
{
for (int i = 0; i < b1.Length; ++i)
{
if (b1[i] != b2[i])
return false;
}
return true;
}
return false;
}
/// <summary>
/// 创建DebugLZQ ,http://www.cnblogs.com/DebugLZQ
/// </summary>
/// <param name="password">密码</param>
/// <param name="salt"></param>
/// <returns>加密对象</returns>
private static SymmetricAlgorithm CreateRijndael(string password, byte[] salt)
{
PasswordDeriveBytes pdb = new PasswordDeriveBytes(password, salt, "SHA256", 1000);
SymmetricAlgorithm sma = Rijndael.Create();
sma.KeySize = 256;
sma.Key = pdb.GetBytes(32);
sma.Padding = PaddingMode.PKCS7;
return sma;
}
/// <summary>
/// 生成指定长度的随机Byte数组
/// </summary>
/// <param name="count">Byte数组长度</param>
/// <returns>随机Byte数组</returns>
private static byte[] GenerateRandomBytes(int count)
{
// 加密文件随机数生成
RandomNumberGenerator rand = new RNGCryptoServiceProvider();
byte[] bytes = new byte[count];
rand.GetBytes(bytes);
return bytes;
}
/// <summary>
/// DES加密字符串
/// </summary>
/// <param name="encryptString">待加密的字符串</param>
/// <param name="encryptKey">加密密钥,要求为8位</param>
/// <returns>加密成功返回加密后的字符串,失败返回源串 </returns>
public static string EncryptString(string encryptString, string encryptKey)
{
try
{
byte[] rgbKey = Encoding.UTF8.GetBytes(encryptKey.Substring(0, 8));//转换为字节
byte[] rgbIV = Encoding.UTF8.GetBytes(encryptKey.Substring(0, 8));
byte[] inputByteArray = Encoding.UTF8.GetBytes(encryptString);
DESCryptoServiceProvider dCSP = new DESCryptoServiceProvider();//实例化数据加密标准
MemoryStream mStream = new MemoryStream();//实例化内存流
//将数据流链接到加密转换的流
CryptoStream cStream = new CryptoStream(mStream, dCSP.CreateEncryptor(rgbKey, rgbIV), CryptoStreamMode.Write);
cStream.Write(inputByteArray, 0, inputByteArray.Length);
cStream.FlushFinalBlock();
// 转base64
return Convert.ToBase64String(mStream.ToArray());
}
catch (Exception e)
{
Console.WriteLine("EncryptString()发生异常: {0}", e);
return encryptString;
}
}
/// <summary>
/// DES解密字符串
/// </summary>
/// <param name="decryptString">待解密的字符串</param>
/// <param name="decryptKey">解密密钥,要求为8位,和加密密钥相同</param>
/// <returns>解密成功返回解密后的字符串,失败返源串</returns>
public static string DecryptString(string decryptString, string decryptKey)
{
try
{
byte[] rgbKey = Encoding.UTF8.GetBytes(decryptKey);
byte[] rgbIV = Encoding.UTF8.GetBytes(decryptKey);
byte[] inputByteArray = Convert.FromBase64String(decryptString);
DESCryptoServiceProvider DCSP = new DESCryptoServiceProvider();
MemoryStream mStream = new MemoryStream();
CryptoStream cStream = new CryptoStream(mStream, DCSP.CreateDecryptor(rgbKey, rgbIV), CryptoStreamMode.Write);
cStream.Write(inputByteArray, 0, inputByteArray.Length);
cStream.FlushFinalBlock();
return Encoding.UTF8.GetString(mStream.ToArray());
}
catch (Exception e)
{
Console.WriteLine("DecryptString()发生异常: {0}", e);
return decryptString;
}
}
/// <summary>
/// 计算字符串MD5值
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public static string GetMd5Hash(string input)
{
if (input == null)
{
return null;
}
MD5 md5Hash = MD5.Create();
// 将输入字符串转换为字节数组并计算哈希数据
byte[] data = md5Hash.ComputeHash(Encoding.UTF8.GetBytes(input));
// 创建一个 Stringbuilder 来收集字节并创建字符串
StringBuilder sBuilder = new StringBuilder();
// 循环遍历哈希数据的每一个字节并格式化为十六进制字符串
for (int i = 0; i < data.Length; i++)
{
sBuilder.Append(data[i].ToString("x2"));
}
// 返回十六进制字符串
return sBuilder.ToString();
}
}
/// <summary>
/// 异常处理类
/// </summary>
public class CryptoHelpException : ApplicationException
{
public CryptoHelpException(string msg) : base(msg) { }
}
}
+254
View File
@@ -0,0 +1,254 @@
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(); //等待进程结束
}
}
}
}
+198
View File
@@ -0,0 +1,198 @@
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; //清空临时储存
}
}
}
+142
View File
@@ -0,0 +1,142 @@
using System;
using System.Management;
namespace Core
{
public class MachineCode
{
private static MachineCode machineCode;
/// <summary>
/// 获取机器码
/// </summary>
/// <returns></returns>
public static string GetMachineCodeString()
{
if (machineCode == null)
{
machineCode = new MachineCode();
}
string machineCodeString = "PC." +
machineCode.GetMainBordId() + "." +
machineCode.GetCpuInfo() + "." +
machineCode.GetDiskID();// + "." +
//machineCode.GetMoAddress();
return machineCodeString.Replace(" ", "");
}
/// <summary>
/// 获取主板ID
/// </summary>
/// <returns></returns>
public string GetMainBordId()
{
string strId = "";
try
{
using (ManagementClass mc = new ManagementClass("Win32_BaseBoard"))
{
ManagementObjectCollection moc = mc.GetInstances();
foreach (ManagementObject mo in moc)
{
strId = mo.Properties["SerialNumber"].Value.ToString();
mo.Dispose();
break;
}
}
}
catch (Exception)
{
return "unknown";
//throw;
}
return strId;
}
/// <summary>
/// 获取cpu序列号
/// </summary>
/// <returns></returns>
public string GetCpuInfo()
{
string cpuInfo = "";
try
{
using (ManagementClass cimobject = new ManagementClass("Win32_Processor"))
{
ManagementObjectCollection moc = cimobject.GetInstances();
foreach (ManagementObject mo in moc)
{
cpuInfo = mo.Properties["ProcessorId"].Value.ToString();
mo.Dispose();
}
}
}
catch (Exception)
{
return "unknown";
//throw;
}
return cpuInfo;
}
/// <summary>
/// 获取硬盘ID
/// </summary>
/// <returns></returns>
public string GetDiskID()
{
string diskName = "";
string diskID = "";
try
{
using (ManagementClass cimobject1 = new ManagementClass("Win32_DiskDrive"))
{
ManagementObjectCollection moc1 = cimobject1.GetInstances();
foreach (ManagementObject mo in moc1)
{
diskName = mo.Properties["Model"].Value.ToString();
diskID = mo.Properties["SerialNumber"].Value.ToString();
mo.Dispose();
}
}
}
catch (Exception)
{
return "unknown";
//throw;
}
return diskName + diskID;
}
/// <summary>
/// 获取网卡硬件地址
/// </summary>
/// <returns></returns>
public string GetMoAddress()
{
string MoAddress = "";
try
{
using (ManagementClass mc = new ManagementClass("Win32_NetworkAdapterConfiguration"))
{
ManagementObjectCollection moc2 = mc.GetInstances();
foreach (ManagementObject mo in moc2)
{
if ((bool)mo["IPEnabled"] == true)
MoAddress = mo["MacAddress"].ToString();
mo.Dispose();
}
}
}
catch (Exception)
{
return "unknown";
//throw;
}
return MoAddress;
}
}
}
+148
View File
@@ -0,0 +1,148 @@
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;
// }
//}
}
}
+430
View File
@@ -0,0 +1,430 @@
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;
}
}
}
+209
View File
@@ -0,0 +1,209 @@
using System.Collections.Generic;
namespace Core
{
public class VideoZone
{
private static VideoZone that;
private readonly List<ZoneAttr> zones = new List<ZoneAttr>();
/// <summary>
/// 使用单例模式获取分区,注意未搜索到的分区需要额外处理
/// </summary>
/// <returns></returns>
public static VideoZone Instance()
{
if (that == null)
{
that = new VideoZone();
}
return that;
}
public List<ZoneAttr> GetZone()
{
return zones;
}
private VideoZone()
{
//动画
zones.Add(new ZoneAttr(1, "douga", "动画")); // 主分区
zones.Add(new ZoneAttr(24, "mad", "MAD·AMV", 1)); //具有一定制作程度的动画或静画的二次创作视频
zones.Add(new ZoneAttr(25, "mmd", "MMD·3D", 1)); //使用MMD(MikuMikuDance)和其他3D建模类软件制作的视频
zones.Add(new ZoneAttr(47, "voice", "短片·手书·配音", 1)); //追求创新并具有强烈特色的短片、手书(绘)及ACG相关配音
zones.Add(new ZoneAttr(210, "garage_kit", "手办·模玩", 1)); //手办模玩的测评、改造或其他衍生内容
zones.Add(new ZoneAttr(86, "tokusatsu", "特摄", 1)); //特摄相关衍生视频
zones.Add(new ZoneAttr(27, "other", "综合", 1)); //以动画及动画相关内容为素材,包括但不仅限于音频替换、杂谈、排行榜等内容
//番剧
zones.Add(new ZoneAttr(13, "anime", "番剧")); // 主分区
zones.Add(new ZoneAttr(33, "serial", "连载动画", 13)); //当季连载的动画番剧
zones.Add(new ZoneAttr(32, "finish", "完结动画", 13)); //已完结的动画番剧合集
zones.Add(new ZoneAttr(51, "information", "资讯", 13)); //动画番剧相关资讯视频
zones.Add(new ZoneAttr(152, "offical", "官方延伸", 13)); //动画番剧为主题的宣传节目、采访视频,及声优相关视频
//国创
zones.Add(new ZoneAttr(167, "guochuang", "国创")); // 主分区
zones.Add(new ZoneAttr(153, "chinese", "国产动画", 167)); //我国出品的PGC动画
zones.Add(new ZoneAttr(168, "original", "国产原创相关", 167)); //
zones.Add(new ZoneAttr(169, "puppetry", "布袋戏", 167)); //
zones.Add(new ZoneAttr(195, "motioncomic", "动态漫·广播剧", 167)); //
zones.Add(new ZoneAttr(170, "information", "资讯", 167)); //
//音乐
zones.Add(new ZoneAttr(3, "music", "音乐")); // 主分区
zones.Add(new ZoneAttr(28, "original", "原创音乐", 3)); //个人或团队制作以音乐为主要原创因素的歌曲或纯音乐
zones.Add(new ZoneAttr(31, "cover", "翻唱", 3)); //一切非官方的人声再演绎歌曲作品
zones.Add(new ZoneAttr(30, "vocaloid", "VOCALOID·UTAU", 3)); //以雅马哈Vocaloid和UTAU引擎为基础,包含其他调教引擎,运用各类音源进行的歌曲创作内容
zones.Add(new ZoneAttr(194, "electronic", "电音", 3)); //以电子合成器、音乐软体等产生的电子声响制作的音乐
zones.Add(new ZoneAttr(59, "perform", "演奏", 3)); //传统或非传统乐器及器材的演奏作品
zones.Add(new ZoneAttr(193, "mv", "MV", 3)); //音乐录影带,为搭配音乐而拍摄的短片
zones.Add(new ZoneAttr(29, "live", "音乐现场", 3)); //音乐实况表演视频
zones.Add(new ZoneAttr(130, "other", "音乐综合", 3)); //收录无法定义到其他音乐子分区的音乐视频
//舞蹈
zones.Add(new ZoneAttr(129, "dance", "舞蹈")); // 主分区
zones.Add(new ZoneAttr(20, "otaku", "宅舞", 129)); //与ACG相关的翻跳、原创舞蹈
zones.Add(new ZoneAttr(198, "hiphop", "街舞", 129)); //收录街舞相关内容,包括赛事现场、舞室作品、个人翻跳、FREESTYLE等
zones.Add(new ZoneAttr(199, "star", "明星舞蹈", 129)); //国内外明星发布的官方舞蹈及其翻跳内容
zones.Add(new ZoneAttr(200, "china", "中国舞", 129)); //传承中国艺术文化的舞蹈内容,包括古典舞、民族民间舞、汉唐舞、古风舞等
zones.Add(new ZoneAttr(154, "three_d", "舞蹈综合", 129)); //收录无法定义到其他舞蹈子分区的舞蹈视频
zones.Add(new ZoneAttr(156, "demo", "舞蹈教程", 129)); //镜面慢速,动作分解,基础教程等具有教学意义的舞蹈视频
//游戏
zones.Add(new ZoneAttr(4, "game", "游戏")); // 主分区
zones.Add(new ZoneAttr(17, "stand_alone", "单机游戏", 4)); //以所有平台(PC、主机、移动端)的单机或联机游戏为主的视频内容,包括游戏预告、CG、实况解说及相关的评测、杂谈与视频剪辑等
zones.Add(new ZoneAttr(171, "esports", "电子竞技", 4)); //具有高对抗性的电子竞技游戏项目,其相关的赛事、实况、攻略、解说、短剧等视频。
zones.Add(new ZoneAttr(172, "mobile", "手机游戏", 4)); //以手机及平板设备为主要平台的游戏,其相关的实况、攻略、解说、短剧、演示等视频。
zones.Add(new ZoneAttr(65, "online", "网络游戏", 4)); //由网络运营商运营的多人在线游戏,以及电子竞技的相关游戏内容。包括赛事、攻略、实况、解说等相关视频
zones.Add(new ZoneAttr(173, "board", "桌游棋牌", 4)); //桌游、棋牌、卡牌对战等及其相关电子版游戏的实况、攻略、解说、演示等视频。
zones.Add(new ZoneAttr(121, "gmv", "GMV", 4)); //由游戏素材制作的MV视频。以游戏内容或CG为主制作的,具有一定创作程度的MV类型的视频
zones.Add(new ZoneAttr(136, "music", "音游", 4)); //各个平台上,通过配合音乐与节奏而进行的音乐类游戏视频
zones.Add(new ZoneAttr(19, "mugen", "Mugen", 4)); //以Mugen引擎为平台制作、或与Mugen相关的游戏视频
//知识
zones.Add(new ZoneAttr(36, "technology", "知识")); // 主分区
zones.Add(new ZoneAttr(201, "science", "科学科普", 36)); //回答你的十万个为什么
zones.Add(new ZoneAttr(124, "fun", "社科人文", 36)); //聊聊互联网社会法律,看看历史趣闻艺术,品品文化心理人物
zones.Add(new ZoneAttr(207, "finance", "财经", 36)); //宏观经济分析,证券市场动态,商业帝国故事,知识与财富齐飞~
zones.Add(new ZoneAttr(208, "campus", "校园学习", 36)); //老师很有趣,同学多人才,我们都爱搞学习
zones.Add(new ZoneAttr(209, "career", "职业职场", 36)); //职场加油站,成为最有料的职场人
zones.Add(new ZoneAttr(122, "wild", "野生技术协会", 36)); //炫酷技能大集合,是时候展现真正的技术了
//数码
zones.Add(new ZoneAttr(188, "digital", "数码")); // 主分区
zones.Add(new ZoneAttr(95, "mobile", "手机平板", 188)); //手机平板、app 和产品教程等相关视频
zones.Add(new ZoneAttr(189, "pc", "电脑装机", 188)); //电脑、笔记本、装机配件、外设和软件教程等相关视频
zones.Add(new ZoneAttr(190, "photography", "摄影摄像", 188)); //摄影摄像器材、拍摄剪辑技巧、拍摄作品分享等相关视频
zones.Add(new ZoneAttr(191, "intelligence_av", "影音智能", 188)); //影音设备、智能硬件、生活家电等相关视频
//汽车
zones.Add(new ZoneAttr(223, "car", "汽车")); // 主分区
zones.Add(new ZoneAttr(176, "life", "汽车生活", 223)); //分享汽车及出行相关的生活体验类视频
zones.Add(new ZoneAttr(224, "culture", "汽车文化", 223)); //车迷的精神圣地,包括汽车赛事、品牌历史、汽车改装、经典车型和汽车模型等
zones.Add(new ZoneAttr(225, "geek", "汽车极客", 223)); //汽车硬核达人聚集地,包括DIY造车、专业评测和技术知识分享
zones.Add(new ZoneAttr(226, "smart", "智能出行", 223)); //探索新能源汽车和未来智能出行的前沿阵地
zones.Add(new ZoneAttr(227, "strategy", "购车攻略", 223)); //丰富详实的购车建议和新车体验
//生活
zones.Add(new ZoneAttr(160, "life", "生活")); // 主分区
zones.Add(new ZoneAttr(138, "funny", "搞笑", 160)); //各种沙雕有趣的搞笑剪辑,挑战,表演,配音等视频
zones.Add(new ZoneAttr(21, "daily", "日常", 160)); //记录日常生活,分享生活故事
zones.Add(new ZoneAttr(161, "handmake", "手工", 160)); //手工制品的制作过程或成品展示、教程、测评类视频
zones.Add(new ZoneAttr(162, "painting", "绘画", 160)); //绘画过程或绘画教程,以及绘画相关的所有视频
zones.Add(new ZoneAttr(163, "sports", "运动", 160)); //运动相关的记录、教程、装备评测和精彩瞬间剪辑视频
zones.Add(new ZoneAttr(174, "other", "其他", 160)); //对分区归属不明的视频进行归纳整合的特定分区
//美食
zones.Add(new ZoneAttr(211, "food", "美食")); // 主分区
zones.Add(new ZoneAttr(76, "make", "美食制作", 211)); //学做人间美味,展示精湛厨艺
zones.Add(new ZoneAttr(212, "detective", "美食侦探", 211)); //寻找美味餐厅,发现街头美食
zones.Add(new ZoneAttr(213, "measurement", "美食测评", 211)); //吃货世界,品尝世间美味
zones.Add(new ZoneAttr(214, "rural", "田园美食", 211)); //品味乡野美食,寻找山与海的味道
zones.Add(new ZoneAttr(215, "record", "美食记录", 211)); //记录一日三餐,给生活添一点幸福感
//动物圈
zones.Add(new ZoneAttr(217, "animal", "动物圈")); // 主分区
zones.Add(new ZoneAttr(218, "cat", "喵星人", 217)); //喵喵喵喵喵
zones.Add(new ZoneAttr(219, "dog", "汪星人", 217)); //汪汪汪汪汪
zones.Add(new ZoneAttr(220, "panda", "大熊猫", 217)); //芝麻汤圆营业中
zones.Add(new ZoneAttr(221, "wild_animal", "野生动物", 217)); //内有“猛兽”出没
zones.Add(new ZoneAttr(222, "reptiles", "爬宠", 217)); //鳞甲有灵
zones.Add(new ZoneAttr(75, "animal_composite", "动物综合", 217)); //收录除上述子分区外,其余动物相关视频以及非动物主体或多个动物主体的动物相关延伸内容
//鬼畜
zones.Add(new ZoneAttr(119, "kichiku", "鬼畜")); // 主分区
zones.Add(new ZoneAttr(22, "guide", "鬼畜调教", 119)); //使用素材在音频、画面上做一定处理,达到与BGM一定的同步感
zones.Add(new ZoneAttr(26, "mad", "音MAD", 119)); //使用素材音频进行一定的二次创作来达到还原原曲的非商业性质稿件
zones.Add(new ZoneAttr(126, "manual_vocaloid", "人力VOCALOID", 119)); //将人物或者角色的无伴奏素材进行人工调音,使其就像VOCALOID一样歌唱的技术
zones.Add(new ZoneAttr(216, "theatre", "鬼畜剧场", 119)); //使用素材进行人工剪辑编排的有剧情的作品
zones.Add(new ZoneAttr(127, "course", "教程演示", 119)); //鬼畜相关的教程演示
//时尚
zones.Add(new ZoneAttr(155, "fashion", "时尚")); // 主分区
zones.Add(new ZoneAttr(157, "makeup", "美妆", 155)); //涵盖妆容、发型、美甲等教程,彩妆、护肤相关产品测评、分享等
zones.Add(new ZoneAttr(158, "clothing", "服饰", 155)); //服饰风格、搭配技巧相关的展示和教程视频
zones.Add(new ZoneAttr(164, "aerobics", "健身", 155)); //器械、有氧、拉伸运动等,以达到强身健体、减肥瘦身、形体塑造目的
zones.Add(new ZoneAttr(159, "catwalk", "T台", 155)); //发布会走秀现场及模特相关时尚片、采访、后台花絮
zones.Add(new ZoneAttr(192, "trends", "风尚标", 155)); //时尚明星专访、街拍、时尚购物相关知识科普
//资讯
zones.Add(new ZoneAttr(202, "information", "资讯")); // 主分区
zones.Add(new ZoneAttr(203, "hotspot", "热点", 202)); //全民关注的时政热门资讯
zones.Add(new ZoneAttr(204, "global", "环球", 202)); //全球范围内发生的具有重大影响力的事件动态
zones.Add(new ZoneAttr(205, "social", "社会", 202)); //日常生活的社会事件、社会问题、社会风貌的报道
zones.Add(new ZoneAttr(206, "multiple", "综合", 202)); //除上述领域外其它垂直领域的综合资讯
//娱乐
zones.Add(new ZoneAttr(5, "ent", "娱乐")); // 主分区
zones.Add(new ZoneAttr(71, "variety", "综艺", 5)); //国内外有趣的综艺和综艺相关精彩剪辑
zones.Add(new ZoneAttr(137, "star", "明星", 5)); //娱乐圈动态、明星资讯相关
//影视
zones.Add(new ZoneAttr(181, "cinephile", "影视")); // 主分区
zones.Add(new ZoneAttr(182, "cinecism", "影视杂谈", 181)); //影视评论、解说、吐槽、科普等
zones.Add(new ZoneAttr(183, "montage", "影视剪辑", 181)); //对影视素材进行剪辑再创作的视频
zones.Add(new ZoneAttr(85, "shortfilm", "短片", 181)); //追求自我表达且具有特色的短片
zones.Add(new ZoneAttr(184, "trailer_info", "预告·资讯", 181)); //影视类相关资讯,预告,花絮等视频
//纪录片
zones.Add(new ZoneAttr(177, "documentary", "纪录片")); // 主分区
zones.Add(new ZoneAttr(37, "history", "人文·历史", 177)); //
zones.Add(new ZoneAttr(178, "science", "科学·探索·自然", 177)); //
zones.Add(new ZoneAttr(179, "military", "军事", 177)); //
zones.Add(new ZoneAttr(180, "travel", "社会·美食·旅行", 177)); //
//电影
zones.Add(new ZoneAttr(23, "movie", "电影")); // 主分区
zones.Add(new ZoneAttr(147, "chinese", "华语电影", 23)); //
zones.Add(new ZoneAttr(145, "west", "欧美电影", 23)); //
zones.Add(new ZoneAttr(146, "japan", "日本电影", 23)); //
zones.Add(new ZoneAttr(83, "movie", "其他国家", 23)); //
//电视剧
zones.Add(new ZoneAttr(11, "tv", "电视剧")); // 主分区
zones.Add(new ZoneAttr(185, "mainland", "国产剧", 11)); //
zones.Add(new ZoneAttr(187, "overseas", "海外剧", 11)); //
}
}
public class ZoneAttr
{
public int Id { get; }
public string Type { get; }
public string Name { get; }
public int ParentId { get; }
public ZoneAttr(int id, string type, string name, int parentId = 0)
{
Id = id;
Type = type;
Name = name;
ParentId = parentId;
}
}
}
+36
View File
@@ -0,0 +1,36 @@
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}";
}
}
}
+115
View File
@@ -0,0 +1,115 @@
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;
}
}
}
+814
View File
@@ -0,0 +1,814 @@
// <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
+20
View File
@@ -0,0 +1,20 @@
syntax = "proto3";
message DanmakuElem {
int64 id = 1; //弹幕dmID
int32 progress = 2; //出现时间
int32 mode = 3; //弹幕类型
int32 fontsize = 4; //文字大小
uint32 color = 5; //弹幕颜色
string midHash = 6; //发送者UID的HASH
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; //弹幕条目
}
@@ -0,0 +1,42 @@
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);
}
}
}
@@ -0,0 +1,24 @@
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; }
}
}
@@ -0,0 +1,317 @@
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;
//}
}
}
@@ -0,0 +1,77 @@
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; }
}
}
+43
View File
@@ -0,0 +1,43 @@
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;
}
}
}
@@ -0,0 +1,11 @@
namespace Core.api.fileDownload
{
internal class ThreadDownloadInfo
{
// 开始位置
public long StartLength { get; set; }
// 下载量
public int Length { get; set; }
}
}
+90
View File
@@ -0,0 +1,90 @@
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, // 文章
}
}
+58
View File
@@ -0,0 +1,58 @@
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;
}
}
}
}
+107
View File
@@ -0,0 +1,107 @@
using Core.entity2.login;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
namespace Core.api.login
{
public class Login
{
private static Login instance;
/// <summary>
/// 获取Login实例
/// </summary>
/// <returns></returns>
public static Login GetInstance()
{
if (instance == null)
{
instance = new Login();
}
return instance;
}
/// <summary>
/// 隐藏Login()方法,必须使用单例模式
/// </summary>
private Login() { }
/// <summary>
/// 申请二维码URL及扫码密钥(web端)
/// </summary>
/// <returns></returns>
public LoginUrlOrigin GetLoginUrl()
{
string getLoginUrl = "https://passport.bilibili.com/qrcode/getLoginUrl";
string referer = "https://passport.bilibili.com/login";
string response = Utils.RequestWeb(getLoginUrl, referer);
try
{
var loginUrl = JsonConvert.DeserializeObject<LoginUrlOrigin>(response);
return loginUrl;
}
catch (Exception e)
{
Console.WriteLine("GetLoginUrl()发生异常: {0}", e);
return null;
}
}
/// <summary>
/// 使用扫码登录(web端)
/// </summary>
/// <param name="oauthKey"></param>
/// <param name="goUrl"></param>
/// <returns></returns>
public LoginStatus GetLoginStatus(string oauthKey, string goUrl = "https://www.bilibili.com")
{
string url = "https://passport.bilibili.com/qrcode/getLoginInfo";
string referer = "https://passport.bilibili.com/login";
Dictionary<string, string> parameters = new Dictionary<string, string>
{
{ "oauthKey", oauthKey },
{ "gourl", goUrl }
};
string response = Utils.RequestWeb(url, referer, "POST", parameters);
var loginInfo = new LoginStatus();
try
{
if (response.Contains("\"code\":0") || response.Contains("\"code\": 0"))
{
var ready = JsonConvert.DeserializeObject<LoginStatusReady>(response);
if (ready == null)
{ return null; }
loginInfo.Code = ready.Code;
loginInfo.Status = ready.Status;
loginInfo.Message = "登录成功";
loginInfo.Url = ready.Data.Url;
}
else
{
var scanning = JsonConvert.DeserializeObject<LoginStatusScanning>(response);
if (scanning == null)
{ return null; }
loginInfo.Code = scanning.Data;
loginInfo.Status = scanning.Status;
loginInfo.Message = scanning.Message;
loginInfo.Url = "";
}
return loginInfo;
}
catch (Exception e)
{
Console.WriteLine("GetLoginInfo()发生异常: {0}", e);
return null;
}
}
}
}
+231
View File
@@ -0,0 +1,231 @@
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;
}
}
}
+58
View File
@@ -0,0 +1,58 @@
using Core.entity2.login;
using Newtonsoft.Json;
using System;
namespace Core.api.login
{
/// <summary>
/// 登录基本信息
/// </summary>
public class LoginInfo
{
private static LoginInfo instance;
/// <summary>
/// 获取UserInfo实例
/// </summary>
/// <returns></returns>
public static LoginInfo GetInstance()
{
if (instance == null)
{
instance = new LoginInfo();
}
return instance;
}
/// <summary>
/// 隐藏LoginInfo()方法,必须使用单例模式
/// </summary>
private LoginInfo() { }
/// <summary>
/// 导航栏用户信息
/// </summary>
/// <returns></returns>
public UserInfoForNavigation GetUserInfoForNavigation()
{
string url = "https://api.bilibili.com/x/web-interface/nav";
string referer = "https://www.bilibili.com";
string response = Utils.RequestWeb(url, referer);
try
{
var userInfo = JsonConvert.DeserializeObject<UserInfoForNavigationOrigin>(response);
if (userInfo == null || userInfo.Data == null) { return null; }
if (userInfo.Data.IsLogin) { return userInfo.Data; }
else { return null; }
}
catch (Exception e)
{
Console.WriteLine("GetUserInfoForNavigation()发生异常: {0}", e);
return null;
}
}
}
}
+81
View File
@@ -0,0 +1,81 @@
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;
}
}
}
}
+290
View File
@@ -0,0 +1,290 @@
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 // 按照最常访问排列
}
}
+520
View File
@@ -0,0 +1,520 @@
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 // 剧集、电影
}
}
+83
View File
@@ -0,0 +1,83 @@
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;
}
}
}
}
+63
View File
@@ -0,0 +1,63 @@
using System;
namespace Core.api.utils
{
public static class BvId
{
private const string tableStr = "fZodR9XQDSUm21yCkr6zBqiveYah8bt4xsWpHnJE7jL5VG3guMTKNPAwcF"; //码表
private static readonly char[] table = tableStr.ToCharArray();
private static readonly char[] tr = new char[124]; //反查码表
private const ulong Xor = 177451812; //固定异或值
private const ulong add = 8728348608; //固定加法值
private static readonly int[] s = { 11, 10, 3, 8, 4, 6 }; //位置编码表
static BvId()
{
Tr_init();
}
//初始化反查码表
private static void Tr_init()
{
for (int i = 0; i < 58; i++)
tr[table[i]] = (char)i;
}
/// <summary>
/// bvid转avid
/// </summary>
/// <param name="bvid"></param>
/// <returns></returns>
public static ulong Bv2Av(string bvid)
{
char[] bv = bvid.ToCharArray();
ulong r = 0;
ulong av;
for (int i = 0; i < 6; i++)
r += tr[bv[s[i]]] * (ulong)Math.Pow(58, i);
av = (r - add) ^ Xor;
return av;
}
/// <summary>
/// avid转bvid
/// </summary>
/// <param name="av"></param>
/// <returns></returns>
public static string Av2Bv(ulong av)
{
//编码结果
string res = "BV1 4 1 7 ";
char[] result = res.ToCharArray();
av = (av ^ Xor) + add;
for (int i = 0; i < 6; i++)
result[s[i]] = table[av / (ulong)Math.Pow(58, i) % 58];
string bv = new string(result);
return bv;
}
}
}
+149
View File
@@ -0,0 +1,149 @@
using System;
namespace Core.api.utils
{
public static class DanmakuSender
{
private const uint CRCPOLYNOMIAL = 0xEDB88320;
private static readonly uint[] crctable = new uint[256];
static DanmakuSender()
{
CreateTable();
}
private static void CreateTable()
{
for (int i = 0; i < 256; i++)
{
uint crcreg = (uint)i;
for (int j = 0; j < 8; j++)
{
if ((crcreg & 1) != 0)
{
crcreg = CRCPOLYNOMIAL ^ (crcreg >> 1);
}
else
{
crcreg >>= 1;
}
}
crctable[i] = crcreg;
}
}
private static uint Crc32(string userId)
{
uint crcstart = 0xFFFFFFFF;
for (int i = 0; i < userId.Length; i++)
{
uint index = (uint)(crcstart ^ (int)userId[i]) & 255;
crcstart = (crcstart >> 8) ^ crctable[index];
}
return crcstart;
}
private static uint Crc32LastIndex(string userId)
{
uint index = 0;
uint crcstart = 0xFFFFFFFF;
for (int i = 0; i < userId.Length; i++)
{
index = (uint)((crcstart ^ (int)userId[i]) & 255);
crcstart = (crcstart >> 8) ^ crctable[index];
}
return index;
}
private static int GetCrcIndex(long t)
{
for (int i = 0; i < 256; i++)
{
if ((crctable[i] >> 24) == t)
{
return i;
}
}
return -1;
}
private static object[] DeepCheck(int i, int[] index)
{
object[] resultArray = new object[2];
string result = "";
uint tc;// = 0x00;
var hashcode = Crc32(i.ToString());
tc = (uint)(hashcode & 0xff ^ index[2]);
if (!(tc <= 57 && tc >= 48))
{
resultArray[0] = 0;
return resultArray;
}
result += (tc - 48).ToString();
hashcode = crctable[index[2]] ^ (hashcode >> 8);
tc = (uint)(hashcode & 0xff ^ index[1]);
if (!(tc <= 57 && tc >= 48))
{
resultArray[0] = 0;
return resultArray;
}
result += (tc - 48).ToString();
hashcode = crctable[index[1]] ^ (hashcode >> 8);
tc = (uint)(hashcode & 0xff ^ index[0]);
if (!(tc <= 57 && tc >= 48))
{
resultArray[0] = 0;
return resultArray;
}
result += (tc - 48).ToString();
//hashcode = crctable[index[0]] ^ (hashcode >> 8);
resultArray[0] = 1;
resultArray[1] = result;
return resultArray;
}
public static string FindDanmakuSender(string userId)
{
object[] deepCheckData = new object[2];
int[] index = new int[4];
uint ht = (uint)Convert.ToInt32($"0x{userId}", 16);
ht ^= 0xffffffff;
int i;
for (i = 3; i > -1; i--)
{
index[3 - i] = GetCrcIndex(ht >> (i * 8));
uint snum = crctable[index[3 - i]];
ht ^= snum >> ((3 - i) * 8);
}
for (i = 0; i < 100000000; i++)
{
uint lastindex = Crc32LastIndex(i.ToString());
if (lastindex == index[3])
{
deepCheckData = DeepCheck(i, index);
if ((int)deepCheckData[0] != 0)
{
break;
}
}
}
if (i == 100000000)
{
return "-1";
}
return $"{i}{deepCheckData[1]}";
}
}
}
+433
View File
@@ -0,0 +1,433 @@
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;
}
}
}
+34 -9
View File
@@ -14,14 +14,6 @@ namespace Core.aria2cNet
TellStatus?.Invoke(totalLength, completedLength, speed, gid);
}
// 全局下载状态
public delegate void GetGlobalStatusHandler(long speed);
public event GetGlobalStatusHandler GetGlobalStatus;
protected virtual void OnGetGlobalStatus(long speed)
{
GetGlobalStatus?.Invoke(speed);
}
// 下载结果回调
public delegate void DownloadFinishHandler(bool isSuccess, string downloadPath, string gid, string msg = null);
public event DownloadFinishHandler DownloadFinish;
@@ -30,6 +22,19 @@ namespace Core.aria2cNet
DownloadFinish?.Invoke(isSuccess, downloadPath, gid, msg);
}
// 全局下载状态
public delegate void GetGlobalStatusHandler(long speed);
public event GetGlobalStatusHandler GlobalStatus;
protected virtual void OnGlobalStatus(long speed)
{
GlobalStatus?.Invoke(speed);
}
/// <summary>
/// 获取gid下载项的状态
/// </summary>
/// <param name="gid"></param>
/// <returns></returns>
public DownloadStatus GetDownloadStatus(string gid)
{
string filePath = "";
@@ -83,12 +88,32 @@ namespace Core.aria2cNet
}
// 降低CPU占用
Thread.Sleep(500);
Thread.Sleep(100);
}
OnDownloadFinish(true, filePath, gid, null);
return DownloadStatus.SUCCESS;
}
/// <summary>
/// 获取全局下载速度
/// </summary>
public async void GetGlobalStatus()
{
while (true)
{
// 查询全局status
var globalStatus = await AriaClient.GetGlobalStatAsync();
if (globalStatus == null || globalStatus.Result == null) { continue; }
long globalSpeed = long.Parse(globalStatus.Result.DownloadSpeed);
// 回调
OnGlobalStatus(globalSpeed);
// 降低CPU占用
Thread.Sleep(100);
}
}
//private async void Poll()
//{
+3 -1
View File
@@ -1035,8 +1035,10 @@ namespace Core.aria2cNet.client
/// <returns></returns>
private async static Task<T> GetRpcResponseAsync<T>(AriaSendData ariaSend)
{
// 去掉null
var jsonSetting = new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore };
// 转换为json字符串
string sendJson = JsonConvert.SerializeObject(ariaSend);
string sendJson = JsonConvert.SerializeObject(ariaSend, Formatting.Indented, jsonSetting);
// 向服务器请求数据
string result = string.Empty;
await Task.Run(() =>
@@ -0,0 +1,111 @@
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 -2
View File
@@ -62,7 +62,7 @@ namespace Core.aria2cNet.server
try
{
var stream = File.Open(logFile, FileMode.Open);
if (stream.Length >= 1024 * 1024 * 1024L)
if (stream.Length >= 512 * 1024 * 1024L)
{
stream.SetLength(0);
}
@@ -83,7 +83,6 @@ namespace Core.aria2cNet.server
headers += $"--header=\"{header}\" ";
}
}
Console.WriteLine(headers);
ExcuteProcess("aria2c.exe",
$"--enable-rpc --rpc-listen-all=true --rpc-allow-origin-all=true " +
+163
View File
@@ -0,0 +1,163 @@
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;
}
}
}
+61
View File
@@ -0,0 +1,61 @@
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);
}
}
}
+55
View File
@@ -0,0 +1,55 @@
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";
}
}
+88
View File
@@ -0,0 +1,88 @@
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;
}
}
}
+12
View File
@@ -0,0 +1,12 @@
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; }
}
}
+6
View File
@@ -0,0 +1,6 @@
namespace Core.danmaku2ass
{
public class Dictionary<T>
{
}
}
+406
View File
@@ -0,0 +1,406 @@
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);
}
}
}
+89
View File
@@ -0,0 +1,89 @@
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);
}
}
}
+105
View File
@@ -0,0 +1,105 @@
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);
}
}
}
+84
View File
@@ -0,0 +1,84 @@
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},
};
}
}
}
+155
View File
@@ -0,0 +1,155 @@
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}";
}
}
}
+228
View File
@@ -0,0 +1,228 @@
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;
}
}
}
+35
View File
@@ -0,0 +1,35 @@
// 注释掉未使用的属性
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; }
//}
}
+199
View File
@@ -0,0 +1,199 @@
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; }
}
}
+44
View File
@@ -0,0 +1,44 @@
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; } // 总的视频数量
}
}
+52
View File
@@ -0,0 +1,52 @@
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; }
}
}
+25
View File
@@ -0,0 +1,25 @@
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; }
}
}
+49
View File
@@ -0,0 +1,49 @@
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; }
}
}
+54
View File
@@ -0,0 +1,54 @@
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; }
}
}
+50
View File
@@ -0,0 +1,50 @@
// 注释掉未使用的属性
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; }
}
}
+96
View File
@@ -0,0 +1,96 @@
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; }
}
}
+88
View File
@@ -0,0 +1,88 @@
// 注释掉未使用的属性
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; }
}
}
+89
View File
@@ -0,0 +1,89 @@
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; }
}
}
+21
View File
@@ -0,0 +1,21 @@
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; } // 悄悄关注数
}
}
+31
View File
@@ -0,0 +1,31 @@
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; }
}
}
+28
View File
@@ -0,0 +1,28 @@
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; }
// ...
}
}
+207
View File
@@ -0,0 +1,207 @@
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; }
}
}
+30
View File
@@ -0,0 +1,30 @@
using Newtonsoft.Json;
namespace Core.entity2
{
public abstract class BaseEntity
{
public string ToString(string format = "")
{
// 设置为去掉null
var jsonSetting = new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore };
switch (format)
{
case "":
return JsonConvert.SerializeObject(this);
case "F":
// 整理json格式
return JsonConvert.SerializeObject(this, Formatting.Indented);
case "N":
// 去掉null后,转换为json字符串
return JsonConvert.SerializeObject(this, Formatting.None, jsonSetting);
case "FN":
case "NF":
return JsonConvert.SerializeObject(this, Formatting.Indented, jsonSetting);
default:
return ToString();
}
}
}
}
+101
View File
@@ -0,0 +1,101 @@
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; }
}
}
+60
View File
@@ -0,0 +1,60 @@
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; }
}
}
+49
View File
@@ -0,0 +1,49 @@
using Newtonsoft.Json;
namespace Core.entity2.login
{
// https://passport.bilibili.com/qrcode/getLoginInfo
[JsonObject]
public class LoginStatus : BaseEntity
{
[JsonProperty("code")]
public int Code { get; set; }
[JsonProperty("status")]
public bool Status { get; set; }
[JsonProperty("message")]
public string Message { get; set; }
[JsonProperty("url")]
public string Url { get; set; }
}
[JsonObject]
public class LoginStatusScanning : BaseEntity
{
[JsonProperty("status")]
public bool Status { get; set; }
[JsonProperty("data")]
public int Data { get; set; }
[JsonProperty("message")]
public string Message { get; set; }
}
[JsonObject]
public class LoginStatusReady : BaseEntity
{
[JsonProperty("code")]
public int Code { get; set; }
[JsonProperty("status")]
public bool Status { get; set; }
//public long ts { get; set; }
[JsonProperty("data")]
public LoginStatusData Data { get; set; }
}
[JsonObject]
public class LoginStatusData : BaseEntity
{
[JsonProperty("url")]
public string Url { get; set; }
}
}
+26
View File
@@ -0,0 +1,26 @@
using Newtonsoft.Json;
namespace Core.entity2.login
{
// https://passport.bilibili.com/qrcode/getLoginUrl
[JsonObject]
public class LoginUrlOrigin : BaseEntity
{
//public int code { get; set; }
[JsonProperty("data")]
public LoginUrl Data { get; set; }
[JsonProperty("status")]
public bool Status { get; set; }
//public long ts { get; set; }
}
[JsonObject]
public class LoginUrl : BaseEntity
{
[JsonProperty("oauthKey")]
public string OauthKey { get; set; }
[JsonProperty("url")]
public string Url { get; set; }
}
}
@@ -0,0 +1,108 @@
using Newtonsoft.Json;
namespace Core.entity2.login
{
// https://api.bilibili.com/x/web-interface/nav
[JsonObject]
public class UserInfoForNavigationOrigin : BaseEntity
{
//[JsonProperty("code")]
//public int Code { get; set; }
[JsonProperty("data")]
public UserInfoForNavigation Data { get; set; }
//[JsonProperty("message")]
//public string Message { get; set; }
//[JsonProperty("ttl")]
//public int Ttl { get; set; }
}
[JsonObject]
public class UserInfoForNavigation : BaseEntity
{
//public int allowance_count { get; set; }
//public int answer_status { get; set; }
//public int email_verified { get; set; }
[JsonProperty("face")]
public string Face { get; set; }
//public bool has_shop { get; set; }
[JsonProperty("isLogin")]
public bool IsLogin { get; set; }
//public NavDataLevelInfo level_info { get; set; }
[JsonProperty("mid")]
public long Mid { get; set; }
//public int mobile_verified { get; set; }
[JsonProperty("money")]
public float Money { get; set; }
//public int moral { get; set; }
//public NavDataOfficial official { get; set; }
//public NavDataOfficialVerify officialVerify { get; set; }
//public NavDataPendant pendant { get; set; }
//public int scores { get; set; }
//public string shop_url { get; set; }
[JsonProperty("uname")]
public string Name { get; set; }
//public long vipDueDate { get; set; }
[JsonProperty("vipStatus")]
public int VipStatus { get; set; }
//public int vipType { get; set; }
//public int vip_avatar_subscript { get; set; }
//public NavDataVipLabel vip_label { get; set; }
//public string vip_nickname_color { get; set; }
//public int vip_pay_type { get; set; }
//public int vip_theme_type { get; set; }
[JsonProperty("wallet")]
public UserInfoWallet Wallet { get; set; }
}
//public class NavDataLevelInfo
//{
// public int current_exp { get; set; }
// public int current_level { get; set; }
// public int current_min { get; set; }
// //public int next_exp { get; set; } // 当等级为6时,next_exp为string类型,值为"--"
//}
//public class NavDataOfficial
//{
// public string desc { get; set; }
// public int role { get; set; }
// public string title { get; set; }
// public int type { get; set; }
//}
//public class NavDataOfficialVerify
//{
// public string desc { get; set; }
// public int type { get; set; }
//}
//public class NavDataPendant
//{
// public int expire { get; set; }
// public string image { get; set; }
// public string image_enhance { get; set; }
// public string name { get; set; }
// public int pid { get; set; }
//}
//public class NavDataVipLabel
//{
// public string label_theme { get; set; }
// public string path { get; set; }
// public string text { get; set; }
//}
[JsonObject]
public class UserInfoWallet : BaseEntity
{
[JsonProperty("bcoin_balance")]
public float BcoinBalance { get; set; }
[JsonProperty("coupon_balance")]
public float CouponBalance { get; set; }
[JsonProperty("coupon_due_time")]
public long CouponDueTime { get; set; }
[JsonProperty("mid")]
public long Mid { get; set; }
}
}
+103
View File
@@ -0,0 +1,103 @@
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; }
}
}
+33
View File
@@ -0,0 +1,33 @@
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; }
}
}
@@ -0,0 +1,42 @@
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; }
// ...
}
}
+166
View File
@@ -0,0 +1,166 @@
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; }
}
}
+43
View File
@@ -0,0 +1,43 @@
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; }
// ...
}
}
+56
View File
@@ -0,0 +1,56 @@
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; }
// ...
}
}
+43
View File
@@ -0,0 +1,43 @@
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; }
// ...
}
}
@@ -0,0 +1,48 @@
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; }
}
}
+103
View File
@@ -0,0 +1,103 @@
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; }
}
}
+65
View File
@@ -0,0 +1,65 @@
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; }
}
}
@@ -0,0 +1,79 @@
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; }
}
}
@@ -0,0 +1,89 @@
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; }
}
}
+77
View File
@@ -0,0 +1,77 @@
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; }
}
}
+150
View File
@@ -0,0 +1,150 @@
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; }
}
}
+46
View File
@@ -0,0 +1,46 @@
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; }
}
}
+31
View File
@@ -0,0 +1,31 @@
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; } // 视频播放量
}
}
@@ -0,0 +1,28 @@
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; }
}
}
+167
View File
@@ -0,0 +1,167 @@
# 设置
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);
```
+65
View File
@@ -0,0 +1,65 @@
namespace Core.settings
{
public partial class Settings
{
// 是否接收测试版更新
private readonly ALLOW_STATUS isReceiveBetaVersion = ALLOW_STATUS.NO;
// 是否在启动时自动检查更新
private readonly ALLOW_STATUS autoUpdateWhenLaunch = ALLOW_STATUS.YES;
/// <summary>
/// 获取是否接收测试版更新
/// </summary>
/// <returns></returns>
public ALLOW_STATUS IsReceiveBetaVersion()
{
if (settingsEntity.IsReceiveBetaVersion == 0)
{
// 第一次获取,先设置默认值
IsReceiveBetaVersion(isReceiveBetaVersion);
return isReceiveBetaVersion;
}
return settingsEntity.IsReceiveBetaVersion;
}
/// <summary>
/// 设置是否接收测试版更新
/// </summary>
/// <param name="isReceiveBetaVersion"></param>
/// <returns></returns>
public bool IsReceiveBetaVersion(ALLOW_STATUS isReceiveBetaVersion)
{
settingsEntity.IsReceiveBetaVersion = isReceiveBetaVersion;
return SetEntity();
}
/// <summary>
/// 获取是否允许启动时检查更新
/// </summary>
/// <returns></returns>
public ALLOW_STATUS GetAutoUpdateWhenLaunch()
{
if (settingsEntity.AutoUpdateWhenLaunch == 0)
{
// 第一次获取,先设置默认值
SetAutoUpdateWhenLaunch(autoUpdateWhenLaunch);
return autoUpdateWhenLaunch;
}
return settingsEntity.AutoUpdateWhenLaunch;
}
/// <summary>
/// 设置是否允许启动时检查更新
/// </summary>
/// <param name="autoUpdateWhenLaunch"></param>
/// <returns></returns>
public bool SetAutoUpdateWhenLaunch(ALLOW_STATUS autoUpdateWhenLaunch)
{
settingsEntity.AutoUpdateWhenLaunch = autoUpdateWhenLaunch;
return SetEntity();
}
}
}
+123
View File
@@ -0,0 +1,123 @@
namespace Core.settings
{
public partial class Settings
{
// 默认下载完成后的操作
private readonly AfterDownloadOperation afterDownload = AfterDownloadOperation.NONE;
// 是否监听剪贴板
private readonly ALLOW_STATUS isListenClipboard = ALLOW_STATUS.YES;
// 视频详情页面是否自动解析
private readonly ALLOW_STATUS isAutoParseVideo = ALLOW_STATUS.NO;
// 下载完成列表排序
private readonly DownloadFinishedSort finishedSort = DownloadFinishedSort.DOWNLOAD;
/// <summary>
/// 获取下载完成后的操作
/// </summary>
/// <returns></returns>
public AfterDownloadOperation GetAfterDownloadOperation()
{
if (settingsEntity.AfterDownload == 0)
{
// 第一次获取,先设置默认值
SetAfterDownloadOperation(afterDownload);
return afterDownload;
}
return settingsEntity.AfterDownload;
}
/// <summary>
/// 设置下载完成后的操作
/// </summary>
/// <param name="afterDownload"></param>
/// <returns></returns>
public bool SetAfterDownloadOperation(AfterDownloadOperation afterDownload)
{
settingsEntity.AfterDownload = afterDownload;
return SetEntity();
}
/// <summary>
/// 是否监听剪贴板
/// </summary>
/// <returns></returns>
public ALLOW_STATUS IsListenClipboard()
{
if (settingsEntity.IsListenClipboard == 0)
{
// 第一次获取,先设置默认值
IsListenClipboard(isListenClipboard);
return isListenClipboard;
}
return settingsEntity.IsListenClipboard;
}
/// <summary>
/// 是否监听剪贴板
/// </summary>
/// <param name="isListen"></param>
/// <returns></returns>
public bool IsListenClipboard(ALLOW_STATUS isListen)
{
settingsEntity.IsListenClipboard = isListen;
return SetEntity();
}
/// <summary>
/// 视频详情页面是否自动解析
/// </summary>
/// <returns></returns>
public ALLOW_STATUS IsAutoParseVideo()
{
if (settingsEntity.IsAutoParseVideo == 0)
{
// 第一次获取,先设置默认值
IsAutoParseVideo(isAutoParseVideo);
return isAutoParseVideo;
}
return settingsEntity.IsAutoParseVideo;
}
/// <summary>
/// 视频详情页面是否自动解析
/// </summary>
/// <param name="IsAuto"></param>
/// <returns></returns>
public bool IsAutoParseVideo(ALLOW_STATUS IsAuto)
{
settingsEntity.IsAutoParseVideo = IsAuto;
return SetEntity();
}
/// <summary>
/// 获取下载完成列表排序
/// </summary>
/// <returns></returns>
public DownloadFinishedSort GetDownloadFinishedSort()
{
if (settingsEntity.DownloadFinishedSort == 0)
{
// 第一次获取,先设置默认值
SetDownloadFinishedSort(finishedSort);
return finishedSort;
}
return settingsEntity.DownloadFinishedSort;
}
/// <summary>
/// 设置下载完成列表排序
/// </summary>
/// <param name="finishedSort"></param>
/// <returns></returns>
public bool SetDownloadFinishedSort(DownloadFinishedSort finishedSort)
{
settingsEntity.DownloadFinishedSort = finishedSort;
return SetEntity();
}
}
}
+90
View File
@@ -0,0 +1,90 @@
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
}
}
+132
View File
@@ -0,0 +1,132 @@
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();
}
}
}
+298
View File
@@ -0,0 +1,298 @@
namespace Core.settings
{
public partial class Settings
{
// 是否屏蔽顶部弹幕
private readonly ALLOW_STATUS danmakuTopFilter = ALLOW_STATUS.NO;
// 是否屏蔽底部弹幕
private readonly ALLOW_STATUS danmakuBottomFilter = ALLOW_STATUS.NO;
// 是否屏蔽滚动弹幕
private readonly ALLOW_STATUS danmakuScrollFilter = ALLOW_STATUS.NO;
// 是否自定义分辨率
private readonly ALLOW_STATUS isCustomDanmakuResolution = ALLOW_STATUS.NO;
// 分辨率-宽
private readonly int danmakuScreenWidth = 1920;
// 分辨率-高
private readonly int danmakuScreenHeight = 1080;
// 弹幕字体
private readonly string danmakuFontName = "黑体";
// 弹幕字体大小
private readonly int danmakuFontSize = 50;
// 弹幕限制行数
private readonly int danmakuLineCount = 0;
// 弹幕布局算法
private readonly DanmakuLayoutAlgorithm danmakuLayoutAlgorithm = DanmakuLayoutAlgorithm.SYNC;
/// <summary>
/// 获取是否屏蔽顶部弹幕
/// </summary>
/// <returns></returns>
public ALLOW_STATUS GetDanmakuTopFilter()
{
if (settingsEntity.DanmakuTopFilter == 0)
{
// 第一次获取,先设置默认值
SetDanmakuTopFilter(danmakuTopFilter);
return danmakuTopFilter;
}
return settingsEntity.DanmakuTopFilter;
}
/// <summary>
/// 设置是否屏蔽顶部弹幕
/// </summary>
/// <param name="danmakuFilter"></param>
/// <returns></returns>
public bool SetDanmakuTopFilter(ALLOW_STATUS danmakuFilter)
{
settingsEntity.DanmakuTopFilter = danmakuFilter;
return SetEntity();
}
/// <summary>
/// 获取是否屏蔽底部弹幕
/// </summary>
/// <returns></returns>
public ALLOW_STATUS GetDanmakuBottomFilter()
{
if (settingsEntity.DanmakuBottomFilter == 0)
{
// 第一次获取,先设置默认值
SetDanmakuBottomFilter(danmakuBottomFilter);
return danmakuBottomFilter;
}
return settingsEntity.DanmakuBottomFilter;
}
/// <summary>
/// 设置是否屏蔽底部弹幕
/// </summary>
/// <param name="danmakuFilter"></param>
/// <returns></returns>
public bool SetDanmakuBottomFilter(ALLOW_STATUS danmakuFilter)
{
settingsEntity.DanmakuBottomFilter = danmakuFilter;
return SetEntity();
}
/// <summary>
/// 获取是否屏蔽滚动弹幕
/// </summary>
/// <returns></returns>
public ALLOW_STATUS GetDanmakuScrollFilter()
{
if (settingsEntity.DanmakuScrollFilter == 0)
{
// 第一次获取,先设置默认值
SetDanmakuScrollFilter(danmakuScrollFilter);
return danmakuScrollFilter;
}
return settingsEntity.DanmakuScrollFilter;
}
/// <summary>
/// 设置是否屏蔽滚动弹幕
/// </summary>
/// <param name="danmakuFilter"></param>
/// <returns></returns>
public bool SetDanmakuScrollFilter(ALLOW_STATUS danmakuFilter)
{
settingsEntity.DanmakuScrollFilter = danmakuFilter;
return SetEntity();
}
/// <summary>
/// 获取是否自定义分辨率
/// </summary>
/// <returns></returns>
public ALLOW_STATUS IsCustomDanmakuResolution()
{
if (settingsEntity.IsCustomDanmakuResolution == 0)
{
// 第一次获取,先设置默认值
IsCustomDanmakuResolution(isCustomDanmakuResolution);
return isCustomDanmakuResolution;
}
return settingsEntity.IsCustomDanmakuResolution;
}
/// <summary>
/// 设置是否自定义分辨率
/// </summary>
/// <param name="isCustomResolution"></param>
/// <returns></returns>
public bool IsCustomDanmakuResolution(ALLOW_STATUS isCustomResolution)
{
settingsEntity.IsCustomDanmakuResolution = isCustomResolution;
return SetEntity();
}
/// <summary>
/// 获取分辨率-宽
/// </summary>
/// <returns></returns>
public int GetDanmakuScreenWidth()
{
if (settingsEntity.DanmakuScreenWidth == 0)
{
// 第一次获取,先设置默认值
SetDanmakuScreenWidth(danmakuScreenWidth);
return danmakuScreenWidth;
}
return settingsEntity.DanmakuScreenWidth;
}
/// <summary>
/// 设置分辨率-宽
/// </summary>
/// <param name="screenWidth"></param>
/// <returns></returns>
public bool SetDanmakuScreenWidth(int screenWidth)
{
settingsEntity.DanmakuScreenWidth = screenWidth;
return SetEntity();
}
/// <summary>
/// 获取分辨率-高
/// </summary>
/// <returns></returns>
public int GetDanmakuScreenHeight()
{
if (settingsEntity.DanmakuScreenHeight == 0)
{
// 第一次获取,先设置默认值
SetDanmakuScreenHeight(danmakuScreenHeight);
return danmakuScreenHeight;
}
return settingsEntity.DanmakuScreenHeight;
}
/// <summary>
/// 设置分辨率-高
/// </summary>
/// <param name="screenHeight"></param>
/// <returns></returns>
public bool SetDanmakuScreenHeight(int screenHeight)
{
settingsEntity.DanmakuScreenHeight = screenHeight;
return SetEntity();
}
/// <summary>
/// 获取弹幕字体
/// </summary>
/// <returns></returns>
public string GetDanmakuFontName()
{
if (settingsEntity.DanmakuFontName == null)
{
// 第一次获取,先设置默认值
SetDanmakuFontName(danmakuFontName);
return danmakuFontName;
}
return settingsEntity.DanmakuFontName;
}
/// <summary>
/// 设置弹幕字体
/// </summary>
/// <param name="danmakuFontName"></param>
/// <returns></returns>
public bool SetDanmakuFontName(string danmakuFontName)
{
settingsEntity.DanmakuFontName = danmakuFontName;
return SetEntity();
}
/// <summary>
/// 获取弹幕字体大小
/// </summary>
/// <returns></returns>
public int GetDanmakuFontSize()
{
if (settingsEntity.DanmakuFontSize == 0)
{
// 第一次获取,先设置默认值
SetDanmakuFontSize(danmakuFontSize);
return danmakuFontSize;
}
return settingsEntity.DanmakuFontSize;
}
/// <summary>
/// 设置弹幕字体大小
/// </summary>
/// <param name="danmakuFontSize"></param>
/// <returns></returns>
public bool SetDanmakuFontSize(int danmakuFontSize)
{
settingsEntity.DanmakuFontSize = danmakuFontSize;
return SetEntity();
}
/// <summary>
/// 获取弹幕限制行数
/// </summary>
/// <returns></returns>
public int GetDanmakuLineCount()
{
if (settingsEntity.DanmakuLineCount == 0)
{
// 第一次获取,先设置默认值
SetDanmakuLineCount(danmakuLineCount);
return danmakuLineCount;
}
return settingsEntity.DanmakuLineCount;
}
/// <summary>
/// 设置弹幕限制行数
/// </summary>
/// <param name="danmakuLineCount"></param>
/// <returns></returns>
public bool SetDanmakuLineCount(int danmakuLineCount)
{
settingsEntity.DanmakuLineCount = danmakuLineCount;
return SetEntity();
}
/// <summary>
/// 获取弹幕布局算法
/// </summary>
/// <returns></returns>
public DanmakuLayoutAlgorithm GetDanmakuLayoutAlgorithm()
{
if (settingsEntity.DanmakuLayoutAlgorithm == 0)
{
// 第一次获取,先设置默认值
SetDanmakuLayoutAlgorithm(danmakuLayoutAlgorithm);
return danmakuLayoutAlgorithm;
}
return settingsEntity.DanmakuLayoutAlgorithm;
}
/// <summary>
/// 设置弹幕布局算法
/// </summary>
/// <param name="danmakuLayoutAlgorithm"></param>
/// <returns></returns>
public bool SetDanmakuLayoutAlgorithm(DanmakuLayoutAlgorithm danmakuLayoutAlgorithm)
{
settingsEntity.DanmakuLayoutAlgorithm = danmakuLayoutAlgorithm;
return SetEntity();
}
}
}
+324
View File
@@ -0,0 +1,324 @@
using Core.aria2cNet.server;
namespace Core.settings
{
public partial class Settings
{
// 是否开启解除地区限制
private readonly ALLOW_STATUS isLiftingOfRegion = ALLOW_STATUS.YES;
// Aria服务器端口号
private readonly int ariaListenPort = 6800;
// Aria日志等级
private readonly AriaConfigLogLevel ariaLogLevel = AriaConfigLogLevel.INFO;
// Aria最大同时下载数(任务数)
private readonly int ariaMaxConcurrentDownloads = 3;
// Aria单文件最大线程数
private readonly int ariaSplit = 5;
// Aria下载速度限制
private readonly int ariaMaxOverallDownloadLimit = 0;
// Aria下载单文件速度限制
private readonly int ariaMaxDownloadLimit = 0;
// Aria文件预分配
private readonly AriaConfigFileAllocation ariaFileAllocation = AriaConfigFileAllocation.PREALLOC;
// Aria HttpProxy代理
private readonly ALLOW_STATUS isAriaHttpProxy = ALLOW_STATUS.NO;
private readonly string ariaHttpProxy = "";
private readonly int ariaHttpProxyListenPort = 0;
/// <summary>
/// 获取是否解除地区限制
/// </summary>
/// <returns></returns>
public ALLOW_STATUS IsLiftingOfRegion()
{
if (settingsEntity.IsLiftingOfRegion == 0)
{
// 第一次获取,先设置默认值
IsLiftingOfRegion(isLiftingOfRegion);
return isLiftingOfRegion;
}
return settingsEntity.IsLiftingOfRegion;
}
/// <summary>
/// 设置是否解除地区限制
/// </summary>
/// <param name="isLiftingOfRegion"></param>
/// <returns></returns>
public bool IsLiftingOfRegion(ALLOW_STATUS isLiftingOfRegion)
{
settingsEntity.IsLiftingOfRegion = isLiftingOfRegion;
return SetEntity();
}
/// <summary>
/// 获取Aria服务器的端口号
/// </summary>
/// <returns></returns>
public int GetAriaListenPort()
{
if (settingsEntity.AriaListenPort == 0)
{
// 第一次获取,先设置默认值
SetAriaListenPort(ariaListenPort);
return ariaListenPort;
}
return settingsEntity.AriaListenPort;
}
/// <summary>
/// 设置Aria服务器的端口号
/// </summary>
/// <param name="ariaListenPort"></param>
/// <returns></returns>
public bool SetAriaListenPort(int ariaListenPort)
{
settingsEntity.AriaListenPort = ariaListenPort;
return SetEntity();
}
/// <summary>
/// 获取Aria日志等级
/// </summary>
/// <returns></returns>
public AriaConfigLogLevel GetAriaLogLevel()
{
if (settingsEntity.AriaLogLevel == 0)
{
// 第一次获取,先设置默认值
SetAriaLogLevel(ariaLogLevel);
return ariaLogLevel;
}
return settingsEntity.AriaLogLevel;
}
/// <summary>
/// 设置Aria日志等级
/// </summary>
/// <param name="ariaLogLevel"></param>
/// <returns></returns>
public bool SetAriaLogLevel(AriaConfigLogLevel ariaLogLevel)
{
settingsEntity.AriaLogLevel = ariaLogLevel;
return SetEntity();
}
/// <summary>
/// 获取Aria最大同时下载数(任务数)
/// </summary>
/// <returns></returns>
public int GetAriaMaxConcurrentDownloads()
{
if (settingsEntity.AriaMaxConcurrentDownloads == 0)
{
// 第一次获取,先设置默认值
SetAriaMaxConcurrentDownloads(ariaMaxConcurrentDownloads);
return ariaMaxConcurrentDownloads;
}
return settingsEntity.AriaMaxConcurrentDownloads;
}
/// <summary>
/// 设置Aria最大同时下载数(任务数)
/// </summary>
/// <param name="ariaMaxConcurrentDownloads"></param>
/// <returns></returns>
public bool SetAriaMaxConcurrentDownloads(int ariaMaxConcurrentDownloads)
{
settingsEntity.AriaMaxConcurrentDownloads = ariaMaxConcurrentDownloads;
return SetEntity();
}
/// <summary>
/// 获取Aria单文件最大线程数
/// </summary>
/// <returns></returns>
public int GetAriaSplit()
{
if (settingsEntity.AriaSplit == 0)
{
// 第一次获取,先设置默认值
SetAriaSplit(ariaSplit);
return ariaSplit;
}
return settingsEntity.AriaSplit;
}
/// <summary>
/// 设置Aria单文件最大线程数
/// </summary>
/// <param name="ariaSplit"></param>
/// <returns></returns>
public bool SetAriaSplit(int ariaSplit)
{
settingsEntity.AriaSplit = ariaSplit;
return SetEntity();
}
/// <summary>
/// 获取Aria下载速度限制
/// </summary>
/// <returns></returns>
public int GetAriaMaxOverallDownloadLimit()
{
if (settingsEntity.AriaMaxOverallDownloadLimit == 0)
{
// 第一次获取,先设置默认值
SetAriaMaxOverallDownloadLimit(ariaMaxOverallDownloadLimit);
return ariaMaxOverallDownloadLimit;
}
return settingsEntity.AriaMaxOverallDownloadLimit;
}
/// <summary>
/// 设置Aria下载速度限制
/// </summary>
/// <param name="ariaMaxOverallDownloadLimit"></param>
/// <returns></returns>
public bool SetAriaMaxOverallDownloadLimit(int ariaMaxOverallDownloadLimit)
{
settingsEntity.AriaMaxOverallDownloadLimit = ariaMaxOverallDownloadLimit;
return SetEntity();
}
/// <summary>
/// 获取Aria下载单文件速度限制
/// </summary>
/// <returns></returns>
public int GetAriaMaxDownloadLimit()
{
if (settingsEntity.AriaMaxDownloadLimit == 0)
{
// 第一次获取,先设置默认值
SetAriaMaxDownloadLimit(ariaMaxDownloadLimit);
return ariaMaxDownloadLimit;
}
return settingsEntity.AriaMaxDownloadLimit;
}
/// <summary>
/// 设置Aria下载单文件速度限制
/// </summary>
/// <param name="ariaMaxDownloadLimit"></param>
/// <returns></returns>
public bool SetAriaMaxDownloadLimit(int ariaMaxDownloadLimit)
{
settingsEntity.AriaMaxDownloadLimit = ariaMaxDownloadLimit;
return SetEntity();
}
/// <summary>
/// 获取Aria文件预分配
/// </summary>
/// <returns></returns>
public AriaConfigFileAllocation GetAriaFileAllocation()
{
if (settingsEntity.AriaFileAllocation == 0)
{
// 第一次获取,先设置默认值
SetAriaFileAllocation(ariaFileAllocation);
return ariaFileAllocation;
}
return settingsEntity.AriaFileAllocation;
}
/// <summary>
/// 设置Aria文件预分配
/// </summary>
/// <param name="ariaFileAllocation"></param>
/// <returns></returns>
public bool SetAriaFileAllocation(AriaConfigFileAllocation ariaFileAllocation)
{
settingsEntity.AriaFileAllocation = ariaFileAllocation;
return SetEntity();
}
/// <summary>
/// 获取是否开启Aria http代理
/// </summary>
/// <returns></returns>
public ALLOW_STATUS IsAriaHttpProxy()
{
if (settingsEntity.IsAriaHttpProxy == 0)
{
// 第一次获取,先设置默认值
IsAriaHttpProxy(isAriaHttpProxy);
return isAriaHttpProxy;
}
return settingsEntity.IsAriaHttpProxy;
}
/// <summary>
/// 设置是否开启Aria http代理
/// </summary>
/// <param name="isAriaHttpProxy"></param>
/// <returns></returns>
public bool IsAriaHttpProxy(ALLOW_STATUS isAriaHttpProxy)
{
settingsEntity.IsAriaHttpProxy = isAriaHttpProxy;
return SetEntity();
}
/// <summary>
/// 获取Aria的http代理的地址
/// </summary>
/// <returns></returns>
public string GetAriaHttpProxy()
{
if (settingsEntity.AriaHttpProxy == null)
{
// 第一次获取,先设置默认值
SetAriaHttpProxy(ariaHttpProxy);
return ariaHttpProxy;
}
return settingsEntity.AriaHttpProxy;
}
/// <summary>
/// 设置Aria的http代理的地址
/// </summary>
/// <param name="ariaHttpProxy"></param>
/// <returns></returns>
public bool SetAriaHttpProxy(string ariaHttpProxy)
{
settingsEntity.AriaHttpProxy = ariaHttpProxy;
return SetEntity();
}
/// <summary>
/// 获取Aria的http代理的端口
/// </summary>
/// <returns></returns>
public int GetAriaHttpProxyListenPort()
{
if (settingsEntity.AriaHttpProxyListenPort == 0)
{
// 第一次获取,先设置默认值
SetAriaHttpProxyListenPort(ariaHttpProxyListenPort);
return ariaHttpProxyListenPort;
}
return settingsEntity.AriaHttpProxyListenPort;
}
/// <summary>
/// 设置Aria的http代理的端口
/// </summary>
/// <param name="ariaHttpProxyListenPort"></param>
/// <returns></returns>
public bool SetAriaHttpProxyListenPort(int ariaHttpProxyListenPort)
{
settingsEntity.AriaHttpProxyListenPort = ariaHttpProxyListenPort;
return SetEntity();
}
}
}
+273
View File
@@ -0,0 +1,273 @@
namespace Core.settings
{
public partial class Settings
{
// 设置优先下载的视频编码
private readonly VideoCodecs videoCodecs = VideoCodecs.AVC;
// 设置优先下载画质
private readonly int quality = 120;
// 是否在下载的视频前增加序号
private readonly ALLOW_STATUS isAddOrder = ALLOW_STATUS.NO;
// 是否下载flv视频后转码为mp4
private readonly ALLOW_STATUS isTranscodingFlvToMp4 = ALLOW_STATUS.YES;
// 默认下载目录
private readonly string saveVideoRootPath = "./Media";
// 是否使用默认下载目录,如果是,则每次点击下载选中项时不再询问下载目录
private readonly ALLOW_STATUS isUseSaveVideoRootPath = ALLOW_STATUS.NO;
// 是否为不同视频分别创建文件夹
private readonly ALLOW_STATUS isCreateFolderForMedia = ALLOW_STATUS.YES;
// 是否在下载视频的同时下载弹幕
private readonly ALLOW_STATUS isDownloadDanmaku = ALLOW_STATUS.YES;
// 是否在下载视频的同时下载封面
private readonly ALLOW_STATUS isDownloadCover = ALLOW_STATUS.YES;
/// <summary>
/// 获取优先下载的视频编码
/// </summary>
/// <returns></returns>
public VideoCodecs GetVideoCodecs()
{
if (settingsEntity.VideoCodecs == 0)
{
// 第一次获取,先设置默认值
SetVideoCodecs(videoCodecs);
return videoCodecs;
}
return settingsEntity.VideoCodecs;
}
/// <summary>
/// 设置优先下载的视频编码
/// </summary>
/// <param name="videoCodecs"></param>
/// <returns></returns>
public bool SetVideoCodecs(VideoCodecs videoCodecs)
{
settingsEntity.VideoCodecs = videoCodecs;
return SetEntity();
}
/// <summary>
/// 获取优先下载画质
/// </summary>
/// <returns></returns>
public int GetQuality()
{
if (settingsEntity.Quality == 0)
{
// 第一次获取,先设置默认值
SetQuality(quality);
return quality;
}
return settingsEntity.Quality;
}
/// <summary>
/// 设置优先下载画质
/// </summary>
/// <param name="quality"></param>
/// <returns></returns>
public bool SetQuality(int quality)
{
settingsEntity.Quality = quality;
return SetEntity();
}
/// <summary>
/// 获取是否给视频增加序号
/// </summary>
/// <returns></returns>
public ALLOW_STATUS IsAddOrder()
{
if (settingsEntity.IsAddOrder == 0)
{
// 第一次获取,先设置默认值
IsAddOrder(isAddOrder);
return isAddOrder;
}
return settingsEntity.IsAddOrder;
}
/// <summary>
/// 设置是否给视频增加序号
/// </summary>
/// <param name="isAddOrder"></param>
/// <returns></returns>
public bool IsAddOrder(ALLOW_STATUS isAddOrder)
{
settingsEntity.IsAddOrder = isAddOrder;
return SetEntity();
}
/// <summary>
/// 获取是否下载flv视频后转码为mp4
/// </summary>
/// <returns></returns>
public ALLOW_STATUS IsTranscodingFlvToMp4()
{
if (settingsEntity.IsTranscodingFlvToMp4 == 0)
{
// 第一次获取,先设置默认值
IsTranscodingFlvToMp4(isTranscodingFlvToMp4);
return isTranscodingFlvToMp4;
}
return settingsEntity.IsTranscodingFlvToMp4;
}
/// <summary>
/// 设置是否下载flv视频后转码为mp4
/// </summary>
/// <param name="isTranscodingFlvToMp4"></param>
/// <returns></returns>
public bool IsTranscodingFlvToMp4(ALLOW_STATUS isTranscodingFlvToMp4)
{
settingsEntity.IsTranscodingFlvToMp4 = isTranscodingFlvToMp4;
return SetEntity();
}
/// <summary>
/// 获取下载目录
/// </summary>
/// <returns></returns>
public string GetSaveVideoRootPath()
{
if (settingsEntity.SaveVideoRootPath == null)
{
// 第一次获取,先设置默认值
SetSaveVideoRootPath(saveVideoRootPath);
return saveVideoRootPath;
}
return settingsEntity.SaveVideoRootPath;
}
/// <summary>
/// 设置下载目录
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
public bool SetSaveVideoRootPath(string path)
{
settingsEntity.SaveVideoRootPath = path;
return SetEntity();
}
/// <summary>
/// 获取是否使用默认下载目录
/// </summary>
/// <returns></returns>
public ALLOW_STATUS IsUseSaveVideoRootPath()
{
if (settingsEntity.IsUseSaveVideoRootPath == 0)
{
// 第一次获取,先设置默认值
IsUseSaveVideoRootPath(isUseSaveVideoRootPath);
return isUseSaveVideoRootPath;
}
return settingsEntity.IsUseSaveVideoRootPath;
}
/// <summary>
/// 设置是否使用默认下载目录
/// </summary>
/// <param name="isUseSaveVideoRootPath"></param>
/// <returns></returns>
public bool IsUseSaveVideoRootPath(ALLOW_STATUS isUseSaveVideoRootPath)
{
settingsEntity.IsUseSaveVideoRootPath = isUseSaveVideoRootPath;
return SetEntity();
}
/// <summary>
/// 获取是否为不同视频分别创建文件夹
/// </summary>
/// <returns></returns>
public ALLOW_STATUS IsCreateFolderForMedia()
{
if (settingsEntity.IsCreateFolderForMedia == 0)
{
// 第一次获取,先设置默认值
IsCreateFolderForMedia(isCreateFolderForMedia);
return isCreateFolderForMedia;
}
return settingsEntity.IsCreateFolderForMedia;
}
/// <summary>
/// 设置是否为不同视频分别创建文件夹
/// </summary>
/// <param name="isCreateFolderForMedia"></param>
/// <returns></returns>
public bool IsCreateFolderForMedia(ALLOW_STATUS isCreateFolderForMedia)
{
settingsEntity.IsCreateFolderForMedia = isCreateFolderForMedia;
return SetEntity();
}
/// <summary>
/// 获取是否在下载视频的同时下载弹幕
/// </summary>
/// <returns></returns>
public ALLOW_STATUS IsDownloadDanmaku()
{
if (settingsEntity.IsDownloadDanmaku == 0)
{
// 第一次获取,先设置默认值
IsDownloadDanmaku(isDownloadDanmaku);
return isDownloadDanmaku;
}
return settingsEntity.IsDownloadDanmaku;
}
/// <summary>
/// 设置是否在下载视频的同时下载弹幕
/// </summary>
/// <param name="isDownloadDanmaku"></param>
/// <returns></returns>
public bool IsDownloadDanmaku(ALLOW_STATUS isDownloadDanmaku)
{
settingsEntity.IsDownloadDanmaku = isDownloadDanmaku;
return SetEntity();
}
/// <summary>
/// 获取是否在下载视频的同时下载封面
/// </summary>
/// <returns></returns>
public ALLOW_STATUS IsDownloadCover()
{
if (settingsEntity.IsDownloadCover == 0)
{
// 第一次获取,先设置默认值
IsDownloadCover(isDownloadCover);
return isDownloadCover;
}
return settingsEntity.IsDownloadCover;
}
/// <summary>
/// 设置是否在下载视频的同时下载封面
/// </summary>
/// <param name="isDownloadCover"></param>
/// <returns></returns>
public bool IsDownloadCover(ALLOW_STATUS isDownloadCover)
{
settingsEntity.IsDownloadCover = isDownloadCover;
return SetEntity();
}
}
}