提交功能

This commit is contained in:
Bob.Song
2026-02-08 16:58:32 +08:00
commit 9dd1e6c278
67 changed files with 4588 additions and 0 deletions

View File

@@ -0,0 +1,177 @@
using System.ComponentModel;
using System.Text.RegularExpressions;
using Downloader;
using Newtonsoft.Json;
using RestSharp;
namespace ACBuildService;
public class DouYin : DownloadPlatforms
{
private static readonly Dictionary<string, string> _defaultHeaders = new()
{
{
"User-Agent",
"Mozilla/5.0 (Linux; Android 8.0.0; SM-G955U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Mobile Safari/537.36"
},
{ "sec-fetch-site", "same-origin" },
{ "sec-fetch-mode", "cors" },
{ "sec-fetch-dest", "empty" },
{ "sec-ch-ua-platform", "Windows" },
{ "sec-ch-ua-mobile", "?0" },
{ "sec-ch-ua", "\"Not/A)Brand\";v=\"8\", \"Chromium\";v=\"126\", \"Google Chrome\";v=\"126\"" },
{ "referer", "https://www.douyin.com/?recommend=1" },
{ "priority", "u=1, i" },
{ "pragma", "no-cache" },
{ "cache-control", "no-cache" },
{ "accept-language", "zh-CN,zh;q=0.9,en;q=0.8" },
{
"accept",
"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7"
},
{ "dnt", "1" }
};
public async override Task<string> ExtractUrlAsync(string text)
{
Log.Info($"开始解析抖音链接 {text}");
return Regex.Match(text, @"https?://[^\s]+").Value;
}
public override async Task<VideoModel> ParseShare(string DownloadUrlText)
{
if (!DownloadUrlText.Contains("https://"))
{
Log.Error("请输入正确的分享链接");
return null;
}
var downloadUrl = await ExtractUrlAsync(DownloadUrlText);
VideoModel Data = await ExtractVideoDataAsync(downloadUrl);
Data.ShareId = downloadUrl.Replace("https://v.douyin.com/", "").Replace("/", "");
return Data;
}
/// <summary>
/// 根据链接 https://v.douyin.com/ircqoExo/ 解析出页面中的数据
/// </summary>
/// <param name="url"></param>
/// <returns></returns>
public override Task<VideoModel> ExtractVideoDataAsync(string url)
{
try
{
Log.Info($"开始解析链接 {url}");
// 创建RestClient
RestClient client = new(url);
// 创建请求对象
RestRequest request = new();
// 设置 User-Agent 模拟手机浏览器
request.AddHeaders(_defaultHeaders);
// 发送请求并获取响应
var response = client.Execute(request);
if (!response.IsSuccessful) throw new HttpRequestException("request is fail");
var content = response.Content;
Log.Info($"开始解析响应内容 {content}");
if (content is null) throw new InvalidDataException("content is null");
const string routerDataPattern = @"_ROUTER_DATA\s*=\s*(\{.*?\})<";
var matchJson = Regex.Match(content, routerDataPattern);
Log.Info($"开始解析匹配到的json {matchJson}");
if (matchJson.Groups.Count < 2) throw new InvalidDataException("未匹配到合法的数据matchJson.Groups.Count < 2");
var videoJson = matchJson.Groups[1].Value;
Log.Info($"开始解析匹配到的json {videoJson}");
// 反序列化JSON字符串为C#对象
var videoData = JsonConvert.DeserializeObject<DouYinShareRouterData>(videoJson);
if (videoData is null) throw new InvalidDataException("JSON解析数据为空请检查分享链接是否正确如有更多问题请查看日志");
var videoInfoData = videoData.LoaderData.VideoIdPage.VideoInfoRes.ItemList.First();
var video = new VideoModel
{
Platform = ShortVideoPlatformEnum.DouYin,
VideoId = videoInfoData.AwemeId,
AuthorName = videoInfoData.Author.Nickname,
UniqueId = videoInfoData.Author.UniqueId == ""
? videoInfoData.Author.ShortId
: videoInfoData.Author.UniqueId,
AuthorAvatar = videoInfoData.Author.AvatarThumb.UrlList.First().ToString(),
Title = videoInfoData.Author.Signature,
Cover = videoInfoData.Video.Cover.UrlList.Last().ToString(),
Mp3Url = "",
CreatedTime =
DateTimeOffset.FromUnixTimeSeconds(videoInfoData.CreateTime)
.ToString("yyyy-MM-dd HH:mm:ss"),
Desc = videoInfoData.Desc,
Duration = "",
DiggCount = videoInfoData.Statistics.DiggCount,
CollectCount = videoInfoData.Statistics.CollectCount,
CommentCount = videoInfoData.Statistics.CommentCount,
ShareCount = videoInfoData.Statistics.ShareCount
};
switch (videoInfoData.AwemeType)
{
case 2:
video.VideoUrl = videoInfoData.Video.Cover.UrlList.First().ToString();
break;
default:
video.VideoUrl = videoInfoData.Video.PlayAddr.UrlList.First().ToString().Replace("playwm", "play");
break;
}
if (video.VideoUrl.Contains("ratio=720p"))
{
video.VideoUrl = video.VideoUrl.Replace("ratio=720p", "ratio=1080p");
}
return Task.FromResult(video);
}
catch (Exception e)
{
Log.Error(e.Message);
throw;
}
}
public override async Task<bool> DownloadAsync(string url, string savePath, string fileName,
EventHandler<DownloadProgressChangedEventArgs> onProgressChanged,
EventHandler<AsyncCompletedEventArgs> onProgressCompleted)
{
DownloadConfiguration downloadConfiguration = new()
{
ChunkCount = 8, // Download in 8 chunks (increase for larger files)
MaxTryAgainOnFailure = 5,
Timeout = 10000, // 10 seconds timeout for each request
RequestConfiguration = new RequestConfiguration
{
UserAgent = _defaultHeaders.GetValueOrDefault("User-Agent")
}
};
DownloadService downloader = new(downloadConfiguration);
downloader.DownloadProgressChanged += onProgressChanged;
downloader.DownloadFileCompleted += onProgressCompleted;
try
{
await downloader.DownloadFileTaskAsync(url, Path.Combine(savePath, fileName));
return true;
}
catch (Exception ex)
{
Log.Info($"Download failed: {ex}");
}
return false;
}
}

