Optimize youku search api

This commit is contained in:
cxfksword
2023-02-03 10:50:02 +08:00
parent 1a7a684f89
commit 4f736adbf8
6 changed files with 95 additions and 60 deletions

View File

@@ -24,7 +24,7 @@ namespace Jellyfin.Plugin.Danmu.Test
[TestMethod]
public void TestSearch()
{
var keyword = "夏洛特";
var keyword = "一拳超人";
var api = new YoukuApi(loggerFactory);
Task.Run(async () =>

View File

@@ -0,0 +1,51 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
namespace Jellyfin.Plugin.Danmu.Scrapers.Youku.Entity
{
public class YoukuSearchResult
{
[JsonPropertyName("pageComponentList")]
public List<YoukuSearchComponent> PageComponentList { get; set; }
}
public class YoukuSearchComponent
{
[JsonPropertyName("commonData")]
public YoukuSearchComponentData CommonData { get; set; }
}
public class YoukuSearchComponentData
{
[JsonPropertyName("showId")]
public string ShowId { get; set; }
[JsonPropertyName("episodeTotal")]
public int EpisodeTotal { get; set; }
[JsonPropertyName("feature")]
public string Feature { get; set; }
[JsonPropertyName("isYouku")]
public int IsYouku { get; set; }
[JsonPropertyName("hasYouku")]
public int HasYouku { get; set; }
[JsonPropertyName("ugcSupply")]
public int UgcSupply { get; set; }
[JsonPropertyName("titleDTO")]
public YoukuSearchTitle TitleDTO { get; set; }
}
public class YoukuSearchTitle
{
[JsonPropertyName("displayName")]
public string DisplayName { get; set; }
}
}

View File

@@ -1,31 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
namespace Jellyfin.Plugin.Danmu.Scrapers.Youku.Entity
{
public class YoukuTrackInfo
{
[JsonPropertyName("group_id")]
public string GroupID { get; set; }
[JsonPropertyName("object_type")]
public int ObjectType { get; set; }
[JsonPropertyName("object_title")]
public string ObjectTitle { get; set; }
[JsonPropertyName("object_url")]
public string ObjectUrl { get; set; }
[JsonIgnore]
public int? Year { get; set; }
[JsonIgnore]
public string Type { get; set; }
}
}

View File

@@ -15,5 +15,17 @@ namespace Jellyfin.Plugin.Danmu.Scrapers.Youku.Entity
[JsonPropertyName("videos")]
public List<YoukuEpisode> Videos { get; set; } = new List<YoukuEpisode>();
[JsonIgnore]
public string ID { get; set; }
[JsonIgnore]
public string Title { get; set; }
[JsonIgnore]
public int? Year { get; set; }
[JsonIgnore]
public string Type { get; set; }
}
}

View File

