diff --git a/.idea/.idea.ACBuildService/.idea/workspace.xml b/.idea/.idea.ACBuildService/.idea/workspace.xml
index dd69e0f..3bbe4f8 100644
--- a/.idea/.idea.ACBuildService/.idea/workspace.xml
+++ b/.idea/.idea.ACBuildService/.idea/workspace.xml
@@ -73,11 +73,13 @@
+
+
@@ -96,6 +98,7 @@
+
@@ -176,7 +179,7 @@
1768872588133
-
+
diff --git a/BabyVideoService.sln.DotSettings.user b/BabyVideoService.sln.DotSettings.user
index b5453ae..95ffa19 100644
--- a/BabyVideoService.sln.DotSettings.user
+++ b/BabyVideoService.sln.DotSettings.user
@@ -13,4 +13,5 @@
ForceIncluded
ForceIncluded
ForceIncluded
- ForceIncluded
\ No newline at end of file
+ ForceIncluded
+ ForceIncluded
\ No newline at end of file
diff --git a/VideoDownload/Platforms/DouYin.cs b/VideoDownload/Platforms/DouYin.cs
index 6efee04..ff7573c 100644
--- a/VideoDownload/Platforms/DouYin.cs
+++ b/VideoDownload/Platforms/DouYin.cs
@@ -1,5 +1,6 @@
using System.ComponentModel;
using System.Text.RegularExpressions;
+using ACBuildService.Platforms.DouYin;
using Downloader;
using Newtonsoft.Json;
using RestSharp;
diff --git a/VideoDownload/DouyinShareRouterData.cs b/VideoDownload/Platforms/DouyinShareRouterData.cs
similarity index 99%
rename from VideoDownload/DouyinShareRouterData.cs
rename to VideoDownload/Platforms/DouyinShareRouterData.cs
index 6957292..2d46e5e 100644
--- a/VideoDownload/DouyinShareRouterData.cs
+++ b/VideoDownload/Platforms/DouyinShareRouterData.cs
@@ -1,6 +1,6 @@
using Newtonsoft.Json;
-namespace ACBuildService;
+namespace ACBuildService.Platforms.DouYin;
///
/// 抖音 分享文本中的视频数据
diff --git a/VideoDownload/Platforms/KuaiShou.cs b/VideoDownload/Platforms/KuaiShou.cs
index d328673..8d9ffa1 100644
--- a/VideoDownload/Platforms/KuaiShou.cs
+++ b/VideoDownload/Platforms/KuaiShou.cs
@@ -1,53 +1,206 @@
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 _defaultHeaders = new()
+ private static readonly Dictionary _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 _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"
},
- { "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" }
+ { "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 Task ExtractUrlAsync(string text)
+
+ public override async Task ExtractUrlAsync(string text)
{
- throw new NotImplementedException();
+ Log.Info($"开始解析快手链接 {text}");
+ return text.Trim();
}
- public override Task ParseShare(string DownloadUrlText)
+ public override async Task ParseShare(string DownloadUrlText)
{
- throw new NotImplementedException();
+ if (!DownloadUrlText.Contains("https://"))
+ {
+ Log.Error("请输入正确的分享链接");
+ return null;
+ }
+
+ var downloadUrl = await ExtractUrlAsync(DownloadUrlText);
+ VideoModel Data = await ExtractVideoDataAsync(downloadUrl);
+
+ return Data;
}
- public override Task ExtractVideoDataAsync(string url)
+ public override async Task ExtractVideoDataAsync(string url)
{
- throw new NotImplementedException();
+ 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(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 Task DownloadAsync(string url, string savePath, string fileName,
+ public override async Task DownloadAsync(string url, string savePath, string fileName,
EventHandler onProgressChanged,
EventHandler onProgressCompleted)
{
- throw new NotImplementedException();
+ 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;
}
}
\ No newline at end of file
diff --git a/VideoDownload/Platforms/KuaishouShareVideoData.cs b/VideoDownload/Platforms/KuaishouShareVideoData.cs
new file mode 100644
index 0000000..a973725
--- /dev/null
+++ b/VideoDownload/Platforms/KuaishouShareVideoData.cs
@@ -0,0 +1,293 @@
+using Newtonsoft.Json;
+
+namespace ACBuildService.Platforms.KuaiShow;
+
+public partial class KuaishouShareVideoData
+{
+ [JsonProperty("adminTags")] public List