mirror of
https://github.com/jellyfin/jellyfin-plugin-anisearch.git
synced 2024-11-23 13:59:43 +00:00
Merge pull request #3 from DaniGTA/master
Adding german metadata support
This commit is contained in:
commit
8cfe6d27a0
BIN
.vs/MediaBrowser.Plugins.Anime/v15/sqlite3/storage.ide
Normal file
BIN
.vs/MediaBrowser.Plugins.Anime/v15/sqlite3/storage.ide
Normal file
Binary file not shown.
@ -12,7 +12,7 @@ namespace MediaBrowser.Plugins.Anime
|
||||
private static readonly Task Completed = Task.FromResult(true);
|
||||
private readonly Queue<TaskCompletionSource<bool>> _waiters = new Queue<TaskCompletionSource<bool>>();
|
||||
private int _currentCount;
|
||||
|
||||
|
||||
public AsyncSemaphore(int initialCount)
|
||||
{
|
||||
if (initialCount < 0) throw new ArgumentOutOfRangeException("initialCount");
|
||||
@ -66,7 +66,7 @@ namespace MediaBrowser.Plugins.Anime
|
||||
Task wait = _semaphore.WaitAsync();
|
||||
return wait.IsCompleted
|
||||
? _releaser
|
||||
: wait.ContinueWith((_, state) => new Releaser((AsyncLock) state),
|
||||
: wait.ContinueWith((_, state) => new Releaser((AsyncLock)state),
|
||||
this, CancellationToken.None,
|
||||
TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
|
||||
}
|
||||
|
@ -1,7 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using MediaBrowser.Model.Plugins;
|
||||
using MediaBrowser.Model.Plugins;
|
||||
|
||||
namespace MediaBrowser.Plugins.Anime.Configuration
|
||||
{
|
||||
@ -21,6 +18,11 @@ namespace MediaBrowser.Plugins.Anime.Configuration
|
||||
/// Use titles in Japanese romaji.
|
||||
/// </summary>
|
||||
JapaneseRomaji,
|
||||
|
||||
/// <summary>
|
||||
/// Use titles in German.
|
||||
/// </summary>
|
||||
German,
|
||||
}
|
||||
|
||||
public class PluginConfiguration
|
||||
@ -32,6 +34,8 @@ namespace MediaBrowser.Plugins.Anime.Configuration
|
||||
public int MaxGenres { get; set; }
|
||||
public bool AddAnimeGenre { get; set; }
|
||||
public bool UseAnidbOrderingWithSeasons { get; set; }
|
||||
public string MyAnimeList_API_Name { get; set; }
|
||||
public string MyAnimeList_API_Pw { get; set; }
|
||||
|
||||
public PluginConfiguration()
|
||||
{
|
||||
@ -41,6 +45,8 @@ namespace MediaBrowser.Plugins.Anime.Configuration
|
||||
MaxGenres = 5;
|
||||
AddAnimeGenre = true;
|
||||
UseAnidbOrderingWithSeasons = false;
|
||||
MyAnimeList_API_Name = "";
|
||||
MyAnimeList_API_Pw = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -18,6 +18,7 @@
|
||||
<option id="optLanguageLocalized" value="Localized">Localized</option>
|
||||
<option id="optLanguageRomaji" value="JapaneseRomaji">Romaji</option>
|
||||
<option id="optLanguageJapanese" value="Japanese">Japanese</option>
|
||||
<option id="optLanguageGerman" value="German">German</option>
|
||||
</select>
|
||||
</li>
|
||||
<li>
|
||||
@ -36,13 +37,25 @@
|
||||
<label for="chkMaxGenres">
|
||||
Max Genres [0: unlimited]
|
||||
</label>
|
||||
<input id="chkMaxGenres" name="chkMaxGenres" type="number" min="0" value="maxGenres"/>
|
||||
<input id="chkMaxGenres" name="chkMaxGenres" type="number" min="0" value="maxGenres" />
|
||||
</li>
|
||||
<li>
|
||||
<label for="chkMyAnimeList_API_Name">
|
||||
MyAnimeList Name. -not rly needed
|
||||
</label>
|
||||
<input id="chkMyAnimeList_API_Name" name="chkMyAnimeList_API_Name" type="text" value="" disabled/>
|
||||
</li>
|
||||
<li>
|
||||
<label for="chkMyAnimeList_API_Pw">
|
||||
MyAnimeList Pw. -not rly needed
|
||||
</label>
|
||||
<input id="chkMyAnimeList_API_Pw" name="chkMyAnimeList_API_Pw" type="password" value="" disabled/>
|
||||
</li>
|
||||
<li>
|
||||
<label for="chkAnidbSeasonOne">
|
||||
Use AniDB Odering with Seasons
|
||||
</label>
|
||||
<input id="chkAnidbSeasonOne" name="chkAnidbSeasonOne" type="checkbox" value="anidbSeasonOne"/>
|
||||
<input id="chkAnidbSeasonOne" name="chkAnidbSeasonOne" type="checkbox" value="anidbSeasonOne" />
|
||||
</li>
|
||||
<li>
|
||||
<button type="submit" data-theme="b">Save</button>
|
||||
@ -52,12 +65,12 @@
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<script type="text/javascript">
|
||||
var AnimeConfigurationPage =
|
||||
{
|
||||
pluginUniqueId: "1d0dddf7-1877-4473-8d7b-03f7dac1e559",
|
||||
|
||||
|
||||
virtualFolders: [],
|
||||
physicalFolders: [],
|
||||
|
||||
@ -70,10 +83,12 @@
|
||||
$('#titleLanguage', page).val(config.TitlePreference).change();
|
||||
$('#chkAutomaticUpdates', page).checked(config.AllowAutomaticMetadataUpdates).checkboxradio("refresh");
|
||||
$('#chkTidyGenres', page).checked(config.TidyGenreList).checkboxradio("refresh");
|
||||
$('#chkMyAnimeList_API_Name', page, val(config.MyAnimeList_API_Name)).change();
|
||||
$('#chkMyAnimeList_API_Pw', page, val(config.MyAnimeList_API_Pw)).change();
|
||||
$('#chkMaxGenres', page).val(config.MaxGenres).change();
|
||||
$('#chkMoveExcessGenresToTags', page).checked(config.MoveExcessGenresToTags).checkboxradio("refresh");
|
||||
$('#chkAnidbSeasonOne', page).checked(config.UseAnidbOrderingWithSeasons).checkboxradio("refresh");
|
||||
|
||||
|
||||
Dashboard.hideLoadingMsg();
|
||||
});
|
||||
},
|
||||
@ -89,9 +104,12 @@
|
||||
config.AllowAutomaticMetadataUpdates = $('#chkAutomaticUpdates', page).prop('checked');
|
||||
config.TidyGenreList = $('#chkTidyGenres').prop('checked');
|
||||
config.MaxGenres = $('#chkMaxGenres').val();
|
||||
config.MaxGenres = $('#chkNames').val();
|
||||
config.MyAnimeList_API_Name = $('#chkMyAnimeList_API_Name').val();
|
||||
config.MyAnimeList_API_Pw= $('#chkMyAnimeList_API_Pw').val();
|
||||
config.MoveExcessGenresToTags = $('#chkMoveExcessGenresToTags').prop('checked');
|
||||
config.UseAnidbOrderingWithSeasons = $('#chkAnidbSeasonOne').prop('checked');
|
||||
|
||||
|
||||
ApiClient.updatePluginConfiguration(AnimeConfigurationPage.pluginUniqueId, config).then(function (result) {
|
||||
Dashboard.processPluginConfigurationUpdateResult(result);
|
||||
});
|
||||
|
@ -13,4 +13,4 @@ namespace MediaBrowser.Plugins.Anime
|
||||
return default(T);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -6,6 +6,10 @@
|
||||
<FileVersion>1.2.1.1</FileVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|netstandard2.0|AnyCPU'">
|
||||
<OutputPath>bin\</OutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="Configuration\configPage.html" />
|
||||
</ItemGroup>
|
||||
|
@ -1,13 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Common.Plugins;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using MediaBrowser.Model.Plugins;
|
||||
using MediaBrowser.Model.Serialization;
|
||||
using MediaBrowser.Plugins.Anime.Configuration;
|
||||
using MediaBrowser.Plugins.Anime.Providers.AniDB.Converter;
|
||||
using MediaBrowser.Plugins.Anime.Providers.AniDB.Identity;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace MediaBrowser.Plugins.Anime
|
||||
{
|
||||
@ -41,9 +40,10 @@ namespace MediaBrowser.Plugins.Anime
|
||||
}
|
||||
|
||||
private Guid _id = new Guid("1d0dddf7-1877-4473-8d7b-03f7dac1e559");
|
||||
|
||||
public override Guid Id
|
||||
{
|
||||
get { return _id; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,9 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using AnimeLists;
|
||||
using AnimeLists;
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using System.IO;
|
||||
|
||||
namespace MediaBrowser.Plugins.Anime.Providers.AniDB.Converter
|
||||
{
|
||||
@ -23,4 +20,4 @@ namespace MediaBrowser.Plugins.Anime.Providers.AniDB.Converter
|
||||
Mapper = new Mapper(animelist);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,8 +1,3 @@
|
||||
using System.Threading.Tasks;
|
||||
using AnimeLists;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Plugins.Anime.Configuration;
|
||||
|
||||
namespace MediaBrowser.Plugins.Anime.Providers.AniDB.Converter
|
||||
{
|
||||
//public class AnidbTvdbEpisodeConverter : IItemIdentityConverter<EpisodeInfo>
|
||||
@ -29,7 +24,7 @@ namespace MediaBrowser.Plugins.Anime.Providers.AniDB.Converter
|
||||
// }
|
||||
// }
|
||||
|
||||
// var overrideTvdb = string.IsNullOrEmpty(tvdb)
|
||||
// var overrideTvdb = string.IsNullOrEmpty(tvdb)
|
||||
// || info.ParentIndexNumber == null
|
||||
// || (info.ParentIndexNumber < 2 && Plugin.Instance.Configuration.UseAnidbOrderingWithSeasons);
|
||||
|
||||
|
@ -1,7 +1,3 @@
|
||||
using System.Threading.Tasks;
|
||||
using AnimeLists;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
|
||||
namespace MediaBrowser.Plugins.Anime.Providers.AniDB.Converter
|
||||
{
|
||||
//public class AnidbTvdbSeasonConverter : IItemIdentityConverter<SeasonInfo>
|
||||
@ -39,7 +35,7 @@ namespace MediaBrowser.Plugins.Anime.Providers.AniDB.Converter
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
// return false;
|
||||
// }
|
||||
|
||||
|
@ -1,12 +1,12 @@
|
||||
using System;
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using MediaBrowser.Plugins.Anime.Providers.AniDB.Metadata;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Net;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using MediaBrowser.Plugins.Anime.Providers.AniDB.Metadata;
|
||||
|
||||
namespace MediaBrowser.Plugins.Anime.Providers.AniDB.Identity
|
||||
{
|
||||
@ -22,11 +22,13 @@ namespace MediaBrowser.Plugins.Anime.Providers.AniDB.Identity
|
||||
|
||||
private readonly IApplicationPaths _paths;
|
||||
private readonly ILogger _logger;
|
||||
public static string s_paths;
|
||||
|
||||
public AniDbTitleDownloader(ILogger logger, IApplicationPaths paths)
|
||||
{
|
||||
_logger = logger;
|
||||
_paths = paths;
|
||||
s_paths = GetDataPath(paths);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -39,6 +41,23 @@ namespace MediaBrowser.Plugins.Anime.Providers.AniDB.Identity
|
||||
return Path.Combine(applicationPaths.CachePath, "anidb");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Load XML static| Too prevent EXCEPTIONS
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
public static async Task Load_static(CancellationToken cancellationToken)
|
||||
{
|
||||
var titlesFile = TitlesFilePath_;
|
||||
var titlesFileInfo = new FileInfo(titlesFile);
|
||||
|
||||
// download titles if we do not already have them, or have not updated for a week
|
||||
if (!titlesFileInfo.Exists || (DateTime.UtcNow - titlesFileInfo.LastWriteTimeUtc).TotalDays > 7)
|
||||
{
|
||||
await DownloadTitles_static(titlesFile).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task Load(CancellationToken cancellationToken)
|
||||
{
|
||||
var titlesFile = TitlesFilePath;
|
||||
@ -72,14 +91,46 @@ namespace MediaBrowser.Plugins.Anime.Providers.AniDB.Identity
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// static|Downloads an xml file from AniDB which contains all of the titles for every anime, and their IDs,
|
||||
/// and saves it to disk.
|
||||
/// </summary>
|
||||
/// <param name="titlesFile"></param>
|
||||
/// <returns></returns>
|
||||
private static async Task DownloadTitles_static(string titlesFile)
|
||||
{
|
||||
var client = new WebClient();
|
||||
|
||||
await AniDbSeriesProvider.RequestLimiter.Tick();
|
||||
|
||||
using (var stream = await client.OpenReadTaskAsync(TitlesUrl))
|
||||
using (var unzipped = new GZipStream(stream, CompressionMode.Decompress))
|
||||
using (var writer = File.Open(titlesFile, FileMode.Create, FileAccess.Write))
|
||||
{
|
||||
await unzipped.CopyToAsync(writer).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
public string TitlesFilePath
|
||||
{
|
||||
get
|
||||
{
|
||||
var data = GetDataPath(_paths);
|
||||
Directory.CreateDirectory(data);
|
||||
Directory.CreateDirectory(s_paths);
|
||||
|
||||
return Path.Combine(data, "titles.xml");
|
||||
return Path.Combine(s_paths, "titles.xml");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the FilePath
|
||||
/// </summary>
|
||||
public static string TitlesFilePath_
|
||||
{
|
||||
get
|
||||
{
|
||||
Directory.CreateDirectory(s_paths);
|
||||
|
||||
return Path.Combine(s_paths, "titles.xml");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
@ -6,7 +7,6 @@ using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml;
|
||||
using MediaBrowser.Model.Logging;
|
||||
|
||||
namespace MediaBrowser.Plugins.Anime.Providers.AniDB.Identity
|
||||
{
|
||||
@ -16,7 +16,7 @@ namespace MediaBrowser.Plugins.Anime.Providers.AniDB.Identity
|
||||
/// </summary>
|
||||
public class AniDbTitleMatcher : IAniDbTitleMatcher
|
||||
{
|
||||
private enum TitleType
|
||||
public enum TitleType
|
||||
{
|
||||
Main = 0,
|
||||
Official = 1,
|
||||
@ -24,9 +24,10 @@ namespace MediaBrowser.Plugins.Anime.Providers.AniDB.Identity
|
||||
Synonym = 3
|
||||
}
|
||||
|
||||
private struct TitleInfo
|
||||
public struct TitleInfo
|
||||
{
|
||||
public string AniDbId { get; set; }
|
||||
public string Title { get; set; }
|
||||
public TitleType Type { get; set; }
|
||||
}
|
||||
|
||||
@ -35,13 +36,13 @@ namespace MediaBrowser.Plugins.Anime.Providers.AniDB.Identity
|
||||
/// Gets or sets the global <see cref="IAniDbTitleMatcher"/> instance.
|
||||
/// </summary>
|
||||
public static IAniDbTitleMatcher DefaultInstance { get; set; }
|
||||
|
||||
|
||||
private readonly ILogger _logger;
|
||||
private readonly IAniDbTitleDownloader _downloader;
|
||||
public readonly IAniDbTitleDownloader _downloader;
|
||||
private readonly AsyncLock _lock;
|
||||
|
||||
private Dictionary<string, TitleInfo> _titles;
|
||||
|
||||
public static Dictionary<string, TitleInfo> _titles;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the AniDbTitleMatcher class.
|
||||
/// </summary>
|
||||
@ -58,7 +59,7 @@ namespace MediaBrowser.Plugins.Anime.Providers.AniDB.Identity
|
||||
{
|
||||
return FindSeries(title, CancellationToken.None);
|
||||
}
|
||||
|
||||
|
||||
public async Task<string> FindSeries(string title, CancellationToken cancellationToken)
|
||||
{
|
||||
using (await _lock.LockAsync())
|
||||
@ -75,7 +76,7 @@ namespace MediaBrowser.Plugins.Anime.Providers.AniDB.Identity
|
||||
private string LookupAniDbId(string title)
|
||||
{
|
||||
TitleInfo info;
|
||||
if (_titles.TryGetValue(title, out info))
|
||||
if (_titles.TryGetValue(title, out info))
|
||||
{
|
||||
return info.AniDbId;
|
||||
}
|
||||
@ -83,8 +84,21 @@ namespace MediaBrowser.Plugins.Anime.Providers.AniDB.Identity
|
||||
return null;
|
||||
}
|
||||
|
||||
const string Remove = "\"'!`?";
|
||||
const string Spacers = "/,.:;\\(){}[]+-_=–*"; // (there are not actually two - in the they are different char codes)
|
||||
public static TitleInfo GetTitleInfos(string title)
|
||||
{
|
||||
TitleInfo info;
|
||||
if (!string.IsNullOrEmpty(title))
|
||||
{
|
||||
if (_titles.TryGetValue(title, out info))
|
||||
{
|
||||
return info;
|
||||
}
|
||||
}
|
||||
return new TitleInfo();
|
||||
}
|
||||
|
||||
private const string Remove = "\"'!`?";
|
||||
private const string Spacers = "/,.:;\\(){}[]+-_=–*"; // (there are not actually two - in the they are different char codes)
|
||||
|
||||
internal static string GetComparableName(string name)
|
||||
{
|
||||
@ -95,7 +109,7 @@ namespace MediaBrowser.Plugins.Anime.Providers.AniDB.Identity
|
||||
{
|
||||
if (c >= 0x2B0 && c <= 0x0333)
|
||||
{
|
||||
// skip char modifier and diacritics
|
||||
// skip char modifier and diacritics
|
||||
}
|
||||
else if (Remove.IndexOf(c) > -1)
|
||||
{
|
||||
@ -133,7 +147,7 @@ namespace MediaBrowser.Plugins.Anime.Providers.AniDB.Identity
|
||||
{
|
||||
get { return _titles != null; }
|
||||
}
|
||||
|
||||
|
||||
private async Task Load(CancellationToken cancellationToken)
|
||||
{
|
||||
if (_titles == null)
|
||||
@ -155,7 +169,7 @@ namespace MediaBrowser.Plugins.Anime.Providers.AniDB.Identity
|
||||
_logger.ErrorException("Failed to load AniDB titles", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private Task ReadTitlesFile()
|
||||
{
|
||||
return Task.Run(() =>
|
||||
@ -187,16 +201,18 @@ namespace MediaBrowser.Plugins.Anime.Providers.AniDB.Identity
|
||||
reader.MoveToAttribute("aid");
|
||||
aid = reader.Value;
|
||||
break;
|
||||
|
||||
case "title":
|
||||
var title = reader.ReadElementContentAsString();
|
||||
if (!string.IsNullOrEmpty(aid) && !string.IsNullOrEmpty(title))
|
||||
if (!string.IsNullOrEmpty(aid) && !string.IsNullOrEmpty(title))
|
||||
{
|
||||
var type = ParseType(reader.GetAttribute("type"));
|
||||
|
||||
TitleInfo currentTitleInfo;
|
||||
|
||||
if (!_titles.TryGetValue(title, out currentTitleInfo) || (int)currentTitleInfo.Type < (int)type)
|
||||
{
|
||||
_titles[title] = new TitleInfo {AniDbId = aid, Type = type};
|
||||
_titles[title] = new TitleInfo { AniDbId = aid, Type = type, Title = title };
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -208,7 +224,7 @@ namespace MediaBrowser.Plugins.Anime.Providers.AniDB.Identity
|
||||
var comparable = (from pair in _titles
|
||||
let comp = GetComparableName(pair.Key)
|
||||
where !_titles.ContainsKey(comp)
|
||||
select new {Title = comp, Id = pair.Value})
|
||||
select new { Title = comp, Id = pair.Value })
|
||||
.ToArray();
|
||||
|
||||
foreach (var pair in comparable)
|
||||
@ -220,13 +236,17 @@ namespace MediaBrowser.Plugins.Anime.Providers.AniDB.Identity
|
||||
|
||||
private TitleType ParseType(string type)
|
||||
{
|
||||
switch (type) {
|
||||
switch (type)
|
||||
{
|
||||
case "main":
|
||||
return TitleType.Main;
|
||||
|
||||
case "official":
|
||||
return TitleType.Official;
|
||||
|
||||
case "short":
|
||||
return TitleType.Short;
|
||||
|
||||
case "syn":
|
||||
return TitleType.Synonym;
|
||||
}
|
||||
|
@ -1,8 +1,3 @@
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Plugins.Anime.Configuration;
|
||||
using MediaBrowser.Plugins.Anime.Providers.AniDB.Converter;
|
||||
|
||||
namespace MediaBrowser.Plugins.Anime.Providers.AniDB.Identity
|
||||
{
|
||||
//public class AnidbEpisodeIdentityProvider : IItemIdentityProvider<EpisodeInfo>
|
||||
|
@ -1,8 +1,4 @@
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
|
||||
namespace MediaBrowser.Plugins.Anime.Providers.AniDB.Identity
|
||||
namespace MediaBrowser.Plugins.Anime.Providers.AniDB.Identity
|
||||
{
|
||||
//public class AnidbSeriesIdentityProvider : IItemIdentityProvider<SeriesInfo>
|
||||
//{
|
||||
@ -19,4 +15,4 @@ namespace MediaBrowser.Plugins.Anime.Providers.AniDB.Identity
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
}
|
||||
}
|
@ -1,18 +1,16 @@
|
||||
using System;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Providers;
|
||||
using MediaBrowser.Plugins.Anime.Providers.AniDB.Converter;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Providers;
|
||||
using MediaBrowser.Plugins.Anime.Configuration;
|
||||
using MediaBrowser.Plugins.Anime.Providers.AniDB.Converter;
|
||||
using MediaBrowser.Plugins.Anime.Providers.AniDB.Identity;
|
||||
|
||||
namespace MediaBrowser.Plugins.Anime.Providers.AniDB.Metadata
|
||||
{
|
||||
@ -177,6 +175,7 @@ namespace MediaBrowser.Plugins.Anime.Providers.AniDB.Metadata
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case "title":
|
||||
var language = reader.GetAttribute("xml:lang");
|
||||
var name = reader.ReadElementContentAsString();
|
||||
@ -238,6 +237,7 @@ namespace MediaBrowser.Plugins.Anime.Providers.AniDB.Metadata
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case "airdate":
|
||||
var airdate = reader.ReadElementContentAsString();
|
||||
if (!string.IsNullOrEmpty(airdate))
|
||||
@ -248,6 +248,7 @@ namespace MediaBrowser.Plugins.Anime.Providers.AniDB.Metadata
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case "rating":
|
||||
int count;
|
||||
float rating;
|
||||
@ -258,6 +259,7 @@ namespace MediaBrowser.Plugins.Anime.Providers.AniDB.Metadata
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case "title":
|
||||
var language = reader.GetAttribute("xml:lang");
|
||||
var name = reader.ReadElementContentAsString();
|
||||
|
@ -18,4 +18,4 @@ namespace MediaBrowser.Plugins.Anime.Providers.AniDB.Metadata
|
||||
Cast = new List<AniDbPersonInfo>();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,14 +1,14 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Providers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Plugins.Anime.Providers.AniDB.Metadata
|
||||
{
|
||||
|
@ -1,14 +1,14 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Providers;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Plugins.Anime.Providers.AniDB.Metadata
|
||||
{
|
||||
@ -33,7 +33,7 @@ namespace MediaBrowser.Plugins.Anime.Providers.AniDB.Metadata
|
||||
|
||||
public async Task<IEnumerable<RemoteImageInfo>> GetImages(IHasMetadata item, CancellationToken cancellationToken)
|
||||
{
|
||||
var season = (Season) item;
|
||||
var season = (Season)item;
|
||||
var series = season.Series;
|
||||
|
||||
var seriesId = series.ProviderIds.GetOrDefault(ProviderNames.AniDb);
|
||||
@ -45,7 +45,7 @@ namespace MediaBrowser.Plugins.Anime.Providers.AniDB.Metadata
|
||||
|
||||
public IEnumerable<ImageType> GetSupportedImages(IHasMetadata item)
|
||||
{
|
||||
return new[] {ImageType.Primary};
|
||||
return new[] { ImageType.Primary };
|
||||
}
|
||||
|
||||
public string Name => "AniDB";
|
||||
|
@ -1,12 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Providers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Plugins.Anime.Providers.AniDB.Metadata
|
||||
{
|
||||
|
@ -1,16 +1,16 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml;
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Providers;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml;
|
||||
|
||||
namespace MediaBrowser.Plugins.Anime.Providers.AniDB.Metadata
|
||||
{
|
||||
@ -34,7 +34,6 @@ namespace MediaBrowser.Plugins.Anime.Providers.AniDB.Metadata
|
||||
CancellationToken = cancellationToken,
|
||||
Url = url,
|
||||
ResourcePool = AniDbSeriesProvider.ResourcePool
|
||||
|
||||
}).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,13 @@
|
||||
using System;
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Providers;
|
||||
using MediaBrowser.Plugins.Anime.Configuration;
|
||||
using MediaBrowser.Plugins.Anime.Providers.AniDB.Identity;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
@ -11,15 +20,6 @@ using System.Threading.Tasks;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
using System.Xml.Serialization;
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Providers;
|
||||
using MediaBrowser.Plugins.Anime.Configuration;
|
||||
using MediaBrowser.Plugins.Anime.Providers.AniDB.Identity;
|
||||
|
||||
namespace MediaBrowser.Plugins.Anime.Providers.AniDB.Metadata
|
||||
{
|
||||
@ -28,10 +28,12 @@ namespace MediaBrowser.Plugins.Anime.Providers.AniDB.Metadata
|
||||
private const string SeriesDataFile = "series.xml";
|
||||
private const string SeriesQueryUrl = "http://api.anidb.net:9001/httpapi?request=anime&client={0}&clientver=1&protover=1&aid={1}";
|
||||
private const string ClientName = "mediabrowser";
|
||||
|
||||
// AniDB has very low request rate limits, a minimum of 2 seconds between requests, and an average of 4 seconds between requests
|
||||
public static readonly SemaphoreSlim ResourcePool = new SemaphoreSlim(1, 1);
|
||||
|
||||
public static readonly RateLimiter RequestLimiter = new RateLimiter(TimeSpan.FromSeconds(3), TimeSpan.FromSeconds(5), TimeSpan.FromMinutes(5));
|
||||
private static readonly int[] IgnoredCategoryIds = {6, 22, 23, 60, 128, 129, 185, 216, 242, 255, 268, 269, 289};
|
||||
private static readonly int[] IgnoredCategoryIds = { 6, 22, 23, 60, 128, 129, 185, 216, 242, 255, 268, 269, 289 };
|
||||
private static readonly Regex AniDbUrlRegex = new Regex(@"http://anidb.net/\w+ \[(?<name>[^\]]*)\]");
|
||||
private readonly IApplicationPaths _appPaths;
|
||||
private readonly IHttpClient _httpClient;
|
||||
@ -62,8 +64,11 @@ namespace MediaBrowser.Plugins.Anime.Providers.AniDB.Metadata
|
||||
var result = new MetadataResult<Series>();
|
||||
|
||||
var aid = info.ProviderIds.GetOrDefault(ProviderNames.AniDb);
|
||||
if (string.IsNullOrEmpty(aid))
|
||||
aid = await TitleMatcher.FindSeries(info.Name, cancellationToken).ConfigureAwait(false);
|
||||
if (string.IsNullOrEmpty(aid) && !string.IsNullOrEmpty(info.Name))
|
||||
{
|
||||
aid = Equals_check.Fast_xml_search(info.Name, info.Name, true);
|
||||
aid = Equals_check.Fast_xml_search(Equals_check.clear_name(info.Name), Equals_check.clear_name(info.Name), true);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(aid))
|
||||
{
|
||||
@ -106,7 +111,12 @@ namespace MediaBrowser.Plugins.Anime.Providers.AniDB.Metadata
|
||||
|
||||
public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
return _httpClient.GetResponse(new HttpRequestOptions
|
||||
{
|
||||
CancellationToken = cancellationToken,
|
||||
Url = url,
|
||||
ResourcePool = ResourcePool
|
||||
});
|
||||
}
|
||||
|
||||
public static async Task<string> GetSeriesData(IApplicationPaths appPaths, IHttpClient httpClient, string seriesId, CancellationToken cancellationToken)
|
||||
@ -120,7 +130,7 @@ namespace MediaBrowser.Plugins.Anime.Providers.AniDB.Metadata
|
||||
{
|
||||
await DownloadSeriesData(seriesId, seriesDataPath, appPaths.CachePath, httpClient, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
|
||||
return seriesDataPath;
|
||||
}
|
||||
|
||||
@ -165,6 +175,7 @@ namespace MediaBrowser.Plugins.Anime.Providers.AniDB.Metadata
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case "enddate":
|
||||
var endDate = reader.ReadElementContentAsString();
|
||||
|
||||
@ -179,6 +190,7 @@ namespace MediaBrowser.Plugins.Anime.Providers.AniDB.Metadata
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case "titles":
|
||||
using (var subtree = reader.ReadSubtree())
|
||||
{
|
||||
@ -190,6 +202,7 @@ namespace MediaBrowser.Plugins.Anime.Providers.AniDB.Metadata
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case "creators":
|
||||
using (var subtree = reader.ReadSubtree())
|
||||
{
|
||||
@ -197,10 +210,12 @@ namespace MediaBrowser.Plugins.Anime.Providers.AniDB.Metadata
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case "description":
|
||||
series.Overview = ReplaceLineFeedWithNewLine(StripAniDbLinks(reader.ReadElementContentAsString()));
|
||||
|
||||
break;
|
||||
|
||||
case "ratings":
|
||||
using (var subtree = reader.ReadSubtree())
|
||||
{
|
||||
@ -208,6 +223,7 @@ namespace MediaBrowser.Plugins.Anime.Providers.AniDB.Metadata
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case "resources":
|
||||
using (var subtree = reader.ReadSubtree())
|
||||
{
|
||||
@ -215,6 +231,7 @@ namespace MediaBrowser.Plugins.Anime.Providers.AniDB.Metadata
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case "characters":
|
||||
using (var subtree = reader.ReadSubtree())
|
||||
{
|
||||
@ -222,12 +239,14 @@ namespace MediaBrowser.Plugins.Anime.Providers.AniDB.Metadata
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case "tags":
|
||||
using (var subtree = reader.ReadSubtree())
|
||||
{
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case "categories":
|
||||
using (var subtree = reader.ReadSubtree())
|
||||
{
|
||||
@ -235,6 +254,7 @@ namespace MediaBrowser.Plugins.Anime.Providers.AniDB.Metadata
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case "episodes":
|
||||
using (var subtree = reader.ReadSubtree())
|
||||
{
|
||||
@ -311,7 +331,7 @@ namespace MediaBrowser.Plugins.Anime.Providers.AniDB.Metadata
|
||||
if (categorySubtree.NodeType == XmlNodeType.Element && categorySubtree.Name == "name")
|
||||
{
|
||||
var name = categorySubtree.ReadElementContentAsString();
|
||||
genres.Add(new GenreInfo {Name = name, Weight = weight});
|
||||
genres.Add(new GenreInfo { Name = name, Weight = weight });
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -351,10 +371,11 @@ namespace MediaBrowser.Plugins.Anime.Providers.AniDB.Metadata
|
||||
{
|
||||
var firstId = ids.OrderBy(i => i).First().ToString(CultureInfo.InvariantCulture);
|
||||
series.ProviderIds.Add(ProviderNames.MyAnimeList, firstId);
|
||||
// series.ProviderIds.Add(ProviderNames.AniList, firstId);
|
||||
// series.ProviderIds.Add(ProviderNames.AniList, firstId);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case "4":
|
||||
while (reader.Read())
|
||||
{
|
||||
@ -412,6 +433,7 @@ namespace MediaBrowser.Plugins.Anime.Providers.AniDB.Metadata
|
||||
case "name":
|
||||
role = reader.ReadElementContentAsString();
|
||||
break;
|
||||
|
||||
case "seiyuu":
|
||||
name = reader.ReadElementContentAsString();
|
||||
break;
|
||||
@ -440,7 +462,7 @@ namespace MediaBrowser.Plugins.Anime.Providers.AniDB.Metadata
|
||||
CultureInfo.InvariantCulture,
|
||||
out rating))
|
||||
{
|
||||
series.CommunityRating = (float) Math.Round(rating, 1);
|
||||
series.CommunityRating = (float)Math.Round(rating, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -637,7 +659,7 @@ namespace MediaBrowser.Plugins.Anime.Providers.AniDB.Metadata
|
||||
}
|
||||
}
|
||||
|
||||
var serializer = new XmlSerializer(typeof (AniDbPersonInfo));
|
||||
var serializer = new XmlSerializer(typeof(AniDbPersonInfo));
|
||||
foreach (var person in cast)
|
||||
{
|
||||
var path = GetCastPath(person.Name, cachePath);
|
||||
|
@ -1,16 +1,18 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using MediaBrowser.Model.Serialization;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Plugins.Anime.Providers.AniList
|
||||
{
|
||||
public class AniListApiClient
|
||||
{
|
||||
public static readonly SemaphoreSlim ResourcePool = new SemaphoreSlim(1, 1);
|
||||
|
||||
public class AccessToken
|
||||
{
|
||||
public string access_token { get; set; }
|
||||
@ -56,18 +58,21 @@ namespace MediaBrowser.Plugins.Anime.Providers.AniList
|
||||
|
||||
try
|
||||
{
|
||||
var json = "";
|
||||
string urlWithToken = url;
|
||||
if (url.Contains("?"))
|
||||
urlWithToken += $"&access_token={_accessToken}";
|
||||
else
|
||||
urlWithToken += $"?access_token={_accessToken}";
|
||||
|
||||
using (var stream = await _http.Get(urlWithToken, CancellationToken.None).ConfigureAwait(false))
|
||||
using (var reader = new StreamReader(stream))
|
||||
var _webRequest = WebRequest.Create(@"" + Uri.EscapeUriString(urlWithToken));
|
||||
using (var _response = _webRequest.GetResponse())
|
||||
using (var _content = _response.GetResponseStream())
|
||||
using (var _reader = new StreamReader(_content))
|
||||
{
|
||||
var json = reader.ReadToEnd().Trim();
|
||||
return _jsonSerializer.DeserializeFromString<T>(json);
|
||||
json = _reader.ReadToEnd().Trim();
|
||||
}
|
||||
return _jsonSerializer.DeserializeFromString<T>(json);
|
||||
}
|
||||
catch
|
||||
{
|
||||
@ -102,4 +107,4 @@ namespace MediaBrowser.Plugins.Anime.Providers.AniList
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,13 +1,4 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using MediaBrowser.Model.Serialization;
|
||||
using MediaBrowser.Plugins.Anime.Providers.AniDB.Identity;
|
||||
|
||||
namespace MediaBrowser.Plugins.Anime.Providers.AniList
|
||||
namespace MediaBrowser.Plugins.Anime.Providers.AniList
|
||||
{
|
||||
//public class AniListSeriesIdentityProvider : IItemIdentityProvider<SeriesInfo>
|
||||
//{
|
||||
@ -38,7 +29,7 @@ namespace MediaBrowser.Plugins.Anime.Providers.AniList
|
||||
|
||||
// if (first == null)
|
||||
// return;
|
||||
|
||||
|
||||
// info.ProviderIds.Remove(ProviderNames.AniList);
|
||||
// info.ProviderIds.Add(ProviderNames.AniList, first.id.ToString());
|
||||
// }
|
||||
|
@ -1,11 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
@ -16,7 +9,12 @@ using MediaBrowser.Model.Providers;
|
||||
using MediaBrowser.Model.Serialization;
|
||||
using MediaBrowser.Plugins.Anime.Configuration;
|
||||
using MediaBrowser.Plugins.Anime.Providers.AniDB.Identity;
|
||||
using MediaBrowser.Plugins.Anime.Providers.AniDB.Metadata;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Plugins.Anime.Providers.AniList
|
||||
{
|
||||
@ -24,14 +22,18 @@ namespace MediaBrowser.Plugins.Anime.Providers.AniList
|
||||
{
|
||||
private readonly IApplicationPaths _paths;
|
||||
private readonly AniListApiClient _api;
|
||||
|
||||
private readonly IHttpClient _httpClient;
|
||||
private readonly ILogger _log;
|
||||
public static readonly SemaphoreSlim ResourcePool = new SemaphoreSlim(1, 1);
|
||||
public int Order => -2;
|
||||
public string Name => "AniList";
|
||||
|
||||
public AniListSeriesProvider(IHttpClient http, IApplicationPaths paths, ILogManager logManager, IJsonSerializer jsonSerializer)
|
||||
{
|
||||
_httpClient = http;
|
||||
_paths = paths;
|
||||
_api = new AniListApiClient(http, logManager, jsonSerializer);
|
||||
_log = logManager.GetLogger("AniList");
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<RemoteSearchResult>> GetSearchResults(SeriesInfo searchInfo, CancellationToken cancellationToken)
|
||||
@ -93,8 +95,59 @@ namespace MediaBrowser.Plugins.Anime.Providers.AniList
|
||||
var result = new MetadataResult<Series>();
|
||||
|
||||
var aid = info.ProviderIds.GetOrDefault(ProviderNames.AniList);
|
||||
if (string.IsNullOrEmpty(aid))
|
||||
return result;
|
||||
if (string.IsNullOrEmpty(aid) && !string.IsNullOrEmpty(info.Name))
|
||||
{
|
||||
var search = await _api.Search(info.Name);
|
||||
foreach (var a in search)
|
||||
{
|
||||
if (string.IsNullOrEmpty(aid))
|
||||
{
|
||||
if (Equals_check.Compare_strings(a.title_english, info.Name))
|
||||
aid = a.id.ToString();
|
||||
|
||||
if (Equals_check.Compare_strings(a.title_japanese, info.Name))
|
||||
aid = a.id.ToString();
|
||||
|
||||
if (Equals_check.Compare_strings(a.title_romaji, info.Name))
|
||||
aid = a.id.ToString();
|
||||
_log.Log(LogSeverity.Info, a.title_romaji + "vs" + info.Name);
|
||||
}
|
||||
}
|
||||
if (string.IsNullOrEmpty(aid))
|
||||
{
|
||||
var cleaned = AniDbTitleMatcher.GetComparableName(Equals_check.clear_name(info.Name));
|
||||
if (String.Compare(cleaned, info.Name, StringComparison.OrdinalIgnoreCase) != 0)
|
||||
{
|
||||
search = await _api.Search(cleaned);
|
||||
foreach (var b in search)
|
||||
{
|
||||
if (Equals_check.Compare_strings(b.title_english, info.Name))
|
||||
aid = b.id.ToString();
|
||||
|
||||
if (Equals_check.Compare_strings(b.title_japanese, info.Name))
|
||||
aid = b.id.ToString();
|
||||
|
||||
if (Equals_check.Compare_strings(b.title_romaji, info.Name))
|
||||
aid = b.id.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (string.IsNullOrEmpty(aid))
|
||||
{
|
||||
search = await _api.Search(Equals_check.clear_name(info.Name));
|
||||
foreach (var b in search)
|
||||
{
|
||||
if (Equals_check.Compare_strings(b.title_english, info.Name))
|
||||
aid = b.id.ToString();
|
||||
|
||||
if (Equals_check.Compare_strings(b.title_japanese, info.Name))
|
||||
aid = b.id.ToString();
|
||||
|
||||
if (Equals_check.Compare_strings(b.title_romaji, info.Name))
|
||||
aid = b.id.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(aid))
|
||||
{
|
||||
@ -119,9 +172,10 @@ namespace MediaBrowser.Plugins.Anime.Providers.AniList
|
||||
if (anime.genres != null)
|
||||
{
|
||||
foreach (var genre in anime.genres)
|
||||
|
||||
if(!string.IsNullOrEmpty(genre))
|
||||
result.Item.AddGenre(genre);
|
||||
|
||||
|
||||
GenreHelper.CleanupGenres(result.Item);
|
||||
}
|
||||
|
||||
@ -130,6 +184,14 @@ namespace MediaBrowser.Plugins.Anime.Providers.AniList
|
||||
|
||||
if (!string.IsNullOrEmpty(anime.image_url_banner))
|
||||
StoreImageUrl(aid, anime.image_url_banner, "banner");
|
||||
|
||||
if (string.IsNullOrEmpty(result.Item.Name))
|
||||
{
|
||||
if (!string.IsNullOrEmpty(anime.title_romaji))
|
||||
{
|
||||
result.Item.Name = anime.title_romaji;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
@ -155,88 +217,92 @@ namespace MediaBrowser.Plugins.Anime.Providers.AniList
|
||||
File.WriteAllText(path, url);
|
||||
}
|
||||
|
||||
public static string GetSeriesImage(IApplicationPaths paths, string series, string type)
|
||||
public static async Task<string> GetSeriesImage(IApplicationPaths paths, string series, string type)
|
||||
{
|
||||
var path = Path.Combine(paths.CachePath, "anilist", type, series + ".txt");
|
||||
if (File.Exists(path))
|
||||
return File.ReadAllText(path);
|
||||
return await Task.Run(() => File.ReadAllText(path));
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public class AniListSeriesImageProvider : IRemoteImageProvider
|
||||
{
|
||||
private readonly IHttpClient _httpClient;
|
||||
private readonly IApplicationPaths _appPaths;
|
||||
|
||||
public AniListSeriesImageProvider(IHttpClient httpClient, IApplicationPaths appPaths)
|
||||
{
|
||||
_httpClient = httpClient;
|
||||
_appPaths = appPaths;
|
||||
}
|
||||
|
||||
public string Name => "AniList";
|
||||
|
||||
public bool Supports(IHasMetadata item) => item is Series || item is Season;
|
||||
|
||||
public IEnumerable<ImageType> GetSupportedImages(IHasMetadata item)
|
||||
{
|
||||
return new[] {ImageType.Primary, ImageType.Banner};
|
||||
}
|
||||
|
||||
public Task<IEnumerable<RemoteImageInfo>> GetImages(IHasMetadata item, CancellationToken cancellationToken)
|
||||
{
|
||||
var seriesId = item.GetProviderId(ProviderNames.AniList);
|
||||
return GetImages(seriesId, cancellationToken);
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<RemoteImageInfo>> GetImages(string aid, CancellationToken cancellationToken)
|
||||
{
|
||||
var list = new List<RemoteImageInfo>();
|
||||
|
||||
if (!string.IsNullOrEmpty(aid))
|
||||
{
|
||||
var primary = AniListSeriesProvider.GetSeriesImage(_appPaths, aid, "image");
|
||||
if (!string.IsNullOrEmpty(primary))
|
||||
{
|
||||
list.Add(new RemoteImageInfo
|
||||
{
|
||||
ProviderName = Name,
|
||||
Type = ImageType.Primary,
|
||||
Url = primary
|
||||
});
|
||||
}
|
||||
|
||||
var banner = AniListSeriesProvider.GetSeriesImage(_appPaths, aid, "banner");
|
||||
if (!string.IsNullOrEmpty(banner))
|
||||
{
|
||||
list.Add(new RemoteImageInfo
|
||||
{
|
||||
ProviderName = Name,
|
||||
Type = ImageType.Banner,
|
||||
Url = banner
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken)
|
||||
{
|
||||
return _httpClient.GetResponse(new HttpRequestOptions
|
||||
{
|
||||
CancellationToken = cancellationToken,
|
||||
Url = url,
|
||||
ResourcePool = AniDbSeriesProvider.ResourcePool
|
||||
|
||||
ResourcePool = ResourcePool
|
||||
});
|
||||
}
|
||||
|
||||
public class AniListSeriesImageProvider : IRemoteImageProvider
|
||||
{
|
||||
private readonly IHttpClient _httpClient;
|
||||
private readonly IApplicationPaths _appPaths;
|
||||
|
||||
public AniListSeriesImageProvider(IHttpClient httpClient, IApplicationPaths appPaths)
|
||||
{
|
||||
_httpClient = httpClient;
|
||||
_appPaths = appPaths;
|
||||
}
|
||||
|
||||
public string Name => "AniList";
|
||||
|
||||
public bool Supports(IHasMetadata item) => item is Series || item is Season;
|
||||
|
||||
public IEnumerable<ImageType> GetSupportedImages(IHasMetadata item)
|
||||
{
|
||||
return new[] { ImageType.Primary, ImageType.Banner };
|
||||
}
|
||||
|
||||
public Task<IEnumerable<RemoteImageInfo>> GetImages(IHasMetadata item, CancellationToken cancellationToken)
|
||||
{
|
||||
var seriesId = item.GetProviderId(ProviderNames.AniList);
|
||||
return GetImages(seriesId, cancellationToken);
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<RemoteImageInfo>> GetImages(string aid, CancellationToken cancellationToken)
|
||||
{
|
||||
var list = new List<RemoteImageInfo>();
|
||||
|
||||
if (!string.IsNullOrEmpty(aid))
|
||||
{
|
||||
var primary = await GetSeriesImage(_appPaths, aid, "image");
|
||||
if (!string.IsNullOrEmpty(primary))
|
||||
{
|
||||
list.Add(new RemoteImageInfo
|
||||
{
|
||||
ProviderName = Name,
|
||||
Type = ImageType.Primary,
|
||||
Url = primary
|
||||
});
|
||||
}
|
||||
|
||||
var banner = await GetSeriesImage(_appPaths, aid, "banner");
|
||||
if (!string.IsNullOrEmpty(banner))
|
||||
{
|
||||
list.Add(new RemoteImageInfo
|
||||
{
|
||||
ProviderName = Name,
|
||||
Type = ImageType.Banner,
|
||||
Url = banner
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken)
|
||||
{
|
||||
return _httpClient.GetResponse(new HttpRequestOptions
|
||||
{
|
||||
CancellationToken = cancellationToken,
|
||||
Url = url,
|
||||
ResourcePool = ResourcePool
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace MediaBrowser.Plugins.Anime.Providers.AniList
|
||||
{
|
||||
|
@ -0,0 +1,134 @@
|
||||
/*using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Providers;
|
||||
using MediaBrowser.Plugins.Anime.Providers.AniDB.Converter;
|
||||
|
||||
namespace MediaBrowser.Plugins.Anime.Providers.AniSearch
|
||||
{
|
||||
/// <summary>
|
||||
/// The <see cref="AniSearchEpisodeProvider" /> class provides episode metadata from AniSearch.
|
||||
/// </summary>
|
||||
public class AniSearchEpisodeProvider : IRemoteMetadataProvider<Episode, EpisodeInfo>
|
||||
{
|
||||
private readonly IServerConfigurationManager _configurationManager;
|
||||
private readonly IHttpClient _httpClient;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the <see cref="AniDbEpisodeProvider" /> class.
|
||||
/// </summary>
|
||||
/// <param name="configurationManager">The configuration manager.</param>
|
||||
/// <param name="httpClient">The HTTP client.</param>
|
||||
public AniSearchEpisodeProvider(IServerConfigurationManager configurationManager, IHttpClient httpClient)
|
||||
{
|
||||
_configurationManager = configurationManager;
|
||||
_httpClient = httpClient;
|
||||
}
|
||||
|
||||
public async Task<MetadataResult<Episode>> GetMetadata(EpisodeInfo info, CancellationToken cancellationToken)
|
||||
{
|
||||
var result = new MetadataResult<Episode>();
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
var anisearchId = info.ProviderIds.GetOrDefault(ProviderNames.AniSearch);
|
||||
if (string.IsNullOrEmpty(anisearchId))
|
||||
return result;
|
||||
|
||||
var id = AnidbEpisodeIdentity.Parse(anisearchId);
|
||||
if (id == null)
|
||||
return result;
|
||||
|
||||
result.Item = new Episode
|
||||
{
|
||||
IndexNumber = info.IndexNumber,
|
||||
ParentIndexNumber = info.ParentIndexNumber
|
||||
};
|
||||
string url= "https://www.anisearch.de/anime/"+id+"/episodes";
|
||||
string web_content = await api.WebRequestAPI(url);
|
||||
result.HasMetadata = true;
|
||||
|
||||
if (id.Value.EpisodeNumberEnd != null && id.Value.EpisodeNumberEnd > id.Value.EpisodeNumber)
|
||||
{
|
||||
for (var i = id.Value.EpisodeNumber + 1; i <= id.Value.EpisodeNumberEnd; i++)
|
||||
{
|
||||
string episode = await api.One_line_regex(new System.Text.RegularExpressions.Regex("<span itemprop=\"name\" lang=\"de\" class=\"bold\">" + @"(.*?)<"), web_content, 1, i);
|
||||
if(episode == "")
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public string Name => "AniSearch";
|
||||
|
||||
public async Task<IEnumerable<RemoteSearchResult>> GetSearchResults(EpisodeInfo searchInfo, CancellationToken cancellationToken)
|
||||
{
|
||||
var list = new List<RemoteSearchResult>();
|
||||
|
||||
var id = AnidbEpisodeIdentity.Parse(searchInfo.ProviderIds.GetOrDefault(ProviderNames.AniSearch));
|
||||
if (id == null)
|
||||
{
|
||||
//var episodeIdentifier = new AnidbEpisodeIdentityProvider();
|
||||
//await episodeIdentifier.Identify(searchInfo);
|
||||
|
||||
//var converter = new AnidbTvdbEpisodeConverter();
|
||||
//await converter.Convert(searchInfo);
|
||||
|
||||
//id = AnidbEpisodeIdentity.Parse(searchInfo.ProviderIds.GetOrDefault(ProviderNames.AniDb));
|
||||
}
|
||||
|
||||
if (id == null)
|
||||
return list;
|
||||
|
||||
try
|
||||
{
|
||||
var metadataResult = await GetMetadata(searchInfo, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
if (metadataResult.HasMetadata)
|
||||
{
|
||||
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
|
||||
});
|
||||
}
|
||||
}
|
||||
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<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
@ -0,0 +1,29 @@
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Entities;
|
||||
|
||||
namespace MediaBrowser.Plugins.Anime.Providers.AniSearch
|
||||
{
|
||||
public class AniSearchExternalId : IExternalId
|
||||
{
|
||||
public bool Supports(IHasProviderIds item)
|
||||
{
|
||||
return item is Series;
|
||||
}
|
||||
|
||||
public string Name
|
||||
{
|
||||
get { return "AniSearch"; }
|
||||
}
|
||||
|
||||
public string Key
|
||||
{
|
||||
get { return ProviderNames.AniSearch; }
|
||||
}
|
||||
|
||||
public string UrlFormatString
|
||||
{
|
||||
get { return "http://www.anisearch.de/anime/{0}"; }
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,162 @@
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using MediaBrowser.Model.Providers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Plugins.Anime.Providers.AniSearch
|
||||
{
|
||||
public class AniSearchSeriesProvider : IRemoteMetadataProvider<Series, SeriesInfo>, IHasOrder
|
||||
{
|
||||
private readonly IHttpClient _httpClient;
|
||||
private readonly IApplicationPaths _paths;
|
||||
private readonly ILogger _log;
|
||||
public int Order => -3;
|
||||
public string Name => "AniSearch";
|
||||
public static readonly SemaphoreSlim ResourcePool = new SemaphoreSlim(1, 1);
|
||||
|
||||
public AniSearchSeriesProvider(IApplicationPaths appPaths, IHttpClient httpClient, ILogManager logManager)
|
||||
{
|
||||
_log = logManager.GetLogger("AniSearch");
|
||||
_httpClient = httpClient;
|
||||
_paths = appPaths;
|
||||
}
|
||||
|
||||
public async Task<MetadataResult<Series>> GetMetadata(SeriesInfo info, CancellationToken cancellationToken)
|
||||
{
|
||||
var result = new MetadataResult<Series>();
|
||||
|
||||
var aid = info.ProviderIds.GetOrDefault(ProviderNames.AniSearch);
|
||||
if (string.IsNullOrEmpty(aid))
|
||||
{
|
||||
_log.Info("Start AniSearch... Searching(" + info.Name + ")");
|
||||
aid = await api.FindSeries(info.Name, cancellationToken);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(aid))
|
||||
{
|
||||
string WebContent = await api.WebRequestAPI(api.AniSearch_anime_link + aid);
|
||||
result.Item = new Series();
|
||||
result.HasMetadata = true;
|
||||
|
||||
result.Item.ProviderIds.Add(ProviderNames.AniSearch, aid);
|
||||
result.Item.Overview = await api.Get_Overview(WebContent);
|
||||
try
|
||||
{
|
||||
//AniSearch has a max rating of 5
|
||||
result.Item.CommunityRating = (float.Parse(await api.Get_Rating(WebContent), System.Globalization.CultureInfo.InvariantCulture) * 2);
|
||||
}
|
||||
catch (Exception) { }
|
||||
foreach (var genre in await api.Get_Genre(WebContent))
|
||||
result.Item.AddGenre(genre);
|
||||
GenreHelper.CleanupGenres(result.Item);
|
||||
StoreImageUrl(aid, await api.Get_ImageUrl(WebContent), "image");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<RemoteSearchResult>> GetSearchResults(SeriesInfo searchInfo, CancellationToken cancellationToken)
|
||||
{
|
||||
var results = new Dictionary<string, RemoteSearchResult>();
|
||||
|
||||
var aid = searchInfo.ProviderIds.GetOrDefault(ProviderNames.AniSearch);
|
||||
if (!string.IsNullOrEmpty(aid))
|
||||
{
|
||||
if (!results.ContainsKey(aid))
|
||||
results.Add(aid, await api.GetAnime(aid));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(searchInfo.Name))
|
||||
{
|
||||
List<string> ids = await api.Search_GetSeries_list(searchInfo.Name, cancellationToken);
|
||||
foreach (string a in ids)
|
||||
{
|
||||
results.Add(a, await api.GetAnime(a));
|
||||
}
|
||||
}
|
||||
|
||||
return results.Values;
|
||||
}
|
||||
|
||||
private void StoreImageUrl(string series, string url, string type)
|
||||
{
|
||||
var path = Path.Combine(_paths.CachePath, "anisearch", type, series + ".txt");
|
||||
var directory = Path.GetDirectoryName(path);
|
||||
Directory.CreateDirectory(directory);
|
||||
|
||||
File.WriteAllText(path, url);
|
||||
}
|
||||
|
||||
public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken)
|
||||
{
|
||||
return _httpClient.GetResponse(new HttpRequestOptions
|
||||
{
|
||||
CancellationToken = cancellationToken,
|
||||
Url = url,
|
||||
ResourcePool = ResourcePool
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public class AniSearchSeriesImageProvider : IRemoteImageProvider
|
||||
{
|
||||
private readonly IHttpClient _httpClient;
|
||||
private readonly IApplicationPaths _appPaths;
|
||||
|
||||
public AniSearchSeriesImageProvider(IHttpClient httpClient, IApplicationPaths appPaths)
|
||||
{
|
||||
_httpClient = httpClient;
|
||||
_appPaths = appPaths;
|
||||
}
|
||||
|
||||
public string Name => "AniSearch";
|
||||
|
||||
public bool Supports(IHasMetadata item) => item is Series || item is Season;
|
||||
|
||||
public IEnumerable<ImageType> GetSupportedImages(IHasMetadata item)
|
||||
{
|
||||
return new[] { ImageType.Primary };
|
||||
}
|
||||
|
||||
public Task<IEnumerable<RemoteImageInfo>> GetImages(IHasMetadata item, CancellationToken cancellationToken)
|
||||
{
|
||||
var seriesId = item.GetProviderId(ProviderNames.AniSearch);
|
||||
return GetImages(seriesId, cancellationToken);
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<RemoteImageInfo>> GetImages(string aid, CancellationToken cancellationToken)
|
||||
{
|
||||
var list = new List<RemoteImageInfo>();
|
||||
|
||||
if (!string.IsNullOrEmpty(aid))
|
||||
{
|
||||
var primary = await api.Get_ImageUrl(await api.WebRequestAPI(api.AniSearch_anime_link + aid));
|
||||
list.Add(new RemoteImageInfo
|
||||
{
|
||||
ProviderName = Name,
|
||||
Type = ImageType.Primary,
|
||||
Url = primary
|
||||
});
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken)
|
||||
{
|
||||
return _httpClient.GetResponse(new HttpRequestOptions
|
||||
{
|
||||
CancellationToken = cancellationToken,
|
||||
Url = url,
|
||||
ResourcePool = AniSearchSeriesProvider.ResourcePool
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
306
MediaBrowser.Plugins.Anime/Providers/AniSearch/api.cs
Normal file
306
MediaBrowser.Plugins.Anime/Providers/AniSearch/api.cs
Normal file
@ -0,0 +1,306 @@
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Providers;
|
||||
using MediaBrowser.Plugins.Anime.Configuration;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Plugins.Anime.Providers.AniSearch
|
||||
{
|
||||
/// <summary>
|
||||
/// API for http://anisearch.de a german anime database
|
||||
/// 🛈 Anisearch does not have an API interface to work with
|
||||
/// </summary>
|
||||
internal class api
|
||||
{
|
||||
public static List<string> anime_search_names = new List<string>();
|
||||
public static List<string> anime_search_ids = new List<string>();
|
||||
public static string SearchLink = "https://www.anisearch.de/anime/index/?char=all&page=1&text={0}&smode=2&sort=title&order=asc&view=2&title=de,en,fr,it,pl,ru,es,tr&titlex=1,2&hentai=yes";
|
||||
public static string AniSearch_anime_link = "https://www.anisearch.de/anime/";
|
||||
|
||||
/// <summary>
|
||||
/// API call to get the anime with the id
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
public static async Task<RemoteSearchResult> GetAnime(string id)
|
||||
{
|
||||
string WebContent = await WebRequestAPI(AniSearch_anime_link + id);
|
||||
var result = new RemoteSearchResult
|
||||
{
|
||||
Name = await SelectName(WebContent, Plugin.Instance.Configuration.TitlePreference, "en")
|
||||
};
|
||||
|
||||
result.SearchProviderName = await One_line_regex(new Regex("\"" + "Japanisch" + "\"" + @"> <strong>(.*?)<\/"), WebContent);
|
||||
result.ImageUrl = await Get_ImageUrl(WebContent);
|
||||
result.SetProviderId(ProviderNames.AniSearch, id);
|
||||
result.Overview = await Get_Overview(WebContent);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// API call to select the lang
|
||||
/// </summary>
|
||||
/// <param name="WebContent"></param>
|
||||
/// <param name="preference"></param>
|
||||
/// <param name="language"></param>
|
||||
/// <returns></returns>
|
||||
private static async Task<string> SelectName(string WebContent, TitlePreferenceType preference, string language)
|
||||
{
|
||||
if (preference == TitlePreferenceType.Localized && language == "en")
|
||||
return await Get_title("en", WebContent);
|
||||
if (preference == TitlePreferenceType.Localized && language == "de")
|
||||
return await Get_title("de", WebContent);
|
||||
if (preference == TitlePreferenceType.Localized && language == "ger")
|
||||
return await Get_title("de", WebContent);
|
||||
if (preference == TitlePreferenceType.Japanese)
|
||||
return await Get_title("jap", WebContent);
|
||||
|
||||
return await Get_title("jap_r", WebContent);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// API call to get the title with the right lang
|
||||
/// </summary>
|
||||
/// <param name="lang"></param>
|
||||
/// <param name="WebContent"></param>
|
||||
/// <returns></returns>
|
||||
public static async Task<string> Get_title(string lang, string WebContent)
|
||||
{
|
||||
switch (lang)
|
||||
{
|
||||
case "en":
|
||||
return await One_line_regex(new Regex("\"" + "Englisch" + "\"" + @"> <strong>(.*?)<\/"), WebContent);
|
||||
|
||||
case "de":
|
||||
return await One_line_regex(new Regex("\"" + "Deutsch" + "\"" + @"> <strong>(.*?)<\/"), WebContent);
|
||||
|
||||
case "jap":
|
||||
return await One_line_regex(new Regex("<div class=\"grey\">" + @"(.*?)<\/"), await One_line_regex(new Regex("\"" + "Englisch" + "\"" + @"> <strong>(.*?)<\/div"), WebContent));
|
||||
|
||||
//Default is jap_r
|
||||
default:
|
||||
return await One_line_regex(new Regex("\"" + "Japanisch" + "\"" + @"> <strong>(.*?)<\/"), WebContent);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// API call to get the genre of the anime
|
||||
/// </summary>
|
||||
/// <param name="WebContent"></param>
|
||||
/// <returns></returns>
|
||||
public static async Task<List<string>> Get_Genre(string WebContent)
|
||||
{
|
||||
List<string> result = new List<string>();
|
||||
string Genres = await One_line_regex(new Regex("<ul class=\"cloud\">" + @"(.*?)<\/ul>"), WebContent);
|
||||
int x = 0;
|
||||
string AniSearch_Genre = null;
|
||||
while (AniSearch_Genre != "")
|
||||
{
|
||||
AniSearch_Genre = await One_line_regex(new Regex(@"<li>(.*?)<\/li>"), Genres, 0, x);
|
||||
AniSearch_Genre = await One_line_regex(new Regex("\">" + @"(.*?)<\/a>"), AniSearch_Genre);
|
||||
if (AniSearch_Genre != "")
|
||||
{
|
||||
result.Add(AniSearch_Genre);
|
||||
}
|
||||
x++;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// API call to get the img url
|
||||
/// </summary>
|
||||
/// <param name="WebContent"></param>
|
||||
/// <returns></returns>
|
||||
public static async Task<string> Get_ImageUrl(string WebContent)
|
||||
{
|
||||
return await One_line_regex(new Regex("<img itemprop=\"image\" src=\"" + @"(.*?)" + "\""), WebContent);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// API call too get the rating
|
||||
/// </summary>
|
||||
/// <param name="WebContent"></param>
|
||||
/// <returns></returns>
|
||||
public static async Task<string> Get_Rating(string WebContent)
|
||||
{
|
||||
return await One_line_regex(new Regex("<span itemprop=\"ratingValue\">" + @"(.*?)" + @"<\/span>"), WebContent);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// API call to get the description
|
||||
/// </summary>
|
||||
/// <param name="WebContent"></param>
|
||||
/// <returns></returns>
|
||||
public static async Task<string> Get_Overview(string WebContent)
|
||||
{
|
||||
return Regex.Replace(await One_line_regex(new Regex("<span itemprop=\"description\" lang=\"de\" id=\"desc-de\" class=\"desc-zz textblock\">" + @"(.*?)<\/span>"), WebContent), "<.*?>", String.Empty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// API call to search a title and return the right one back
|
||||
/// </summary>
|
||||
/// <param name="title"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
public static async Task<string> Search_GetSeries(string title, CancellationToken cancellationToken)
|
||||
{
|
||||
anime_search_names.Clear();
|
||||
anime_search_ids.Clear();
|
||||
string result = null;
|
||||
string result_text = null;
|
||||
string WebContent = await WebRequestAPI(string.Format(SearchLink, title));
|
||||
int x = 0;
|
||||
while (result_text != "")
|
||||
{
|
||||
result_text = await One_line_regex(new Regex("<th scope=\"row\" class=\"showpop\" data-width=\"200\"" + @".*?>(.*)<\/th>"), WebContent, 1, x);
|
||||
if (result_text != "")
|
||||
{
|
||||
//get id
|
||||
int _x = 0;
|
||||
string a_name = null;
|
||||
while (a_name != "")
|
||||
{
|
||||
try
|
||||
{
|
||||
string id = await One_line_regex(new Regex(@"anime\/(.*?),"), result_text);
|
||||
a_name = Regex.Replace(await One_line_regex(new Regex(@"((<a|<d).*?>)(.*?)(<\/a>|<\/div>)"), result_text, 3, _x), "<.*?>", String.Empty);
|
||||
if (a_name != "")
|
||||
{
|
||||
if (await Task.Run(() => Equals_check.Compare_strings(a_name, title)))
|
||||
{
|
||||
return id;
|
||||
}
|
||||
int n;
|
||||
if (Int32.TryParse(id, out n))
|
||||
{
|
||||
anime_search_names.Add(a_name);
|
||||
anime_search_ids.Add(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception) { }
|
||||
|
||||
_x++;
|
||||
}
|
||||
}
|
||||
x++;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// API call to search a title and return a list back
|
||||
/// </summary>
|
||||
/// <param name="title"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
public static async Task<List<string>> Search_GetSeries_list(string title, CancellationToken cancellationToken)
|
||||
{
|
||||
List<string> result = new List<string>();
|
||||
string result_text = null;
|
||||
string WebContent = await WebRequestAPI(string.Format(SearchLink, title));
|
||||
int x = 0;
|
||||
while (result_text != "")
|
||||
{
|
||||
result_text = await One_line_regex(new Regex("<th scope=\"row\" class=\"showpop\" data-width=\"200\"" + @".*?>(.*)<\/th>"), WebContent, 1, x);
|
||||
if (result_text != "")
|
||||
{
|
||||
//get id
|
||||
int _x = 0;
|
||||
string a_name = null;
|
||||
while (a_name != "")
|
||||
{
|
||||
string id = await One_line_regex(new Regex(@"anime\/(.*?),"), result_text);
|
||||
a_name = Regex.Replace(await One_line_regex(new Regex(@"((<a|<d).*?>)(.*?)(<\/a>|<\/div>)"), result_text, 3, _x), "<.*?>", String.Empty);
|
||||
if (a_name != "")
|
||||
{
|
||||
if (Equals_check.Compare_strings(a_name, title))
|
||||
{
|
||||
result.Add(id);
|
||||
return result;
|
||||
}
|
||||
int n;
|
||||
if (Int32.TryParse(id, out n))
|
||||
{
|
||||
result.Add(id);
|
||||
}
|
||||
}
|
||||
_x++;
|
||||
}
|
||||
}
|
||||
x++;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// SEARCH Title
|
||||
/// </summary>
|
||||
public static async Task<string> FindSeries(string title, CancellationToken cancellationToken)
|
||||
{
|
||||
string aid = await Search_GetSeries(title, cancellationToken);
|
||||
if (!string.IsNullOrEmpty(aid))
|
||||
{
|
||||
return aid;
|
||||
}
|
||||
else
|
||||
{
|
||||
int x = 0;
|
||||
|
||||
foreach (string a_name in anime_search_names)
|
||||
{
|
||||
if (Equals_check.Compare_strings(a_name, title))
|
||||
{
|
||||
return anime_search_ids[x];
|
||||
}
|
||||
x++;
|
||||
}
|
||||
}
|
||||
aid = await Search_GetSeries(Equals_check.clear_name(title), cancellationToken);
|
||||
if (!string.IsNullOrEmpty(aid))
|
||||
{
|
||||
return aid;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Simple regex
|
||||
/// </summary>
|
||||
public static async Task<string> One_line_regex(Regex regex, string match, int group = 1, int match_int = 0)
|
||||
{
|
||||
Regex _regex = regex;
|
||||
int x = 0;
|
||||
MatchCollection matches = await Task.Run(() => regex.Matches(match));
|
||||
foreach (Match _match in matches)
|
||||
{
|
||||
if (x == match_int)
|
||||
{
|
||||
return await Task.Run(() => _match.Groups[group].Value.ToString());
|
||||
}
|
||||
x++;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// GET website content from the link
|
||||
/// </summary>
|
||||
public static async Task<string> WebRequestAPI(string link)
|
||||
{
|
||||
string _strContent = "";
|
||||
using (WebClient client = new WebClient())
|
||||
{
|
||||
Task<string> async_content = client.DownloadStringTaskAsync(link);
|
||||
_strContent = await async_content;
|
||||
}
|
||||
return _strContent;
|
||||
}
|
||||
}
|
||||
}
|
@ -33,7 +33,7 @@
|
||||
// public async Task Run(Series series, CancellationToken cancellationToken)
|
||||
// {
|
||||
// await RemoveObsoleteSeasons(series).ConfigureAwait(false);
|
||||
//
|
||||
//
|
||||
// var hasNewSeasons = await AddDummySeasonFolders(series, cancellationToken).ConfigureAwait(false);
|
||||
//
|
||||
// if (hasNewSeasons)
|
||||
@ -115,7 +115,7 @@
|
||||
// };
|
||||
//
|
||||
// season.SetParent(series);
|
||||
//
|
||||
//
|
||||
// await series.AddChild(season, cancellationToken).ConfigureAwait(false);
|
||||
//
|
||||
// await season.RefreshMetadata(new MetadataRefreshOptions(), cancellationToken).ConfigureAwait(false);
|
||||
@ -179,4 +179,4 @@
|
||||
// return hasChanges;
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
//}
|
@ -1,8 +1,8 @@
|
||||
using System;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Plugins.Anime.Configuration;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Plugins.Anime.Configuration;
|
||||
|
||||
namespace MediaBrowser.Plugins.Anime.Providers
|
||||
{
|
||||
@ -49,19 +49,159 @@ namespace MediaBrowser.Plugins.Anime.Providers
|
||||
{"Vampire", "Supernatural"},
|
||||
{"Yaoi", "Adult"},
|
||||
{"Yuri", "Adult"},
|
||||
{"Zombie", "Supernatural"}
|
||||
{"Zombie", "Supernatural"},
|
||||
//AniSearch Genre
|
||||
{"Geistergeschichten", "Geistergeschichten"},
|
||||
{"Romanze", "Romance"},
|
||||
{"Alltagsdrama", "Slice of Life"},
|
||||
{"Alltagsleben", "Slice of Life"},
|
||||
{"Psychodrama", "Psycho"},
|
||||
{"Actiondrama", "Action"},
|
||||
{"Nonsense-Komödie", "Comedy"},
|
||||
{"Magie", "Fantasy"},
|
||||
{"Abenteuer", "Adventure"},
|
||||
{"Komödie", "Comedy"},
|
||||
{"Erotik", "Adult"},
|
||||
{"Historisch", "Period & Historical"},
|
||||
//Proxer
|
||||
{"Slice_of_Life", "Slice of Life"},
|
||||
};
|
||||
|
||||
private static readonly string[] GenresAsTags =
|
||||
{
|
||||
"Hentai",
|
||||
"Space",
|
||||
"Vampire",
|
||||
"Weltraum",
|
||||
"Yaoi",
|
||||
"Yuri",
|
||||
"Zombie",
|
||||
"Demons",
|
||||
"Witch"
|
||||
"Witch",
|
||||
//AniSearchTags
|
||||
"Krieg",
|
||||
"Militär",
|
||||
"Satire",
|
||||
"Übermäßige Gewaltdarstellung",
|
||||
"Monster",
|
||||
"Zeitgenössische Fantasy",
|
||||
"Dialogwitz",
|
||||
"Romantische Komödie",
|
||||
"Slapstick",
|
||||
"Alternative Welt",
|
||||
"4-panel",
|
||||
"CG-Anime",
|
||||
"Episodisch",
|
||||
"Moe",
|
||||
"Parodie",
|
||||
"Splatter",
|
||||
"Tragödie",
|
||||
"Verworrene Handlung",
|
||||
//Themen
|
||||
"Erwachsenwerden",
|
||||
"Gender Bender",
|
||||
"Ältere Frau, jüngerer Mann",
|
||||
"Älterer Mann, jüngere Frau",
|
||||
//Schule (School)
|
||||
"Grundschule",
|
||||
"Kindergarten",
|
||||
"Klubs",
|
||||
"Mittelschule",
|
||||
"Oberschule",
|
||||
"Schule",
|
||||
"Universität",
|
||||
//Zeit (Time)
|
||||
"Altes Asien",
|
||||
"Frühe Neuzeit",
|
||||
"Gegenwart",
|
||||
"industrialisierung",
|
||||
"Meiji-Ära",
|
||||
"Mittelalter",
|
||||
"Weltkriege",
|
||||
//Fantasy
|
||||
"Dunkle Fantasy",
|
||||
"Epische Fantasy",
|
||||
"Zeitgenössische Fantasy",
|
||||
//Ort
|
||||
"Alternative Welt",
|
||||
"In einem Raumschiff",
|
||||
"Weltraum",
|
||||
//Setting
|
||||
"Cyberpunk",
|
||||
"Endzeit",
|
||||
"Space Opera",
|
||||
//Hauptfigur
|
||||
"Charakterschache Heldin",
|
||||
"Charakterschacher Held",
|
||||
"Charakterstarke Heldin",
|
||||
"Charakterstarker Held",
|
||||
"Gedächtnisverlust",
|
||||
"Stoische Heldin",
|
||||
"Stoischer Held",
|
||||
"Widerwillige Heldin",
|
||||
"Widerwilliger Held",
|
||||
//Figuren
|
||||
"Diva",
|
||||
"Genie",
|
||||
"Schul-Delinquent",
|
||||
"Tomboy",
|
||||
"Tsundere",
|
||||
"Yandere",
|
||||
//Kampf (fight)
|
||||
"Bionische Kräfte",
|
||||
"Martial Arts",
|
||||
"PSI-Kräfte",
|
||||
"Real Robots",
|
||||
"Super Robots",
|
||||
"Schusswaffen",
|
||||
"Schwerter & co",
|
||||
//Sports (Sport)
|
||||
"Baseball",
|
||||
"Boxen",
|
||||
"Denk- und Glücksspiele",
|
||||
"Football",
|
||||
"Fußball",
|
||||
"Kampfsport",
|
||||
"Rennsport",
|
||||
"Tennis",
|
||||
//Kunst (Art)
|
||||
"Anime & Film",
|
||||
"Malerei",
|
||||
"Manga & Doujinshi",
|
||||
"Musik",
|
||||
"Theater",
|
||||
//Tätigkeit
|
||||
"Band",
|
||||
"Detektiv",
|
||||
"Dieb",
|
||||
"Essenszubereitung",
|
||||
"Idol",
|
||||
"Kopfgeldjäger",
|
||||
"Ninja",
|
||||
"Polizist",
|
||||
"Ritter",
|
||||
"Samurai",
|
||||
"Solosänger",
|
||||
//Wesen
|
||||
"Außerirdische",
|
||||
"Cyborgs",
|
||||
"Dämonen",
|
||||
"Elfen",
|
||||
"Geister",
|
||||
"Hexen",
|
||||
"Himmlische Wesen",
|
||||
"Kamis",
|
||||
"Kemonomimi",
|
||||
"Monster",
|
||||
"Roboter & Androiden",
|
||||
"Tiermenschen",
|
||||
"Vampire",
|
||||
"Youkai",
|
||||
"Zombie",
|
||||
//Proxer
|
||||
"Virtual Reality",
|
||||
"Game",
|
||||
"Survival",
|
||||
"Fanservice",
|
||||
"Schlauer Protagonist",
|
||||
};
|
||||
|
||||
private static readonly Dictionary<string, string> IgnoreIfPresent = new Dictionary<string, string>
|
||||
@ -90,7 +230,7 @@ namespace MediaBrowser.Plugins.Anime.Providers
|
||||
|
||||
max = Math.Max(max - 1, 0);
|
||||
}
|
||||
|
||||
|
||||
if (config.MaxGenres > 0)
|
||||
{
|
||||
series.Genres = series.Genres.Take(max).ToList();
|
||||
|
@ -525,4 +525,4 @@
|
||||
// return airDate;
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
//}
|
@ -0,0 +1,29 @@
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Entities;
|
||||
|
||||
namespace MediaBrowser.Plugins.Anime.Providers.MyAnimeList
|
||||
{
|
||||
public class MyAnimeListrExternalId : IExternalId
|
||||
{
|
||||
public bool Supports(IHasProviderIds item)
|
||||
{
|
||||
return item is Series;
|
||||
}
|
||||
|
||||
public string Name
|
||||
{
|
||||
get { return "MyAnimeList"; }
|
||||
}
|
||||
|
||||
public string Key
|
||||
{
|
||||
get { return ProviderNames.MyAnimeList; }
|
||||
}
|
||||
|
||||
public string UrlFormatString
|
||||
{
|
||||
get { return "https://myanimelist.net/anime/{0}"; }
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,169 @@
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using MediaBrowser.Model.Providers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Plugins.Anime.Providers.MyAnimeList
|
||||
{
|
||||
public class MyAnimeListSeriesProvider : IRemoteMetadataProvider<Series, SeriesInfo>, IHasOrder
|
||||
{
|
||||
private readonly ILogger _log;
|
||||
private readonly IHttpClient _httpClient;
|
||||
private readonly IApplicationPaths _paths;
|
||||
public static readonly SemaphoreSlim ResourcePool = new SemaphoreSlim(1, 1);
|
||||
public static string provider_name = ProviderNames.MyAnimeList;
|
||||
public int Order => -5;
|
||||
public string Name => "MyAnimeList";
|
||||
|
||||
public MyAnimeListSeriesProvider(IApplicationPaths appPaths, IHttpClient httpClient, ILogManager logManager)
|
||||
{
|
||||
_log = logManager.GetLogger("MyAnimeList");
|
||||
_httpClient = httpClient;
|
||||
_paths = appPaths;
|
||||
}
|
||||
|
||||
public async Task<MetadataResult<Series>> GetMetadata(SeriesInfo info, CancellationToken cancellationToken)
|
||||
{
|
||||
var result = new MetadataResult<Series>();
|
||||
|
||||
var aid = info.ProviderIds.GetOrDefault(provider_name);
|
||||
if (string.IsNullOrEmpty(aid))
|
||||
{
|
||||
_log.Info("Start MyAnimeList... Searching(" + info.Name + ")");
|
||||
aid = await api.FindSeries(info.Name, cancellationToken);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(aid))
|
||||
{
|
||||
string WebContent = await api.WebRequestAPI(api.anime_link + aid);
|
||||
result.Item = new Series();
|
||||
result.HasMetadata = true;
|
||||
|
||||
result.Item.ProviderIds.Add(provider_name, aid);
|
||||
result.Item.Overview = await api.Get_OverviewAsync(WebContent);
|
||||
result.ResultLanguage = "eng";
|
||||
try
|
||||
{
|
||||
result.Item.CommunityRating = float.Parse(await api.Get_RatingAsync(WebContent), System.Globalization.CultureInfo.InvariantCulture);
|
||||
}
|
||||
catch (Exception) { }
|
||||
foreach (var genre in await api.Get_GenreAsync(WebContent))
|
||||
{
|
||||
if (!string.IsNullOrEmpty(genre))
|
||||
{
|
||||
result.Item.AddGenre(genre);
|
||||
}
|
||||
}
|
||||
GenreHelper.CleanupGenres(result.Item);
|
||||
StoreImageUrl(aid, await api.Get_ImageUrlAsync(WebContent), "image");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<RemoteSearchResult>> GetSearchResults(SeriesInfo searchInfo, CancellationToken cancellationToken)
|
||||
{
|
||||
var results = new Dictionary<string, RemoteSearchResult>();
|
||||
|
||||
var aid = searchInfo.ProviderIds.GetOrDefault(provider_name);
|
||||
if (!string.IsNullOrEmpty(aid))
|
||||
{
|
||||
if (!results.ContainsKey(aid))
|
||||
results.Add(aid, await api.GetAnime(aid, cancellationToken));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(searchInfo.Name))
|
||||
{
|
||||
List<string> ids = await api.Search_GetSeries_list(searchInfo.Name, cancellationToken);
|
||||
foreach (string a in ids)
|
||||
{
|
||||
results.Add(a, await api.GetAnime(a, cancellationToken));
|
||||
}
|
||||
}
|
||||
|
||||
return results.Values;
|
||||
}
|
||||
|
||||
private void StoreImageUrl(string series, string url, string type)
|
||||
{
|
||||
var path = Path.Combine(_paths.CachePath, "myanimelist", type, series + ".txt");
|
||||
var directory = Path.GetDirectoryName(path);
|
||||
Directory.CreateDirectory(directory);
|
||||
|
||||
File.WriteAllText(path, url);
|
||||
}
|
||||
|
||||
public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken)
|
||||
{
|
||||
return _httpClient.GetResponse(new HttpRequestOptions
|
||||
{
|
||||
CancellationToken = cancellationToken,
|
||||
Url = url,
|
||||
ResourcePool = ResourcePool
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public class MyAnimeListSeriesImageProvider : IRemoteImageProvider
|
||||
{
|
||||
private readonly IHttpClient _httpClient;
|
||||
private readonly IApplicationPaths _appPaths;
|
||||
public static readonly SemaphoreSlim ResourcePool = new SemaphoreSlim(1, 1);
|
||||
|
||||
public MyAnimeListSeriesImageProvider(IHttpClient httpClient, IApplicationPaths appPaths)
|
||||
{
|
||||
_httpClient = httpClient;
|
||||
_appPaths = appPaths;
|
||||
}
|
||||
|
||||
public string Name => "MyAnimeList";
|
||||
|
||||
public bool Supports(IHasMetadata item) => item is Series || item is Season;
|
||||
|
||||
public IEnumerable<ImageType> GetSupportedImages(IHasMetadata item)
|
||||
{
|
||||
return new[] { ImageType.Primary };
|
||||
}
|
||||
|
||||
public Task<IEnumerable<RemoteImageInfo>> GetImages(IHasMetadata item, CancellationToken cancellationToken)
|
||||
{
|
||||
var seriesId = item.GetProviderId(MyAnimeListSeriesProvider.provider_name);
|
||||
return GetImages(seriesId, cancellationToken);
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<RemoteImageInfo>> GetImages(string aid, CancellationToken cancellationToken)
|
||||
{
|
||||
var list = new List<RemoteImageInfo>();
|
||||
|
||||
if (!string.IsNullOrEmpty(aid))
|
||||
{
|
||||
var primary = await api.Get_ImageUrlAsync(await api.WebRequestAPI(api.anime_link + aid));
|
||||
list.Add(new RemoteImageInfo
|
||||
{
|
||||
ProviderName = Name,
|
||||
Type = ImageType.Primary,
|
||||
Url = primary
|
||||
});
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken)
|
||||
{
|
||||
return _httpClient.GetResponse(new HttpRequestOptions
|
||||
{
|
||||
CancellationToken = cancellationToken,
|
||||
Url = url,
|
||||
ResourcePool = MyAnimeListSeriesProvider.ResourcePool
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
352
MediaBrowser.Plugins.Anime/Providers/MyAnimeList/api.cs
Normal file
352
MediaBrowser.Plugins.Anime/Providers/MyAnimeList/api.cs
Normal file
@ -0,0 +1,352 @@
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Providers;
|
||||
using MediaBrowser.Plugins.Anime.Configuration;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Plugins.Anime.Providers.MyAnimeList
|
||||
{
|
||||
/// <summary>
|
||||
/// This API use the WebContent of MyAnimelist and the API of MyAnimelist
|
||||
/// </summary>
|
||||
internal class api
|
||||
{
|
||||
public static List<string> anime_search_names = new List<string>();
|
||||
public static List<string> anime_search_ids = new List<string>();
|
||||
|
||||
//Use API too search
|
||||
public static string SearchLink = "https://myanimelist.net/api/anime/search.xml?q={0}";
|
||||
|
||||
//No API funktion exist too get anime
|
||||
public static string anime_link = "https://myanimelist.net/anime/info/";
|
||||
|
||||
/// <summary>
|
||||
/// WebContent API call to get a anime with id
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
public static async Task<RemoteSearchResult> GetAnime(string id, CancellationToken cancellationToken)
|
||||
{
|
||||
string WebContent = await WebRequestAPI(anime_link + id);
|
||||
|
||||
var result = new RemoteSearchResult
|
||||
{
|
||||
Name = await SelectName(WebContent, Plugin.Instance.Configuration.TitlePreference, "en", cancellationToken)
|
||||
};
|
||||
|
||||
result.SearchProviderName = WebUtility.HtmlDecode(await one_line_regex(new Regex("<span itemprop=\"name\">" + @"(.*?)<"), WebContent));
|
||||
result.ImageUrl = await Get_ImageUrlAsync(WebContent);
|
||||
result.SetProviderId(MyAnimeListSeriesProvider.provider_name, id);
|
||||
result.Overview = await Get_OverviewAsync(WebContent);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// WebContent API call to select a prefence title
|
||||
/// </summary>
|
||||
/// <param name="WebContent"></param>
|
||||
/// <param name="preference"></param>
|
||||
/// <param name="language"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
private static async Task<string> SelectName(string WebContent, TitlePreferenceType preference, string language, CancellationToken cancellationToken)
|
||||
{
|
||||
if (preference == TitlePreferenceType.Localized && language == "en")
|
||||
return await Get_title("en", WebContent);
|
||||
if (preference == TitlePreferenceType.Localized && language == "de")
|
||||
return await Get_title("de", WebContent);
|
||||
if (preference == TitlePreferenceType.Localized && language == "ger")
|
||||
return await Get_title("de", WebContent);
|
||||
if (preference == TitlePreferenceType.Japanese)
|
||||
return await Get_title("jap", WebContent);
|
||||
|
||||
return await Get_title("jap_r", WebContent);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// WebContent API call get a specific title
|
||||
/// </summary>
|
||||
/// <param name="lang"></param>
|
||||
/// <param name="WebContent"></param>
|
||||
/// <returns></returns>
|
||||
public static async Task<string> Get_title(string lang, string WebContent)
|
||||
{
|
||||
switch (lang)
|
||||
{
|
||||
case "en":
|
||||
return WebUtility.HtmlDecode(await one_line_regex(new Regex(@">([\S\s]*?)<"), await one_line_regex(new Regex(@"English:<\/span>(?s)(.*?)<"), WebContent)));
|
||||
|
||||
case "jap":
|
||||
return WebUtility.HtmlDecode(await one_line_regex(new Regex(@">([\S\s]*?)<"), await one_line_regex(new Regex(@"Japanese:<\/span>(?s)(.*?)<"), WebContent)));
|
||||
|
||||
//Default is jap_r
|
||||
default:
|
||||
return WebUtility.HtmlDecode(await one_line_regex(new Regex("<span itemprop=\"name\">" + @"(.*?)<"), WebContent));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// WebContent API call get genre
|
||||
/// </summary>
|
||||
/// <param name="WebContent"></param>
|
||||
/// <returns></returns>
|
||||
public static async Task<List<string>> Get_GenreAsync(string WebContent)
|
||||
{
|
||||
try
|
||||
{
|
||||
List<string> result = new List<string>();
|
||||
string Genres = await one_line_regex(new Regex(@"\.setTargeting\(" + "\"genres\"" + @", \[(.*?)\])"), WebContent);
|
||||
int x = 1;
|
||||
Genres = Genres.Replace("\"", "");
|
||||
foreach (string Genre in Genres.Split(','))
|
||||
{
|
||||
if (!string.IsNullOrEmpty(Genre))
|
||||
{
|
||||
result.Add(Genre);
|
||||
}
|
||||
x++;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
List<string> test = new List<string>();
|
||||
test.Add("");
|
||||
return test;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// WebContent API call get rating
|
||||
/// </summary>
|
||||
/// <param name="WebContent"></param>
|
||||
public static async Task<string> Get_RatingAsync(string WebContent)
|
||||
{
|
||||
return await one_line_regex(new Regex("<span itemprop=\"ratingValue\">" + @"(.*?)<"), WebContent);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// WebContent API call to get the imgurl
|
||||
/// </summary>
|
||||
/// <param name="WebContent"></param>
|
||||
/// <returns></returns>
|
||||
public static async Task<string> Get_ImageUrlAsync(string WebContent)
|
||||
{
|
||||
return await one_line_regex(new Regex("src=\"" + @"(?s)(.*?)" + "\""), await one_line_regex(new Regex(" < div style=\"text - align: center; \">" + @"(?s)(.*?)alt="), WebContent));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// WebContent API call to get the description
|
||||
/// </summary>
|
||||
/// <param name="WebContent"></param>
|
||||
/// <returns></returns>
|
||||
public static async Task<string> Get_OverviewAsync(string WebContent)
|
||||
{
|
||||
return System.Net.WebUtility.HtmlDecode(await one_line_regex(new Regex("\"og: description\" content=\"" + @"(.*?)" + "\">"), WebContent));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// MyAnimeListAPI call to search the right series
|
||||
/// </summary>
|
||||
/// <param name="title"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
public static async Task<string> Search_GetSeries(string title, CancellationToken cancellationToken)
|
||||
{
|
||||
anime_search_names.Clear();
|
||||
anime_search_ids.Clear();
|
||||
string result = null;
|
||||
string result_text = null;
|
||||
string WebContent = await WebRequestAPI(string.Format(SearchLink, Uri.EscapeUriString(title)), Plugin.Instance.Configuration.MyAnimeList_API_Name, Plugin.Instance.Configuration.MyAnimeList_API_Pw);
|
||||
int x = 0;
|
||||
while (result_text != "")
|
||||
{
|
||||
result_text = await one_line_regex(new Regex(@"<entry>(.*?)<\/entry>"), WebContent, 1, x);
|
||||
if (result_text != "")
|
||||
{
|
||||
//get id
|
||||
string id = await one_line_regex(new Regex(@"<id>(.*?)<\/id>"), result_text);
|
||||
string a_name = await one_line_regex(new Regex(@"<title>(.*?)<\/title>"), result_text);
|
||||
string b_name = await one_line_regex(new Regex(@"<english>(.*?)<\/english>"), result_text);
|
||||
string c_name = await one_line_regex(new Regex(@"<synonyms>(.*?)<\/synonyms>"), result_text);
|
||||
|
||||
if (Equals_check.Compare_strings(a_name, title))
|
||||
{
|
||||
result = id;
|
||||
return result;
|
||||
}
|
||||
if (Equals_check.Compare_strings(b_name, title))
|
||||
{
|
||||
result = id;
|
||||
return result;
|
||||
}
|
||||
foreach (string d_name in c_name.Split(';'))
|
||||
{
|
||||
if (Equals_check.Compare_strings(d_name, title))
|
||||
{
|
||||
result = id;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
int n;
|
||||
if (Int32.TryParse(id, out n))
|
||||
{
|
||||
anime_search_names.Add(a_name);
|
||||
anime_search_ids.Add(id);
|
||||
}
|
||||
}
|
||||
x++;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// MyAnimeListAPI call to search the series and return a list
|
||||
/// </summary>
|
||||
/// <param name="title"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
public static async Task<List<string>> Search_GetSeries_list(string title, CancellationToken cancellationToken)
|
||||
{
|
||||
List<string> result = new List<string>();
|
||||
string result_text = null;
|
||||
string WebContent = await WebRequestAPI(string.Format(SearchLink, Uri.EscapeUriString(title)), Plugin.Instance.Configuration.MyAnimeList_API_Name, Plugin.Instance.Configuration.MyAnimeList_API_Pw);
|
||||
int x = 0;
|
||||
while (result_text != "")
|
||||
{
|
||||
result_text = await one_line_regex(new Regex(@"<entry>(.*?)<\/entry>"), WebContent, 1, x);
|
||||
if (result_text != "")
|
||||
{
|
||||
//get id
|
||||
string id = await one_line_regex(new Regex(@"<id>(.*?)<\/id>"), result_text);
|
||||
string a_name = await one_line_regex(new Regex(@"<title>(.*?)<\/title>"), result_text);
|
||||
string b_name = await one_line_regex(new Regex(@"<english>(.*?)<\/english>"), result_text);
|
||||
string c_name = await one_line_regex(new Regex(@"<synonyms>(.*?)<\/synonyms>"), result_text);
|
||||
|
||||
if (Equals_check.Compare_strings(a_name, title))
|
||||
{
|
||||
result.Add(id);
|
||||
return result;
|
||||
}
|
||||
if (Equals_check.Compare_strings(b_name, title))
|
||||
{
|
||||
result.Add(id);
|
||||
return result;
|
||||
}
|
||||
foreach (string d_name in c_name.Split(';'))
|
||||
{
|
||||
if (Equals_check.Compare_strings(d_name, title))
|
||||
{
|
||||
result.Add(id);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
int n;
|
||||
if (Int32.TryParse(id, out n))
|
||||
{
|
||||
result.Add(id);
|
||||
}
|
||||
}
|
||||
x++;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// MyAnimeListAPI call to find a series
|
||||
/// </summary>
|
||||
/// <param name="title"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
public static async Task<string> FindSeries(string title, CancellationToken cancellationToken)
|
||||
{
|
||||
string aid = await Search_GetSeries(title, cancellationToken);
|
||||
if (!string.IsNullOrEmpty(aid))
|
||||
{
|
||||
return aid;
|
||||
}
|
||||
else
|
||||
{
|
||||
int x = 0;
|
||||
|
||||
foreach (string a_name in anime_search_names)
|
||||
{
|
||||
if (Equals_check.Compare_strings(a_name, title))
|
||||
{
|
||||
return anime_search_ids[x];
|
||||
}
|
||||
x++;
|
||||
}
|
||||
}
|
||||
aid = await Search_GetSeries(Equals_check.clear_name(title), cancellationToken);
|
||||
if (!string.IsNullOrEmpty(aid))
|
||||
{
|
||||
return aid;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// simple regex
|
||||
/// </summary>
|
||||
/// <param name="regex"></param>
|
||||
/// <param name="match"></param>
|
||||
/// <param name="group"></param>
|
||||
/// <param name="match_int"></param>
|
||||
/// <returns></returns>
|
||||
public static async Task<string> one_line_regex(Regex regex, string match, int group = 1, int match_int = 0)
|
||||
{
|
||||
Regex _regex = regex;
|
||||
int x = 0;
|
||||
MatchCollection matches = await Task.Run(() => regex.Matches(match));
|
||||
foreach (Match _match in matches)
|
||||
{
|
||||
if (x == match_int)
|
||||
{
|
||||
return await Task.Run(() => _match.Groups[group].Value.ToString());
|
||||
}
|
||||
x++;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A WebRequestAPI too handle the Webcontent and the API of MyAnimeList
|
||||
/// </summary>
|
||||
/// <param name="link"></param>
|
||||
/// <param name="name"></param>
|
||||
/// <param name="pw"></param>
|
||||
/// <returns></returns>
|
||||
public static async Task<string> WebRequestAPI(string link, string name = null, string pw = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
string encoded = await Task.Run(() => Convert.ToBase64String(Encoding.GetEncoding("ISO-8859-1").GetBytes(name + ":" + pw)));
|
||||
string _strContent;
|
||||
using (WebClient client = new WebClient())
|
||||
{
|
||||
if (!await Task.Run(() => string.IsNullOrEmpty(name)) && !await Task.Run(() => string.IsNullOrEmpty(pw)))
|
||||
{
|
||||
client.Headers.Add("Authorization", "Basic " + encoded);
|
||||
}
|
||||
Task<string> async_content = client.DownloadStringTaskAsync(link);
|
||||
_strContent = await async_content;
|
||||
}
|
||||
return _strContent;
|
||||
}
|
||||
catch (WebException)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -5,5 +5,7 @@
|
||||
public const string AniDb = "AniDB";
|
||||
public const string MyAnimeList = "MyAnimeList";
|
||||
public const string AniList = "AniList";
|
||||
public const string AniSearch = "AniSearch";
|
||||
public const string Proxer = "Proxer";
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Entities;
|
||||
|
||||
namespace MediaBrowser.Plugins.Anime.Providers.Proxer
|
||||
{
|
||||
public class ProxerExternalId : IExternalId
|
||||
{
|
||||
public bool Supports(IHasProviderIds item)
|
||||
{
|
||||
return item is Series;
|
||||
}
|
||||
|
||||
public string Name
|
||||
{
|
||||
get { return "Proxer"; }
|
||||
}
|
||||
|
||||
public string Key
|
||||
{
|
||||
get { return ProviderNames.Proxer; }
|
||||
}
|
||||
|
||||
public string UrlFormatString
|
||||
{
|
||||
get { return "https://proxer.me/info/{0}"; }
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,163 @@
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using MediaBrowser.Model.Providers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Plugins.Anime.Providers.Proxer
|
||||
{
|
||||
public class ProxerSeriesProvider : IRemoteMetadataProvider<Series, SeriesInfo>, IHasOrder
|
||||
{
|
||||
private readonly ILogger _log;
|
||||
private readonly IHttpClient _httpClient;
|
||||
private readonly IApplicationPaths _paths;
|
||||
public static string provider_name = ProviderNames.Proxer;
|
||||
public static readonly SemaphoreSlim ResourcePool = new SemaphoreSlim(1, 1);
|
||||
public int Order => -4;
|
||||
public string Name => "Proxer";
|
||||
|
||||
public ProxerSeriesProvider(IApplicationPaths appPaths, IHttpClient httpClient, ILogManager logManager)
|
||||
{
|
||||
_log = logManager.GetLogger("Proxer");
|
||||
_httpClient = httpClient;
|
||||
_paths = appPaths;
|
||||
}
|
||||
|
||||
public async Task<MetadataResult<Series>> GetMetadata(SeriesInfo info, CancellationToken cancellationToken)
|
||||
{
|
||||
var result = new MetadataResult<Series>();
|
||||
|
||||
var aid = info.ProviderIds.GetOrDefault(provider_name);
|
||||
if (string.IsNullOrEmpty(aid))
|
||||
{
|
||||
_log.Info("Start Proxer... Searching(" + info.Name + ")");
|
||||
aid = await api.FindSeries(info.Name, cancellationToken);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(aid))
|
||||
{
|
||||
string WebContent = await api.WebRequestAPI(api.Proxer_anime_link + aid);
|
||||
result.Item = new Series();
|
||||
result.HasMetadata = true;
|
||||
|
||||
result.Item.ProviderIds.Add(provider_name, aid);
|
||||
result.Item.Overview = await api.Get_Overview(WebContent);
|
||||
result.ResultLanguage = "ger";
|
||||
try
|
||||
{
|
||||
result.Item.CommunityRating = float.Parse(await api.Get_Rating(WebContent), System.Globalization.CultureInfo.InvariantCulture);
|
||||
}
|
||||
catch (Exception) { }
|
||||
foreach (var genre in await api.Get_Genre(WebContent))
|
||||
result.Item.AddGenre(genre);
|
||||
GenreHelper.CleanupGenres(result.Item);
|
||||
StoreImageUrl(aid, await api.Get_ImageUrl(WebContent), "image");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<RemoteSearchResult>> GetSearchResults(SeriesInfo searchInfo, CancellationToken cancellationToken)
|
||||
{
|
||||
var results = new Dictionary<string, RemoteSearchResult>();
|
||||
|
||||
var aid = searchInfo.ProviderIds.GetOrDefault(provider_name);
|
||||
if (!string.IsNullOrEmpty(aid))
|
||||
{
|
||||
if (!results.ContainsKey(aid))
|
||||
results.Add(aid, await api.GetAnime(aid));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(searchInfo.Name))
|
||||
{
|
||||
List<string> ids = await api.Search_GetSeries_list(searchInfo.Name, cancellationToken);
|
||||
foreach (string a in ids)
|
||||
{
|
||||
results.Add(a, await api.GetAnime(a));
|
||||
}
|
||||
}
|
||||
|
||||
return results.Values;
|
||||
}
|
||||
|
||||
private void StoreImageUrl(string series, string url, string type)
|
||||
{
|
||||
var path = Path.Combine(_paths.CachePath, "proxer", type, series + ".txt");
|
||||
var directory = Path.GetDirectoryName(path);
|
||||
Directory.CreateDirectory(directory);
|
||||
|
||||
File.WriteAllText(path, url);
|
||||
}
|
||||
|
||||
public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken)
|
||||
{
|
||||
return _httpClient.GetResponse(new HttpRequestOptions
|
||||
{
|
||||
CancellationToken = cancellationToken,
|
||||
Url = url,
|
||||
ResourcePool = ResourcePool
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public class ProxerSeriesImageProvider : IRemoteImageProvider
|
||||
{
|
||||
private readonly IHttpClient _httpClient;
|
||||
private readonly IApplicationPaths _appPaths;
|
||||
|
||||
public ProxerSeriesImageProvider(IHttpClient httpClient, IApplicationPaths appPaths)
|
||||
{
|
||||
_httpClient = httpClient;
|
||||
_appPaths = appPaths;
|
||||
}
|
||||
|
||||
public string Name => "Proxer";
|
||||
|
||||
public bool Supports(IHasMetadata item) => item is Series || item is Season;
|
||||
|
||||
public IEnumerable<ImageType> GetSupportedImages(IHasMetadata item)
|
||||
{
|
||||
return new[] { ImageType.Primary };
|
||||
}
|
||||
|
||||
public Task<IEnumerable<RemoteImageInfo>> GetImages(IHasMetadata item, CancellationToken cancellationToken)
|
||||
{
|
||||
var seriesId = item.GetProviderId(ProxerSeriesProvider.provider_name);
|
||||
return GetImages(seriesId, cancellationToken);
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<RemoteImageInfo>> GetImages(string aid, CancellationToken cancellationToken)
|
||||
{
|
||||
var list = new List<RemoteImageInfo>();
|
||||
|
||||
if (!string.IsNullOrEmpty(aid))
|
||||
{
|
||||
var primary = api.Get_ImageUrl(await api.WebRequestAPI(api.Proxer_anime_link + aid));
|
||||
list.Add(new RemoteImageInfo
|
||||
{
|
||||
ProviderName = Name,
|
||||
Type = ImageType.Primary,
|
||||
Url = await primary
|
||||
});
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken)
|
||||
{
|
||||
return _httpClient.GetResponse(new HttpRequestOptions
|
||||
{
|
||||
CancellationToken = cancellationToken,
|
||||
Url = url,
|
||||
ResourcePool = ProxerSeriesProvider.ResourcePool
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
311
MediaBrowser.Plugins.Anime/Providers/Proxer/api.cs
Normal file
311
MediaBrowser.Plugins.Anime/Providers/Proxer/api.cs
Normal file
@ -0,0 +1,311 @@
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Providers;
|
||||
using MediaBrowser.Plugins.Anime.Configuration;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Plugins.Anime.Providers.Proxer
|
||||
{
|
||||
/// <summary>
|
||||
/// API for http://proxer.me/ german anime database.
|
||||
/// 🛈 Proxer does not have an API interface to work with
|
||||
/// </summary>
|
||||
internal class api
|
||||
{
|
||||
public static List<string> anime_search_names = new List<string>();
|
||||
public static List<string> anime_search_ids = new List<string>();
|
||||
public static string SearchLink = "http://proxer.me/search?s=search&name={0}&typ=all-anime&tags=¬ags=#top";
|
||||
public static string Proxer_anime_link = "http://proxer.me/info/";
|
||||
|
||||
/// <summary>
|
||||
/// API call to get a anime with the id
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
public static async Task<RemoteSearchResult> GetAnime(string id)
|
||||
{
|
||||
string WebContent = await WebRequestAPI(Proxer_anime_link + id);
|
||||
|
||||
var result = new RemoteSearchResult
|
||||
{
|
||||
Name = await SelectName(WebContent, Plugin.Instance.Configuration.TitlePreference, "en")
|
||||
};
|
||||
|
||||
result.SearchProviderName = await one_line_regex(new Regex(@">([\S\s]*?)<"), await one_line_regex(new Regex(@"<td><b>Original Titel<\/b><\/td>([\S\s]*?)\/td>"), WebContent));
|
||||
result.ImageUrl = await Get_ImageUrl(WebContent);
|
||||
result.SetProviderId(ProxerSeriesProvider.provider_name, id);
|
||||
result.Overview = await Get_Overview(WebContent);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the right name lang
|
||||
/// </summary>
|
||||
/// <param name="WebContent"></param>
|
||||
/// <param name="preference"></param>
|
||||
/// <param name="language"></param>
|
||||
/// <returns></returns>
|
||||
private static async Task<string> SelectName(string WebContent, TitlePreferenceType preference, string language)
|
||||
{
|
||||
if (preference == TitlePreferenceType.Localized && language == "en")
|
||||
return await Get_title("en", WebContent);
|
||||
if (preference == TitlePreferenceType.Localized && language == "de")
|
||||
return await Get_title("de", WebContent);
|
||||
if (preference == TitlePreferenceType.Localized && language == "ger")
|
||||
return await Get_title("de", WebContent);
|
||||
if (preference == TitlePreferenceType.Japanese)
|
||||
return await Get_title("jap", WebContent);
|
||||
|
||||
return await Get_title("jap_r", WebContent);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// API call to get the name in the called lang
|
||||
/// </summary>
|
||||
/// <param name="lang"></param>
|
||||
/// <param name="WebContent"></param>
|
||||
/// <returns></returns>
|
||||
public static async Task<string> Get_title(string lang, string WebContent)
|
||||
{
|
||||
switch (lang)
|
||||
{
|
||||
case "en":
|
||||
return await one_line_regex(new Regex(@">([\S\s]*?)<"), await one_line_regex(new Regex(@"<td><b>Englischer Titel<\/b><\/td>([\S\s]*?)\/td>"), WebContent));
|
||||
|
||||
case "de":
|
||||
|
||||
return await one_line_regex(new Regex(@">([\S\s]*?)<"), await one_line_regex(new Regex(@"<td><b>Deutscher Titel<\/b><\/td>([\S\s]*?)\/td>"), WebContent));
|
||||
|
||||
case "jap":
|
||||
return await one_line_regex(new Regex(@">([\S\s]*?)<"), await one_line_regex(new Regex(@"<td><b>Japanischer Titel<\/b><\/td>([\S\s]*?)\/td>"), WebContent));
|
||||
|
||||
//Default is jap_r
|
||||
default:
|
||||
return await one_line_regex(new Regex(@">([\S\s]*?)<"), await one_line_regex(new Regex(@"<td><b>Original Titel<\/b><\/td>([\S\s]*?)\/td>"), WebContent));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// API call to get the genres of the anime
|
||||
/// </summary>
|
||||
/// <param name="WebContent"></param>
|
||||
/// <returns></returns>
|
||||
public static async Task<List<string>> Get_Genre(string WebContent)
|
||||
{
|
||||
List<string> result = new List<string>();
|
||||
string Genres = await one_line_regex(new Regex(@"<b>Genre<\/b>((?:.*?\r?\n?)*)<\/tr>"), WebContent);
|
||||
int x = 1;
|
||||
string Proxer_Genre = null;
|
||||
while (Proxer_Genre != "")
|
||||
{
|
||||
Proxer_Genre = await one_line_regex(new Regex("\">" + @"((?:.*?\r?\n?)*)<"), Genres, 1, x);
|
||||
if (Proxer_Genre != "")
|
||||
{
|
||||
result.Add(Proxer_Genre);
|
||||
}
|
||||
x++;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// API call to get the ratings of the anime
|
||||
/// </summary>
|
||||
/// <param name="WebContent"></param>
|
||||
/// <returns></returns>
|
||||
public static async Task<string> Get_Rating(string WebContent)
|
||||
{
|
||||
return await one_line_regex(new Regex("<span class=\"average\">" + @"(.*?)<"), WebContent);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// API call to get the ImageUrl if the anime
|
||||
/// </summary>
|
||||
/// <param name="WebContent"></param>
|
||||
/// <returns></returns>
|
||||
public static async Task<string> Get_ImageUrl(string WebContent)
|
||||
{
|
||||
return "http://" + await one_line_regex(new Regex("<img src=\"" + @"\/\/((?:.*?\r?\n?)*)" + "\""), WebContent);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// API call to get the description of the anime
|
||||
/// </summary>
|
||||
/// <param name="WebContent"></param>
|
||||
/// <returns></returns>
|
||||
public static async Task<string> Get_Overview(string WebContent)
|
||||
{
|
||||
return await one_line_regex(new Regex(@"Beschreibung:<\/b><br>((?:.*?\r?\n?)*)<\/td>"), WebContent);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Search a title and return the right one back
|
||||
/// </summary>
|
||||
/// <param name="title"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
public static async Task<string> Search_GetSeries(string title, CancellationToken cancellationToken,bool bettersearchresults=false)
|
||||
{
|
||||
anime_search_names.Clear();
|
||||
anime_search_ids.Clear();
|
||||
string result = null;
|
||||
string result_text = null;
|
||||
string WebContent = "";
|
||||
if (bettersearchresults)
|
||||
{
|
||||
WebContent = await WebRequestAPI(string.Format(SearchLink, Uri.EscapeUriString(Equals_check.Half_string(title, 4,60))));
|
||||
}
|
||||
else
|
||||
{
|
||||
WebContent = await WebRequestAPI(string.Format(SearchLink, Uri.EscapeUriString(title)));
|
||||
}
|
||||
int x = 0;
|
||||
while (result_text != "")
|
||||
{
|
||||
result_text = await one_line_regex(new Regex("<tr align=\"" + @"left(.*?)tr>"), WebContent, 1, x);
|
||||
if (result_text != "")
|
||||
{
|
||||
//get id
|
||||
string id = await one_line_regex(new Regex("class=\"entry" + @"(.*?)" + "\">"), result_text);
|
||||
string a_name = await one_line_regex(new Regex("#top\">" + @"(.*?)</a>"), result_text);
|
||||
if (Equals_check.Compare_strings(a_name, title))
|
||||
{
|
||||
result = id;
|
||||
return result;
|
||||
}
|
||||
int n;
|
||||
if (Int32.TryParse(id, out n))
|
||||
{
|
||||
anime_search_names.Add(a_name);
|
||||
anime_search_ids.Add(id);
|
||||
}
|
||||
}
|
||||
x++;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Search a title and return a list back
|
||||
/// </summary>
|
||||
/// <param name="title"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
public static async Task<List<string>> Search_GetSeries_list(string title, CancellationToken cancellationToken)
|
||||
{
|
||||
List<string> result = new List<string>();
|
||||
string result_text = null;
|
||||
string WebContent = await WebRequestAPI(string.Format(SearchLink, Uri.EscapeUriString(title)));
|
||||
int x = 0;
|
||||
while (result_text != "")
|
||||
{
|
||||
result_text = await one_line_regex(new Regex("<tr align=\"" + @"left(.*?)tr>"), WebContent, 1, x);
|
||||
if (result_text != "")
|
||||
{
|
||||
//get id
|
||||
|
||||
string id = await one_line_regex(new Regex("class=\"entry" + @"(.*?)" + "\">"), result_text);
|
||||
string a_name = await one_line_regex(new Regex("#top\">" + @"(.*?)</a>"), result_text);
|
||||
if (Equals_check.Compare_strings(a_name, title))
|
||||
{
|
||||
result.Add(id);
|
||||
return result;
|
||||
}
|
||||
int n;
|
||||
if (Int32.TryParse(id, out n))
|
||||
{
|
||||
result.Add(id);
|
||||
}
|
||||
}
|
||||
x++;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// API call too find a series
|
||||
/// </summary>
|
||||
/// <param name="title"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
public static async Task<string> FindSeries(string title, CancellationToken cancellationToken)
|
||||
{
|
||||
string aid = await Search_GetSeries(title, cancellationToken);
|
||||
if (!string.IsNullOrEmpty(aid))
|
||||
{
|
||||
return aid;
|
||||
}
|
||||
else
|
||||
{
|
||||
int x = 0;
|
||||
|
||||
foreach (string a_name in anime_search_names)
|
||||
{
|
||||
if (Equals_check.Compare_strings(a_name, title))
|
||||
{
|
||||
return anime_search_ids[x];
|
||||
}
|
||||
x++;
|
||||
}
|
||||
}
|
||||
aid = await Search_GetSeries(Equals_check.clear_name(title), cancellationToken,true);
|
||||
if (!string.IsNullOrEmpty(aid))
|
||||
{
|
||||
return aid;
|
||||
}
|
||||
aid = await Search_GetSeries(Equals_check.clear_name_step2(title), cancellationToken,true);
|
||||
if (!string.IsNullOrEmpty(aid))
|
||||
{
|
||||
return aid;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Simple async regex call
|
||||
/// </summary>
|
||||
/// <param name="regex"></param>
|
||||
/// <param name="match"></param>
|
||||
/// <param name="group"></param>
|
||||
/// <param name="match_int"></param>
|
||||
/// <returns></returns>
|
||||
public static async Task<string> one_line_regex(Regex regex, string match, int group = 1, int match_int = 0)
|
||||
{
|
||||
Regex _regex = regex;
|
||||
int x = 0;
|
||||
MatchCollection matches = await Task.Run(() => regex.Matches(match));
|
||||
foreach (Match _match in matches)
|
||||
{
|
||||
if (x == match_int)
|
||||
{
|
||||
return await Task.Run(() => _match.Groups[group].Value.ToString());
|
||||
}
|
||||
x++;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Need too get the Webcontent for some API calls.
|
||||
/// </summary>
|
||||
/// <param name="link"></param>
|
||||
/// <returns></returns>
|
||||
public static async Task<string> WebRequestAPI(string link)
|
||||
{
|
||||
string _strContent = "";
|
||||
using (WebClient client = new WebClient())
|
||||
{
|
||||
client.Headers.Add(HttpRequestHeader.Cookie, "Adult=1");
|
||||
Task<string> async_content = client.DownloadStringTaskAsync(link);
|
||||
_strContent = await async_content;
|
||||
}
|
||||
return _strContent;
|
||||
}
|
||||
}
|
||||
}
|
@ -140,4 +140,4 @@
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//}
|
||||
//}
|
465
MediaBrowser.Plugins.Anime/Providers/equals_check.cs
Normal file
465
MediaBrowser.Plugins.Anime/Providers/equals_check.cs
Normal file
@ -0,0 +1,465 @@
|
||||
using MediaBrowser.Model.Logging;
|
||||
using MediaBrowser.Plugins.Anime.Providers.AniDB.Identity;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace MediaBrowser.Plugins.Anime.Providers
|
||||
{
|
||||
internal class Equals_check
|
||||
{
|
||||
public readonly ILogger _logger;
|
||||
|
||||
public Equals_check(ILogger logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clear name
|
||||
/// </summary>
|
||||
/// <param name="a"></param>
|
||||
/// <returns></returns>
|
||||
public static string clear_name(string a)
|
||||
{
|
||||
try
|
||||
{
|
||||
a = a.Trim().Replace(one_line_regex(new Regex(@"(?s) \(.*?\)"), a.Trim(), 0), "");
|
||||
}
|
||||
catch (Exception)
|
||||
{ }
|
||||
a = a.Replace(".", " ");
|
||||
a = a.Replace("-", " ");
|
||||
a = a.Replace("`", "");
|
||||
a = a.Replace("'", "");
|
||||
a = a.Replace("&", "and");
|
||||
try
|
||||
{
|
||||
a = a.Replace(one_line_regex(new Regex(@"(?s)(S[0-9]+)"), a.Trim()), one_line_regex(new Regex(@"(?s)S([0-9]+)"), a.Trim()));
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clear name heavy.
|
||||
/// Example: Text & Text to Text and Text
|
||||
/// </summary>
|
||||
/// <param name="a"></param>
|
||||
/// <returns></returns>
|
||||
public static string clear_name_step2(string a)
|
||||
{
|
||||
try
|
||||
{
|
||||
a = a.Trim().Replace(one_line_regex(new Regex(@"(?s) \(.*?\)"), a.Trim(), 0), "");
|
||||
}
|
||||
catch (Exception)
|
||||
{ }
|
||||
a = a.Replace(".", " ");
|
||||
a = a.Replace("-", " ");
|
||||
a = a.Replace("`", "");
|
||||
a = a.Replace("'", "");
|
||||
a = a.Replace("&", "and");
|
||||
a = a.Replace(":", "");
|
||||
a = a.Replace("␣", "");
|
||||
a = a.Replace("2wei", "zwei");
|
||||
return a;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If a and b match it return true
|
||||
/// </summary>
|
||||
/// <param name="a"></param>
|
||||
/// <param name="b"></param>
|
||||
/// <returns></returns>
|
||||
public static bool Compare_strings(string a, string b)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(a) && !string.IsNullOrEmpty(b))
|
||||
{
|
||||
if (simple_compare(a, b))
|
||||
return true;
|
||||
if (Fast_xml_search(a, b))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cut p(%) away from the string
|
||||
/// </summary>
|
||||
/// <param name="string_"></param>
|
||||
/// <param name="min_lenght"></param>
|
||||
/// <param name="p"></param>
|
||||
/// <returns></returns>
|
||||
public static string Half_string(string string_, int min_lenght = 0, int p = 50)
|
||||
{
|
||||
decimal length = 0;
|
||||
if ((int)((decimal)string_.Length - (((decimal)string_.Length / 100m) * (decimal)p)) > min_lenght)
|
||||
{
|
||||
length = (decimal)string_.Length - (((decimal)string_.Length / 100m) * (decimal)p);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (string_.Length < min_lenght)
|
||||
{
|
||||
length = string_.Length;
|
||||
}
|
||||
else
|
||||
{
|
||||
length = min_lenght;
|
||||
}
|
||||
}
|
||||
return string_.Substring(0, (int)length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// simple regex
|
||||
/// </summary>
|
||||
/// <param name="regex"></param>
|
||||
/// <param name="match"></param>
|
||||
/// <param name="group"></param>
|
||||
/// <param name="match_int"></param>
|
||||
/// <returns></returns>
|
||||
public static string one_line_regex(Regex regex, string match, int group = 1, int match_int = 0)
|
||||
{
|
||||
Regex _regex = regex;
|
||||
int x = 0;
|
||||
foreach (Match _match in regex.Matches(match))
|
||||
{
|
||||
if (x == match_int)
|
||||
{
|
||||
return _match.Groups[group].Value.ToString();
|
||||
}
|
||||
x++;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///Return true if a and b match return false if not
|
||||
///It loads the titles.xml on exceptions
|
||||
/// </summary>
|
||||
private static bool Fast_xml_search(string a, string b, bool return_AniDBid = false, bool retry = false)
|
||||
{
|
||||
//Get AID aid=\"([s\S].*)\">
|
||||
try
|
||||
{
|
||||
List<string> pre_aid = new List<string>();
|
||||
string xml = File.ReadAllText(get_anidb_xml_file());
|
||||
int x = 0;
|
||||
string s1 = "-";
|
||||
string s2 = "-";
|
||||
while (!string.IsNullOrEmpty(s1) && !string.IsNullOrEmpty(s2))
|
||||
{
|
||||
s1 = one_line_regex(new Regex("<anime aid=" + "\"" + @"(\d+)" + "\"" + @">(?>[^<>]+|<(?!\/anime>)[^<>]*>)*?" + Regex.Escape(Half_string(a, 4))), xml, 1, x);
|
||||
if (s1 != "")
|
||||
{
|
||||
pre_aid.Add(s1);
|
||||
}
|
||||
s2 = one_line_regex(new Regex("<anime aid=" + "\"" + @"(\d+)" + "\"" + @">(?>[^<>]+|<(?!\/anime>)[^<>]*>)*?" + Regex.Escape(Half_string(b, 4))), xml, 1, x);
|
||||
if (s1 != "")
|
||||
{
|
||||
if (s1 != s2)
|
||||
{
|
||||
pre_aid.Add(s2);
|
||||
}
|
||||
}
|
||||
x++;
|
||||
}
|
||||
foreach (string _aid in pre_aid)
|
||||
{
|
||||
XElement doc = XElement.Parse("<?xml version=\"1.0\" encoding=\"UTF - 8\"?>" + "<animetitles>" + one_line_regex(new Regex("<anime aid=\"" + _aid + "\">" + @"(?s)(.*?)<\/anime>"), xml, 0) + "</animetitles>");
|
||||
var a_ = from page in doc.Elements("anime")
|
||||
where _aid == page.Attribute("aid").Value
|
||||
select page;
|
||||
if (simple_compare(a_.Elements("title"), b) && simple_compare(a_.Elements("title"), a))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
if (retry)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
Task.Run(() => AniDbTitleDownloader.Load_static(new System.Threading.CancellationToken()));
|
||||
return Fast_xml_search(a, b, false, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return the AniDB ID if a and b match
|
||||
/// </summary>
|
||||
public static string Fast_xml_search(string a, string b, bool return_AniDBid, int x_ = 0)
|
||||
{
|
||||
//Get AID aid=\"([s\S].*)\">
|
||||
try
|
||||
{
|
||||
List<string> pre_aid = new List<string>();
|
||||
string xml = File.ReadAllText(get_anidb_xml_file());
|
||||
int x = 0;
|
||||
string s1 = "-";
|
||||
string s2 = "-";
|
||||
while (!string.IsNullOrEmpty(s1) && !string.IsNullOrEmpty(s2))
|
||||
{
|
||||
s1 = one_line_regex(new Regex("<anime aid=" + "\"" + @"(\d+)" + "\"" + @">(?>[^<>]+|<(?!\/anime>)[^<>]*>)*?" + Regex.Escape(Half_string(a, 4))), xml, 1, x);
|
||||
if (s1 != "")
|
||||
{
|
||||
pre_aid.Add(s1);
|
||||
}
|
||||
s2 = one_line_regex(new Regex("<anime aid=" + "\"" + @"(\d+)" + "\"" + @">(?>[^<>]+|<(?!\/anime>)[^<>]*>)*?" + Regex.Escape(Half_string(b, 4))), xml, 1, x);
|
||||
if (s1 != "")
|
||||
{
|
||||
if (s1 != s2)
|
||||
{
|
||||
pre_aid.Add(s2);
|
||||
}
|
||||
}
|
||||
x++;
|
||||
}
|
||||
foreach (string _aid in pre_aid)
|
||||
{
|
||||
XElement doc = XElement.Parse("<?xml version=\"1.0\" encoding=\"UTF - 8\"?>" + "<animetitles>" + one_line_regex(new Regex("<anime aid=\"" + _aid + "\">" + @"(?s)(.*?)<\/anime>"), xml, 0) + "</animetitles>");
|
||||
var a_ = from page in doc.Elements("anime")
|
||||
where _aid == page.Attribute("aid").Value
|
||||
select page;
|
||||
if (simple_compare(a_.Elements("title"), b) && simple_compare(a_.Elements("title"), a))
|
||||
{
|
||||
return _aid;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
if (x_ == 1)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
else
|
||||
{
|
||||
Task.Run(() => AniDbTitleDownloader.Load_static(new System.Threading.CancellationToken()));
|
||||
return Fast_xml_search(a, b, true, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// get file Path from anidb xml file
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private static string get_anidb_xml_file()
|
||||
{
|
||||
return AniDbTitleDownloader.TitlesFilePath_;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compare 2 Strings, and it just works
|
||||
/// SeriesA S2 == SeriesA Second Season | True;
|
||||
/// </summary>
|
||||
private static bool simple_compare(string a, string b, bool fastmode = false)
|
||||
{
|
||||
if (fastmode)
|
||||
{
|
||||
if (a[0] == b[0])
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (Core_compare(a, b))
|
||||
return true;
|
||||
if (Core_compare(b, a))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compare 2 Strings, and it just works
|
||||
/// </summary>
|
||||
private static bool Core_compare(string a, string b)
|
||||
{
|
||||
if (a == b)
|
||||
return true;
|
||||
|
||||
a = a.ToLower().Replace(" ", "").Trim().Replace(".", "");
|
||||
b = b.ToLower().Replace(" ", "").Trim().Replace(".", "");
|
||||
|
||||
if (clear_name(a) == clear_name(b))
|
||||
return true;
|
||||
if (clear_name_step2(a) == clear_name_step2(b))
|
||||
return true;
|
||||
if (a.Replace("-", " ") == b.Replace("-", " "))
|
||||
return true;
|
||||
if (a.Replace(" 2", ":secondseason") == b.Replace(" 2", ":secondseason"))
|
||||
return true;
|
||||
if (a.Replace("2", "secondseason") == b.Replace("2", "secondseason"))
|
||||
return true;
|
||||
if (convert_symbols_too_numbers(a, "I") == convert_symbols_too_numbers(b, "I"))
|
||||
return true;
|
||||
if (convert_symbols_too_numbers(a, "!") == convert_symbols_too_numbers(b, "!"))
|
||||
return true;
|
||||
if (a.Replace("ndseason", "") == b.Replace("ndseason", ""))
|
||||
return true;
|
||||
if (a.Replace("ndseason", "") == b)
|
||||
return true;
|
||||
if (one_line_regex(new Regex(@"((.*)s([0 - 9]))"), a, 2) + one_line_regex(new Regex(@"((.*)s([0 - 9]))"), a, 3) == one_line_regex(new Regex(@"((.*)s([0 - 9]))"), b, 2) + one_line_regex(new Regex(@"((.*)s([0 - 9]))"), b, 3))
|
||||
if (!string.IsNullOrEmpty(one_line_regex(new Regex(@"((.*)s([0 - 9]))"), a, 2) + one_line_regex(new Regex(@"((.*)s([0 - 9]))"), a, 3)))
|
||||
return true;
|
||||
if (one_line_regex(new Regex(@"((.*)s([0 - 9]))"), a, 2) + one_line_regex(new Regex(@"((.*)s([0 - 9]))"), a, 3) == b)
|
||||
if (!string.IsNullOrEmpty(one_line_regex(new Regex(@"((.*)s([0 - 9]))"), a, 2) + one_line_regex(new Regex(@"((.*)s([0 - 9]))"), a, 3)))
|
||||
return true;
|
||||
if (a.Replace("rdseason", "") == b.Replace("rdseason", ""))
|
||||
return true;
|
||||
if (a.Replace("rdseason", "") == b)
|
||||
return true;
|
||||
try
|
||||
{
|
||||
if (a.Replace("2", "secondseason").Replace(one_line_regex(new Regex(@"(?s)\(.*?\)"), a, 0), "") == b.Replace("2", "secondseason").Replace(one_line_regex(new Regex(@"(?s)\(.*?\)"), b, 0), ""))
|
||||
return true;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
try
|
||||
{
|
||||
if (a.Replace("2", "secondseason").Replace(one_line_regex(new Regex(@"(?s)\(.*?\)"), a, 0), "") == b)
|
||||
return true;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
try
|
||||
{
|
||||
if (a.Replace(" 2", ":secondseason").Replace(one_line_regex(new Regex(@"(?s)\(.*?\)"), a, 0), "") == b.Replace(" 2", ":secondseason").Replace(one_line_regex(new Regex(@"(?s)\(.*?\)"), b, 0), ""))
|
||||
return true;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
try
|
||||
{
|
||||
if (a.Replace(" 2", ":secondseason").Replace(one_line_regex(new Regex(@"(?s)\(.*?\)"), a, 0), "") == b)
|
||||
return true;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
try
|
||||
{
|
||||
if (a.Replace(one_line_regex(new Regex(@"(?s)\(.*?\)"), a, 0), "") == b.Replace(one_line_regex(new Regex(@"(?s)\(.*?\)"), b, 0), ""))
|
||||
return true;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
try
|
||||
{
|
||||
if (a.Replace(one_line_regex(new Regex(@"(?s)\(.*?\)"), a, 0), "") == b)
|
||||
return true;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
try
|
||||
{
|
||||
if (b.Replace(one_line_regex(new Regex(@"(?s)\(.*?\)"), b, 0), "").Replace(" 2", ": second Season") == a)
|
||||
return true;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
try
|
||||
{
|
||||
if (a.Replace(" 2ndseason", ":secondseason") + " vs " + b == a)
|
||||
return true;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
try
|
||||
{
|
||||
if (a.Replace(one_line_regex(new Regex(@"(?s)\(.*?\)"), a, 0), "").Replace(" 2", ":secondseason") == b)
|
||||
return true;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Example: Convert II to 2
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <param name="symbol"></param>
|
||||
/// <returns></returns>
|
||||
private static string convert_symbols_too_numbers(string input, string symbol)
|
||||
{
|
||||
try
|
||||
{
|
||||
string regex_c = "_";
|
||||
int x = 0;
|
||||
int highest_number = 0;
|
||||
while (!string.IsNullOrEmpty(regex_c))
|
||||
{
|
||||
regex_c = one_line_regex(new Regex(@"(" + symbol + @"+)"), input.ToLower().Trim(), 1, x).Trim();
|
||||
if (highest_number < regex_c.Count())
|
||||
highest_number = regex_c.Count();
|
||||
x++;
|
||||
}
|
||||
x = 0;
|
||||
string output = "";
|
||||
while (x != highest_number)
|
||||
{
|
||||
output = output + symbol;
|
||||
x++;
|
||||
}
|
||||
output = input.Replace(output, highest_number.ToString());
|
||||
if (string.IsNullOrEmpty(output))
|
||||
{
|
||||
output = input;
|
||||
}
|
||||
return output;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return input;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Simple Compare a XElemtent with a string
|
||||
/// </summary>
|
||||
/// <param name="a_"></param>
|
||||
/// <param name="b"></param>
|
||||
/// <returns></returns>
|
||||
private static bool simple_compare(IEnumerable<XElement> a_, string b)
|
||||
{
|
||||
foreach (XElement a in a_)
|
||||
{
|
||||
if (simple_compare(a.Value, b, true))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
@ -38,7 +38,7 @@ namespace MediaBrowser.Plugins.Anime
|
||||
_targetInterval = targetInterval;
|
||||
_timeWindowDuration = timeWindow;
|
||||
|
||||
_maxAllowedInWindow = (int) (timeWindow.Ticks/targetInterval.Ticks);
|
||||
_maxAllowedInWindow = (int)(timeWindow.Ticks / targetInterval.Ticks);
|
||||
|
||||
_lastTake = DateTime.Now - minimumInterval;
|
||||
}
|
||||
@ -74,10 +74,10 @@ namespace MediaBrowser.Plugins.Anime
|
||||
DateTime now = DateTime.Now;
|
||||
TimeSpan minWait = (_lastTake + _minimumInterval) - now;
|
||||
|
||||
float load = (float) _window.Count/_maxAllowedInWindow;
|
||||
float load = (float)_window.Count / _maxAllowedInWindow;
|
||||
|
||||
float waitTicks = minWait.Ticks + (_targetInterval.Ticks - minWait.Ticks)*load;
|
||||
return new TimeSpan((long) waitTicks);
|
||||
float waitTicks = minWait.Ticks + (_targetInterval.Ticks - minWait.Ticks) * load;
|
||||
return new TimeSpan((long)waitTicks);
|
||||
}
|
||||
|
||||
private void FlushExpiredRecords()
|
||||
|
@ -11,7 +11,7 @@ namespace AnimeLists
|
||||
|
||||
/// <remarks />
|
||||
[XmlArray("mapping-list")]
|
||||
[XmlArrayItem("mapping", typeof (AnimelistMapping), IsNullable = false)]
|
||||
[XmlArrayItem("mapping", typeof(AnimelistMapping), IsNullable = false)]
|
||||
public AnimelistMapping[] Mappinglist { get; set; }
|
||||
|
||||
/// <remarks />
|
||||
@ -26,6 +26,18 @@ namespace AnimeLists
|
||||
[XmlAttribute("anidbid")]
|
||||
public string AnidbId { get; set; }
|
||||
|
||||
/// <remarks />
|
||||
[XmlAttribute("anisearch")]
|
||||
public string AniSearchId { get; set; }
|
||||
|
||||
/// <remarks />
|
||||
[XmlAttribute("proxer")]
|
||||
public string ProxerId { get; set; }
|
||||
|
||||
/// <remarks />
|
||||
[XmlAttribute("myanimelist")]
|
||||
public string MyAnimeListId { get; set; }
|
||||
|
||||
/// <remarks />
|
||||
[XmlAttribute("tvdbid")]
|
||||
public string TvdbId { get; set; }
|
||||
|
@ -7,11 +7,11 @@ namespace AnimeLists
|
||||
public class AnimelistSupplementalinfo
|
||||
{
|
||||
/// <remarks />
|
||||
[XmlElement("credits", typeof (string))]
|
||||
[XmlElement("director", typeof (string))]
|
||||
[XmlElement("fanart", typeof (AnimelistSupplementalinfoFanart))]
|
||||
[XmlElement("genre", typeof (string))]
|
||||
[XmlElement("studio", typeof (string))]
|
||||
[XmlElement("credits", typeof(string))]
|
||||
[XmlElement("director", typeof(string))]
|
||||
[XmlElement("fanart", typeof(AnimelistSupplementalinfoFanart))]
|
||||
[XmlElement("genre", typeof(string))]
|
||||
[XmlElement("studio", typeof(string))]
|
||||
[XmlChoiceIdentifier("ItemsElementName")]
|
||||
public object[] Items { get; set; }
|
||||
|
||||
|
@ -1,7 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@ -87,4 +85,4 @@ namespace AnimeLists
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -31,7 +31,7 @@ namespace AnimeLists
|
||||
}
|
||||
}
|
||||
|
||||
XmlSerializer serializer = new XmlSerializer(typeof (Animelist));
|
||||
XmlSerializer serializer = new XmlSerializer(typeof(Animelist));
|
||||
|
||||
using (var stream = File.OpenRead(_temp))
|
||||
return serializer.Deserialize(stream) as Animelist;
|
||||
|
@ -39,7 +39,7 @@ namespace AnimeLists
|
||||
List<AnimelistAnime> animeList;
|
||||
if (!_tvdbMappings.TryGetValue(tvdb.Series, out animeList))
|
||||
return null;
|
||||
|
||||
|
||||
// look for exact mapping in mapping list
|
||||
foreach (var anime in animeList.Where(x => x.Mappinglist != null))
|
||||
{
|
||||
@ -61,9 +61,9 @@ namespace AnimeLists
|
||||
}
|
||||
|
||||
var seasonMatch = animeList
|
||||
.Select(x => new {Season = Parse(x.DefaultTvdbSeason), Match = x})
|
||||
.Select(x => new { Season = Parse(x.DefaultTvdbSeason), Match = x })
|
||||
.Where(x => x.Season == tvdb.Season)
|
||||
.Select(x => new {Offset = x.Match.EpisodeOffsetSpecified ? x.Match.EpisodeOffset : 0, x.Match})
|
||||
.Select(x => new { Offset = x.Match.EpisodeOffsetSpecified ? x.Match.EpisodeOffset : 0, x.Match })
|
||||
.Where(x => x.Offset <= tvdb.Index)
|
||||
.OrderByDescending(x => x.Offset)
|
||||
.FirstOrDefault();
|
||||
@ -101,7 +101,7 @@ namespace AnimeLists
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public TvdbEpisode ToTvdb(AnidbEpisode anidb)
|
||||
{
|
||||
AnimelistAnime anime;
|
||||
|
Loading…
Reference in New Issue
Block a user