@@ -45,8 +45,8 @@ public class Youku : AbstractScraper
var videos = await this._api.SearchAsync(searchName, CancellationToken.None).ConfigureAwait(false);
foreach (var video in videos)
{
var videoId = video.GroupID;
var title = video.ObjectTitle;
var videoId = video.ID;
var title = video.Title;
var pubYear = video.Year;
var isMovieItemType = item is MediaBrowser.Controller.Entities.Movies.Movie;

View File

@@ -48,60 +48,61 @@ public class YoukuApi : AbstractApi
}
public async Task<List<YoukuTrackInfo>> SearchAsync(string keyword, CancellationToken cancellationToken)
public async Task<List<YoukuVideo>> SearchAsync(string keyword, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(keyword))
{
return new List<YoukuTrackInfo>();
return new List<YoukuVideo>();
}
var cacheKey = $"search_{keyword}";
var expiredOption = new MemoryCacheEntryOptions() { AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(30) };
if (_memoryCache.TryGetValue<List<YoukuTrackInfo>>(cacheKey, out var searchResult))
if (_memoryCache.TryGetValue<List<YoukuVideo>>(cacheKey, out var cacheValue))
{
return searchResult;
return cacheValue;
}
await this.LimitRequestFrequently();
keyword = HttpUtility.UrlEncode(keyword);
var url = $"https://search.youku.com/search_video?keyword={keyword}";
var ua = HttpUtility.UrlEncode(HTTP_USER_AGENT);
var url = $"https://search.youku.com/api/search?keyword={keyword}&userAgent={ua}&site=1&categories=0&ftype=0&ob=0&pg=1";
var response = await httpClient.GetAsync(url, cancellationToken).ConfigureAwait(false);
response.EnsureSuccessStatusCode();
var body = await response.Content.ReadAsStringAsync(cancellationToken).ConfigureAwait(false);
var result = new List<YoukuTrackInfo>();
var matchs = moviesReg.Matches(body);
foreach (Match match in matchs)
var result = new List<YoukuVideo>();
var searchResult = await response.Content.ReadFromJsonAsync<YoukuSearchResult>(_jsonOptions, cancellationToken).ConfigureAwait(false);
if (searchResult != null && searchResult.PageComponentList != null)
{
var text = HttpUtility.HtmlDecode(match.Groups[1].Value);
var trackInfoJson = trackInfoReg.FirstMatchGroup(text);
try
foreach (YoukuSearchComponent component in searchResult.PageComponentList)
{
if (string.IsNullOrEmpty(trackInfoJson))
if (component.CommonData == null
|| component.CommonData.TitleDTO == null
|| component.CommonData.HasYouku != 1
|| component.CommonData.IsYouku != 1
|| component.CommonData.UgcSupply == 1)
{
continue;
}
var trackInfo = JsonSerializer.Deserialize<YoukuTrackInfo>(trackInfoJson);
if (trackInfo != null && trackInfo.ObjectType == 101 && !trackInfo.ObjectTitle.Contains("中配版"))
if (component.CommonData.TitleDTO.DisplayName.Contains("中配版"))
{
var featureInfo = featureReg.FirstMatchGroup(text);
var year = yearReg.FirstMatch(featureInfo).ToInt();
trackInfo.Year = year > 0 ? year : null;
trackInfo.Type = featureInfo.Contains("电影") ? "movie" : "tv";
trackInfo.ObjectTitle = unusedReg.Replace(trackInfo.ObjectTitle, "");
result.Add(trackInfo);
continue;
}
}
catch (Exception ex)
{
var year = yearReg.FirstMatch(component.CommonData.Feature).ToInt();
result.Add(new YoukuVideo()
{
ID = component.CommonData.ShowId,
Type = component.CommonData.Feature.Contains("电影") ? "movie" : "tv",
Year = year > 0 ? year : null,
Title = unusedReg.Replace(component.CommonData.TitleDTO.DisplayName, ""),
Total = component.CommonData.EpisodeTotal
});
}
}
_memoryCache.Set<List<YoukuTrackInfo>>(cacheKey, result, expiredOption);
_memoryCache.Set<List<YoukuVideo>>(cacheKey, result, expiredOption);
return result;
}
@@ -119,6 +120,8 @@ public class YoukuApi : AbstractApi
return video;
}
// 获取影片信息https://openapi.youku.com/v2/shows/show.json?client_id=53e6cc67237fc59a&package=com.huawei.hwvplayer.youku&show_id=0b39c5b6569311e5b2ad
// 获取影片剧集信息https://openapi.youku.com/v2/shows/videos.json?client_id=53e6cc67237fc59a&package=com.huawei.hwvplayer.youku&ext=show&show_id=XMTM1MTc4MDU3Ng==
var url = $"https://openapi.youku.com/v2/shows/videos.json?client_id=53e6cc67237fc59a&package=com.huawei.hwvplayer.youku&ext=show&show_id={id}";
var response = await httpClient.GetAsync(url, cancellationToken).ConfigureAwait(false);
response.EnsureSuccessStatusCode();