167 lines
5.9 KiB
C#
167 lines
5.9 KiB
C#
using ErsatzTV.Core;
|
|
using ErsatzTV.Core.Domain;
|
|
using ErsatzTV.Core.Interfaces.Emby;
|
|
using ErsatzTV.Core.Interfaces.Repositories;
|
|
using ErsatzTV.Scanner.Core.Interfaces;
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
namespace ErsatzTV.Scanner.Core.Emby;
|
|
|
|
public class EmbyCollectionScanner : IEmbyCollectionScanner
|
|
{
|
|
private readonly IEmbyApiClient _embyApiClient;
|
|
private readonly IScannerProxy _scannerProxy;
|
|
private readonly IEmbyCollectionRepository _embyCollectionRepository;
|
|
private readonly ILogger<EmbyCollectionScanner> _logger;
|
|
|
|
public EmbyCollectionScanner(
|
|
IScannerProxy scannerProxy,
|
|
IEmbyCollectionRepository embyCollectionRepository,
|
|
IEmbyApiClient embyApiClient,
|
|
ILogger<EmbyCollectionScanner> logger)
|
|
{
|
|
_scannerProxy = scannerProxy;
|
|
_embyCollectionRepository = embyCollectionRepository;
|
|
_embyApiClient = embyApiClient;
|
|
_logger = logger;
|
|
}
|
|
|
|
public async Task<Either<BaseError, Unit>> ScanCollections(string address, string apiKey, bool deepScan)
|
|
{
|
|
try
|
|
{
|
|
// need to call get libraries to find library that contains collections (box sets)
|
|
await _embyApiClient.GetLibraries(address, apiKey);
|
|
|
|
var incomingItemIds = new List<string>();
|
|
|
|
// get all collections from db (item id, etag)
|
|
List<EmbyCollection> existingCollections = await _embyCollectionRepository.GetCollections();
|
|
|
|
await foreach ((EmbyCollection collection, int _) in _embyApiClient.GetCollectionLibraryItems(
|
|
address,
|
|
apiKey))
|
|
{
|
|
incomingItemIds.Add(collection.ItemId);
|
|
|
|
Option<EmbyCollection> maybeExisting = existingCollections.Find(c => c.ItemId == collection.ItemId);
|
|
|
|
// skip if unchanged (etag)
|
|
if (!deepScan && await maybeExisting.Map(e => e.Etag ?? string.Empty).IfNoneAsync(string.Empty) ==
|
|
collection.Etag)
|
|
{
|
|
_logger.LogDebug("Emby collection {Name} is unchanged", collection.Name);
|
|
continue;
|
|
}
|
|
|
|
// add if new
|
|
if (maybeExisting.IsNone)
|
|
{
|
|
_logger.LogDebug("Emby collection {Name} is new", collection.Name);
|
|
await _embyCollectionRepository.AddCollection(collection);
|
|
}
|
|
|
|
if (await SyncCollectionItems(address, apiKey, collection))
|
|
{
|
|
// save collection etag
|
|
await _embyCollectionRepository.SetEtag(collection);
|
|
}
|
|
}
|
|
|
|
// remove missing collections (and remove any lingering tags from those collections)
|
|
foreach (EmbyCollection collection in existingCollections.Filter(e => !incomingItemIds.Contains(e.ItemId)))
|
|
{
|
|
await _embyCollectionRepository.RemoveCollection(collection);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogWarning(ex, "Failed to get collections from Emby");
|
|
return BaseError.New(ex.Message);
|
|
}
|
|
|
|
return Unit.Default;
|
|
}
|
|
|
|
private async Task<bool> SyncCollectionItems(string address, string apiKey, EmbyCollection collection)
|
|
{
|
|
try
|
|
{
|
|
// get collection items from Emby
|
|
IAsyncEnumerable<Tuple<MediaItem, int>> items = _embyApiClient.GetCollectionItems(
|
|
address,
|
|
apiKey,
|
|
collection.ItemId);
|
|
|
|
List<int> removedIds = await _embyCollectionRepository.RemoveAllTags(collection);
|
|
|
|
var movies = 0;
|
|
var shows = 0;
|
|
var seasons = 0;
|
|
var episodes = 0;
|
|
|
|
// sync tags on items
|
|
var addedIds = new List<int>();
|
|
await foreach ((MediaItem item, int _) in items)
|
|
{
|
|
Option<int> maybeId = await _embyCollectionRepository.AddTag(item, collection);
|
|
foreach (int id in maybeId)
|
|
{
|
|
addedIds.Add(id);
|
|
|
|
switch (item)
|
|
{
|
|
case Movie:
|
|
movies++;
|
|
break;
|
|
case Show:
|
|
shows++;
|
|
break;
|
|
case Season:
|
|
seasons++;
|
|
break;
|
|
case Episode:
|
|
episodes++;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (addedIds.Count > 0)
|
|
{
|
|
_logger.LogDebug(
|
|
"Emby collection {Name} contains {Count} items ({Movies} movies, {Shows} shows, {Seasons} seasons, {Episodes} episodes)",
|
|
collection.Name,
|
|
addedIds.Count,
|
|
movies,
|
|
shows,
|
|
seasons,
|
|
episodes);
|
|
}
|
|
else
|
|
{
|
|
_logger.LogDebug("Emby collection {Name} contains no items that are also in ErsatzTV", collection.Name);
|
|
}
|
|
|
|
int[] changedIds = removedIds.Concat(addedIds).Distinct().ToArray();
|
|
// if (changedIds.Length > 0)
|
|
// {
|
|
// _logger.LogDebug("Reindexing ids {Ids}", changedIds.ToList());
|
|
// }
|
|
|
|
if (!await _scannerProxy.ReindexMediaItems(changedIds, CancellationToken.None))
|
|
{
|
|
_logger.LogWarning("Failed to reindex media items from scanner process");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogWarning(ex, "Failed to synchronize Emby collection {Name}", collection.Name);
|
|
return false;
|
|
}
|
|
}
|
|
}
|