Fix actor image error #5
This commit is contained in:
parent
ff7286af98
commit
66bafb9199
|
@ -60,7 +60,7 @@ namespace Jellyfin.Plugin.MetaShark.Test
|
|||
|
||||
|
||||
[TestMethod]
|
||||
public void TestGetVideoByBvidAsync()
|
||||
public void TestGetVideoBySidAsync()
|
||||
{
|
||||
var sid = "26654184";
|
||||
|
||||
|
@ -80,6 +80,28 @@ namespace Jellyfin.Plugin.MetaShark.Test
|
|||
}).GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestFixGetImage()
|
||||
{
|
||||
// 演员入驻了豆瓣, 下载的不是演员的头像#5
|
||||
var sid = "35460157";
|
||||
|
||||
var api = new DoubanApi(loggerFactory);
|
||||
|
||||
Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = await api.GetMovieAsync(sid, CancellationToken.None);
|
||||
Assert.AreEqual<string>("https://img2.doubanio.com/view/celebrity/raw/public/p1598199472.61.jpg", result.Celebrities.First(x => x.Name == "刘陆").Img);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex.Message);
|
||||
}
|
||||
}).GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestGetCelebritiesBySidAsync()
|
||||
{
|
||||
|
@ -100,5 +122,26 @@ namespace Jellyfin.Plugin.MetaShark.Test
|
|||
}
|
||||
}).GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestGetCelebritiesByCidAsync()
|
||||
{
|
||||
var sid = "1340364";
|
||||
|
||||
var api = new DoubanApi(loggerFactory);
|
||||
|
||||
Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = await api.GetCelebrityAsync(sid, CancellationToken.None);
|
||||
TestContext.WriteLine(result.ToJson());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex.Message);
|
||||
}
|
||||
}).GetAwaiter().GetResult();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ using Jellyfin.Plugin.MetaShark.Core;
|
|||
using Jellyfin.Plugin.MetaShark.Providers;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Moq;
|
||||
using System;
|
||||
|
@ -69,5 +70,26 @@ namespace Jellyfin.Plugin.MetaShark.Test
|
|||
}).GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestGetMetadataByTMDB()
|
||||
{
|
||||
var info = new MovieInfo() { Name = "人生大事", MetadataLanguage = "zh", ProviderIds = new Dictionary<string, string> { { MetadataProvider.Tmdb.ToString(), "945664" } } };
|
||||
var doubanApi = new DoubanApi(loggerFactory);
|
||||
var tmdbApi = new TmdbApi(loggerFactory);
|
||||
var omdbApi = new OmdbApi(loggerFactory);
|
||||
var httpClientFactory = new DefaultHttpClientFactory();
|
||||
var libraryManagerStub = new Mock<ILibraryManager>();
|
||||
|
||||
Task.Run(async () =>
|
||||
{
|
||||
var provider = new MovieProvider(httpClientFactory, loggerFactory, libraryManagerStub.Object, doubanApi, tmdbApi, omdbApi);
|
||||
var result = await provider.GetMetadata(info, CancellationToken.None);
|
||||
Assert.IsNotNull(result);
|
||||
|
||||
var str = result.ToJson();
|
||||
Console.WriteLine(result.ToJson());
|
||||
}).GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -62,7 +62,7 @@ namespace Jellyfin.Plugin.MetaShark.Api
|
|||
Regex regSite = new Regex(@"官方网站: (.+?)\n", RegexOptions.Compiled);
|
||||
Regex regNameMath = new Regex(@"(.+第\w季|[\w\uff1a\uff01\uff0c\u00b7]+)\s*(.*)", RegexOptions.Compiled);
|
||||
Regex regRole = new Regex(@"\([饰|配] (.+?)\)", RegexOptions.Compiled);
|
||||
Regex regBackgroundImage = new Regex(@"url\((.+?)\)", RegexOptions.Compiled);
|
||||
Regex regBackgroundImage = new Regex(@"url\(([^)]+?)\)$", RegexOptions.Compiled);
|
||||
Regex regGender = new Regex(@"性别: \n(.+?)\n", RegexOptions.Compiled);
|
||||
Regex regConstellation = new Regex(@"星座: \n(.+?)\n", RegexOptions.Compiled);
|
||||
Regex regBirthdate = new Regex(@"出生日期: \n(.+?)\n", RegexOptions.Compiled);
|
||||
|
@ -336,7 +336,7 @@ namespace Jellyfin.Plugin.MetaShark.Api
|
|||
var celebrityImg = celebrityImgStr.GetMatchGroup(this.regBackgroundImage);
|
||||
var celebrityNameStr = node.GetText("div.info a.name") ?? string.Empty;
|
||||
var arr = celebrityNameStr.Split(" ");
|
||||
var celebrityName = arr.Length > 1 ? arr[0] : string.Empty;
|
||||
var celebrityName = arr.Length > 1 ? arr[0] : celebrityNameStr;
|
||||
var celebrityRoleStr = node.GetText("div.info span.role") ?? string.Empty;
|
||||
var celebrityRole = celebrityRoleStr.GetMatchGroup(this.regRole);
|
||||
var arrRole = celebrityRoleStr.Split(" ");
|
||||
|
@ -393,7 +393,10 @@ namespace Jellyfin.Plugin.MetaShark.Api
|
|||
if (contentNode != null)
|
||||
{
|
||||
var img = contentNode.GetAttr("#headline .nbg img", "src") ?? string.Empty;
|
||||
var name = contentNode.GetText("h1") ?? string.Empty;
|
||||
var nameStr = contentNode.GetText("h1") ?? string.Empty;
|
||||
var arr = nameStr.Split(" ");
|
||||
var name = arr.Length > 1 ? arr[0] : nameStr;
|
||||
|
||||
var intro = contentNode.GetText("#intro span.all") ?? string.Empty;
|
||||
if (string.IsNullOrEmpty(intro))
|
||||
{
|
||||
|
@ -434,6 +437,59 @@ namespace Jellyfin.Plugin.MetaShark.Api
|
|||
return null;
|
||||
}
|
||||
|
||||
|
||||
public async Task<List<DoubanCelebrity>> SearchCelebrityAsync(string keyword, CancellationToken cancellationToken)
|
||||
{
|
||||
var list = new List<DoubanCelebrity>();
|
||||
if (string.IsNullOrEmpty(keyword))
|
||||
{
|
||||
return list;
|
||||
}
|
||||
|
||||
var cacheKey = $"search_celebrity_{keyword}";
|
||||
var expiredOption = new MemoryCacheEntryOptions() { AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(30) };
|
||||
List<DoubanCelebrity> searchResult;
|
||||
if (_memoryCache.TryGetValue<List<DoubanCelebrity>>(cacheKey, out searchResult))
|
||||
{
|
||||
return searchResult;
|
||||
}
|
||||
|
||||
|
||||
keyword = HttpUtility.UrlEncode(keyword);
|
||||
var url = $"https://movie.douban.com/celebrities/search?search_text={keyword}";
|
||||
var response = await httpClient.GetAsync(url, cancellationToken).ConfigureAwait(false);
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
return list;
|
||||
}
|
||||
|
||||
var body = await response.Content.ReadAsStringAsync(cancellationToken).ConfigureAwait(false);
|
||||
var context = BrowsingContext.New();
|
||||
var doc = await context.OpenAsync(req => req.Content(body), cancellationToken).ConfigureAwait(false);
|
||||
var elements = doc.QuerySelectorAll("div.article .result");
|
||||
|
||||
foreach (var el in elements)
|
||||
{
|
||||
|
||||
var celebrity = new DoubanCelebrity();
|
||||
var img = el.GetAttr("div.pic img", "src") ?? string.Empty;
|
||||
var href = el.GetAttr("h3>a", "href") ?? string.Empty;
|
||||
var cid = href.GetMatchGroup(this.regId);
|
||||
var nameStr = el.GetText("h3>a") ?? string.Empty;
|
||||
var arr = nameStr.Split(" ");
|
||||
var name = arr.Length > 1 ? arr[0] : nameStr;
|
||||
|
||||
celebrity.Name = name;
|
||||
celebrity.Img = img;
|
||||
celebrity.Id = cid;
|
||||
list.Add(celebrity);
|
||||
}
|
||||
|
||||
|
||||
_memoryCache.Set<List<DoubanCelebrity>>(cacheKey, list, expiredOption);
|
||||
return list;
|
||||
}
|
||||
|
||||
public async Task<List<DoubanPhoto>> GetWallpaperBySidAsync(string sid, CancellationToken cancellationToken)
|
||||
{
|
||||
if (string.IsNullOrEmpty(sid))
|
||||
|
|
|
@ -26,9 +26,6 @@ public enum SomeOptions
|
|||
public class PluginConfiguration : BasePluginConfiguration
|
||||
{
|
||||
public string Version { get; } = Assembly.GetExecutingAssembly().GetName().Version.ToString();
|
||||
|
||||
public string Pattern { get; set; } = @"(S\d{2}|E\d{2}|HDR|\d{3,4}p|WEBRip|WEB|YIFY|BrRip|BluRay|H265|H264|x264|AAC\.\d\.\d|AAC|HDTV|mkv|mp4)|(\[.*\])|(\-\w+|\{.*\}|【.*】|\(.*\)|\d+MB)|(\.|\-)";
|
||||
|
||||
public bool EnableTmdb { get; set; } = true;
|
||||
|
||||
public bool EnableTmdbSearch { get; set; } = false;
|
||||
|
|
|
@ -77,7 +77,8 @@
|
|||
.addEventListener('pageshow', function () {
|
||||
Dashboard.showLoadingMsg();
|
||||
ApiClient.getPluginConfiguration(TemplateConfig.pluginUniqueId).then(function (config) {
|
||||
document.querySelector('#current_version').value = "v" + config.Version;
|
||||
$('#current_version').text("v" + config.Version);
|
||||
|
||||
document.querySelector('#DoubanCookies').value = config.DoubanCookies;
|
||||
document.querySelector('#EnableTmdb').checked = config.EnableTmdb;
|
||||
document.querySelector('#EnableTmdbSearch').checked = config.EnableTmdbSearch;
|
||||
|
|
|
@ -40,9 +40,8 @@ namespace Jellyfin.Plugin.MetaShark.Controllers
|
|||
|
||||
|
||||
/// <summary>
|
||||
/// 获取弹幕文件内容.
|
||||
/// 代理访问图片.
|
||||
/// </summary>
|
||||
/// <returns>xml弹幕文件内容</returns>
|
||||
[Route("proxy/image")]
|
||||
[HttpGet]
|
||||
public async Task<Stream> ProxyImage(string url)
|
||||
|
@ -54,7 +53,22 @@ namespace Jellyfin.Plugin.MetaShark.Controllers
|
|||
}
|
||||
|
||||
var httpClient = GetHttpClient();
|
||||
return await httpClient.GetStreamAsync(url).ConfigureAwait(false);
|
||||
var response = await httpClient.GetAsync(url);
|
||||
var stream = await response.Content.ReadAsStreamAsync();
|
||||
|
||||
Response.StatusCode = (int)response.StatusCode;
|
||||
if (response.Content.Headers.ContentType != null)
|
||||
{
|
||||
Response.ContentType = response.Content.Headers.ContentType.ToString();
|
||||
}
|
||||
Response.ContentLength = response.Content.Headers.ContentLength;
|
||||
|
||||
foreach (var header in response.Headers)
|
||||
{
|
||||
Response.Headers.Add(header.Key, header.Value.First());
|
||||
}
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
private HttpClient GetHttpClient()
|
||||
|
|
|
@ -20,15 +20,39 @@ namespace Jellyfin.Plugin.MetaShark.Core
|
|||
return null;
|
||||
}
|
||||
|
||||
public static string GetTextOrDefault(this IElement el, string css, string defaultVal = "")
|
||||
{
|
||||
var node = el.QuerySelector(css);
|
||||
if (node != null)
|
||||
{
|
||||
return node.Text().Trim();
|
||||
}
|
||||
|
||||
return defaultVal;
|
||||
}
|
||||
|
||||
public static string? GetAttr(this IElement el, string css, string attr)
|
||||
{
|
||||
var node = el.QuerySelector(css);
|
||||
if (node != null)
|
||||
{
|
||||
return node.GetAttribute(attr).Trim();
|
||||
var attrVal = node.GetAttribute(attr);
|
||||
return attrVal != null ? attrVal.Trim() : null;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static string? GetAttrOrDefault(this IElement el, string css, string attr, string defaultVal = "")
|
||||
{
|
||||
var node = el.QuerySelector(css);
|
||||
if (node != null)
|
||||
{
|
||||
var attrVal = node.GetAttribute(attr);
|
||||
return attrVal != null ? attrVal.Trim() : defaultVal;
|
||||
}
|
||||
|
||||
return defaultVal;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,14 +50,6 @@ namespace Jellyfin.Plugin.MetaShark.Providers
|
|||
|
||||
protected Regex regMetaSourcePrefix = new Regex(@"^\[.+\]", RegexOptions.Compiled);
|
||||
|
||||
public string Pattern
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.config.Pattern;
|
||||
}
|
||||
}
|
||||
|
||||
protected PluginConfiguration config
|
||||
{
|
||||
get
|
||||
|
|
|
@ -125,6 +125,7 @@ namespace Jellyfin.Plugin.MetaShark.Providers
|
|||
Genres = subject.Genres,
|
||||
// ProductionLocations = [x?.Country],
|
||||
PremiereDate = subject.ScreenTime,
|
||||
Tagline = string.Empty,
|
||||
};
|
||||
if (!string.IsNullOrEmpty(subject.Imdb))
|
||||
{
|
||||
|
@ -175,8 +176,9 @@ namespace Jellyfin.Plugin.MetaShark.Providers
|
|||
Tagline = movieResult.Tagline,
|
||||
ProductionLocations = movieResult.ProductionCountries.Select(pc => pc.Name).ToArray()
|
||||
};
|
||||
var metadataResult = new MetadataResult<Movie>
|
||||
result = new MetadataResult<Movie>
|
||||
{
|
||||
QueriedById = true,
|
||||
HasMetadata = true,
|
||||
ResultLanguage = info.MetadataLanguage,
|
||||
Item = movie
|
||||
|
@ -207,7 +209,7 @@ namespace Jellyfin.Plugin.MetaShark.Providers
|
|||
result.AddPerson(person);
|
||||
}
|
||||
|
||||
return metadataResult;
|
||||
return result;
|
||||
}
|
||||
|
||||
return result;
|
||||
|
|
|
@ -0,0 +1,111 @@
|
|||
using Jellyfin.Plugin.MetaShark.Api;
|
||||
using Jellyfin.Plugin.MetaShark.Core;
|
||||
using Jellyfin.Plugin.MetaShark.Model;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.Movies;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Extensions;
|
||||
using MediaBrowser.Model.Providers;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using TMDbLib.Objects.Languages;
|
||||
|
||||
namespace Jellyfin.Plugin.MetaShark.Providers
|
||||
{
|
||||
public class PersonImageProvider : BaseProvider, IRemoteImageProvider
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="MovieImageProvider"/> class.
|
||||
/// </summary>
|
||||
/// <param name="httpClientFactory">Instance of the <see cref="IHttpClientFactory"/> interface.</param>
|
||||
/// <param name="logger">Instance of the <see cref="ILogger{OddbImageProvider}"/> interface.</param>
|
||||
/// <param name="doubanApi">Instance of <see cref="DoubanApi"/>.</param>
|
||||
public PersonImageProvider(IHttpClientFactory httpClientFactory, ILoggerFactory loggerFactory, ILibraryManager libraryManager, DoubanApi doubanApi, TmdbApi tmdbApi, OmdbApi omdbApi)
|
||||
: base(httpClientFactory, loggerFactory.CreateLogger<MovieImageProvider>(), libraryManager, doubanApi, tmdbApi, omdbApi)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Name => Plugin.PluginName;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Supports(BaseItem item) => item is Person;
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<ImageType> GetSupportedImages(BaseItem item)
|
||||
{
|
||||
yield return ImageType.Primary;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<IEnumerable<RemoteImageInfo>> GetImages(BaseItem item, CancellationToken cancellationToken)
|
||||
{
|
||||
var cid = item.GetProviderId(DoubanProviderId);
|
||||
var metaSource = item.GetProviderId(Plugin.ProviderId);
|
||||
this.Log($"GetImages for item: {item.Name} [metaSource]: {metaSource}");
|
||||
if (!string.IsNullOrEmpty(cid))
|
||||
{
|
||||
var celebrity = await this._doubanApi.GetCelebrityAsync(cid, cancellationToken).ConfigureAwait(false);
|
||||
if (celebrity != null)
|
||||
{
|
||||
return new List<RemoteImageInfo> {
|
||||
new RemoteImageInfo
|
||||
{
|
||||
ProviderName = celebrity.Name,
|
||||
Url = celebrity.Img,
|
||||
Type = ImageType.Primary
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
this.Log($"Got images failed because the sid of \"{item.Name}\" is empty!");
|
||||
return new List<RemoteImageInfo>();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<HttpResponseMessage> GetImageResponse(string url, CancellationToken cancellationToken)
|
||||
{
|
||||
this.Log("GetImageResponse url: {0}", url);
|
||||
return await this._httpClientFactory.CreateClient().GetAsync(new Uri(url), cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Query for a background photo
|
||||
/// </summary>
|
||||
/// <param name="sid">a subject/movie id</param>
|
||||
/// <param name="cancellationToken">Instance of the <see cref="CancellationToken"/> interface.</param>
|
||||
private async Task<IEnumerable<RemoteImageInfo>> GetBackdrop(string sid, CancellationToken cancellationToken)
|
||||
{
|
||||
this.Log("GetBackdrop of sid: {0}", sid);
|
||||
var photo = await this._doubanApi.GetWallpaperBySidAsync(sid, cancellationToken);
|
||||
var list = new List<RemoteImageInfo>();
|
||||
|
||||
if (photo == null)
|
||||
{
|
||||
return list;
|
||||
}
|
||||
|
||||
return photo.Where(x => x.Width > x.Height * 1.3).Select(x =>
|
||||
{
|
||||
return new RemoteImageInfo
|
||||
{
|
||||
ProviderName = Name,
|
||||
Url = x.Large,
|
||||
Type = ImageType.Backdrop,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,4 +1,6 @@
|
|||
using Jellyfin.Plugin.MetaShark.Api;
|
||||
using System.Net.Mime;
|
||||
using System.Xml.Schema;
|
||||
using Jellyfin.Plugin.MetaShark.Api;
|
||||
using Jellyfin.Plugin.MetaShark.Core;
|
||||
using Jellyfin.Plugin.MetaShark.Model;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
|
@ -42,7 +44,42 @@ namespace Jellyfin.Plugin.MetaShark.Providers
|
|||
public async Task<IEnumerable<RemoteSearchResult>> GetSearchResults(PersonLookupInfo searchInfo, CancellationToken cancellationToken)
|
||||
{
|
||||
this.Log($"GetPersonSearchResults of [name]: {searchInfo.Name}");
|
||||
return await Task.FromResult<IEnumerable<RemoteSearchResult>>(new List<RemoteSearchResult>());
|
||||
|
||||
var result = new List<RemoteSearchResult>();
|
||||
var cid = searchInfo.GetProviderId(DoubanProviderId);
|
||||
if (!string.IsNullOrEmpty(cid))
|
||||
{
|
||||
var celebrity = await this._doubanApi.GetCelebrityAsync(cid, cancellationToken).ConfigureAwait(false);
|
||||
if (celebrity != null)
|
||||
{
|
||||
result.Add(new RemoteSearchResult
|
||||
{
|
||||
SearchProviderName = DoubanProviderName,
|
||||
ProviderIds = new Dictionary<string, string> { { DoubanProviderId, celebrity.Id } },
|
||||
ImageUrl = this.GetProxyImageUrl(celebrity.Img),
|
||||
Name = celebrity.Name,
|
||||
}
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
var res = await this._doubanApi.SearchCelebrityAsync(searchInfo.Name, cancellationToken).ConfigureAwait(false);
|
||||
result.AddRange(res.Take(this.config.MaxSearchResult).Select(x =>
|
||||
{
|
||||
return new RemoteSearchResult
|
||||
{
|
||||
SearchProviderName = DoubanProviderName,
|
||||
ProviderIds = new Dictionary<string, string> { { DoubanProviderId, x.Id } },
|
||||
ImageUrl = this.GetProxyImageUrl(x.Img),
|
||||
Name = x.Name,
|
||||
};
|
||||
}));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
@ -83,6 +120,7 @@ namespace Jellyfin.Plugin.MetaShark.Providers
|
|||
}
|
||||
}
|
||||
|
||||
result.QueriedById = true;
|
||||
result.HasMetadata = true;
|
||||
result.Item = item;
|
||||
|
||||
|
|
|
@ -60,8 +60,8 @@ rm -rf MediaBrowser*.dll Microsoft*.dll Newtonsoft*.dll System*.dll Emby*.dll Je
|
|||
3. Move folder `metashark` to jellyfin `data/plugins` folder
|
||||
|
||||
|
||||
## QA
|
||||
## FAQ
|
||||
|
||||
1. Plugin run in error: `System.BadImageFormatException: Bad IL format.`
|
||||
#### Plugin run in error: `System.BadImageFormatException: Bad IL format.`
|
||||
|
||||
> Remove all hidden file in `metashark` plugin folder
|
||||
Remove all hidden file and `meta.json` in `metashark` plugin folder
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"category": "Metadata",
|
||||
"changelog": "NA",
|
||||
"description": "jellyfin电影元数据插件,影片信息只要从豆瓣获取,并由TMDB补充缺失的季数据和剧集数据。",
|
||||
"description": "jellyfin电影元数据插件,影片信息只要从豆瓣获取,并由TMDB补充缺失的剧集数据。",
|
||||
"guid": "9a19103f-16f7-4668-be54-9a1e7a4f7556",
|
||||
"imageUrl": "https://github.com/cxfksword/jellyfin-plugin-metashark/raw/main/doc/logo.png",
|
||||
"name": "MetaShark",
|
||||
|
|
Loading…
Reference in New Issue