From 209ccf57456181445f163d8c6005193cea07164e Mon Sep 17 00:00:00 2001 From: assimon Date: Fri, 30 Dec 2022 13:31:42 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=8A=96=E9=9F=B3=E8=A7=A3?= =?UTF-8?q?=E6=9E=90=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- video_adapter_test.go | 2 +- videos/adapter/douyin_adapter.go | 501 ++++++++++++++++++++++++------- 2 files changed, 386 insertions(+), 117 deletions(-) diff --git a/video_adapter_test.go b/video_adapter_test.go index 2aea7d3..a86843d 100644 --- a/video_adapter_test.go +++ b/video_adapter_test.go @@ -29,7 +29,7 @@ func TestPipixiaAdapter_GetShortVideoInfo(t *testing.T) { func TestHuoshanAdapter_GetShortVideoInfo(t *testing.T) { adapter := &adapter2.HuoshanAdapter{} - resp, err := adapter.GetShortVideoInfo("https://share.huoshan.com/hotsoon/s/EU67vTEfHx8/") + resp, err := adapter.GetShortVideoInfo("https://share.huoshan.com/hotsoon/s/6LtxUndlBy8/") if err != nil { t.Error(err) } diff --git a/videos/adapter/douyin_adapter.go b/videos/adapter/douyin_adapter.go index 4f6e052..9af9d05 100644 --- a/videos/adapter/douyin_adapter.go +++ b/videos/adapter/douyin_adapter.go @@ -6,162 +6,431 @@ import ( "github.com/assimon/svbot/internal/log" "github.com/assimon/svbot/internal/restyHttp" "regexp" - "strings" ) type DouyinAdapter struct{} type DouyinAdapterResponse struct { - StatusCode int `json:"status_code"` - ItemList []struct { - AwemeID string `json:"aweme_id"` - Desc string `json:"desc"` - CreateTime int `json:"create_time"` - Author struct { - UID string `json:"uid"` - ShortID string `json:"short_id"` - Nickname string `json:"nickname"` - Signature string `json:"signature"` - AvatarLarger struct { - URI string `json:"uri"` - URLList []string `json:"url_list"` - } `json:"avatar_larger"` + AwemeDetail struct { + Anchors interface{} `json:"anchors"` + Author struct { AvatarThumb struct { + Height int `json:"height"` URI string `json:"uri"` URLList []string `json:"url_list"` + Width int `json:"width"` } `json:"avatar_thumb"` + CfList interface{} `json:"cf_list"` + CloseFriendType int `json:"close_friend_type"` + ContactsStatus int `json:"contacts_status"` + ContrailList interface{} `json:"contrail_list"` + CoverURL []struct { + Height int `json:"height"` + URI string `json:"uri"` + URLList []string `json:"url_list"` + Width int `json:"width"` + } `json:"cover_url"` + CreateTime int `json:"create_time"` + CustomVerify string `json:"custom_verify"` + DataLabelList interface{} `json:"data_label_list"` + EndorsementInfoList interface{} `json:"endorsement_info_list"` + EnterpriseVerifyReason string `json:"enterprise_verify_reason"` + FavoritingCount int `json:"favoriting_count"` + FollowStatus int `json:"follow_status"` + FollowerCount int `json:"follower_count"` + FollowerListSecondaryInformationStruct interface{} `json:"follower_list_secondary_information_struct"` + FollowerStatus int `json:"follower_status"` + FollowingCount int `json:"following_count"` + ImRoleIds interface{} `json:"im_role_ids"` + IsAdFake bool `json:"is_ad_fake"` + IsBlockedV2 bool `json:"is_blocked_v2"` + IsBlockingV2 bool `json:"is_blocking_v2"` + IsCf int `json:"is_cf"` + MaxFollowerCount int `json:"max_follower_count"` + Nickname string `json:"nickname"` + NotSeenItemIDList interface{} `json:"not_seen_item_id_list"` + NotSeenItemIDListV2 interface{} `json:"not_seen_item_id_list_v2"` + OfflineInfoList interface{} `json:"offline_info_list"` + PersonalTagList interface{} `json:"personal_tag_list"` + PreventDownload bool `json:"prevent_download"` + RiskNoticeText string `json:"risk_notice_text"` + SecUID string `json:"sec_uid"` + Secret int `json:"secret"` + ShareInfo struct { + ShareDesc string `json:"share_desc"` + ShareDescInfo string `json:"share_desc_info"` + ShareQrcodeURL struct { + Height int `json:"height"` + URI string `json:"uri"` + URLList []string `json:"url_list"` + Width int `json:"width"` + } `json:"share_qrcode_url"` + ShareTitle string `json:"share_title"` + ShareTitleMyself string `json:"share_title_myself"` + ShareTitleOther string `json:"share_title_other"` + ShareURL string `json:"share_url"` + ShareWeiboDesc string `json:"share_weibo_desc"` + } `json:"share_info"` + ShortID string `json:"short_id"` + Signature string `json:"signature"` + SignatureExtra interface{} `json:"signature_extra"` + SpecialPeopleLabels interface{} `json:"special_people_labels"` + Status int `json:"status"` + TextExtra interface{} `json:"text_extra"` + TotalFavorited int `json:"total_favorited"` + UID string `json:"uid"` + UniqueID string `json:"unique_id"` + UserAge int `json:"user_age"` + UserCanceled bool `json:"user_canceled"` + UserPermissions interface{} `json:"user_permissions"` + VerificationType int `json:"verification_type"` + } `json:"author"` + AuthorMaskTag int `json:"author_mask_tag"` + AuthorUserID int64 `json:"author_user_id"` + AwemeControl struct { + CanComment bool `json:"can_comment"` + CanForward bool `json:"can_forward"` + CanShare bool `json:"can_share"` + CanShowComment bool `json:"can_show_comment"` + } `json:"aweme_control"` + AwemeID string `json:"aweme_id"` + AwemeType int `json:"aweme_type"` + ChallengePosition interface{} `json:"challenge_position"` + ChapterList interface{} `json:"chapter_list"` + CollectStat int `json:"collect_stat"` + CommentGid int64 `json:"comment_gid"` + CommentList interface{} `json:"comment_list"` + CommentPermissionInfo struct { + CanComment bool `json:"can_comment"` + CommentPermissionStatus int `json:"comment_permission_status"` + ItemDetailEntry bool `json:"item_detail_entry"` + PressEntry bool `json:"press_entry"` + ToastGuide bool `json:"toast_guide"` + } `json:"comment_permission_info"` + CommerceConfigData interface{} `json:"commerce_config_data"` + CommonBarInfo string `json:"common_bar_info"` + ComponentInfoV2 string `json:"component_info_v2"` + CoverLabels interface{} `json:"cover_labels"` + CreateTime int `json:"create_time"` + Desc string `json:"desc"` + DiggLottie struct { + CanBomb int `json:"can_bomb"` + LottieID string `json:"lottie_id"` + } `json:"digg_lottie"` + DisableRelationBar int `json:"disable_relation_bar"` + DislikeDimensionList interface{} `json:"dislike_dimension_list"` + DuetAggregateInMusicTab bool `json:"duet_aggregate_in_music_tab"` + Duration int `json:"duration"` + Geofencing []interface{} `json:"geofencing"` + GeofencingRegions interface{} `json:"geofencing_regions"` + GroupID string `json:"group_id"` + HybridLabel interface{} `json:"hybrid_label"` + ImageAlbumMusicInfo struct { + BeginTime int `json:"begin_time"` + EndTime int `json:"end_time"` + Volume int `json:"volume"` + } `json:"image_album_music_info"` + ImageInfos interface{} `json:"image_infos"` + ImageList interface{} `json:"image_list"` + Images interface{} `json:"images"` + ImgBitrate interface{} `json:"img_bitrate"` + ImpressionData struct { + GroupIDListA []int64 `json:"group_id_list_a"` + GroupIDListB []int64 `json:"group_id_list_b"` + SimilarIDListA interface{} `json:"similar_id_list_a"` + SimilarIDListB interface{} `json:"similar_id_list_b"` + } `json:"impression_data"` + InteractionStickers interface{} `json:"interaction_stickers"` + IsAds bool `json:"is_ads"` + IsCollectsSelected int `json:"is_collects_selected"` + IsDuetSing bool `json:"is_duet_sing"` + IsImageBeat bool `json:"is_image_beat"` + IsLifeItem bool `json:"is_life_item"` + IsStory int `json:"is_story"` + IsTop int `json:"is_top"` + ItemWarnNotification struct { + Content string `json:"content"` + Show bool `json:"show"` + Type int `json:"type"` + } `json:"item_warn_notification"` + LabelTopText interface{} `json:"label_top_text"` + LongVideo interface{} `json:"long_video"` + Music struct { + Album string `json:"album"` + ArtistUserInfos interface{} `json:"artist_user_infos"` + Artists []interface{} `json:"artists"` + AuditionDuration int `json:"audition_duration"` + Author string `json:"author"` + AuthorDeleted bool `json:"author_deleted"` + AuthorPosition interface{} `json:"author_position"` + AuthorStatus int `json:"author_status"` + AvatarLarge struct { + Height int `json:"height"` + URI string `json:"uri"` + URLList []string `json:"url_list"` + Width int `json:"width"` + } `json:"avatar_large"` AvatarMedium struct { + Height int `json:"height"` URI string `json:"uri"` URLList []string `json:"url_list"` + Width int `json:"width"` } `json:"avatar_medium"` - FollowStatus int `json:"follow_status"` - UniqueID string `json:"unique_id"` - FollowersDetail interface{} `json:"followers_detail"` - PlatformSyncInfo interface{} `json:"platform_sync_info"` - Geofencing interface{} `json:"geofencing"` - PolicyVersion interface{} `json:"policy_version"` - TypeLabel interface{} `json:"type_label"` - CardEntries interface{} `json:"card_entries"` - MixInfo interface{} `json:"mix_info"` - } `json:"author"` - Music struct { - ID int64 `json:"id"` - Mid string `json:"mid"` - Title string `json:"title"` - Author string `json:"author"` - CoverHd struct { + AvatarThumb struct { + Height int `json:"height"` + URI string `json:"uri"` + URLList []string `json:"url_list"` + Width int `json:"width"` + } `json:"avatar_thumb"` + BindedChallengeID int `json:"binded_challenge_id"` + CanBackgroundPlay bool `json:"can_background_play"` + CollectStat int `json:"collect_stat"` + CoverHd struct { + Height int `json:"height"` URI string `json:"uri"` URLList []string `json:"url_list"` + Width int `json:"width"` } `json:"cover_hd"` CoverLarge struct { + Height int `json:"height"` URI string `json:"uri"` URLList []string `json:"url_list"` + Width int `json:"width"` } `json:"cover_large"` CoverMedium struct { + Height int `json:"height"` URI string `json:"uri"` URLList []string `json:"url_list"` + Width int `json:"width"` } `json:"cover_medium"` CoverThumb struct { + Height int `json:"height"` URI string `json:"uri"` URLList []string `json:"url_list"` + Width int `json:"width"` } `json:"cover_thumb"` - PlayURL struct { + DmvAutoShow bool `json:"dmv_auto_show"` + DspStatus int `json:"dsp_status"` + Duration int `json:"duration"` + EndTime int `json:"end_time"` + ExternalSongInfo []interface{} `json:"external_song_info"` + Extra string `json:"extra"` + ID int64 `json:"id"` + IDStr string `json:"id_str"` + IsAudioURLWithCookie bool `json:"is_audio_url_with_cookie"` + IsCommerceMusic bool `json:"is_commerce_music"` + IsDelVideo bool `json:"is_del_video"` + IsMatchedMetadata bool `json:"is_matched_metadata"` + IsOriginal bool `json:"is_original"` + IsOriginalSound bool `json:"is_original_sound"` + IsPgc bool `json:"is_pgc"` + IsRestricted bool `json:"is_restricted"` + IsVideoSelfSee bool `json:"is_video_self_see"` + LunaInfo struct { + IsLunaUser bool `json:"is_luna_user"` + } `json:"luna_info"` + LyricShortPosition interface{} `json:"lyric_short_position"` + Mid string `json:"mid"` + MusicChartRanks interface{} `json:"music_chart_ranks"` + MusicStatus int `json:"music_status"` + MusicianUserInfos interface{} `json:"musician_user_infos"` + MuteShare bool `json:"mute_share"` + OfflineDesc string `json:"offline_desc"` + OwnerHandle string `json:"owner_handle"` + OwnerID string `json:"owner_id"` + OwnerNickname string `json:"owner_nickname"` + PgcMusicType int `json:"pgc_music_type"` + PlayURL struct { + Height int `json:"height"` URI string `json:"uri"` + URLKey string `json:"url_key"` URLList []string `json:"url_list"` + Width int `json:"width"` } `json:"play_url"` - Duration int `json:"duration"` - Position interface{} `json:"position"` - Status int `json:"status"` - } `json:"music"` - ChaList []struct { - Cid string `json:"cid"` - ChaName string `json:"cha_name"` - Desc string `json:"desc"` - UserCount int `json:"user_count"` - ConnectMusic interface{} `json:"connect_music"` - Type int `json:"type"` - CoverItem struct { + Position interface{} `json:"position"` + PreventDownload bool `json:"prevent_download"` + PreventItemDownloadStatus int `json:"prevent_item_download_status"` + PreviewEndTime int `json:"preview_end_time"` + PreviewStartTime int `json:"preview_start_time"` + ReasonType int `json:"reason_type"` + Redirect bool `json:"redirect"` + SchemaURL string `json:"schema_url"` + SearchImpr struct { + EntityID string `json:"entity_id"` + } `json:"search_impr"` + SecUID string `json:"sec_uid"` + ShootDuration int `json:"shoot_duration"` + SourcePlatform int `json:"source_platform"` + StartTime int `json:"start_time"` + Status int `json:"status"` + StrongBeatURL struct { + Height int `json:"height"` URI string `json:"uri"` URLList []string `json:"url_list"` - } `json:"cover_item"` - ViewCount int `json:"view_count"` - HashTagProfile string `json:"hash_tag_profile"` - IsCommerce bool `json:"is_commerce"` - } `json:"cha_list"` - Video struct { - PlayAddr struct { - URI string `json:"uri"` - URLList []string `json:"url_list"` - } `json:"play_addr"` + Width int `json:"width"` + } `json:"strong_beat_url"` + TagList interface{} `json:"tag_list"` + Title string `json:"title"` + UnshelveCountries interface{} `json:"unshelve_countries"` + UserCount int `json:"user_count"` + VideoDuration int `json:"video_duration"` + } `json:"music"` + NicknamePosition interface{} `json:"nickname_position"` + OriginCommentIds interface{} `json:"origin_comment_ids"` + OriginTextExtra []interface{} `json:"origin_text_extra"` + OriginalImages interface{} `json:"original_images"` + PackedClips interface{} `json:"packed_clips"` + PhotoSearchEntrance struct { + EcomType int `json:"ecom_type"` + } `json:"photo_search_entrance"` + Position interface{} `json:"position"` + PreviewTitle string `json:"preview_title"` + PreviewVideoStatus int `json:"preview_video_status"` + Promotions []interface{} `json:"promotions"` + Rate int `json:"rate"` + Region string `json:"region"` + RelationLabels interface{} `json:"relation_labels"` + SearchImpr struct { + EntityID string `json:"entity_id"` + EntityType string `json:"entity_type"` + } `json:"search_impr"` + SeriesPaidInfo struct { + ItemPrice int `json:"item_price"` + SeriesPaidStatus int `json:"series_paid_status"` + } `json:"series_paid_info"` + ShareInfo struct { + ShareDesc string `json:"share_desc"` + ShareDescInfo string `json:"share_desc_info"` + ShareLinkDesc string `json:"share_link_desc"` + ShareURL string `json:"share_url"` + } `json:"share_info"` + ShareURL string `json:"share_url"` + ShouldOpenAdReport bool `json:"should_open_ad_report"` + ShowFollowButton struct { + } `json:"show_follow_button"` + SocialTagList interface{} `json:"social_tag_list"` + StandardBarInfoList interface{} `json:"standard_bar_info_list"` + Statistics struct { + AdmireCount int `json:"admire_count"` + AwemeID string `json:"aweme_id"` + CollectCount int `json:"collect_count"` + CommentCount int `json:"comment_count"` + DiggCount int `json:"digg_count"` + PlayCount int `json:"play_count"` + ShareCount int `json:"share_count"` + } `json:"statistics"` + Status struct { + AllowShare bool `json:"allow_share"` + AwemeID string `json:"aweme_id"` + InReviewing bool `json:"in_reviewing"` + IsDelete bool `json:"is_delete"` + IsProhibited bool `json:"is_prohibited"` + ListenVideoStatus int `json:"listen_video_status"` + PartSee int `json:"part_see"` + PrivateStatus int `json:"private_status"` + ReviewResult struct { + ReviewStatus int `json:"review_status"` + } `json:"review_result"` + } `json:"status"` + TextExtra []struct { + End int `json:"end"` + HashtagID string `json:"hashtag_id"` + HashtagName string `json:"hashtag_name"` + IsCommerce bool `json:"is_commerce"` + Start int `json:"start"` + Type int `json:"type"` + } `json:"text_extra"` + UniqidPosition interface{} `json:"uniqid_position"` + UserDigged int `json:"user_digged"` + Video struct { + BigThumbs []struct { + Duration float64 `json:"duration"` + Fext string `json:"fext"` + ImgNum int `json:"img_num"` + ImgURL string `json:"img_url"` + ImgXLen int `json:"img_x_len"` + ImgXSize int `json:"img_x_size"` + ImgYLen int `json:"img_y_len"` + ImgYSize int `json:"img_y_size"` + Interval int `json:"interval"` + URI string `json:"uri"` + } `json:"big_thumbs"` + BitRate []struct { + FPS int `json:"FPS"` + HDRBit string `json:"HDR_bit"` + HDRType string `json:"HDR_type"` + BitRate int `json:"bit_rate"` + GearName string `json:"gear_name"` + IsBytevc1 int `json:"is_bytevc1"` + IsH265 int `json:"is_h265"` + PlayAddr struct { + DataSize int `json:"data_size"` + FileCs string `json:"file_cs"` + FileHash string `json:"file_hash"` + Height int `json:"height"` + URI string `json:"uri"` + URLKey string `json:"url_key"` + URLList []string `json:"url_list"` + Width int `json:"width"` + } `json:"play_addr"` + QualityType int `json:"quality_type"` + } `json:"bit_rate"` Cover struct { + Height int `json:"height"` URI string `json:"uri"` URLList []string `json:"url_list"` + Width int `json:"width"` } `json:"cover"` - Height int `json:"height"` - Width int `json:"width"` + CoverOriginalScale struct { + Height int `json:"height"` + URI string `json:"uri"` + URLList []string `json:"url_list"` + Width int `json:"width"` + } `json:"cover_original_scale"` + Duration int `json:"duration"` DynamicCover struct { + Height int `json:"height"` URI string `json:"uri"` URLList []string `json:"url_list"` + Width int `json:"width"` } `json:"dynamic_cover"` + Height int `json:"height"` + IsH265 int `json:"is_h265"` + IsSourceHDR int `json:"is_source_HDR"` + Meta string `json:"meta"` OriginCover struct { + Height int `json:"height"` URI string `json:"uri"` URLList []string `json:"url_list"` + Width int `json:"width"` } `json:"origin_cover"` - Ratio string `json:"ratio"` - HasWatermark bool `json:"has_watermark"` - BitRate interface{} `json:"bit_rate"` - Duration int `json:"duration"` - Vid string `json:"vid"` + PlayAddr struct { + DataSize int `json:"data_size"` + FileCs string `json:"file_cs"` + FileHash string `json:"file_hash"` + Height int `json:"height"` + URI string `json:"uri"` + URLKey string `json:"url_key"` + URLList []string `json:"url_list"` + Width int `json:"width"` + } `json:"play_addr"` + Ratio string `json:"ratio"` + Width int `json:"width"` } `json:"video"` - ShareURL string `json:"share_url"` - Statistics struct { - AwemeID string `json:"aweme_id"` - CommentCount int `json:"comment_count"` - DiggCount int `json:"digg_count"` - PlayCount int `json:"play_count"` - ShareCount int `json:"share_count"` - } `json:"statistics"` - TextExtra []struct { - Start int `json:"start"` - End int `json:"end"` - Type int `json:"type"` - HashtagName string `json:"hashtag_name"` - HashtagID int64 `json:"hashtag_id"` - } `json:"text_extra"` - ShareInfo struct { - ShareWeiboDesc string `json:"share_weibo_desc"` - ShareDesc string `json:"share_desc"` - ShareTitle string `json:"share_title"` - } `json:"share_info"` VideoLabels interface{} `json:"video_labels"` - Duration int `json:"duration"` - AwemeType int `json:"aweme_type"` - ImageInfos interface{} `json:"image_infos"` - RiskInfos struct { - Warn bool `json:"warn"` - Type int `json:"type"` - Content string `json:"content"` - ReflowUnplayable int `json:"reflow_unplayable"` - } `json:"risk_infos"` - CommentList interface{} `json:"comment_list"` - AuthorUserID int64 `json:"author_user_id"` - Geofencing interface{} `json:"geofencing"` - VideoText interface{} `json:"video_text"` - LabelTopText interface{} `json:"label_top_text"` - Promotions interface{} `json:"promotions"` - LongVideo interface{} `json:"long_video"` - IsPreview int `json:"is_preview"` - GroupID int64 `json:"group_id"` - IsLiveReplay bool `json:"is_live_replay"` - ForwardID string `json:"forward_id"` - Images interface{} `json:"images"` - GroupIDStr string `json:"group_id_str"` - } `json:"item_list"` - FilterList []interface{} `json:"filter_list"` - Extra struct { - Logid string `json:"logid"` - Now int64 `json:"now"` - } `json:"extra"` + VideoTag []struct { + Level int `json:"level"` + TagID int `json:"tag_id"` + TagName string `json:"tag_name"` + } `json:"video_tag"` + VideoText []interface{} `json:"video_text"` + WannaTag struct { + } `json:"wanna_tag"` + } `json:"aweme_detail"` + LogPb struct { + ImprID string `json:"impr_id"` + } `json:"log_pb"` + StatusCode int `json:"status_code"` } func (a DouyinAdapter) GetShortVideoInfo(url string) (*ShortVideoInfoResponse, error) { @@ -175,12 +444,12 @@ func (a DouyinAdapter) GetShortVideoInfo(url string) (*ShortVideoInfoResponse, e return nil, err } loc := headerResp.RawResponse.Request.Response.Header.Get("Location") - re := regexp.MustCompile(`/video\/(.*)\?`) + re := regexp.MustCompile(`/video\/(.*)/\?`) match := re.FindStringSubmatch(loc) if len(match) != 2 { return nil, errors.New("匹配视频id失败") } - getResp, err := restyHttp.GetMobileHttpRequest().Get("https://www.iesdouyin.com/web/api/v2/aweme/iteminfo/?item_ids=" + match[1]) + getResp, err := restyHttp.GetMobileHttpRequest().Get("https://www.iesdouyin.com/aweme/v1/web/aweme/detail/?aweme_id=" + match[1]) if err != nil { return nil, err } @@ -190,12 +459,12 @@ func (a DouyinAdapter) GetShortVideoInfo(url string) (*ShortVideoInfoResponse, e return nil, err } shortVideoInfo := &ShortVideoInfoResponse{ - AuthorName: douyinResponse.ItemList[0].Author.Nickname, - AuthorAvatar: douyinResponse.ItemList[0].Author.AvatarLarger.URLList[0], - Title: douyinResponse.ItemList[0].ShareInfo.ShareTitle, - Cover: douyinResponse.ItemList[0].Video.OriginCover.URLList[0], + AuthorName: douyinResponse.AwemeDetail.Author.Nickname, + AuthorAvatar: douyinResponse.AwemeDetail.Author.AvatarThumb.URLList[0], + Title: douyinResponse.AwemeDetail.Desc, + Cover: douyinResponse.AwemeDetail.Video.OriginCover.URLList[0], CreatedAt: "", - NoWatermarkDownloadUrl: strings.Replace(douyinResponse.ItemList[0].Video.PlayAddr.URLList[0], "playwm", "play", -1), + NoWatermarkDownloadUrl: douyinResponse.AwemeDetail.Video.PlayAddr.URLList[0], } return shortVideoInfo, nil }