mirror of
https://github.com/jellyfin/jellyfin-plugin-anidb.git
synced 2024-11-23 05:49:41 +00:00
Merge branch 'aio' into better-search
This commit is contained in:
commit
638ee89de4
@ -46,6 +46,8 @@ namespace Jellyfin.Plugin.AniDB.Configuration
|
||||
|
||||
public int TitleSimilarityThreshold { get; set; }
|
||||
|
||||
public bool IgnoreSeason { get; set; }
|
||||
|
||||
public int MaxGenres { get; set; }
|
||||
|
||||
public bool TidyGenreList { get; set; }
|
||||
|
@ -26,6 +26,13 @@
|
||||
<option id="optLanguageJapaneseRomaji" value="JapaneseRomaji">Romaji</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="checkboxContainer checkboxContainer-withDescription">
|
||||
<label class="emby-checkbox-label">
|
||||
<input id="chkIgnoreSeason" name="chkIgnoreSeason" type="checkbox" is="emby-checkbox" />
|
||||
<span>Ignore Season</span>
|
||||
</label>
|
||||
<div class="fieldDescription">AniDB doesn't support seasons. If checked, it will treat every season like season one, except for specials.</div>
|
||||
</div>
|
||||
<div class="inputContainer">
|
||||
<label class="inputeLabel inputLabelUnfocused" for="chkTitleSimilarityThreshold">Title Similarity Threshold</label>
|
||||
<input id="chkTitleSimilarityThreshold" name="chkTitleSimilarityThreshold" type="number" is="emby-input" min="0" />
|
||||
@ -87,6 +94,7 @@
|
||||
document.getElementById('titleLanguage').value = config.TitlePreference;
|
||||
document.getElementById('originalTitleLanguage').value = config.OriginalTitlePreference;
|
||||
document.getElementById('chkTitleSimilarityThreshold').value = config.TitleSimilarityThreshold;
|
||||
document.getElementById('chkIgnoreSeason').checked = config.IgnoreSeason;
|
||||
document.getElementById('chkMaxGenres').value = config.MaxGenres;
|
||||
document.getElementById('chkTitleCaseGenres').checked = config.TitleCaseGenres;
|
||||
document.getElementById('chkTidyGenres').checked = config.TidyGenreList;
|
||||
@ -105,6 +113,7 @@
|
||||
config.TitlePreference = document.getElementById('titleLanguage').value;
|
||||
config.OriginalTitlePreference = document.getElementById('originalTitleLanguage').value;
|
||||
config.TitleSimilarityThreshold = document.getElementById('chkTitleSimilarityThreshold').value;
|
||||
config.IgnoreSeason = document.getElementById('chkIgnoreSeason').checked;
|
||||
config.MaxGenres = document.getElementById('chkMaxGenres').value;
|
||||
config.TitleCaseGenres = document.getElementById('chkTitleCaseGenres').checked;
|
||||
config.TidyGenreList = document.getElementById('chkTidyGenres').checked;
|
||||
|
@ -1,50 +0,0 @@
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Jellyfin.Plugin.AniDB.Providers.AniDB.Converter
|
||||
{
|
||||
public struct AniDbEpisodeIdentity
|
||||
{
|
||||
private static readonly Regex _regex = new Regex(@"(?<series>\d+):(?<type>[S])?(?<epno>\d+)(-(?<epnoend>\d+))?");
|
||||
|
||||
public AniDbEpisodeIdentity(string id)
|
||||
{
|
||||
this = Parse(id).Value;
|
||||
}
|
||||
|
||||
public AniDbEpisodeIdentity(string seriesId, int episodeNumber, int? episodeNumberEnd, string episodeType)
|
||||
{
|
||||
SeriesId = seriesId;
|
||||
EpisodeNumber = episodeNumber;
|
||||
EpisodeNumberEnd = episodeNumberEnd;
|
||||
EpisodeType = episodeType;
|
||||
}
|
||||
|
||||
public string SeriesId { get; private set; }
|
||||
public int EpisodeNumber { get; private set; }
|
||||
public int? EpisodeNumberEnd { get; private set; }
|
||||
public string EpisodeType { get; private set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("{0}:{1}{2}",
|
||||
SeriesId,
|
||||
EpisodeType ?? "",
|
||||
EpisodeNumber + (EpisodeNumberEnd != null ? "-" + EpisodeNumberEnd.Value.ToString() : ""));
|
||||
}
|
||||
|
||||
public static AniDbEpisodeIdentity? Parse(string id)
|
||||
{
|
||||
var match = _regex.Match(id);
|
||||
if (match.Success)
|
||||
{
|
||||
return new AniDbEpisodeIdentity(
|
||||
match.Groups["series"].Value,
|
||||
int.Parse(match.Groups["epno"].Value),
|
||||
match.Groups["epnoend"].Success ? int.Parse(match.Groups["epnoend"].Value) : (int?)null,
|
||||
match.Groups["type"].Success ? match.Groups["type"].Value : null);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,71 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Jellyfin.Plugin.AniDB.Providers.AniDB.Converter
|
||||
{
|
||||
public struct TvdbEpisodeIdentity
|
||||
{
|
||||
public TvdbEpisodeIdentity(string id)
|
||||
: this()
|
||||
{
|
||||
this = Parse(id).Value;
|
||||
}
|
||||
|
||||
public TvdbEpisodeIdentity(string seriesId, int? seasonIndex, int episodeNumber, int? episodeNumberEnd)
|
||||
: this()
|
||||
{
|
||||
SeriesId = seriesId;
|
||||
SeasonIndex = seasonIndex;
|
||||
EpisodeNumber = episodeNumber;
|
||||
EpisodeNumberEnd = episodeNumberEnd;
|
||||
}
|
||||
|
||||
public string SeriesId { get; private set; }
|
||||
public int? SeasonIndex { get; private set; }
|
||||
public int EpisodeNumber { get; private set; }
|
||||
public int? EpisodeNumberEnd { get; private set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("{0}:{1}:{2}",
|
||||
SeriesId,
|
||||
SeasonIndex != null ? SeasonIndex.Value.ToString() : "A",
|
||||
EpisodeNumber + (EpisodeNumberEnd != null ? "-" + EpisodeNumberEnd.Value.ToString() : ""));
|
||||
}
|
||||
|
||||
public static TvdbEpisodeIdentity? Parse(string id)
|
||||
{
|
||||
if (string.IsNullOrEmpty(id))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var parts = id.Split(':');
|
||||
var series = parts[0];
|
||||
var season = parts[1] != "A" ? (int?)int.Parse(parts[1]) : null;
|
||||
|
||||
int index;
|
||||
int? indexEnd;
|
||||
|
||||
var split = parts[2].IndexOf("-", StringComparison.OrdinalIgnoreCase);
|
||||
if (split != -1)
|
||||
{
|
||||
index = int.Parse(parts[2].Substring(0, split));
|
||||
indexEnd = int.Parse(parts[2].Substring(split + 1));
|
||||
}
|
||||
else
|
||||
{
|
||||
index = int.Parse(parts[2]);
|
||||
indexEnd = null;
|
||||
}
|
||||
|
||||
return new TvdbEpisodeIdentity(series, season, index, indexEnd);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -6,8 +6,6 @@ using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml;
|
||||
using Jellyfin.Plugin.AniDB.Providers.AniDB.Converter;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
@ -32,30 +30,38 @@ namespace Jellyfin.Plugin.AniDB.Providers.AniDB.Metadata
|
||||
_configurationManager = configurationManager;
|
||||
}
|
||||
|
||||
public string Name => "AniDB";
|
||||
|
||||
public async Task<MetadataResult<Episode>> GetMetadata(EpisodeInfo info, CancellationToken cancellationToken)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
var result = new MetadataResult<Episode>();
|
||||
|
||||
var aniDbId = info.ProviderIds.GetOrDefault(ProviderNames.AniDb);
|
||||
if (string.IsNullOrEmpty(aniDbId))
|
||||
var animeId = info.SeriesProviderIds.GetOrDefault(ProviderNames.AniDb);
|
||||
if (string.IsNullOrEmpty(animeId))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
var id = AniDbEpisodeIdentity.Parse(aniDbId);
|
||||
if (id == null)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
var seriesFolder = await FindSeriesFolder(id.Value.SeriesId, cancellationToken);
|
||||
var seriesFolder = await FindSeriesFolder(animeId, cancellationToken);
|
||||
if (string.IsNullOrEmpty(seriesFolder))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
var xml = GetEpisodeXmlFile(id.Value.EpisodeNumber, id.Value.EpisodeType, seriesFolder);
|
||||
if (!Plugin.Instance.Configuration.IgnoreSeason && info.ParentIndexNumber > 1)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
string episodeType = "";
|
||||
|
||||
if (info.ParentIndexNumber == 0)
|
||||
{
|
||||
episodeType = "S";
|
||||
}
|
||||
|
||||
var xml = GetEpisodeXmlFile(info.IndexNumber, episodeType, seriesFolder);
|
||||
if (xml == null || !xml.Exists)
|
||||
{
|
||||
return result;
|
||||
@ -71,71 +77,39 @@ namespace Jellyfin.Plugin.AniDB.Providers.AniDB.Metadata
|
||||
|
||||
await ParseEpisodeXml(xml, result.Item, info.MetadataLanguage).ConfigureAwait(false);
|
||||
|
||||
if (id.Value.EpisodeNumberEnd != null && id.Value.EpisodeNumberEnd > id.Value.EpisodeNumber)
|
||||
{
|
||||
for (var i = id.Value.EpisodeNumber + 1; i <= id.Value.EpisodeNumberEnd; i++)
|
||||
{
|
||||
var additionalXml = GetEpisodeXmlFile(i, id.Value.EpisodeType, seriesFolder);
|
||||
if (additionalXml == null || !additionalXml.Exists)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
await ParseAdditionalEpisodeXml(additionalXml, result.Item, info.MetadataLanguage).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public string Name => "AniDB";
|
||||
|
||||
public async Task<IEnumerable<RemoteSearchResult>> GetSearchResults(EpisodeInfo searchInfo, CancellationToken cancellationToken)
|
||||
{
|
||||
var list = new List<RemoteSearchResult>();
|
||||
|
||||
var id = AniDbEpisodeIdentity.Parse(searchInfo.ProviderIds.GetOrDefault(ProviderNames.AniDb));
|
||||
if (id == null)
|
||||
if (!searchInfo.IndexNumber.HasValue || !searchInfo.ParentIndexNumber.HasValue)
|
||||
{
|
||||
return list;
|
||||
return new List<RemoteSearchResult>();
|
||||
}
|
||||
|
||||
await AniDbSeriesProvider.GetSeriesData(
|
||||
_configurationManager.ApplicationPaths,
|
||||
id.Value.SeriesId,
|
||||
cancellationToken).ConfigureAwait(false);
|
||||
var metadataResult = await GetMetadata(searchInfo, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
try
|
||||
if (!metadataResult.HasMetadata)
|
||||
{
|
||||
var metadataResult = await GetMetadata(searchInfo, cancellationToken).ConfigureAwait(false);
|
||||
return new List<RemoteSearchResult>();
|
||||
}
|
||||
|
||||
if (metadataResult.HasMetadata)
|
||||
var item = metadataResult.Item;
|
||||
|
||||
return new[]
|
||||
{
|
||||
new RemoteSearchResult
|
||||
{
|
||||
var item = metadataResult.Item;
|
||||
|
||||
list.Add(new RemoteSearchResult
|
||||
{
|
||||
IndexNumber = item.IndexNumber,
|
||||
Name = item.Name,
|
||||
ParentIndexNumber = item.ParentIndexNumber,
|
||||
PremiereDate = item.PremiereDate,
|
||||
ProductionYear = item.ProductionYear,
|
||||
ProviderIds = item.ProviderIds,
|
||||
SearchProviderName = Name,
|
||||
IndexNumberEnd = item.IndexNumberEnd
|
||||
});
|
||||
IndexNumber = item.IndexNumber,
|
||||
Name = item.Name,
|
||||
ParentIndexNumber = item.ParentIndexNumber,
|
||||
PremiereDate = item.PremiereDate,
|
||||
ProductionYear = item.ProductionYear,
|
||||
ProviderIds = item.ProviderIds,
|
||||
SearchProviderName = Name,
|
||||
IndexNumberEnd = item.IndexNumberEnd
|
||||
}
|
||||
}
|
||||
catch (FileNotFoundException)
|
||||
{
|
||||
// Don't fail the provider because this will just keep on going and going.
|
||||
}
|
||||
catch (DirectoryNotFoundException)
|
||||
{
|
||||
// Don't fail the provider because this will just keep on going and going.
|
||||
}
|
||||
|
||||
return list;
|
||||
};
|
||||
}
|
||||
|
||||
public Task<HttpResponseMessage> GetImageResponse(string url, CancellationToken cancellationToken)
|
||||
@ -144,69 +118,6 @@ namespace Jellyfin.Plugin.AniDB.Providers.AniDB.Metadata
|
||||
return imageProvider.GetImageResponse(url, cancellationToken);
|
||||
}
|
||||
|
||||
private async Task ParseAdditionalEpisodeXml(FileInfo xml, Episode episode, string metadataLanguage)
|
||||
{
|
||||
var settings = new XmlReaderSettings
|
||||
{
|
||||
CheckCharacters = false,
|
||||
IgnoreProcessingInstructions = true,
|
||||
IgnoreComments = true,
|
||||
ValidationType = ValidationType.None
|
||||
};
|
||||
|
||||
using (var streamReader = xml.OpenText())
|
||||
using (var reader = XmlReader.Create(streamReader, settings))
|
||||
{
|
||||
await reader.MoveToContentAsync().ConfigureAwait(false);
|
||||
|
||||
var titles = new List<Title>();
|
||||
|
||||
while (await reader.ReadAsync().ConfigureAwait(false))
|
||||
{
|
||||
if (reader.NodeType == XmlNodeType.Element)
|
||||
{
|
||||
switch (reader.Name)
|
||||
{
|
||||
case "length":
|
||||
var length = await reader.ReadElementContentAsStringAsync().ConfigureAwait(false);
|
||||
if (!string.IsNullOrEmpty(length))
|
||||
{
|
||||
long duration;
|
||||
if (long.TryParse(length, out duration))
|
||||
{
|
||||
episode.RunTimeTicks += TimeSpan.FromMinutes(duration).Ticks;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case "title":
|
||||
var language = reader.GetAttribute("xml:lang");
|
||||
var name = await reader.ReadElementContentAsStringAsync().ConfigureAwait(false);
|
||||
|
||||
titles.Add(new Title
|
||||
{
|
||||
Language = language,
|
||||
Type = "main",
|
||||
Name = name
|
||||
});
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var title = titles.Localize(Plugin.Instance.Configuration.TitlePreference, metadataLanguage).Name;
|
||||
if (!string.IsNullOrEmpty(title))
|
||||
{
|
||||
title = ", " + title;
|
||||
episode.Name += Plugin.Instance.Configuration.AniDbReplaceGraves
|
||||
? title.Replace('`', '\'')
|
||||
: title;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<string> FindSeriesFolder(string seriesId, CancellationToken cancellationToken)
|
||||
{
|
||||
var seriesDataPath = await AniDbSeriesProvider.GetSeriesData(_configurationManager.ApplicationPaths, seriesId, cancellationToken).ConfigureAwait(false);
|
||||
@ -217,6 +128,7 @@ namespace Jellyfin.Plugin.AniDB.Providers.AniDB.Metadata
|
||||
{
|
||||
var settings = new XmlReaderSettings
|
||||
{
|
||||
Async = true,
|
||||
CheckCharacters = false,
|
||||
IgnoreProcessingInstructions = true,
|
||||
IgnoreComments = true,
|
||||
@ -284,12 +196,18 @@ namespace Jellyfin.Plugin.AniDB.Providers.AniDB.Metadata
|
||||
Name = name
|
||||
});
|
||||
|
||||
break;
|
||||
|
||||
case "summary":
|
||||
var overview = AniDbSeriesProvider.ReplaceNewLine(reader.ReadElementContentAsString());
|
||||
episode.Overview = Plugin.Instance.Configuration.AniDbReplaceGraves ? overview.Replace('`', '\'') : overview;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var title = titles.Localize(Plugin.Instance.Configuration.TitlePreference, preferredMetadataLanguage).Name;
|
||||
var title = titles.Localize(Configuration.TitlePreferenceType.Localized, preferredMetadataLanguage).Name;
|
||||
if (!string.IsNullOrEmpty(title))
|
||||
{
|
||||
episode.Name = Plugin.Instance.Configuration.AniDbReplaceGraves
|
||||
|
@ -202,6 +202,7 @@ namespace Jellyfin.Plugin.AniDB.Providers.AniDB.Metadata
|
||||
{
|
||||
date = date.ToUniversalTime();
|
||||
series.PremiereDate = date;
|
||||
series.ProductionYear = date.Year;
|
||||
}
|
||||
}
|
||||
|
||||
@ -250,9 +251,10 @@ namespace Jellyfin.Plugin.AniDB.Providers.AniDB.Metadata
|
||||
break;
|
||||
|
||||
case "description":
|
||||
series.Overview = ReplaceLineFeedWithNewLine(
|
||||
StripAniDbLinks(
|
||||
await reader.ReadElementContentAsStringAsync().ConfigureAwait(false)));
|
||||
var description = await reader.ReadElementContentAsStringAsync().ConfigureAwait(false);
|
||||
description = description.TrimStart('*').Trim();
|
||||
series.Overview = ReplaceNewLine(StripAniDbLinks(
|
||||
Plugin.Instance.Configuration.AniDbReplaceGraves ? description.Replace('`', '\'') : description));
|
||||
|
||||
break;
|
||||
|
||||
@ -408,9 +410,9 @@ namespace Jellyfin.Plugin.AniDB.Providers.AniDB.Metadata
|
||||
return AniDbUrlRegex.Replace(text, "${name}");
|
||||
}
|
||||
|
||||
public static string ReplaceLineFeedWithNewLine(string text)
|
||||
public static string ReplaceNewLine(string text)
|
||||
{
|
||||
return text.Replace("\n", Environment.NewLine);
|
||||
return text.Replace("\n", "<br>");
|
||||
}
|
||||
|
||||
private async Task ParseActors(MetadataResult<Series> series, XmlReader reader)
|
||||
@ -521,7 +523,8 @@ namespace Jellyfin.Plugin.AniDB.Providers.AniDB.Metadata
|
||||
}
|
||||
else
|
||||
{
|
||||
series.AddPerson(CreatePerson(name, type));
|
||||
series.AddPerson(CreatePerson(
|
||||
Plugin.Instance.Configuration.AniDbReplaceGraves ? name.Replace('`', '\'') : name, type));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user