Files
BabyVideoService/VideoDownload/Platforms/KuaiShou.cs
2026-02-08 17:47:11 +08:00

206 lines
8.2 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.ComponentModel;
using System.Text.RegularExpressions;
using ACBuildService.Platforms.KuaiShow;
using Downloader;
using Newtonsoft.Json;
using RestSharp;
namespace ACBuildService;
public class KuaiShou : DownloadPlatforms
{
private static readonly Dictionary<string, string> _locationHeaders = new()
{
{
"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"
},
{ "Accept-Language", "zh-CN,zh;q=0.9" },
{ "Cache-Control", "no-cache" },
{ "Connection", "keep-alive" },
{ "DNT", "1" },
{ "Host", "www.kuaishou.com" },
{ "Pragma", "no-cache" },
{ "Sec-Fetch-Dest", "document" },
{ "Sec-Fetch-Mode", "navigate" },
{ "Sec-Fetch-Site", "none" },
{ "Sec-Fetch-User", "?1" },
{ "Upgrade-Insecure-Requests", "1" },
{
"UserAgent",
"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-ch-ua", "\"Chromium\";v=\"128\", \"Not;A=Brand\";v=\"24\", \"Google Chrome\";v=\"128\"" },
{ "sec-ch-ua-mobile", "?1" },
{ "sec-ch-ua-platform", "\"Android\"" }
// {
// "Cookie",
// "kpf=PC_WEB; kpn=KUAISHOU_VISION; clientid=3; did=web_6ece7cfdd334f69ac1fe2579040329d0; didv=1725957114469"
// }
};
private static readonly Dictionary<string, string> _videoInfoHeaders = new()
{
{
"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"
},
{ "Accept-Encoding", "gzip, deflate, br, zstd" },
{ "Accept-Language", "zh-CN,zh;q=0.9" },
{ "Cache-Control", "no-cache" },
{ "Connection", "keep-alive" },
{
"Cookie",
"kpf=PC_WEB; clientid=3; did=web_5ee38d442bc5387e413eeeefc42ed4a2; didv=1734437469000; kpn=KUAISHOU_VISION"
},
{ "DNT", "1" },
{ "Host", "m.gifshow.com" },
{ "Origin", "https://m.gifshow.com" },
{ "Pragma", "no-cache" },
// {
// "Referer",
// "https://m.gifshow.com/fw/photo/3xvfmfagspjxq9q?cc=share_copylink&kpf=PC_WEB&utm_campaign=pc_share&shareMethod=token&utm_medium=pc_share&kpn=KUAISHOU_VISION&subBiz=SINGLE_ROW_WEB&ztDid=web_126778f97e238efa29915c708f0789b6&shareId=18063407013272&shareToken=X-1KuDdzw7LGTYAM&shareMode=app&efid=0&shareObjectId=3xvfmfagspjxq9q&utm_source=pc_share"
// },
{ "Sec-Fetch-Dest", "document" },
{ "Sec-Fetch-Mode", "navigate" },
{ "Sec-Fetch-Site", "none" },
{
"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"
},
{ "content-type", "application/json" },
{ "sec-ch-ua", "\"Chromium\";v=\"128\", \"Not;A=Brand\";v=\"24\", \"Google Chrome\";v=\"128\"" },
{ "sec-ch-ua-mobile", "?1" },
{ "sec-ch-ua-platform", "\"Android\"" }
};
public override async Task<string> ExtractUrlAsync(string text)
{
Log.Info($"开始解析快手链接 {text}");
return text.Trim();
}
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);
return Data;
}
public override async Task<VideoModel> ExtractVideoDataAsync(string url)
{
try
{
Log.Info($"开始解析链接 {url}");
var client = new RestClient();
var locationRequest = new RestRequest(url);
locationRequest.AddHeaders(_locationHeaders);
var locationResponse = client.Execute(locationRequest);
if (locationResponse.ResponseUri is null)
{
Log.Error("获取location参数失败");
throw new InvalidDataException("获取location参数失败");
}
// 发送请求并获取响应
Log.Info($"开始解析location,reponse {locationResponse.ResponseUri.AbsoluteUri}");
var videoRequestUrl =
locationResponse.ResponseUri.AbsoluteUri.Replace("https://www.kuaishou.com/short-video",
"https://m.gifshow.com/fw/photo");
var videoRequest = new RestRequest(videoRequestUrl);
videoRequest.AddHeaders(_videoInfoHeaders);
var videoResponse = client.Execute(videoRequest);
if (!videoResponse.IsSuccessful) throw new HttpRequestException("request is fail");
var content = videoResponse.Content;
Log.Info($"开始解析响应内容 {content}");
if (content is null) throw new InvalidDataException("content is null");
const string routerDataPattern = @"""photo"":\s*\{(.*?)\},\s*""serialInfo""";
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<KuaishouShareVideoData>(videoJson);
if (videoData is null) throw new InvalidDataException("JSON解析数据为空请检查分享链接是否正确如有更多问题请查看日志");
return new VideoModel
{
Platform = ShortVideoPlatformEnum.KuaiShou,
VideoId = videoData.Manifest.VideoId,
AuthorName = videoData.UserName,
AuthorAvatar = videoData.HeadUrl.ToString(),
UniqueId = videoData.Manifest.VideoId,
Title = videoData.Caption,
Cover = videoData.CoverUrls.First().Url.ToString(),
VideoUrl = videoData.MainMvUrls.First().Url.ToString(),
Mp3Url = "",
CreatedTime =
DateTimeOffset.FromUnixTimeMilliseconds(videoData.Timestamp)
.ToString("yyyy-MM-dd HH:mm:ss"),
Desc = videoData.Caption,
Duration = videoData.Duration.ToString(),
DiggCount = videoData.LikeCount,
ViewCount = videoData.ViewCount,
CollectCount = 0,
CommentCount = videoData.CommentCount,
ShareCount = videoData.ShareCount
};
}
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, // Retry up to 5 times on failure
Timeout = 10000, // 10 seconds timeout for each request
RequestConfiguration = new RequestConfiguration
{
UserAgent = _videoInfoHeaders.GetValueOrDefault("User-Agent")
}
};
DownloadService downloader = new(downloadConfiguration);
downloader.DownloadProgressChanged += onProgressChanged;
downloader.DownloadFileCompleted += onProgressCompleted;
try
{
await downloader.DownloadFileTaskAsync(url, savePath + fileName);
return true;
}
catch (Exception ex)
{
Log.Info($"Download failed: {ex}");
}
return false;
}
}