From cca2af3c8709969d579c7a74716cfaebac279ee6 Mon Sep 17 00:00:00 2001 From: "k.12f" Date: Sun, 19 Jan 2025 16:23:38 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E9=87=8D=E6=96=B0=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E5=BF=AB=E6=89=8B=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BlueCatKoKo.Ui/Assets/kuaishou.json | 302 ++++++++++++++++++ ...VideoData.cs => KuaishouShareVideoData.cs} | 278 ++++------------ .../Services/KuaiShouShortVideoService.cs | 114 +++---- 3 files changed, 413 insertions(+), 281 deletions(-) create mode 100644 src/BlueCatKoKo.Ui/Assets/kuaishou.json rename src/BlueCatKoKo.Ui/Models/{KuaiShouShareVideoData.cs => KuaishouShareVideoData.cs} (53%) diff --git a/src/BlueCatKoKo.Ui/Assets/kuaishou.json b/src/BlueCatKoKo.Ui/Assets/kuaishou.json new file mode 100644 index 0000000..7483ccd --- /dev/null +++ b/src/BlueCatKoKo.Ui/Assets/kuaishou.json @@ -0,0 +1,302 @@ +{ + "singlePicture": false, + "type": 1, + "manifest": { + "playInfo": { + "cdnTimeRangeLevel": 0 + }, + "manualDefaultSelect": false, + "videoFeature": { + "mosScore": 0.4918619990348816, + "blurProbability": 0.541552722454071, + "blockyProbability": 0.528388261795044, + "avgEntropy": 21.641622447967528 + }, + "stereoType": 0, + "adaptationSet": [ + { + "duration": 51850, + "id": 1, + "representation": [ + { + "hidden": false, + "backupUrl": [ + "https://v1.kwaicdn.com/upic/2025/01/14/23/BMjAyNTAxMTQyMzIzMzZfNDE1NTUzNzQxNV8xNTM5MzU0MjA5MzRfMF8z_b_B00c75750d0554f88023c179b18ea7c9a.mp4?pkey=AAXz334sB36Mj_vbZNDITWf9T_vy9xgl2VZKRno4PND611At7NCrYouqwqjQBWvJ2sBU4UWgjr8ufoKSXu6i0LWVz2cwRjsOllptMJ3ImadEjzQwz5I55hvbqRq-grKg-zs&tag=1-1737268887-unknown-1-it1tjbcei4-39fc14318c031973&clientCacheKey=3x9rbjrtnjqxai9_b.mp4&di=3ad1aa0a&bp=10000&tt=b&ss=vp" + ], + "normalizeGain": 0, + "maxBitrate": 3300, + "hdrType": 0, + "frameRate": 30, + "qualityLabel": "高清", + "oriLoudness": 0, + "bitratePattern": [ + 1622, + 830, + 2825, + 396, + 597 + ], + "id": 1, + "kvqScore": { + "FRPost": -1, + "NR": 2.9033203125, + "NRPost": -1 + }, + "disableAdaptive": false, + "videoCodec": "avc", + "height": 1280, + "avgBitrate": 1238, + "defaultSelect": false, + "mute": false, + "url": "https://v2.kwaicdn.com/upic/2025/01/14/23/BMjAyNTAxMTQyMzIzMzZfNDE1NTUzNzQxNV8xNTM5MzU0MjA5MzRfMF8z_b_B00c75750d0554f88023c179b18ea7c9a.mp4?pkey=AAUzy4Io41osCrKadhAPqiRhLj8vETN5lvi9xXF1I4f_EIRxdeg_Uxl7WbVEi5VEOGe9GDIyr5jq3FjhiTcj_GdAbcWWrjM_9JQdx-0eD6auQPu0pEa1UiWCivDD55BzmvI&tag=1-1737268887-unknown-0-tsh5oud98c-6869875842dd9fc8&clientCacheKey=3x9rbjrtnjqxai9_b.mp4&di=3ad1aa0a&bp=10000&tt=b&ss=vp", + "p2spCode": "{\"fRsn\":0,\"fixOpt\":-1,\"schTask\":\"\",\"schCode\":-1,\"schRes\":\"\",\"pushTask\":\"v=0&p=0&s=0&d=0\",\"pushCode\":-1}", + "quality": 1.5, + "featureP2sp": false, + "makeupGain": 0, + "fileSize": 8026652, + "width": 720, + "comment": "videoId=27682351d04478f7/ttExplain=AVC_VeryFast_720P_高码率_Basic/tt=b", + "qualityType": "720p", + "minorInfo": "-b1f1", + "agc": false + }, + { + "hidden": false, + "backupUrl": [ + "https://v1.kwaicdn.com/bs2/photo-video-mz/5239656842446790679_27682351d04478f7_2544_v6HighV5.mp4?pkey=AAWlOl0LlINK7AeMO-XVp2DmMs9vJIDDer9_bxFeDJ9dB5UTus_8ckO_sN_MFV3Ou_vy0kEtRkWpiRGEp_cyTi8gi_kawldyrfpgraGbwkKSWlkvV6HpjVAtHnF_FAlPnoI&tag=1-1737268887-unknown-1-zplk1uiita-6ad6dd4a181059a1&clientCacheKey=3x9rbjrtnjqxai9_1245bd40&di=3ad1aa0a&bp=10000&tt=v6HighV5&ss=vp" + ], + "normalizeGain": 1, + "maxBitrate": 3300, + "hdrType": 0, + "frameRate": 30, + "qualityLabel": "高清", + "oriLoudness": -7.355, + "bitratePattern": [ + 1004, + 511, + 1858, + 296, + 324 + ], + "id": 2, + "kvqScore": { + "NR": 3.0227863788604736, + "NRPost": 3.2128 + }, + "disableAdaptive": false, + "videoCodec": "hevc", + "height": 1280, + "avgBitrate": 680, + "defaultSelect": false, + "mute": false, + "url": "https://v2.kwaicdn.com/bs2/photo-video-mz/5239656842446790679_27682351d04478f7_2544_v6HighV5.mp4?pkey=AAUHXX9g2EftAWET99DuEcEYJTkBgs6lzCfoZhxeJXVaxgETnbX_hB7csQTiCbei0Nz6GHZgrGqswt88NjuRDAkJbW3tnvgY-B1hhrT6iaGddHRGHNhSRzHJ8c8xDzie_Is&tag=1-1737268887-unknown-0-ljqqsbydru-7c69e77c3c72b8f6&clientCacheKey=3x9rbjrtnjqxai9_1245bd40&di=3ad1aa0a&bp=10000&tt=v6HighV5&ss=vp", + "p2spCode": "{\"fRsn\":0,\"fixOpt\":-1,\"schTask\":\"\",\"schCode\":-1,\"schRes\":\"\",\"pushTask\":\"v=0&p=0&s=0&d=0\",\"pushCode\":-1}", + "quality": 1.6, + "featureP2sp": false, + "makeupGain": 1.042, + "fileSize": 4412140, + "width": 720, + "comment": "videoId=27682351d04478f7/ttExplain=HEVC_VenusV6_720P_高码率/tt=v6HighV5", + "qualityType": "720p", + "minorInfo": "-b1f1", + "agc": true + }, + { + "hidden": false, + "backupUrl": [ + "https://v1.kwaicdn.com/bs2/photo-video-mz/5239656842446790679_27682351d04478f7_2544_v6UltraV5.mp4?pkey=AAW0KJ5ANF6VzDGw0HmQQlFrT6hYzYYhuYyYiTtzmxQJMrBu2Re8XT4NwNsy9L4qdxYF-CvETt_-WfgeAFVpq6HaFwgTAH_h-j7ZJi7bC_GMjlG7apIjmkwZ0yhQ6gVUggw&tag=1-1737268887-unknown-1-ha8ht5duk5-18af470a74455a89&clientCacheKey=3x9rbjrtnjqxai9_998b6a9e&di=3ad1aa0a&bp=10000&tt=v6UltraV5&ss=vp" + ], + "normalizeGain": 1, + "maxBitrate": 6500, + "hdrType": 0, + "frameRate": 30, + "qualityLabel": "1080p", + "oriLoudness": -7.355, + "bitratePattern": [ + 1334, + 678, + 2691, + 396, + 481 + ], + "id": 3, + "kvqScore": { + "NR": 3.0286457538604736, + "NRPost": 3.1614 + }, + "disableAdaptive": false, + "videoCodec": "hevc", + "height": 1920, + "avgBitrate": 954, + "defaultSelect": false, + "mute": false, + "url": "https://v2.kwaicdn.com/bs2/photo-video-mz/5239656842446790679_27682351d04478f7_2544_v6UltraV5.mp4?pkey=AAVGrYrNrFeYvgOW-LjcvdGsn7_7kgmmFsfrd1QF_-sRCP7Fw0hqevFek3WPsXVZgMQwodeRSb4jbbfisWstsvIgIIm2kXHDEWBeJignavip0D_C9KwDTJ7VYLDQTxj_PgY&tag=1-1737268887-unknown-0-a56ynshvx5-6e6ec10ac66fd289&clientCacheKey=3x9rbjrtnjqxai9_998b6a9e&di=3ad1aa0a&bp=10000&tt=v6UltraV5&ss=vp", + "p2spCode": "{\"fRsn\":0,\"fixOpt\":-1,\"schTask\":\"\",\"schCode\":-1,\"schRes\":\"\",\"pushTask\":\"v=0&p=0&s=0&d=0\",\"pushCode\":-1}", + "quality": 2, + "featureP2sp": false, + "makeupGain": 1.042, + "fileSize": 6184232, + "width": 1080, + "comment": "videoId=27682351d04478f7/ttExplain=HEVC_VenusV6_1080P_高码率/tt=v6UltraV5", + "qualityType": "1080p", + "minorInfo": "-b1f1", + "agc": true + } + ] + } + ], + "mediaType": 2, + "videoId": "27682351d04478f7", + "hideAuto": false, + "businessType": 2, + "version": "2.0.0" + }, + "duration": 51833, + "timestamp": 1736868273365, + "likeCount": 534927, + "userId": 4155537415, + "userName": "巨星小熊猫", + "height": 1280, + "width": 720, + "mainMvUrls": [ + { + "cdn": "v2.kwaicdn.com", + "url": "https://v2.kwaicdn.com/upic/2025/01/14/23/BMjAyNTAxMTQyMzIzMzZfNDE1NTUzNzQxNV8xNTM5MzU0MjA5MzRfMF8z_b_B00c75750d0554f88023c179b18ea7c9a.mp4?pkey=AAVu8ILFJbc56j6UIMpuNDV7y3KHESBkGU0bJiupVSc8bAcYNX-W-gL_ijD4mEfOUvSYIeLr4pTORktj0pxVMORdzeAf8uQUC6yoraZ-KG9JWHj2OZyszfAaeH17q6Sv59g&clientCacheKey=3x9rbjrtnjqxai9_b.mp4&tt=b&di=3ad1aa0a&bp=10000" + }, + { + "cdn": "v1.kwaicdn.com", + "url": "https://v1.kwaicdn.com/upic/2025/01/14/23/BMjAyNTAxMTQyMzIzMzZfNDE1NTUzNzQxNV8xNTM5MzU0MjA5MzRfMF8z_b_B00c75750d0554f88023c179b18ea7c9a.mp4?pkey=AAUpYlIfRBHILNJdgKMsjFgeYB5vUrpUPJSst03CRh8fuFp3s77nswvD0zndzGNNoU7yBWhptNiy81vffUGHNs2QnQIIPBs_FRvJ8ASDtInJuyhO-KsC7YK6LB3S3Aj_uJg&clientCacheKey=3x9rbjrtnjqxai9_b.mp4&tt=b&di=3ad1aa0a&bp=10000" + } + ], + "commentCount": 6918, + "forwardCount": 0, + "viewCount": 5924412, + "shareCount": 16416, + "coverUrls": [ + { + "cdn": "p2.a.yximgs.com", + "url": "https://p2.a.yximgs.com/upic/2025/01/14/23/BMjAyNTAxMTQyMzIzMzZfNDE1NTUzNzQxNV8xNTM5MzU0MjA5MzRfMF8z_B3ad8abe31682e945d43c5ef74c06f291.jpg?clientCacheKey=3x9rbjrtnjqxai9.jpg&di=3ad1aa0a&bp=10000" + }, + { + "cdn": "p1.a.yximgs.com", + "url": "https://p1.a.yximgs.com/upic/2025/01/14/23/BMjAyNTAxMTQyMzIzMzZfNDE1NTUzNzQxNV8xNTM5MzU0MjA5MzRfMF8z_B3ad8abe31682e945d43c5ef74c06f291.jpg?clientCacheKey=3x9rbjrtnjqxai9.jpg&di=3ad1aa0a&bp=10000" + } + ], + "webpCoverUrls": [ + { + "cdn": "p2.a.yximgs.com", + "url": "https://p2.a.yximgs.com/upic/2025/01/14/23/BMjAyNTAxMTQyMzIzMzZfNDE1NTUzNzQxNV8xNTM5MzU0MjA5MzRfMF8z_B3ad8abe31682e945d43c5ef74c06f291.jpg?clientCacheKey=3x9rbjrtnjqxai9.jpg&di=3ad1aa0a&bp=10000" + }, + { + "cdn": "p1.a.yximgs.com", + "url": "https://p1.a.yximgs.com/upic/2025/01/14/23/BMjAyNTAxMTQyMzIzMzZfNDE1NTUzNzQxNV8xNTM5MzU0MjA5MzRfMF8z_B3ad8abe31682e945d43c5ef74c06f291.jpg?clientCacheKey=3x9rbjrtnjqxai9.jpg&di=3ad1aa0a&bp=10000" + } + ], + "headUrls": [ + { + "cdn": "p66-pro.a.yximgs.com", + "url": "https://p66-pro.a.yximgs.com/uhead/AB/2024/05/23/19/BMjAyNDA1MjMxOTI5MDRfNDE1NTUzNzQxNV8yX2hkOTk2XzI0Mw==_s.jpg" + }, + { + "cdn": "p4-pro.a.yximgs.com", + "url": "https://p4-pro.a.yximgs.com/uhead/AB/2024/05/23/19/BMjAyNDA1MjMxOTI5MDRfNDE1NTUzNzQxNV8yX2hkOTk2XzI0Mw==_s.jpg" + } + ], + "verified": false, + "headUrl": "https://p66-pro.a.yximgs.com/uhead/AB/2024/05/23/19/BMjAyNDA1MjMxOTI5MDRfNDE1NTUzNzQxNV8yX2hkOTk2XzI0Mw==_s.jpg", + "userSex": "F", + "soundTrack": { + "name": "巨星小熊猫的作品原声", + "user": { + "following": false, + "user_id": 4155537415, + "user_name": "巨星小熊猫", + "headurl": "https://p66-pro.a.yximgs.com/uhead/AB/2024/05/23/19/BMjAyNDA1MjMxOTI5MDRfNDE1NTUzNzQxNV8yX2hkOTk2XzI0Mw==_s.jpg", + "user_sex": "F", + "eid": "3xkqzpf6t6w6h39", + "visitorBeFollowed": false, + "headurls": [ + { + "cdn": "p66-pro.a.yximgs.com", + "url": "https://p66-pro.a.yximgs.com/uhead/AB/2024/05/23/19/BMjAyNDA1MjMxOTI5MDRfNDE1NTUzNzQxNV8yX2hkOTk2XzI0Mw==_s.jpg" + }, + { + "cdn": "p4-pro.a.yximgs.com", + "url": "https://p4-pro.a.yximgs.com/uhead/AB/2024/05/23/19/BMjAyNDA1MjMxOTI5MDRfNDE1NTUzNzQxNV8yX2hkOTk2XzI0Mw==_s.jpg" + } + ] + }, + "photoId": 5239656842446791000, + "imageUrls": [ + { + "cdn": "hw.a.yximgs.com", + "url": "https://hw.a.yximgs.com/bs2/ost/MTUzOTM1NDIwOTM0XzQxNTU1Mzc0MTU.jpg" + }, + { + "cdn": "ali2.a.yximgs.com", + "url": "https://ali2.a.yximgs.com/bs2/ost/MTUzOTM1NDIwOTM0XzQxNTU1Mzc0MTU.jpg" + } + ], + "audioUrls": [ + { + "cdn": "ali2.a.yximgs.com", + "url": "https://ali2.a.yximgs.com/bs2/ost/MTUzOTM1NDIwOTM0XzQxNTU1Mzc0MTU.m4a" + }, + { + "cdn": "hw.a.yximgs.com", + "url": "https://hw.a.yximgs.com/bs2/ost/MTUzOTM1NDIwOTM0XzQxNTU1Mzc0MTU.m4a" + } + ], + "artist": "巨星小熊猫", + "avatarUrls": [ + { + "cdn": "ali2.a.yximgs.com", + "url": "https://ali2.a.yximgs.com/bs2/ost/MTUzOTM1NDIwOTM0XzQxNTU1Mzc0MTU.jpg" + }, + { + "cdn": "hw.a.yximgs.com", + "url": "https://hw.a.yximgs.com/bs2/ost/MTUzOTM1NDIwOTM0XzQxNTU1Mzc0MTU.jpg" + } + ], + "id": 22503930003, + "type": 9, + "genreId": 0, + "photoCount": 1, + "loudness": -15, + "finalStatus": 0, + "usageCount": 1, + "audioType": 1, + "hasCopyright": true, + "disableEnhancedEntry": true, + "isOffline": false + }, + "tagShow": { + "bizId": "5xicsifhz2hwkjg", + "bannerType": 2, + "usedCount": "1", + "type": 3 + }, + "commentShowType": 1, + "serverExpTag": "feed_photo|5239656842446790679|4155537415|1_u/2004190997180440738_s0", + "ext_params": { + "mtype": 3, + "color": "FC9C32", + "w": 720, + "sound": 51850, + "h": 1280, + "interval": 30, + "video": 51833 + }, + "caption": "狗狗555555555 #狗狗 #动物 #外国人 #感动", + "exp_tag": "1_u/2004190997180440738_s0", + "photoId": "5239656842446790679", + "share_info": "userId=3xkqzpf6t6w6h39&photoId=3x9rbjrtnjqxai9", + "sameFrame": { + "allow": true, + "availableDepth": 7 + }, + "adminTags": [], + "userEid": "3xkqzpf6t6w6h39", + "photoType": "VIDEO", + "forcePublic": "H4sIAAAAAAAA%2F%2BNQEmCQaNszYddeFiNJLvbijMSiVM8UIT5DCyNTI0MTA1MDAwNjEwAJAgArJgAAAA%3D%3D" +} \ No newline at end of file diff --git a/src/BlueCatKoKo.Ui/Models/KuaiShouShareVideoData.cs b/src/BlueCatKoKo.Ui/Models/KuaishouShareVideoData.cs similarity index 53% rename from src/BlueCatKoKo.Ui/Models/KuaiShouShareVideoData.cs rename to src/BlueCatKoKo.Ui/Models/KuaishouShareVideoData.cs index c29dd03..4990944 100644 --- a/src/BlueCatKoKo.Ui/Models/KuaiShouShareVideoData.cs +++ b/src/BlueCatKoKo.Ui/Models/KuaishouShareVideoData.cs @@ -1,100 +1,12 @@ // YApi QuickType插件生成,具体参考文档:https://plugins.jetbrains.com/plugin/18847-yapi-quicktype/documentation +using System.Globalization; using Newtonsoft.Json; - +using Newtonsoft.Json.Converters; namespace BlueCatKoKo.Ui.Models; -public class KuaiShouShareVideoData -{ - [JsonProperty("result")] public long Result { get; set; } - - [JsonProperty("fid")] public long Fid { get; set; } - - [JsonProperty("shareInfo")] public ShareInfo ShareInfo { get; set; } - - [JsonProperty("comments")] public List Comments { get; set; } - - [JsonProperty("counts")] public Counts Counts { get; set; } - - [JsonProperty("photo")] public Photo Photo { get; set; } - - [JsonProperty("trendingInfo")] public TrendingInfo TrendingInfo { get; set; } - - [JsonProperty("mp4Url")] public Uri Mp4Url { get; set; } - - [JsonProperty("photos")] public List Photos { get; set; } - - [JsonProperty("shareUserPhotos")] public List ShareUserPhotos { get; set; } - - [JsonProperty("serialInfo")] public SerialInfo SerialInfo { get; set; } -} - -public class Comment -{ - [JsonProperty("author_name")] public string AuthorName { get; set; } - - [JsonProperty("cashTags")] public CashTags CashTags { get; set; } - - [JsonProperty("commentAuthorTags")] public List CommentAuthorTags { get; set; } - - [JsonProperty("photo_id")] public double PhotoId { get; set; } - - [JsonProperty("headurl")] public Uri Headurl { get; set; } - - [JsonProperty("headurls")] public List Headurls { get; set; } - - [JsonProperty("author_liked")] public bool AuthorLiked { get; set; } - - [JsonProperty("type")] public long Type { get; set; } - - [JsonProperty("comment_id")] public long CommentId { get; set; } - - [JsonProperty("authorVerified")] public bool AuthorVerified { get; set; } - - [JsonProperty("content")] public string Content { get; set; } - - [JsonProperty("user_sex")] public string UserSex { get; set; } - - [JsonProperty("reply_to")] public long ReplyTo { get; set; } - - [JsonProperty("user_id")] public long UserId { get; set; } - - [JsonProperty("replyToUserName", NullValueHandling = NullValueHandling.Ignore)] - public string ReplyToUserName { get; set; } - - [JsonProperty("commentBottomTags")] public List CommentBottomTags { get; set; } - - [JsonProperty("time")] public DateTimeOffset Time { get; set; } - - [JsonProperty("author_id")] public long AuthorId { get; set; } - - [JsonProperty("timestamp")] public long Timestamp { get; set; } -} - -public class CashTags -{ -} - -public class CoverUrl -{ - [JsonProperty("cdn")] public string Cdn { get; set; } - - [JsonProperty("url")] public Uri Url { get; set; } -} - -public class Counts -{ - [JsonProperty("fanCount")] public long FanCount { get; set; } - - [JsonProperty("followCount")] public long FollowCount { get; set; } - - [JsonProperty("collectionCount")] public long CollectionCount { get; set; } - - [JsonProperty("photoCount")] public long PhotoCount { get; set; } -} - -public class Photo +public partial class KuaishouShareVideoData { [JsonProperty("adminTags")] public List AdminTags { get; set; } @@ -112,14 +24,13 @@ public class Photo [JsonProperty("type")] public long Type { get; set; } - [JsonProperty("mainMvUrls")] public List MainMvUrls { get; set; } + [JsonProperty("mainMvUrls")] public List MainMvUrls { get; set; } [JsonProperty("userEid")] public string UserEid { get; set; } [JsonProperty("duration")] public long Duration { get; set; } - [JsonProperty("shareCount", NullValueHandling = NullValueHandling.Ignore)] - public long? ShareCount { get; set; } + [JsonProperty("shareCount")] public long ShareCount { get; set; } [JsonProperty("serverExpTag")] public string ServerExpTag { get; set; } @@ -127,7 +38,7 @@ public class Photo [JsonProperty("viewCount")] public long ViewCount { get; set; } - [JsonProperty("headUrls")] public List HeadUrls { get; set; } + [JsonProperty("headUrls")] public List HeadUrls { get; set; } [JsonProperty("forwardCount")] public long ForwardCount { get; set; } @@ -139,12 +50,11 @@ public class Photo [JsonProperty("height")] public long Height { get; set; } - [JsonProperty("webpCoverUrls")] public List WebpCoverUrls { get; set; } + [JsonProperty("webpCoverUrls")] public List WebpCoverUrls { get; set; } [JsonProperty("userSex")] public string UserSex { get; set; } - [JsonProperty("manifest", NullValueHandling = NullValueHandling.Ignore)] - public Manifest Manifest { get; set; } + [JsonProperty("manifest")] public Manifest Manifest { get; set; } [JsonProperty("share_info")] public string ShareInfo { get; set; } @@ -160,30 +70,23 @@ public class Photo [JsonProperty("commentCount")] public long CommentCount { get; set; } - [JsonProperty("commentShowType", NullValueHandling = NullValueHandling.Ignore)] - public long? CommentShowType { get; set; } + [JsonProperty("commentShowType")] public long CommentShowType { get; set; } [JsonProperty("width")] public long Width { get; set; } [JsonProperty("photoType")] public string PhotoType { get; set; } - [JsonProperty("coverUrls")] public List CoverUrls { get; set; } - - [JsonProperty("cccCoverMap", NullValueHandling = NullValueHandling.Ignore)] - public CccCoverMap CccCoverMap { get; set; } - - [JsonProperty("overrideCoverUrls", NullValueHandling = NullValueHandling.Ignore)] - public OverrideCoverUrls OverrideCoverUrls { get; set; } + [JsonProperty("coverUrls")] public List CoverUrls { get; set; } } -public class CccCoverMap +public partial class KuaiShouShareVideoDatarUrl { - [JsonProperty("width")] public long Width { get; set; } + [JsonProperty("cdn")] public string Cdn { get; set; } - [JsonProperty("height")] public long Height { get; set; } + [JsonProperty("url")] public Uri Url { get; set; } } -public class ExtParams +public partial class ExtParams { [JsonProperty("mtype")] public long Mtype { get; set; } @@ -200,7 +103,7 @@ public class ExtParams [JsonProperty("video")] public long Video { get; set; } } -public class Manifest +public partial class Manifest { [JsonProperty("playInfo")] public PlayInfo PlayInfo { get; set; } @@ -223,7 +126,7 @@ public class Manifest [JsonProperty("version")] public string Version { get; set; } } -public class AdaptationSet +public partial class AdaptationSet { [JsonProperty("duration")] public long Duration { get; set; } @@ -232,19 +135,41 @@ public class AdaptationSet [JsonProperty("representation")] public List Representation { get; set; } } -public class Representation +public partial class Representation { - [JsonProperty("avgBitrate")] public long AvgBitrate { get; set; } - [JsonProperty("hidden")] public bool Hidden { get; set; } [JsonProperty("backupUrl")] public List BackupUrl { get; set; } + [JsonProperty("normalizeGain")] public long NormalizeGain { get; set; } + [JsonProperty("maxBitrate")] public long MaxBitrate { get; set; } + [JsonProperty("hdrType")] public long HdrType { get; set; } + + [JsonProperty("frameRate")] public long FrameRate { get; set; } + + [JsonProperty("qualityLabel")] public string QualityLabel { get; set; } + + [JsonProperty("oriLoudness")] public double OriLoudness { get; set; } + + [JsonProperty("bitratePattern")] public List BitratePattern { get; set; } + + [JsonProperty("id")] public long Id { get; set; } + + [JsonProperty("kvqScore")] public KvqScore KvqScore { get; set; } + + [JsonProperty("disableAdaptive")] public bool DisableAdaptive { get; set; } + + [JsonProperty("videoCodec")] public string VideoCodec { get; set; } + + [JsonProperty("height")] public long Height { get; set; } + + [JsonProperty("avgBitrate")] public long AvgBitrate { get; set; } + [JsonProperty("defaultSelect")] public bool DefaultSelect { get; set; } - [JsonProperty("hdrType")] public long HdrType { get; set; } + [JsonProperty("mute")] public bool Mute { get; set; } [JsonProperty("url")] public Uri Url { get; set; } @@ -254,9 +179,7 @@ public class Representation [JsonProperty("featureP2sp")] public bool FeatureP2Sp { get; set; } - [JsonProperty("frameRate")] public double FrameRate { get; set; } - - [JsonProperty("qualityLabel")] public string QualityLabel { get; set; } + [JsonProperty("makeupGain")] public double MakeupGain { get; set; } [JsonProperty("fileSize")] public long FileSize { get; set; } @@ -264,42 +187,29 @@ public class Representation [JsonProperty("comment")] public string Comment { get; set; } - [JsonProperty("bitratePattern")] public List BitratePattern { get; set; } - - [JsonProperty("id")] public long Id { get; set; } - [JsonProperty("qualityType")] public string QualityType { get; set; } - [JsonProperty("kvqScore")] public KvqScore KvqScore { get; set; } - - [JsonProperty("disableAdaptive")] public bool DisableAdaptive { get; set; } - [JsonProperty("minorInfo")] public string MinorInfo { get; set; } - [JsonProperty("videoCodec")] public string VideoCodec { get; set; } - - [JsonProperty("height")] public long Height { get; set; } + [JsonProperty("agc")] public bool Agc { get; set; } } -public class KvqScore +public partial class KvqScore { - [JsonProperty("FRPost")] public long FrPost { get; set; } + [JsonProperty("FRPost", NullValueHandling = NullValueHandling.Ignore)] + public long? FrPost { get; set; } [JsonProperty("NR")] public double Nr { get; set; } [JsonProperty("NRPost")] public double NrPost { get; set; } - - [JsonProperty("FR")] public double Fr { get; set; } } -public class PlayInfo +public partial class PlayInfo { - [JsonProperty("strategyBus")] public string StrategyBus { get; set; } - [JsonProperty("cdnTimeRangeLevel")] public long CdnTimeRangeLevel { get; set; } } -public class VideoFeature +public partial class VideoFeature { [JsonProperty("mosScore")] public double MosScore { get; set; } @@ -310,32 +220,25 @@ public class VideoFeature [JsonProperty("avgEntropy")] public double AvgEntropy { get; set; } } -public class OverrideCoverUrls -{ - [JsonProperty("jpgCdnNodeView")] public List JpgCdnNodeView { get; set; } - - [JsonProperty("webpCdnNodeView")] public List WebpCdnNodeView { get; set; } -} - -public class SameFrame +public partial class SameFrame { [JsonProperty("allow")] public bool Allow { get; set; } [JsonProperty("availableDepth")] public long AvailableDepth { get; set; } } -public class SoundTrack +public partial class SoundTrack { [JsonProperty("genreId")] public long GenreId { get; set; } - [JsonProperty("audioUrls")] public List AudioUrls { get; set; } + [JsonProperty("audioUrls")] public List AudioUrls { get; set; } [JsonProperty("finalStatus")] public long FinalStatus { get; set; } - [JsonProperty("avatarUrls")] public List AvatarUrls { get; set; } - [JsonProperty("artist")] public string Artist { get; set; } + [JsonProperty("avatarUrls")] public List AvatarUrls { get; set; } + [JsonProperty("hasCopyright")] public bool HasCopyright { get; set; } [JsonProperty("loudness")] public long Loudness { get; set; } @@ -346,9 +249,13 @@ public class SoundTrack [JsonProperty("type")] public long Type { get; set; } + [JsonProperty("usageCount")] public long UsageCount { get; set; } + + [JsonProperty("photoCount")] public long PhotoCount { get; set; } + [JsonProperty("disableEnhancedEntry")] public bool DisableEnhancedEntry { get; set; } - [JsonProperty("imageUrls")] public List ImageUrls { get; set; } + [JsonProperty("imageUrls")] public List ImageUrls { get; set; } [JsonProperty("name")] public string Name { get; set; } @@ -359,7 +266,7 @@ public class SoundTrack [JsonProperty("user")] public User User { get; set; } } -public class User +public partial class User { [JsonProperty("user_sex")] public string UserSex { get; set; } @@ -373,12 +280,12 @@ public class User [JsonProperty("headurl")] public Uri Headurl { get; set; } - [JsonProperty("headurls")] public List Headurls { get; set; } + [JsonProperty("headurls")] public List Headurls { get; set; } [JsonProperty("visitorBeFollowed")] public bool VisitorBeFollowed { get; set; } } -public class TagShow +public partial class TagShow { [JsonProperty("bannerType")] public long BannerType { get; set; } @@ -387,65 +294,4 @@ public class TagShow [JsonProperty("type")] public long Type { get; set; } [JsonProperty("usedCount")] public long UsedCount { get; set; } -} - -public class SerialInfo -{ - [JsonProperty("valid")] public bool Valid { get; set; } - - [JsonProperty("show")] public bool Show { get; set; } -} - -public class ShareInfo -{ - [JsonProperty("groupName")] public string GroupName { get; set; } - - [JsonProperty("shareTitle")] public string ShareTitle { get; set; } - - [JsonProperty("docId")] public long DocId { get; set; } - - [JsonProperty("shareId")] public string ShareId { get; set; } - - [JsonProperty("shareType")] public long ShareType { get; set; } - - [JsonProperty("shareSubTitle")] public string ShareSubTitle { get; set; } -} - -public class TrendingInfo -{ - [JsonProperty("iconRightMargin")] public long IconRightMargin { get; set; } - - [JsonProperty("preTitle")] public string PreTitle { get; set; } - - [JsonProperty("backgroundColor")] public string BackgroundColor { get; set; } - - [JsonProperty("iconHeight")] public long IconHeight { get; set; } - - [JsonProperty("visibility")] public long Visibility { get; set; } - - [JsonProperty("iconWidth")] public long IconWidth { get; set; } - - [JsonProperty("showSeparator")] public bool ShowSeparator { get; set; } - - [JsonProperty("wordId")] public long WordId { get; set; } - - [JsonProperty("notTruncatedTitle")] public string NotTruncatedTitle { get; set; } - - [JsonProperty("bottomWeakStyleType")] public long BottomWeakStyleType { get; set; } - - [JsonProperty("showArrow")] public bool ShowArrow { get; set; } - - [JsonProperty("title")] public string Title { get; set; } - - [JsonProperty("tailIconUrl")] public string TailIconUrl { get; set; } - - [JsonProperty("roundCorner")] public bool RoundCorner { get; set; } - - [JsonProperty("enableForceClose")] public bool EnableForceClose { get; set; } - - [JsonProperty("fontSize")] public long FontSize { get; set; } - - [JsonProperty("iconUrl")] public Uri IconUrl { get; set; } - - [JsonProperty("fontColor")] public string FontColor { get; set; } } \ No newline at end of file diff --git a/src/BlueCatKoKo.Ui/Services/KuaiShouShortVideoService.cs b/src/BlueCatKoKo.Ui/Services/KuaiShouShortVideoService.cs index 93b253c..0dc033a 100644 --- a/src/BlueCatKoKo.Ui/Services/KuaiShouShortVideoService.cs +++ b/src/BlueCatKoKo.Ui/Services/KuaiShouShortVideoService.cs @@ -1,7 +1,7 @@ using System.ComponentModel; using System.IO; -using System.Text; -using System.Web; +using System.Net.Http; +using System.Text.RegularExpressions; using BlueCatKoKo.Ui.Constants; using BlueCatKoKo.Ui.Models; using Downloader; @@ -12,12 +12,10 @@ namespace BlueCatKoKo.Ui.Services; /// -/// 快手下载服务 +/// 快手下载服务 /// public class KuaiShouShortVideoService : IShortVideoService { - private readonly ILogger _logger; - private static readonly Dictionary _locationHeaders = new() { { @@ -41,21 +39,21 @@ public class KuaiShouShortVideoService : IShortVideoService }, { "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" - } + { "sec-ch-ua-platform", "\"Android\"" } + // { + // "Cookie", + // "kpf=PC_WEB; kpn=KUAISHOU_VISION; clientid=3; did=web_6ece7cfdd334f69ac1fe2579040329d0; didv=1725957114469" + // } }; - private static Dictionary _videoInfoHeaders = new() + private static readonly Dictionary _videoInfoHeaders = new() { - { "Accept", "*/*" }, + { "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", "did=web_d38fe86913df4a88b5593f8aa8d2638e; didv=1725940475000" }, + { "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" }, @@ -64,9 +62,9 @@ public class KuaiShouShortVideoService : IShortVideoService // "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", "empty" }, - { "Sec-Fetch-Mode", "cors" }, - { "Sec-Fetch-Site", "same-origin" }, + { "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" @@ -96,6 +94,8 @@ public class KuaiShouShortVideoService : IShortVideoService { "photoId", "3xvfmfagspjxq9q" } }; + private readonly ILogger _logger; + public KuaiShouShortVideoService(ILogger logger) { @@ -103,8 +103,8 @@ public KuaiShouShortVideoService(ILogger logger) } /// - /// 解析快手 - /// https://www.kuaishou.com/f/X-9UuzlPQN2St1Ab + /// 解析快手 + /// https://www.kuaishou.com/f/X-9UuzlPQN2St1Ab /// /// /// @@ -115,7 +115,7 @@ public async Task ExtractUrlAsync(string text) } /// - /// 根据链接 https://www.kuaishou.com/f/X-9UuzlPQN2St1Ab 解析出页面中的数据 + /// 根据链接 https://www.kuaishou.com/f/X-9UuzlPQN2St1Ab 解析出页面中的数据 /// /// /// @@ -137,68 +137,52 @@ public async Task ExtractVideoDataAsync(string url) throw new InvalidDataException("获取location参数失败"); } - var queryParams = HttpUtility.ParseQueryString(locationResponse.ResponseUri.Query); + // 发送请求并获取响应 + _logger.Information("开始解析location,reponse {AbsoluteUri}", locationResponse.ResponseUri.AbsoluteUri); - if (queryParams is null) - { - _logger.Error("解析链接失败"); - throw new InvalidDataException("获取response uri中的query params失败"); - } - - - _requestBodyDict["shareObjectId"] = queryParams.Get("shareObjectId"); - _requestBodyDict["shareId"] = queryParams.Get("shareId"); - _requestBodyDict["shareToken"] = queryParams.Get("shareToken"); - _requestBodyDict["photoId"] = queryParams.Get("shareObjectId"); - var videoInfoRequestBody = JsonConvert.SerializeObject(_requestBodyDict); - - var videoInfoRequest = new RestRequest("https://m.gifshow.com/rest/wd/photo/info"); + 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); - videoInfoRequest.AddQueryParameter("kpn", "KUAISHOU_VISION"); - videoInfoRequest.AddQueryParameter("captchaToken", ""); - videoInfoRequest.AddQueryParameter("__NS_hxfalcon", - "HUDR_sFnX-DtsD0FXsbDPTXTMP-sk0it4QvcKvw970-3Y9BKuNdZNdSz2-t2IHP3dz5U08BXEKWpxQPN-GUB9srS50qlqmo1ekhckPk6DAhrsl4X3gBO4Or08YWx5z5k5GG0OErQIMjn9z-vcaVIak0LdBXbB7ElchtlD-bUnhQif$HE_5f40d8bdbf1df021ce8515f40018bc5d031514141415c98cb8ae0fcb37f070266b0685158f422ace6f422afc14"); - videoInfoRequest.AddQueryParameter("caver", "2"); + if (!videoResponse.IsSuccessful) throw new HttpRequestException("request is fail"); - _videoInfoHeaders["Referer"] = locationResponse.ResponseUri.AbsoluteUri; + var content = videoResponse.Content; + _logger.Information("开始解析响应内容 {content}", content); + if (content is null) throw new InvalidDataException("content is null"); - videoInfoRequest.AddHeaders(_videoInfoHeaders); - videoInfoRequest.AddJsonBody(videoInfoRequestBody); + const string routerDataPattern = @"""photo"":\s*\{(.*?)\},\s*""serialInfo"""; - var videoInfoResponse = client.Execute(videoInfoRequest); + var matchJson = Regex.Match(content, routerDataPattern); + _logger.Information("开始解析匹配到的json {matchJson}", matchJson); + if (matchJson.Groups.Count < 2) throw new InvalidDataException("未匹配到合法的数据,matchJson.Groups.Count < 2"); - if (videoInfoResponse is null || videoInfoResponse.Content is null) - throw new InvalidDataException("响应数据为空,请查看你的日志"); - - _logger.Information("开始解析匹配到的json {videoJson}", videoInfoResponse.Content); - + var videoJson = "{"+matchJson.Groups[1].Value+"}"; + _logger.Information("开始解析匹配到的json {videoJson}", videoJson); // 反序列化JSON字符串为C#对象 - var videoData = JsonConvert.DeserializeObject(videoInfoResponse.Content); - + var videoData = JsonConvert.DeserializeObject(videoJson); if (videoData is null) throw new InvalidDataException("JSON解析数据为空,请检查分享链接是否正确,如有更多问题请查看日志"); - - return new VideoModel { Platform = ShortVideoPlatformEnum.KuaiShou, - VideoId = videoData.Photo.Manifest.VideoId, - AuthorName = videoData.Photo.UserName, - AuthorAvatar = videoData.Photo.HeadUrl.ToString(), - Title = videoData.Photo.Caption, - Cover = videoData.Photo.CoverUrls.First().Url.ToString(), - VideoUrl = videoData.Mp4Url.ToString(), + VideoId = videoData.Manifest.VideoId, + AuthorName = videoData.UserName, + AuthorAvatar = videoData.HeadUrl.ToString(), + Title = videoData.Caption, + Cover = videoData.CoverUrls.First().Url.ToString(), + VideoUrl = videoData.MainMvUrls.First().Url.ToString(), Mp3Url = "", CreatedTime = - DateTimeOffset.FromUnixTimeMilliseconds(videoData.Photo.Timestamp) + DateTimeOffset.FromUnixTimeMilliseconds(videoData.Timestamp) .ToString("yyyy-MM-dd HH:mm:ss"), Desc = "暂无~", - Duration = videoData.Photo.Duration.ToString(), - DiggCount = videoData.Photo.LikeCount, - ViewCount = videoData.Photo.ViewCount, - CollectCount = videoData.Counts.CollectionCount, - CommentCount = videoData.Photo.CommentCount, - ShareCount = videoData.Photo.ShareCount + Duration = videoData.Duration.ToString(), + DiggCount = videoData.LikeCount, + ViewCount = videoData.ViewCount, + CollectCount = 0, + CommentCount = videoData.CommentCount, + ShareCount = videoData.ShareCount }; } catch (Exception e)