Skip to content

Commit

Permalink
Merge pull request #9 from cxfksword/youku
Browse files Browse the repository at this point in the history
Optimize youku search api
  • Loading branch information
cxfksword authored Feb 3, 2023
2 parents a6d84d3 + 4f736ad commit ca09be8
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 60 deletions.
2 changes: 1 addition & 1 deletion Jellyfin.Plugin.Danmu.Test/YoukuApiTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public class YoukuApiTest
[TestMethod]
public void TestSearch()
{
var keyword = "夏洛特";
var keyword = "一拳超人";
var api = new YoukuApi(loggerFactory);

Task.Run(async () =>
Expand Down
51 changes: 51 additions & 0 deletions Jellyfin.Plugin.Danmu/Scrapers/Youku/Entity/YoukuSearchResult.cs
Original file line number Diff line number Diff line change
@@ -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; }
}
}
31 changes: 0 additions & 31 deletions Jellyfin.Plugin.Danmu/Scrapers/Youku/Entity/YoukuTrackInfo.cs

This file was deleted.

12 changes: 12 additions & 0 deletions Jellyfin.Plugin.Danmu/Scrapers/Youku/Entity/YoukuVideo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,17 @@ public class YoukuVideo
[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; }

}
}
4 changes: 2 additions & 2 deletions Jellyfin.Plugin.Danmu/Scrapers/Youku/Youku.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ public Youku(ILoggerFactory logManager)
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;

Expand Down
55 changes: 29 additions & 26 deletions Jellyfin.Plugin.Danmu/Scrapers/Youku/YoukuApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,60 +48,61 @@ public YoukuApi(ILoggerFactory loggerFactory)
}


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;
}

Expand All @@ -119,6 +120,8 @@ public async Task<List<YoukuTrackInfo>> SearchAsync(string keyword, Cancellation
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();
Expand Down

0 comments on commit ca09be8

Please sign in to comment.