mirror of
https://github.com/cxfksword/jellyfin-plugin-danmu.git
synced 2026-07-03 02:56:35 +08:00
refactor: merge metadata provider id to one
This commit is contained in:
105
Jellyfin.Plugin.Danmu.Test/DanmuProviderIdTest.cs
Normal file
105
Jellyfin.Plugin.Danmu.Test/DanmuProviderIdTest.cs
Normal file
@@ -0,0 +1,105 @@
|
||||
using System;
|
||||
using Jellyfin.Plugin.Danmu.Core;
|
||||
using Jellyfin.Plugin.Danmu.Scrapers;
|
||||
using Jellyfin.Plugin.Danmu.Scrapers.Tencent;
|
||||
using MediaBrowser.Controller.Entities.Movies;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Jellyfin.Plugin.Danmu.Test;
|
||||
|
||||
[TestClass]
|
||||
public class DanmuProviderIdTest
|
||||
{
|
||||
private static readonly ILoggerFactory TestLoggerFactory = LoggerFactory.Create(builder => { });
|
||||
|
||||
[DataTestMethod]
|
||||
[DataRow("BilibiliID", "bilibili")]
|
||||
[DataRow("DandanID", "dandan")]
|
||||
[DataRow("DanmuApiID", "danmuapi")]
|
||||
[DataRow("IqiyiID", "iqiyi")]
|
||||
[DataRow("MgtvID", "mgtv")]
|
||||
[DataRow("TencentID", "tencent")]
|
||||
[DataRow("YoukuID", "youku")]
|
||||
public void Encode_UsesMappedLowercasePrefix(string scraperProviderId, string expectedPrefix)
|
||||
{
|
||||
var encodedValue = DanmuProviderId.Encode(scraperProviderId, "provider-value");
|
||||
|
||||
Assert.AreEqual($"{expectedPrefix}:provider-value", encodedValue);
|
||||
}
|
||||
|
||||
[DataTestMethod]
|
||||
[DataRow("TencentID:g41000zu2yv", "TencentID", "g41000zu2yv")]
|
||||
[DataRow("tencent:g41000zu2yv", "TencentID", "g41000zu2yv")]
|
||||
public void TryDecode_SupportsLegacyAndMappedPrefix(string rawValue, string expectedScraperProviderId, string expectedProviderValue)
|
||||
{
|
||||
var success = DanmuProviderId.TryDecode(rawValue, out var scraperProviderId, out var providerValue);
|
||||
|
||||
Assert.IsTrue(success);
|
||||
Assert.AreEqual(expectedScraperProviderId, scraperProviderId);
|
||||
Assert.AreEqual(expectedProviderValue, providerValue);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Set_WritesMappedUnifiedProviderId()
|
||||
{
|
||||
var item = new Movie();
|
||||
|
||||
DanmuProviderId.Set(item, Array.Empty<AbstractScraper>(), Tencent.ScraperProviderId, "g41000zu2yv");
|
||||
|
||||
Assert.AreEqual("tencent:g41000zu2yv", item.ProviderIds[DanmuProviderId.UnifiedProviderId]);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TryGet_ReadsMappedUnifiedProviderIdWithLegacyScraperProviderId()
|
||||
{
|
||||
var item = new Movie();
|
||||
item.ProviderIds[DanmuProviderId.UnifiedProviderId] = "tencent:g41000zu2yv";
|
||||
|
||||
var success = DanmuProviderId.TryGet(item, Tencent.ScraperProviderId, out var providerValue);
|
||||
|
||||
Assert.IsTrue(success);
|
||||
Assert.AreEqual("g41000zu2yv", providerValue);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TryMigrateToUnified_ConvertsLegacyScraperProviderIdToUnifiedProviderId()
|
||||
{
|
||||
var item = new Movie();
|
||||
item.ProviderIds[Tencent.ScraperProviderId] = "g41000zu2yv";
|
||||
|
||||
var migrated = DanmuProviderId.TryMigrateToUnified(item, CreateScrapers(), Tencent.ScraperProviderId, "g41000zu2yv");
|
||||
|
||||
Assert.IsTrue(migrated);
|
||||
Assert.IsFalse(item.ProviderIds.ContainsKey(Tencent.ScraperProviderId));
|
||||
Assert.AreEqual("tencent:g41000zu2yv", item.ProviderIds[DanmuProviderId.UnifiedProviderId]);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TryMigrateToUnified_RewritesLegacyUnifiedValueToCanonicalValue()
|
||||
{
|
||||
var item = new Movie();
|
||||
item.ProviderIds[DanmuProviderId.UnifiedProviderId] = "TencentID:g41000zu2yv";
|
||||
|
||||
var migrated = DanmuProviderId.TryMigrateToUnified(item, CreateScrapers(), Tencent.ScraperProviderId, "g41000zu2yv");
|
||||
|
||||
Assert.IsTrue(migrated);
|
||||
Assert.AreEqual("tencent:g41000zu2yv", item.ProviderIds[DanmuProviderId.UnifiedProviderId]);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TryMigrateToUnified_SkipsCanonicalUnifiedValue()
|
||||
{
|
||||
var item = new Movie();
|
||||
item.ProviderIds[DanmuProviderId.UnifiedProviderId] = "tencent:g41000zu2yv";
|
||||
|
||||
var migrated = DanmuProviderId.TryMigrateToUnified(item, CreateScrapers(), Tencent.ScraperProviderId, "g41000zu2yv");
|
||||
|
||||
Assert.IsFalse(migrated);
|
||||
Assert.AreEqual("tencent:g41000zu2yv", item.ProviderIds[DanmuProviderId.UnifiedProviderId]);
|
||||
}
|
||||
|
||||
private static AbstractScraper[] CreateScrapers()
|
||||
{
|
||||
return new AbstractScraper[] { new Tencent(TestLoggerFactory) };
|
||||
}
|
||||
}
|
||||
@@ -2,12 +2,15 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Plugin.Danmu.Core;
|
||||
using Jellyfin.Plugin.Danmu.Model;
|
||||
using Jellyfin.Plugin.Danmu.Scrapers;
|
||||
using Jellyfin.Plugin.Danmu.Scrapers.Bilibili;
|
||||
using Jellyfin.Plugin.Danmu.Scrapers.Dandan;
|
||||
using Jellyfin.Plugin.Danmu.Scrapers.Tencent;
|
||||
using MediaBrowser.Common;
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Common.Net;
|
||||
@@ -289,6 +292,41 @@ namespace Jellyfin.Plugin.Danmu.Test
|
||||
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ProcessQueuedUpdateMeta_ShouldKeepUnifiedProviderId_WhenQueueItemAndItemAreSameInstance()
|
||||
{
|
||||
var scraperManager = new ScraperManager(loggerFactory);
|
||||
scraperManager.Register(new Tencent(loggerFactory));
|
||||
|
||||
var fileSystemStub = new Mock<Jellyfin.Plugin.Danmu.Core.IFileSystem>();
|
||||
var itemRepositoryStub = new Mock<IItemRepository>();
|
||||
var libraryManagerStub = new Mock<ILibraryManager>();
|
||||
var currentItem = new Movie
|
||||
{
|
||||
Name = "test",
|
||||
ProviderIds = new Dictionary<string, string>
|
||||
{
|
||||
[DanmuProviderId.UnifiedProviderId] = "tencent:p4101tg0b9n",
|
||||
},
|
||||
};
|
||||
|
||||
libraryManagerStub
|
||||
.Setup(x => x.GetItemById(It.IsAny<Guid>()))
|
||||
.Returns(currentItem);
|
||||
libraryManagerStub
|
||||
.Setup(x => x.RunMetadataSavers(It.IsAny<BaseItem>(), It.IsAny<ItemUpdateType>()))
|
||||
.Returns(Task.CompletedTask);
|
||||
|
||||
var libraryManagerEventsHelper = new LibraryManagerEventsHelper(itemRepositoryStub.Object, libraryManagerStub.Object, loggerFactory, fileSystemStub.Object, scraperManager);
|
||||
var queue = new List<BaseItem> { currentItem };
|
||||
var processQueuedUpdateMeta = typeof(LibraryManagerEventsHelper).GetMethod("ProcessQueuedUpdateMeta", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
|
||||
var task = (Task)processQueuedUpdateMeta!.Invoke(libraryManagerEventsHelper, new object[] { queue })!;
|
||||
task.GetAwaiter().GetResult();
|
||||
|
||||
Assert.AreEqual("tencent:p4101tg0b9n", currentItem.ProviderIds[DanmuProviderId.UnifiedProviderId]);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestDownloadDanmu()
|
||||
{
|
||||
|
||||
199
Jellyfin.Plugin.Danmu/Core/DanmuProviderId.cs
Normal file
199
Jellyfin.Plugin.Danmu/Core/DanmuProviderId.cs
Normal file
@@ -0,0 +1,199 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Jellyfin.Plugin.Danmu.Scrapers;
|
||||
using Jellyfin.Plugin.Danmu.Scrapers.Bilibili;
|
||||
using Jellyfin.Plugin.Danmu.Scrapers.Dandan;
|
||||
using Jellyfin.Plugin.Danmu.Scrapers.DanmuApi;
|
||||
using Jellyfin.Plugin.Danmu.Scrapers.Iqiyi;
|
||||
using Jellyfin.Plugin.Danmu.Scrapers.Mgtv;
|
||||
using Jellyfin.Plugin.Danmu.Scrapers.Tencent;
|
||||
using Jellyfin.Plugin.Danmu.Scrapers.Youku;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Model.Entities;
|
||||
|
||||
namespace Jellyfin.Plugin.Danmu.Core;
|
||||
|
||||
public static class DanmuProviderId
|
||||
{
|
||||
public const string UnifiedProviderId = "DanmuID";
|
||||
public const string UnifiedProviderName = "Danmu";
|
||||
|
||||
private const char Separator = ':';
|
||||
|
||||
private static readonly IReadOnlyDictionary<string, string> ScraperProviderIdToPrefixMap = new Dictionary<string, string>(StringComparer.Ordinal)
|
||||
{
|
||||
[Bilibili.ScraperProviderId] = "bilibili",
|
||||
[Dandan.ScraperProviderId] = "dandan",
|
||||
[DanmuApi.ScraperProviderId] = "danmuapi",
|
||||
[Iqiyi.ScraperProviderId] = "iqiyi",
|
||||
[Mgtv.ScraperProviderId] = "mgtv",
|
||||
[Tencent.ScraperProviderId] = "tencent",
|
||||
[Youku.ScraperProviderId] = "youku",
|
||||
};
|
||||
|
||||
private static readonly IReadOnlyDictionary<string, string> PrefixToScraperProviderIdMap = ScraperProviderIdToPrefixMap
|
||||
.ToDictionary(pair => pair.Value, pair => pair.Key, StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
public static string Encode(string scraperProviderId, string providerValue)
|
||||
{
|
||||
return $"{ToPrefix(scraperProviderId)}{Separator}{providerValue}";
|
||||
}
|
||||
|
||||
public static bool TryDecode(string? value, out string scraperProviderId, out string providerValue)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(value))
|
||||
{
|
||||
scraperProviderId = string.Empty;
|
||||
providerValue = string.Empty;
|
||||
return false;
|
||||
}
|
||||
|
||||
var separatorIndex = value.IndexOf(Separator);
|
||||
if (separatorIndex <= 0 || separatorIndex >= value.Length - 1)
|
||||
{
|
||||
scraperProviderId = string.Empty;
|
||||
providerValue = string.Empty;
|
||||
return false;
|
||||
}
|
||||
|
||||
scraperProviderId = ToScraperProviderId(value[..separatorIndex]);
|
||||
providerValue = value[(separatorIndex + 1)..];
|
||||
return true;
|
||||
}
|
||||
|
||||
public static string Get(IHasProviderIds item, string scraperProviderId)
|
||||
{
|
||||
return TryGet(item, scraperProviderId, out var providerValue) ? providerValue : string.Empty;
|
||||
}
|
||||
|
||||
public static bool TryGet(IHasProviderIds item, string scraperProviderId, out string providerValue)
|
||||
{
|
||||
if (item.ProviderIds.ContainsKey(UnifiedProviderId))
|
||||
{
|
||||
if (TryGetUnified(item, out var matchedProviderId, out var unifiedProviderValue)
|
||||
&& string.Equals(matchedProviderId, scraperProviderId, StringComparison.Ordinal))
|
||||
{
|
||||
providerValue = unifiedProviderValue;
|
||||
return true;
|
||||
}
|
||||
|
||||
providerValue = string.Empty;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (item.ProviderIds.TryGetValue(scraperProviderId, out var legacyProviderValue)
|
||||
&& !string.IsNullOrEmpty(legacyProviderValue))
|
||||
{
|
||||
providerValue = legacyProviderValue;
|
||||
return true;
|
||||
}
|
||||
|
||||
providerValue = string.Empty;
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool TryGetFirst(IHasProviderIds item, IEnumerable<AbstractScraper> scrapers, out AbstractScraper? scraper, out string providerValue)
|
||||
{
|
||||
if (item.ProviderIds.ContainsKey(UnifiedProviderId))
|
||||
{
|
||||
if (TryGetUnified(item, out var unifiedScraperProviderId, out var unifiedProviderValue))
|
||||
{
|
||||
scraper = scrapers.FirstOrDefault(current => string.Equals(current.ProviderId, unifiedScraperProviderId, StringComparison.Ordinal));
|
||||
if (scraper != null)
|
||||
{
|
||||
providerValue = unifiedProviderValue;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
scraper = null;
|
||||
providerValue = string.Empty;
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach (var currentScraper in scrapers)
|
||||
{
|
||||
if (item.ProviderIds.TryGetValue(currentScraper.ProviderId, out var legacyProviderValue)
|
||||
&& !string.IsNullOrEmpty(legacyProviderValue))
|
||||
{
|
||||
scraper = currentScraper;
|
||||
providerValue = legacyProviderValue;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
scraper = null;
|
||||
providerValue = string.Empty;
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool HasAny(IHasProviderIds item, IEnumerable<AbstractScraper> scrapers)
|
||||
{
|
||||
return TryGetFirst(item, scrapers, out _, out _);
|
||||
}
|
||||
|
||||
public static bool TryGetUnified(IHasProviderIds item, out string scraperProviderId, out string providerValue)
|
||||
{
|
||||
if (item.ProviderIds.TryGetValue(UnifiedProviderId, out var rawProviderValue)
|
||||
&& TryDecode(rawProviderValue, out scraperProviderId, out providerValue))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
scraperProviderId = string.Empty;
|
||||
providerValue = string.Empty;
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void Clear(BaseItem item, IEnumerable<AbstractScraper> scrapers)
|
||||
{
|
||||
item.ProviderIds.Remove(UnifiedProviderId);
|
||||
foreach (var scraper in scrapers)
|
||||
{
|
||||
item.ProviderIds.Remove(scraper.ProviderId);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Set(BaseItem item, IEnumerable<AbstractScraper> scrapers, string scraperProviderId, string providerValue)
|
||||
{
|
||||
Clear(item, scrapers);
|
||||
item.SetProviderId(UnifiedProviderId, Encode(scraperProviderId, providerValue));
|
||||
}
|
||||
|
||||
public static bool TryMigrateToUnified(BaseItem item, IEnumerable<AbstractScraper> scrapers, string scraperProviderId, string providerValue)
|
||||
{
|
||||
if (string.IsNullOrEmpty(providerValue))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var scraperList = scrapers as IReadOnlyCollection<AbstractScraper> ?? scrapers.ToArray();
|
||||
var encodedProviderValue = Encode(scraperProviderId, providerValue);
|
||||
var hasCanonicalUnifiedProviderId = item.ProviderIds.TryGetValue(UnifiedProviderId, out var rawProviderValue)
|
||||
&& string.Equals(rawProviderValue, encodedProviderValue, StringComparison.Ordinal);
|
||||
var hasLegacyScraperProviderId = scraperList.Any(scraper => item.ProviderIds.ContainsKey(scraper.ProviderId));
|
||||
|
||||
if (hasCanonicalUnifiedProviderId && !hasLegacyScraperProviderId)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Set(item, scraperList, scraperProviderId, providerValue);
|
||||
return true;
|
||||
}
|
||||
|
||||
private static string ToPrefix(string scraperProviderId)
|
||||
{
|
||||
return ScraperProviderIdToPrefixMap.TryGetValue(scraperProviderId, out var prefix)
|
||||
? prefix
|
||||
: scraperProviderId;
|
||||
}
|
||||
|
||||
private static string ToScraperProviderId(string prefix)
|
||||
{
|
||||
return PrefixToScraperProviderIdMap.TryGetValue(prefix, out var scraperProviderId)
|
||||
? scraperProviderId
|
||||
: prefix;
|
||||
}
|
||||
}
|
||||
42
Jellyfin.Plugin.Danmu/ExternalId/SharedExternalIds.cs
Normal file
42
Jellyfin.Plugin.Danmu/ExternalId/SharedExternalIds.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
using Jellyfin.Plugin.Danmu.Core;
|
||||
using MediaBrowser.Controller.Entities.Movies;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Providers;
|
||||
|
||||
namespace Jellyfin.Plugin.Danmu.ExternalId;
|
||||
|
||||
public abstract class BaseExternalId : IExternalId
|
||||
{
|
||||
public string ProviderName => DanmuProviderId.UnifiedProviderName;
|
||||
|
||||
public string Key => DanmuProviderId.UnifiedProviderId;
|
||||
|
||||
public string UrlFormatString => string.Empty;
|
||||
|
||||
public abstract ExternalIdMediaType? Type { get; }
|
||||
|
||||
public abstract bool Supports(IHasProviderIds item);
|
||||
}
|
||||
|
||||
public class MovieExternalId : BaseExternalId
|
||||
{
|
||||
public override ExternalIdMediaType? Type => ExternalIdMediaType.Movie;
|
||||
|
||||
public override bool Supports(IHasProviderIds item) => item is Movie;
|
||||
}
|
||||
|
||||
public class EpisodeExternalId : BaseExternalId
|
||||
{
|
||||
public override ExternalIdMediaType? Type => ExternalIdMediaType.Episode;
|
||||
|
||||
public override bool Supports(IHasProviderIds item) => item is Episode;
|
||||
}
|
||||
|
||||
public class SeasonExternalId : BaseExternalId
|
||||
{
|
||||
public override ExternalIdMediaType? Type => ExternalIdMediaType.Season;
|
||||
|
||||
public override bool Supports(IHasProviderIds item) => item is Season;
|
||||
}
|
||||
@@ -305,7 +305,7 @@ public class LibraryManagerEventsHelper : IDisposable
|
||||
_logger.LogInformation("[{0}]匹配成功:name={1} ProviderId: {2}", scraper.Name, item.Name, providerVal);
|
||||
|
||||
// 更新epid元数据
|
||||
item.SetProviderId(scraper.ProviderId, providerVal);
|
||||
DanmuProviderId.Set(item, _scraperManager.All(), scraper.ProviderId, providerVal);
|
||||
queueUpdateMeta.Add(item);
|
||||
|
||||
// 下载弹幕
|
||||
@@ -331,15 +331,21 @@ public class LibraryManagerEventsHelper : IDisposable
|
||||
// 更新
|
||||
if (eventType == EventType.Update)
|
||||
{
|
||||
var queueUpdateMeta = new List<BaseItem>();
|
||||
foreach (var item in movies)
|
||||
{
|
||||
foreach (var scraper in _scraperManager.All())
|
||||
{
|
||||
try
|
||||
{
|
||||
var providerVal = item.GetProviderId(scraper.ProviderId);
|
||||
var providerVal = DanmuProviderId.Get(item, scraper.ProviderId);
|
||||
if (!string.IsNullOrEmpty(providerVal))
|
||||
{
|
||||
if (DanmuProviderId.TryMigrateToUnified(item, _scraperManager.All(), scraper.ProviderId, providerVal))
|
||||
{
|
||||
queueUpdateMeta.Add(item);
|
||||
}
|
||||
|
||||
var episode = await scraper.GetMediaEpisode(item, providerVal);
|
||||
if (episode != null)
|
||||
{
|
||||
@@ -361,6 +367,8 @@ public class LibraryManagerEventsHelper : IDisposable
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await ProcessQueuedUpdateMeta(queueUpdateMeta).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
// 强制刷新指定来源弹幕
|
||||
@@ -369,15 +377,7 @@ public class LibraryManagerEventsHelper : IDisposable
|
||||
foreach (var queueItem in movies)
|
||||
{
|
||||
// 找到选择的scraper
|
||||
var scraper = _scraperManager.All().FirstOrDefault(x => queueItem.ProviderIds.ContainsKey(x.ProviderId));
|
||||
if (scraper == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// 获取选择的弹幕Id
|
||||
var mediaId = queueItem.GetProviderId(scraper.ProviderId);
|
||||
if (string.IsNullOrEmpty(mediaId))
|
||||
if (!DanmuProviderId.TryGetFirst(queueItem, _scraperManager.All(), out var scraper, out var mediaId) || scraper == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -525,7 +525,7 @@ public class LibraryManagerEventsHelper : IDisposable
|
||||
|
||||
|
||||
// 更新seasonId元数据
|
||||
season.SetProviderId(scraper.ProviderId, mediaId);
|
||||
DanmuProviderId.Set(season, _scraperManager.All(), scraper.ProviderId, mediaId);
|
||||
queueUpdateMeta.Add(season);
|
||||
|
||||
_logger.LogInformation("[{0}]匹配成功:{1}-{2} season_number:{3} ProviderId: {4}", scraper.Name, series.Name, season.Name, season.IndexNumber, mediaId);
|
||||
@@ -569,12 +569,17 @@ public class LibraryManagerEventsHelper : IDisposable
|
||||
{
|
||||
try
|
||||
{
|
||||
var providerVal = season.GetProviderId(scraper.ProviderId);
|
||||
var providerVal = DanmuProviderId.Get(season, scraper.ProviderId);
|
||||
if (string.IsNullOrEmpty(providerVal))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (DanmuProviderId.TryMigrateToUnified(season, _scraperManager.All(), scraper.ProviderId, providerVal))
|
||||
{
|
||||
queueUpdateMeta.Add(season);
|
||||
}
|
||||
|
||||
var media = await scraper.GetMedia(season, providerVal);
|
||||
if (media == null)
|
||||
{
|
||||
@@ -609,10 +614,10 @@ public class LibraryManagerEventsHelper : IDisposable
|
||||
_logger.LogInformation("[{0}]成功匹配. {1}.{2} -> epId: {3} cid: {4}", scraper.Name, indexNumber, episode.Name, epId, commentId);
|
||||
|
||||
// 更新eposide元数据
|
||||
var episodeProviderVal = episode.GetProviderId(scraper.ProviderId);
|
||||
var episodeProviderVal = DanmuProviderId.Get(episode, scraper.ProviderId);
|
||||
if (!string.IsNullOrEmpty(epId) && episodeProviderVal != epId)
|
||||
{
|
||||
episode.SetProviderId(scraper.ProviderId, epId);
|
||||
DanmuProviderId.Set(episode, _scraperManager.All(), scraper.ProviderId, epId);
|
||||
queueUpdateMeta.Add(episode);
|
||||
}
|
||||
|
||||
@@ -670,20 +675,24 @@ public class LibraryManagerEventsHelper : IDisposable
|
||||
// 如果 Episode 没有弹幕元数据,表示该集是刮削完成后再新增的,需要重新匹配获取
|
||||
var scrapers = this._scraperManager.All();
|
||||
var season = item.Season;
|
||||
var allDanmuProviderIds = scrapers.Select(x => x.ProviderId).ToList();
|
||||
var episodeFirstProviderId = allDanmuProviderIds.FirstOrDefault(x => !string.IsNullOrEmpty(item.GetProviderId(x)));
|
||||
var seasonFirstProviderId = allDanmuProviderIds.FirstOrDefault(x => !string.IsNullOrEmpty(season.GetProviderId(x)));
|
||||
if (string.IsNullOrEmpty(episodeFirstProviderId) && !string.IsNullOrEmpty(seasonFirstProviderId) && item.IndexNumber.HasValue)
|
||||
var hasEpisodeProvider = DanmuProviderId.TryGetFirst(item, scrapers, out _, out _);
|
||||
var hasSeasonProvider = DanmuProviderId.TryGetFirst(season, scrapers, out var seasonScraper, out var seasonProviderVal);
|
||||
if (!hasEpisodeProvider && hasSeasonProvider && seasonScraper != null && item.IndexNumber.HasValue)
|
||||
{
|
||||
var scraper = scrapers.First(x => x.ProviderId == seasonFirstProviderId);
|
||||
var providerVal = season.GetProviderId(seasonFirstProviderId);
|
||||
var scraper = seasonScraper;
|
||||
var providerVal = seasonProviderVal;
|
||||
|
||||
if (scraper == null)
|
||||
{
|
||||
_logger.LogInformation("找不到对应的弹幕来源. ProviderId: {0}", seasonFirstProviderId);
|
||||
_logger.LogInformation("找不到对应的弹幕来源. ProviderId: {0}", string.Empty);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (DanmuProviderId.TryMigrateToUnified(season, _scraperManager.All(), scraper.ProviderId, providerVal))
|
||||
{
|
||||
queueUpdateMeta.Add(season);
|
||||
}
|
||||
|
||||
var media = await scraper.GetMedia(season, providerVal);
|
||||
if (media != null)
|
||||
{
|
||||
@@ -714,10 +723,10 @@ public class LibraryManagerEventsHelper : IDisposable
|
||||
this._logger.LogInformation("[{0}]成功匹配. {1}.{2} -> epId: {3} cid: {4}", scraper.Name, item.IndexNumber, item.Name, epId, commentId);
|
||||
|
||||
// 更新 eposide 元数据
|
||||
var episodeProviderVal = item.GetProviderId(scraper.ProviderId);
|
||||
var episodeProviderVal = DanmuProviderId.Get(item, scraper.ProviderId);
|
||||
if (!string.IsNullOrEmpty(epId) && episodeProviderVal != epId)
|
||||
{
|
||||
item.SetProviderId(scraper.ProviderId, epId);
|
||||
DanmuProviderId.Set(item, _scraperManager.All(), scraper.ProviderId, epId);
|
||||
queueUpdateMeta.Add(item);
|
||||
}
|
||||
|
||||
@@ -733,12 +742,17 @@ public class LibraryManagerEventsHelper : IDisposable
|
||||
{
|
||||
try
|
||||
{
|
||||
var providerVal = item.GetProviderId(scraper.ProviderId);
|
||||
var providerVal = DanmuProviderId.Get(item, scraper.ProviderId);
|
||||
if (string.IsNullOrEmpty(providerVal))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (DanmuProviderId.TryMigrateToUnified(item, _scraperManager.All(), scraper.ProviderId, providerVal))
|
||||
{
|
||||
queueUpdateMeta.Add(item);
|
||||
}
|
||||
|
||||
var episode = await scraper.GetMediaEpisode(item, providerVal);
|
||||
if (episode != null)
|
||||
{
|
||||
@@ -769,15 +783,7 @@ public class LibraryManagerEventsHelper : IDisposable
|
||||
foreach (var queueItem in items)
|
||||
{
|
||||
// 找到选择的scraper
|
||||
var scraper = _scraperManager.All().FirstOrDefault(x => queueItem.ProviderIds.ContainsKey(x.ProviderId));
|
||||
if (scraper == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// 获取选择的弹幕Id
|
||||
var mediaId = queueItem.GetProviderId(scraper.ProviderId);
|
||||
if (string.IsNullOrEmpty(mediaId))
|
||||
if (!DanmuProviderId.TryGetFirst(queueItem, _scraperManager.All(), out var scraper, out var mediaId) || scraper == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -869,14 +875,18 @@ public class LibraryManagerEventsHelper : IDisposable
|
||||
var item = _libraryManager.GetItemById(queueItem.Id);
|
||||
if (item != null)
|
||||
{
|
||||
// 合并新添加的provider id
|
||||
foreach (var pair in queueItem.ProviderIds)
|
||||
{
|
||||
if (string.IsNullOrEmpty(pair.Value))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
var providerIdSnapshot = queueItem.ProviderIds
|
||||
.Where(pair => !string.IsNullOrEmpty(pair.Value))
|
||||
.ToDictionary(pair => pair.Key, pair => pair.Value);
|
||||
|
||||
if (providerIdSnapshot.ContainsKey(DanmuProviderId.UnifiedProviderId))
|
||||
{
|
||||
DanmuProviderId.Clear(item, _scraperManager.All());
|
||||
}
|
||||
|
||||
// 合并新添加的provider id
|
||||
foreach (var pair in providerIdSnapshot)
|
||||
{
|
||||
item.ProviderIds[pair.Key] = pair.Value;
|
||||
}
|
||||
|
||||
@@ -993,13 +1003,7 @@ public class LibraryManagerEventsHelper : IDisposable
|
||||
|
||||
private async Task ForceSaveProviderId(BaseItem item, string providerId, string providerVal)
|
||||
{
|
||||
// 先清空旧弹幕的所有元数据
|
||||
foreach (var s in _scraperManager.All())
|
||||
{
|
||||
item.ProviderIds.Remove(s.ProviderId);
|
||||
}
|
||||
// 保存指定弹幕元数据
|
||||
item.ProviderIds[providerId] = providerVal;
|
||||
DanmuProviderId.Set(item, _scraperManager.All(), providerId, providerVal);
|
||||
|
||||
await this.UpdateItemsAsync(item, CancellationToken.None).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Data.Enums;
|
||||
using Jellyfin.Plugin.Danmu.Core;
|
||||
using Jellyfin.Plugin.Danmu.Core.Extensions;
|
||||
using Jellyfin.Plugin.Danmu.Model;
|
||||
using Jellyfin.Plugin.Danmu.Scrapers;
|
||||
@@ -128,24 +129,19 @@ namespace Jellyfin.Plugin.Danmu.ScheduledTasks
|
||||
|
||||
private bool HasAnyScraperProviderId(ReadOnlyCollection<AbstractScraper> scrapers, BaseItem item)
|
||||
{
|
||||
foreach (var scraper in scrapers)
|
||||
{
|
||||
var providerVal = item.GetProviderId(scraper.ProviderId);
|
||||
if (!string.IsNullOrEmpty(providerVal))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return DanmuProviderId.HasAny(item, scrapers);
|
||||
}
|
||||
|
||||
private Dictionary<string, string> GetScraperFilter(ReadOnlyCollection<AbstractScraper> scrapers)
|
||||
{
|
||||
var filter = new Dictionary<string, string>();
|
||||
var filter = new Dictionary<string, string>
|
||||
{
|
||||
{ DanmuProviderId.UnifiedProviderId, string.Empty }
|
||||
};
|
||||
|
||||
foreach (var scraper in scrapers)
|
||||
{
|
||||
filter.Add(scraper.ProviderId, string.Empty);
|
||||
filter[scraper.ProviderId] = string.Empty;
|
||||
}
|
||||
|
||||
return filter;
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Providers;
|
||||
|
||||
namespace Jellyfin.Plugin.Danmu.Scrapers.Bilibili.ExternalId
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public class EpisodeExternalId : IExternalId
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public string ProviderName => Bilibili.ScraperProviderName;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Key => Bilibili.ScraperProviderId;
|
||||
|
||||
/// <inheritdoc />
|
||||
public ExternalIdMediaType? Type => ExternalIdMediaType.Episode;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Supports(IHasProviderIds item) => item is Episode;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Jellyfin.Plugin.Danmu.Core;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.Movies;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
@@ -22,7 +23,7 @@ public class ExternalUrlProvider : IExternalUrlProvider
|
||||
switch (item)
|
||||
{
|
||||
case Season season:
|
||||
if (item.TryGetProviderId(Bilibili.ScraperProviderId, out var externalId))
|
||||
if (DanmuProviderId.TryGet(item, Bilibili.ScraperProviderId, out var externalId))
|
||||
{
|
||||
if (externalId.StartsWith("bv", StringComparison.OrdinalIgnoreCase) || externalId.StartsWith("av", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
@@ -36,14 +37,14 @@ public class ExternalUrlProvider : IExternalUrlProvider
|
||||
|
||||
break;
|
||||
case Episode episode:
|
||||
if (item.TryGetProviderId(Bilibili.ScraperProviderId, out externalId))
|
||||
if (DanmuProviderId.TryGet(item, Bilibili.ScraperProviderId, out externalId))
|
||||
{
|
||||
yield return $"https://www.bilibili.com/bangumi/play/ep{externalId}";
|
||||
}
|
||||
|
||||
break;
|
||||
case Movie:
|
||||
if (item.TryGetProviderId(Bilibili.ScraperProviderId, out externalId))
|
||||
if (DanmuProviderId.TryGet(item, Bilibili.ScraperProviderId, out externalId))
|
||||
{
|
||||
yield return $"https://www.bilibili.com/bangumi/play/ep{externalId}";
|
||||
}
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Controller.Entities.Movies;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Providers;
|
||||
|
||||
namespace Jellyfin.Plugin.Danmu.Scrapers.Bilibili.ExternalId
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public class MovieExternalId : IExternalId
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public string ProviderName => Bilibili.ScraperProviderName;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Key => Bilibili.ScraperProviderId;
|
||||
|
||||
/// <inheritdoc />
|
||||
public ExternalIdMediaType? Type => ExternalIdMediaType.Movie;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Supports(IHasProviderIds item) => item is Movie;
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Providers;
|
||||
|
||||
namespace Jellyfin.Plugin.Danmu.Scrapers.Bilibili.ExternalId
|
||||
{
|
||||
|
||||
/// <inheritdoc />
|
||||
public class SeasonExternalId : IExternalId
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public string ProviderName => Bilibili.ScraperProviderName;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Key => Bilibili.ScraperProviderId;
|
||||
|
||||
/// <inheritdoc />
|
||||
public ExternalIdMediaType? Type => ExternalIdMediaType.Season;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Supports(IHasProviderIds item) => item is Season;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Providers;
|
||||
|
||||
namespace Jellyfin.Plugin.Danmu.Scrapers.Dandan.ExternalId
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public class EpisodeExternalId : IExternalId
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public string ProviderName => Dandan.ScraperProviderName;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Key => Dandan.ScraperProviderId;
|
||||
|
||||
/// <inheritdoc />
|
||||
public ExternalIdMediaType? Type => ExternalIdMediaType.Episode;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Supports(IHasProviderIds item) => item is Episode;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Jellyfin.Plugin.Danmu.Core;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.Movies;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
@@ -22,21 +23,21 @@ public class ExternalUrlProvider : IExternalUrlProvider
|
||||
switch (item)
|
||||
{
|
||||
case Season season:
|
||||
if (item.TryGetProviderId(Dandan.ScraperProviderId, out var externalId))
|
||||
if (DanmuProviderId.TryGet(item, Dandan.ScraperProviderId, out var externalId))
|
||||
{
|
||||
yield return $"https://api.dandanplay.net/api/v2/bangumi/{externalId}";
|
||||
}
|
||||
|
||||
break;
|
||||
case Episode episode:
|
||||
if (item.TryGetProviderId(Dandan.ScraperProviderId, out externalId))
|
||||
if (DanmuProviderId.TryGet(item, Dandan.ScraperProviderId, out externalId))
|
||||
{
|
||||
yield return "#";
|
||||
}
|
||||
|
||||
break;
|
||||
case Movie:
|
||||
if (item.TryGetProviderId(Dandan.ScraperProviderId, out externalId))
|
||||
if (DanmuProviderId.TryGet(item, Dandan.ScraperProviderId, out externalId))
|
||||
{
|
||||
yield return $"https://api.dandanplay.net/api/v2/bangumi/{externalId}";
|
||||
}
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Controller.Entities.Movies;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Providers;
|
||||
|
||||
namespace Jellyfin.Plugin.Danmu.Scrapers.Dandan.ExternalId
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public class MovieExternalId : IExternalId
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public string ProviderName => Dandan.ScraperProviderName;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Key => Dandan.ScraperProviderId;
|
||||
|
||||
/// <inheritdoc />
|
||||
public ExternalIdMediaType? Type => null;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Supports(IHasProviderIds item) => item is Movie;
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Providers;
|
||||
|
||||
namespace Jellyfin.Plugin.Danmu.Scrapers.Dandan.ExternalId
|
||||
{
|
||||
|
||||
/// <inheritdoc />
|
||||
public class SeasonExternalId : IExternalId
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public string ProviderName => Dandan.ScraperProviderName;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Key => Dandan.ScraperProviderId;
|
||||
|
||||
/// <inheritdoc />
|
||||
public ExternalIdMediaType? Type => null;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Supports(IHasProviderIds item) => item is Season;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Providers;
|
||||
|
||||
namespace Jellyfin.Plugin.Danmu.Scrapers.DanmuApi.ExternalId
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public class EpisodeExternalId : IExternalId
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public string ProviderName => DanmuApi.ScraperProviderName;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Key => DanmuApi.ScraperProviderId;
|
||||
|
||||
/// <inheritdoc />
|
||||
public ExternalIdMediaType? Type => ExternalIdMediaType.Episode;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Supports(IHasProviderIds item) => item is Episode;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Jellyfin.Plugin.Danmu.Core;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.Movies;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
@@ -22,7 +23,7 @@ public class ExternalUrlProvider : IExternalUrlProvider
|
||||
switch (item)
|
||||
{
|
||||
case Season season:
|
||||
if (item.TryGetProviderId(DanmuApi.ScraperProviderId, out var externalId))
|
||||
if (DanmuProviderId.TryGet(item, DanmuApi.ScraperProviderId, out var externalId))
|
||||
{
|
||||
var serverUrl = GetServerUrl();
|
||||
if (!string.IsNullOrEmpty(serverUrl))
|
||||
@@ -37,7 +38,7 @@ public class ExternalUrlProvider : IExternalUrlProvider
|
||||
|
||||
break;
|
||||
case Episode episode:
|
||||
if (item.TryGetProviderId(DanmuApi.ScraperProviderId, out externalId))
|
||||
if (DanmuProviderId.TryGet(item, DanmuApi.ScraperProviderId, out externalId))
|
||||
{
|
||||
var serverUrl = GetServerUrl();
|
||||
if (!string.IsNullOrEmpty(serverUrl))
|
||||
@@ -52,7 +53,7 @@ public class ExternalUrlProvider : IExternalUrlProvider
|
||||
|
||||
break;
|
||||
case Movie:
|
||||
if (item.TryGetProviderId(DanmuApi.ScraperProviderId, out externalId))
|
||||
if (DanmuProviderId.TryGet(item, DanmuApi.ScraperProviderId, out externalId))
|
||||
{
|
||||
var serverUrl = GetServerUrl();
|
||||
if (!string.IsNullOrEmpty(serverUrl))
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
using MediaBrowser.Controller.Entities.Movies;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Providers;
|
||||
|
||||
namespace Jellyfin.Plugin.Danmu.Scrapers.DanmuApi.ExternalId
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public class MovieExternalId : IExternalId
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public string ProviderName => DanmuApi.ScraperProviderName;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Key => DanmuApi.ScraperProviderId;
|
||||
|
||||
/// <inheritdoc />
|
||||
public ExternalIdMediaType? Type => null;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Supports(IHasProviderIds item) => item is Movie;
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Providers;
|
||||
|
||||
namespace Jellyfin.Plugin.Danmu.Scrapers.DanmuApi.ExternalId
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public class SeasonExternalId : IExternalId
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public string ProviderName => DanmuApi.ScraperProviderName;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Key => DanmuApi.ScraperProviderId;
|
||||
|
||||
/// <inheritdoc />
|
||||
public ExternalIdMediaType? Type => null;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Supports(IHasProviderIds item) => item is Season;
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Providers;
|
||||
|
||||
namespace Jellyfin.Plugin.Danmu.Scrapers.Iqiyi.ExternalId
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public class EpisodeExternalId : IExternalId
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public string ProviderName => Iqiyi.ScraperProviderName;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Key => Iqiyi.ScraperProviderId;
|
||||
|
||||
/// <inheritdoc />
|
||||
public ExternalIdMediaType? Type => ExternalIdMediaType.Episode;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Supports(IHasProviderIds item) => item is Episode;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Jellyfin.Plugin.Danmu.Core;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.Movies;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
@@ -22,21 +23,21 @@ public class ExternalUrlProvider : IExternalUrlProvider
|
||||
switch (item)
|
||||
{
|
||||
case Season season:
|
||||
if (item.TryGetProviderId(Iqiyi.ScraperProviderId, out var externalId))
|
||||
if (DanmuProviderId.TryGet(item, Iqiyi.ScraperProviderId, out var externalId))
|
||||
{
|
||||
yield return $"https://www.iqiyi.com/v_{externalId}.html";
|
||||
}
|
||||
|
||||
break;
|
||||
case Episode episode:
|
||||
if (item.TryGetProviderId(Iqiyi.ScraperProviderId, out externalId))
|
||||
if (DanmuProviderId.TryGet(item, Iqiyi.ScraperProviderId, out externalId))
|
||||
{
|
||||
yield return $"https://www.iqiyi.com/v_{externalId}.html";
|
||||
}
|
||||
|
||||
break;
|
||||
case Movie:
|
||||
if (item.TryGetProviderId(Iqiyi.ScraperProviderId, out externalId))
|
||||
if (DanmuProviderId.TryGet(item, Iqiyi.ScraperProviderId, out externalId))
|
||||
{
|
||||
yield return $"https://www.iqiyi.com/v_{externalId}.html";
|
||||
}
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Controller.Entities.Movies;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Providers;
|
||||
|
||||
namespace Jellyfin.Plugin.Danmu.Scrapers.Iqiyi.ExternalId
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public class MovieExternalId : IExternalId
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public string ProviderName => Iqiyi.ScraperProviderName;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Key => Iqiyi.ScraperProviderId;
|
||||
|
||||
/// <inheritdoc />
|
||||
public ExternalIdMediaType? Type => null;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Supports(IHasProviderIds item) => item is Movie;
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Providers;
|
||||
|
||||
namespace Jellyfin.Plugin.Danmu.Scrapers.Iqiyi.ExternalId
|
||||
{
|
||||
|
||||
/// <inheritdoc />
|
||||
public class SeasonExternalId : IExternalId
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public string ProviderName => Iqiyi.ScraperProviderName;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Key => Iqiyi.ScraperProviderId;
|
||||
|
||||
/// <inheritdoc />
|
||||
public ExternalIdMediaType? Type => null;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Supports(IHasProviderIds item) => item is Season;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Providers;
|
||||
|
||||
namespace Jellyfin.Plugin.Danmu.Scrapers.Mgtv.ExternalId
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public class EpisodeExternalId : IExternalId
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public string ProviderName => Mgtv.ScraperProviderName;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Key => Mgtv.ScraperProviderId;
|
||||
|
||||
/// <inheritdoc />
|
||||
public ExternalIdMediaType? Type => ExternalIdMediaType.Episode;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Supports(IHasProviderIds item) => item is Episode;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Jellyfin.Plugin.Danmu.Core;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.Movies;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
@@ -22,16 +23,16 @@ public class ExternalUrlProvider : IExternalUrlProvider
|
||||
switch (item)
|
||||
{
|
||||
case Season season:
|
||||
if (item.TryGetProviderId(Mgtv.ScraperProviderId, out var externalId))
|
||||
if (DanmuProviderId.TryGet(item, Mgtv.ScraperProviderId, out var externalId))
|
||||
{
|
||||
yield return $"https://www.mgtv.com/h/{externalId}.html";
|
||||
}
|
||||
|
||||
break;
|
||||
case Episode episode:
|
||||
if (item.TryGetProviderId(Mgtv.ScraperProviderId, out externalId))
|
||||
if (DanmuProviderId.TryGet(item, Mgtv.ScraperProviderId, out externalId))
|
||||
{
|
||||
if (episode.Season?.TryGetProviderId(Mgtv.ScraperProviderId, out var seasonExternalId) == true)
|
||||
if (episode.Season != null && DanmuProviderId.TryGet(episode.Season, Mgtv.ScraperProviderId, out var seasonExternalId))
|
||||
{
|
||||
yield return $"https://www.mgtv.com/b/{seasonExternalId}/{externalId}.html";
|
||||
}
|
||||
@@ -43,7 +44,7 @@ public class ExternalUrlProvider : IExternalUrlProvider
|
||||
|
||||
break;
|
||||
case Movie:
|
||||
if (item.TryGetProviderId(Mgtv.ScraperProviderId, out externalId))
|
||||
if (DanmuProviderId.TryGet(item, Mgtv.ScraperProviderId, out externalId))
|
||||
{
|
||||
yield return $"https://www.mgtv.com/h/{externalId}.html";
|
||||
}
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Controller.Entities.Movies;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Providers;
|
||||
|
||||
namespace Jellyfin.Plugin.Danmu.Scrapers.Mgtv.ExternalId
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public class MovieExternalId : IExternalId
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public string ProviderName => Mgtv.ScraperProviderName;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Key => Mgtv.ScraperProviderId;
|
||||
|
||||
/// <inheritdoc />
|
||||
public ExternalIdMediaType? Type => null;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Supports(IHasProviderIds item) => item is Movie;
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Providers;
|
||||
|
||||
namespace Jellyfin.Plugin.Danmu.Scrapers.Mgtv.ExternalId
|
||||
{
|
||||
|
||||
/// <inheritdoc />
|
||||
public class SeasonExternalId : IExternalId
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public string ProviderName => Mgtv.ScraperProviderName;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Key => Mgtv.ScraperProviderId;
|
||||
|
||||
/// <inheritdoc />
|
||||
public ExternalIdMediaType? Type => null;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Supports(IHasProviderIds item) => item is Season;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Plugin.Danmu.Core;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Jellyfin.Plugin.Danmu.Scrapers.Entity;
|
||||
@@ -176,7 +177,7 @@ public class Mgtv : AbstractScraper
|
||||
// 从季信息元数据中,获取cid值
|
||||
// 不能通过GetParent获取Season,因为没有SXX季文件夹时,GetParent是Series
|
||||
var season = ((MediaBrowser.Controller.Entities.TV.Episode)item).Season;
|
||||
season.ProviderIds.TryGetValue(ScraperProviderId, out var cid);
|
||||
DanmuProviderId.TryGet(season, ScraperProviderId, out var cid);
|
||||
return new ScraperEpisode() { Id = id, CommentId = $"{cid},{id}" };
|
||||
}
|
||||
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Providers;
|
||||
|
||||
namespace Jellyfin.Plugin.Danmu.Scrapers.Tencent.ExternalId
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public class EpisodeExternalId : IExternalId
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public string ProviderName => Tencent.ScraperProviderName;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Key => Tencent.ScraperProviderId;
|
||||
|
||||
/// <inheritdoc />
|
||||
public ExternalIdMediaType? Type => ExternalIdMediaType.Episode;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Supports(IHasProviderIds item) => item is Episode;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Jellyfin.Plugin.Danmu.Core;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.Movies;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
@@ -22,16 +23,16 @@ public class ExternalUrlProvider : IExternalUrlProvider
|
||||
switch (item)
|
||||
{
|
||||
case Season season:
|
||||
if (item.TryGetProviderId(Tencent.ScraperProviderId, out var externalId))
|
||||
if (DanmuProviderId.TryGet(item, Tencent.ScraperProviderId, out var externalId))
|
||||
{
|
||||
yield return $"https://v.qq.com/x/cover/{externalId}.html";
|
||||
}
|
||||
|
||||
break;
|
||||
case Episode episode:
|
||||
if (item.TryGetProviderId(Tencent.ScraperProviderId, out externalId))
|
||||
if (DanmuProviderId.TryGet(item, Tencent.ScraperProviderId, out externalId))
|
||||
{
|
||||
if (episode.Season?.TryGetProviderId(Tencent.ScraperProviderId, out var seasonExternalId) == true)
|
||||
if (episode.Season != null && DanmuProviderId.TryGet(episode.Season, Tencent.ScraperProviderId, out var seasonExternalId))
|
||||
{
|
||||
yield return $"https://v.qq.com/x/cover/{seasonExternalId}/{externalId}.html";
|
||||
}
|
||||
@@ -43,7 +44,7 @@ public class ExternalUrlProvider : IExternalUrlProvider
|
||||
|
||||
break;
|
||||
case Movie:
|
||||
if (item.TryGetProviderId(Tencent.ScraperProviderId, out externalId))
|
||||
if (DanmuProviderId.TryGet(item, Tencent.ScraperProviderId, out externalId))
|
||||
{
|
||||
yield return $"https://v.qq.com/x/cover/{externalId}.html";
|
||||
}
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Controller.Entities.Movies;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Providers;
|
||||
|
||||
namespace Jellyfin.Plugin.Danmu.Scrapers.Tencent.ExternalId
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public class MovieExternalId : IExternalId
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public string ProviderName => Tencent.ScraperProviderName;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Key => Tencent.ScraperProviderId;
|
||||
|
||||
/// <inheritdoc />
|
||||
public ExternalIdMediaType? Type => null;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Supports(IHasProviderIds item) => item is Movie;
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Providers;
|
||||
|
||||
namespace Jellyfin.Plugin.Danmu.Scrapers.Tencent.ExternalId
|
||||
{
|
||||
|
||||
/// <inheritdoc />
|
||||
public class SeasonExternalId : IExternalId
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public string ProviderName => Tencent.ScraperProviderName;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Key => Tencent.ScraperProviderId;
|
||||
|
||||
/// <inheritdoc />
|
||||
public ExternalIdMediaType? Type => null;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Supports(IHasProviderIds item) => item is Season;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Providers;
|
||||
|
||||
namespace Jellyfin.Plugin.Danmu.Scrapers.Youku.ExternalId
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public class EpisodeExternalId : IExternalId
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public string ProviderName => Youku.ScraperProviderName;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Key => Youku.ScraperProviderId;
|
||||
|
||||
/// <inheritdoc />
|
||||
public ExternalIdMediaType? Type => ExternalIdMediaType.Episode;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Supports(IHasProviderIds item) => item is Episode;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Web;
|
||||
using System.Collections.Generic;
|
||||
using Jellyfin.Plugin.Danmu.Core;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.Movies;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
@@ -23,14 +24,14 @@ public class ExternalUrlProvider : IExternalUrlProvider
|
||||
switch (item)
|
||||
{
|
||||
case Season season:
|
||||
if (item.TryGetProviderId(Youku.ScraperProviderId, out var externalId))
|
||||
if (DanmuProviderId.TryGet(item, Youku.ScraperProviderId, out var externalId))
|
||||
{
|
||||
yield return $"https://v.youku.com/v_nextstage/id_{externalId}.html";
|
||||
}
|
||||
|
||||
break;
|
||||
case Episode episode:
|
||||
if (item.TryGetProviderId(Youku.ScraperProviderId, out externalId))
|
||||
if (DanmuProviderId.TryGet(item, Youku.ScraperProviderId, out externalId))
|
||||
{
|
||||
var decodeExternalId = HttpUtility.UrlDecode(externalId).Replace("||", "==");
|
||||
yield return $"https://v.youku.com/v_show/id_{decodeExternalId}.html";
|
||||
@@ -38,7 +39,7 @@ public class ExternalUrlProvider : IExternalUrlProvider
|
||||
|
||||
break;
|
||||
case Movie:
|
||||
if (item.TryGetProviderId(Youku.ScraperProviderId, out externalId))
|
||||
if (DanmuProviderId.TryGet(item, Youku.ScraperProviderId, out externalId))
|
||||
{
|
||||
yield return $"https://v.youku.com/v_nextstage/id_{externalId}.html";
|
||||
}
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Controller.Entities.Movies;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Providers;
|
||||
|
||||
namespace Jellyfin.Plugin.Danmu.Scrapers.Youku.ExternalId
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public class MovieExternalId : IExternalId
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public string ProviderName => Youku.ScraperProviderName;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Key => Youku.ScraperProviderId;
|
||||
|
||||
/// <inheritdoc />
|
||||
public ExternalIdMediaType? Type => null;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string UrlFormatString => "https://v.youku.com/v_show/id_{0}.html";
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Supports(IHasProviderIds item) => item is Movie;
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Providers;
|
||||
|
||||
namespace Jellyfin.Plugin.Danmu.Scrapers.Youku.ExternalId
|
||||
{
|
||||
|
||||
/// <inheritdoc />
|
||||
public class SeasonExternalId : IExternalId
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public string ProviderName => Youku.ScraperProviderName;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Key => Youku.ScraperProviderId;
|
||||
|
||||
/// <inheritdoc />
|
||||
public ExternalIdMediaType? Type => null;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string UrlFormatString => "https://v.youku.com/v_nextstage/id_{0}.html";
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Supports(IHasProviderIds item) => item is Season;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user