View File

@@ -0,0 +1,15 @@
using System.ComponentModel;
using Downloader;
namespace ACBuildService;
public abstract class DownloadPlatforms
{
public abstract Task<string> ExtractUrlAsync(string text);
public abstract Task<VideoModel> ParseShare(string DownloadUrlText);
public abstract Task<VideoModel> ExtractVideoDataAsync(string url);
public abstract Task<bool> DownloadAsync(string url, string savePath, string fileName,
EventHandler<DownloadProgressChangedEventArgs> onProgressChanged,
EventHandler<AsyncCompletedEventArgs> onProgressCompleted);
}

View File

@@ -0,0 +1,53 @@
using System.ComponentModel;
using Downloader;
namespace ACBuildService;
public class KuaiShou : DownloadPlatforms
{
private static readonly Dictionary<string, string> _defaultHeaders = new()
{
{
"User-Agent",
"Mozilla/5.0 (Linux; Android 8.0.0; SM-G955U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Mobile Safari/537.36"
},
{ "sec-fetch-site", "same-origin" },
{ "sec-fetch-mode", "cors" },
{ "sec-fetch-dest", "empty" },
{ "sec-ch-ua-platform", "Windows" },
{ "sec-ch-ua-mobile", "?0" },
{ "sec-ch-ua", "\"Not/A)Brand\";v=\"8\", \"Chromium\";v=\"126\", \"Google Chrome\";v=\"126\"" },
{ "referer", "https://www.douyin.com/?recommend=1" },
{ "priority", "u=1, i" },
{ "pragma", "no-cache" },
{ "cache-control", "no-cache" },
{ "accept-language", "zh-CN,zh;q=0.9,en;q=0.8" },
{
"accept",
"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7"
},
{ "dnt", "1" }
};
public override Task<string> ExtractUrlAsync(string text)
{
throw new NotImplementedException();
}
public override Task<VideoModel> ParseShare(string DownloadUrlText)
{
throw new NotImplementedException();
}
public override Task<VideoModel> ExtractVideoDataAsync(string url)
{
throw new NotImplementedException();
}
public override Task<bool> DownloadAsync(string url, string savePath, string fileName,
EventHandler<DownloadProgressChangedEventArgs> onProgressChanged,
EventHandler<AsyncCompletedEventArgs> onProgressCompleted)
{
throw new NotImplementedException();
}
}