mirror of
https://github.com/Ombi-app/Ombi.git
synced 2025-08-24 06:55:23 -07:00
First step towards played sync
This commit is contained in:
parent
605e746fce
commit
9c84acb6fa
19 changed files with 1018 additions and 118 deletions
|
@ -248,5 +248,36 @@ namespace Ombi.Api.Emby
|
||||||
req.AddContentHeader("Content-Type", "application/json");
|
req.AddContentHeader("Content-Type", "application/json");
|
||||||
req.AddHeader("Device", "Ombi");
|
req.AddHeader("Device", "Ombi");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<EmbyItemContainer<EmbyMovie>> GetMoviesPlayed(string apiKey, string parentIdFilder, int startIndex, int count, string userId, string baseUri)
|
||||||
|
{
|
||||||
|
return await GetPlayed<EmbyMovie>("Movie", apiKey, userId, baseUri, startIndex, count, parentIdFilder);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<EmbyItemContainer<T>> GetPlayed<T>(string type, string apiKey, string userId, string baseUri, int startIndex, int count, string parentIdFilder = default)
|
||||||
|
{
|
||||||
|
var request = new Request($"emby/items", baseUri, HttpMethod.Get);
|
||||||
|
|
||||||
|
request.AddQueryString("Recursive", true.ToString());
|
||||||
|
request.AddQueryString("IncludeItemTypes", type);
|
||||||
|
request.AddQueryString("Fields", "ProviderIds");
|
||||||
|
request.AddQueryString("UserId", userId);
|
||||||
|
|
||||||
|
// paginate and display recently played items first
|
||||||
|
request.AddQueryString("sortBy", "DatePlayed");
|
||||||
|
request.AddQueryString("SortOrder", "Descending");
|
||||||
|
request.AddQueryString("startIndex", startIndex.ToString());
|
||||||
|
request.AddQueryString("limit", count.ToString());
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(parentIdFilder))
|
||||||
|
{
|
||||||
|
request.AddQueryString("ParentId", parentIdFilder);
|
||||||
|
}
|
||||||
|
|
||||||
|
AddHeaders(request, apiKey);
|
||||||
|
|
||||||
|
var obj = await Api.Request<EmbyItemContainer<T>>(request);
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,5 +32,7 @@ namespace Ombi.Api.Emby
|
||||||
Task<EmbyItemContainer<EmbyMovie>> RecentlyAddedMovies(string apiKey, string parentIdFilder, int startIndex, int count, string userId, string baseUri);
|
Task<EmbyItemContainer<EmbyMovie>> RecentlyAddedMovies(string apiKey, string parentIdFilder, int startIndex, int count, string userId, string baseUri);
|
||||||
Task<EmbyItemContainer<EmbyEpisodes>> RecentlyAddedEpisodes(string apiKey, string parentIdFilder, int startIndex, int count, string userId, string baseUri);
|
Task<EmbyItemContainer<EmbyEpisodes>> RecentlyAddedEpisodes(string apiKey, string parentIdFilder, int startIndex, int count, string userId, string baseUri);
|
||||||
Task<EmbyItemContainer<EmbySeries>> RecentlyAddedShows(string apiKey, string parentIdFilder, int startIndex, int count, string userId, string baseUri);
|
Task<EmbyItemContainer<EmbySeries>> RecentlyAddedShows(string apiKey, string parentIdFilder, int startIndex, int count, string userId, string baseUri);
|
||||||
|
|
||||||
|
Task<EmbyItemContainer<EmbyMovie>> GetMoviesPlayed(string apiKey, string parentIdFilder, int startIndex, int count, string userId, string baseUri);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -197,6 +197,7 @@ namespace Ombi.DependencyInjection
|
||||||
services.AddScoped<IEmbyContentRepository, EmbyContentRepository>();
|
services.AddScoped<IEmbyContentRepository, EmbyContentRepository>();
|
||||||
services.AddScoped<IJellyfinContentRepository, JellyfinContentRepository>();
|
services.AddScoped<IJellyfinContentRepository, JellyfinContentRepository>();
|
||||||
services.AddScoped<INotificationTemplatesRepository, NotificationTemplatesRepository>();
|
services.AddScoped<INotificationTemplatesRepository, NotificationTemplatesRepository>();
|
||||||
|
services.AddScoped<IUserPlayedMovieRepository, UserPlayedMovieRepository>();
|
||||||
|
|
||||||
services.AddScoped<ITvRequestRepository, TvRequestRepository>();
|
services.AddScoped<ITvRequestRepository, TvRequestRepository>();
|
||||||
services.AddScoped<IMovieRequestRepository, MovieRequestRepository>();
|
services.AddScoped<IMovieRequestRepository, MovieRequestRepository>();
|
||||||
|
@ -244,6 +245,7 @@ namespace Ombi.DependencyInjection
|
||||||
services.AddTransient<IPlexContentSync, PlexContentSync>();
|
services.AddTransient<IPlexContentSync, PlexContentSync>();
|
||||||
services.AddTransient<IPlexWatchlistImport, PlexWatchlistImport>();
|
services.AddTransient<IPlexWatchlistImport, PlexWatchlistImport>();
|
||||||
services.AddTransient<IEmbyContentSync, EmbyContentSync>();
|
services.AddTransient<IEmbyContentSync, EmbyContentSync>();
|
||||||
|
services.AddTransient<IEmbyPlayedSync, EmbyPlayedSync>();
|
||||||
services.AddTransient<IEmbyEpisodeSync, EmbyEpisodeSync>();
|
services.AddTransient<IEmbyEpisodeSync, EmbyEpisodeSync>();
|
||||||
services.AddTransient<IEmbyAvaliabilityChecker, EmbyAvaliabilityChecker>();
|
services.AddTransient<IEmbyAvaliabilityChecker, EmbyAvaliabilityChecker>();
|
||||||
services.AddTransient<IJellyfinContentSync, JellyfinContentSync>();
|
services.AddTransient<IJellyfinContentSync, JellyfinContentSync>();
|
||||||
|
|
|
@ -19,108 +19,29 @@ using MediaType = Ombi.Store.Entities.MediaType;
|
||||||
|
|
||||||
namespace Ombi.Schedule.Jobs.Emby
|
namespace Ombi.Schedule.Jobs.Emby
|
||||||
{
|
{
|
||||||
public class EmbyContentSync : IEmbyContentSync
|
public class EmbyContentSync : EmbyLibrarySync, IEmbyContentSync
|
||||||
{
|
{
|
||||||
public EmbyContentSync(ISettingsService<EmbySettings> settings, IEmbyApiFactory api, ILogger<EmbyContentSync> logger,
|
public EmbyContentSync(ISettingsService<EmbySettings> settings, IEmbyApiFactory api, ILogger<EmbyContentSync> logger,
|
||||||
IEmbyContentRepository repo, INotificationHubService notification)
|
IEmbyContentRepository repo, INotificationHubService notification):
|
||||||
|
base(settings, api, logger, notification)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
|
||||||
_settings = settings;
|
|
||||||
_apiFactory = api;
|
|
||||||
_repo = repo;
|
_repo = repo;
|
||||||
_notification = notification;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly ILogger<EmbyContentSync> _logger;
|
|
||||||
private readonly ISettingsService<EmbySettings> _settings;
|
|
||||||
private readonly IEmbyApiFactory _apiFactory;
|
|
||||||
private readonly IEmbyContentRepository _repo;
|
private readonly IEmbyContentRepository _repo;
|
||||||
private readonly INotificationHubService _notification;
|
|
||||||
|
|
||||||
private const int AmountToTake = 100;
|
|
||||||
|
|
||||||
private IEmbyApi Api { get; set; }
|
public async override Task Execute(IJobExecutionContext context)
|
||||||
|
|
||||||
public async Task Execute(IJobExecutionContext context)
|
|
||||||
{
|
{
|
||||||
JobDataMap dataMap = context.JobDetail.JobDataMap;
|
|
||||||
var recentlyAddedSearch = false;
|
|
||||||
if (dataMap.TryGetValue(JobDataKeys.EmbyRecentlyAddedSearch, out var recentlyAddedObj))
|
|
||||||
{
|
|
||||||
recentlyAddedSearch = Convert.ToBoolean(recentlyAddedObj);
|
|
||||||
}
|
|
||||||
|
|
||||||
var embySettings = await _settings.GetSettingsAsync();
|
await base.Execute(context);
|
||||||
if (!embySettings.Enable)
|
|
||||||
return;
|
|
||||||
|
|
||||||
Api = _apiFactory.CreateClient(embySettings);
|
|
||||||
|
|
||||||
await _notification.SendNotificationToAdmins(recentlyAddedSearch ? "Emby Recently Added Started" : "Emby Content Sync Started");
|
|
||||||
|
|
||||||
foreach (var server in embySettings.Servers)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await StartServerCache(server, recentlyAddedSearch);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
await _notification.SendNotificationToAdmins("Emby Content Sync Failed");
|
|
||||||
_logger.LogError(e, "Exception when caching Emby for server {0}", server.Name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
await _notification.SendNotificationToAdmins("Emby Content Sync Finished");
|
|
||||||
// Episodes
|
// Episodes
|
||||||
|
await OmbiQuartz.Scheduler.TriggerJob(new JobKey(nameof(IEmbyEpisodeSync), "Emby"), new JobDataMap(new Dictionary<string, string> { { JobDataKeys.EmbyRecentlyAddedSearch, recentlyAdded.ToString() } }));
|
||||||
|
|
||||||
await OmbiQuartz.Scheduler.TriggerJob(new JobKey(nameof(IEmbyEpisodeSync), "Emby"), new JobDataMap(new Dictionary<string, string> { { JobDataKeys.EmbyRecentlyAddedSearch, recentlyAddedSearch.ToString() } }));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private async Task StartServerCache(EmbyServers server, bool recentlyAdded)
|
protected async override Task ProcessTv(EmbyServers server, string parentId = default)
|
||||||
{
|
|
||||||
if (!ValidateSettings(server))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (server.EmbySelectedLibraries.Any() && server.EmbySelectedLibraries.Any(x => x.Enabled))
|
|
||||||
{
|
|
||||||
var movieLibsToFilter = server.EmbySelectedLibraries.Where(x => x.Enabled && x.CollectionType == "movies");
|
|
||||||
|
|
||||||
foreach (var movieParentIdFilder in movieLibsToFilter)
|
|
||||||
{
|
|
||||||
_logger.LogInformation($"Scanning Lib '{movieParentIdFilder.Title}'");
|
|
||||||
await ProcessMovies(server, recentlyAdded, movieParentIdFilder.Key);
|
|
||||||
}
|
|
||||||
|
|
||||||
var tvLibsToFilter = server.EmbySelectedLibraries.Where(x => x.Enabled && x.CollectionType == "tvshows");
|
|
||||||
foreach (var tvParentIdFilter in tvLibsToFilter)
|
|
||||||
{
|
|
||||||
_logger.LogInformation($"Scanning Lib '{tvParentIdFilter.Title}'");
|
|
||||||
await ProcessTv(server, recentlyAdded, tvParentIdFilter.Key);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
var mixedLibs = server.EmbySelectedLibraries.Where(x => x.Enabled && x.CollectionType == "mixed");
|
|
||||||
foreach (var m in mixedLibs)
|
|
||||||
{
|
|
||||||
_logger.LogInformation($"Scanning Lib '{m.Title}'");
|
|
||||||
await ProcessTv(server, recentlyAdded, m.Key);
|
|
||||||
await ProcessMovies(server, recentlyAdded, m.Key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
await ProcessMovies(server, recentlyAdded);
|
|
||||||
await ProcessTv(server, recentlyAdded);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task ProcessTv(EmbyServers server, bool recentlyAdded, string parentId = default)
|
|
||||||
{
|
{
|
||||||
// TV Time
|
// TV Time
|
||||||
var mediaToAdd = new HashSet<EmbyContent>();
|
var mediaToAdd = new HashSet<EmbyContent>();
|
||||||
|
@ -196,7 +117,7 @@ namespace Ombi.Schedule.Jobs.Emby
|
||||||
await _repo.AddRange(mediaToAdd);
|
await _repo.AddRange(mediaToAdd);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task ProcessMovies(EmbyServers server, bool recentlyAdded, string parentId = default)
|
protected override async Task ProcessMovies(EmbyServers server, string parentId = default)
|
||||||
{
|
{
|
||||||
EmbyItemContainer<EmbyMovie> movies;
|
EmbyItemContainer<EmbyMovie> movies;
|
||||||
if (recentlyAdded)
|
if (recentlyAdded)
|
||||||
|
@ -319,36 +240,6 @@ namespace Ombi.Schedule.Jobs.Emby
|
||||||
content.Quality = has4K ? null : quality;
|
content.Quality = has4K ? null : quality;
|
||||||
content.Has4K = has4K;
|
content.Has4K = has4K;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool ValidateSettings(EmbyServers server)
|
|
||||||
{
|
|
||||||
if (server?.Ip == null || string.IsNullOrEmpty(server?.ApiKey))
|
|
||||||
{
|
|
||||||
_logger.LogInformation(LoggingEvents.EmbyContentCacher, $"Server {server?.Name} is not configured correctly");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool _disposed;
|
|
||||||
protected virtual void Dispose(bool disposing)
|
|
||||||
{
|
|
||||||
if (_disposed)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (disposing)
|
|
||||||
{
|
|
||||||
//_settings?.Dispose();
|
|
||||||
}
|
|
||||||
_disposed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
Dispose(true);
|
|
||||||
GC.SuppressFinalize(this);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
146
src/Ombi.Schedule/Jobs/Emby/EmbyLibrarySync.cs
Normal file
146
src/Ombi.Schedule/Jobs/Emby/EmbyLibrarySync.cs
Normal file
|
@ -0,0 +1,146 @@
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Ombi.Api.Emby;
|
||||||
|
using Ombi.Core.Settings;
|
||||||
|
using Ombi.Core.Settings.Models.External;
|
||||||
|
using Ombi.Helpers;
|
||||||
|
using Ombi.Hubs;
|
||||||
|
using Quartz;
|
||||||
|
|
||||||
|
namespace Ombi.Schedule.Jobs.Emby
|
||||||
|
{
|
||||||
|
public abstract class EmbyLibrarySync
|
||||||
|
{
|
||||||
|
public EmbyLibrarySync(ISettingsService<EmbySettings> settings, IEmbyApiFactory api, ILogger<EmbyContentSync> logger,
|
||||||
|
INotificationHubService notification)
|
||||||
|
{
|
||||||
|
_logger = logger;
|
||||||
|
_settings = settings;
|
||||||
|
_apiFactory = api;
|
||||||
|
_notification = notification;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected readonly ILogger<EmbyContentSync> _logger;
|
||||||
|
protected readonly ISettingsService<EmbySettings> _settings;
|
||||||
|
protected readonly IEmbyApiFactory _apiFactory;
|
||||||
|
protected bool recentlyAdded;
|
||||||
|
protected readonly INotificationHubService _notification;
|
||||||
|
|
||||||
|
protected const int AmountToTake = 100;
|
||||||
|
|
||||||
|
protected IEmbyApi Api { get; set; }
|
||||||
|
|
||||||
|
public virtual async Task Execute(IJobExecutionContext context)
|
||||||
|
{
|
||||||
|
|
||||||
|
JobDataMap dataMap = context.JobDetail.JobDataMap;
|
||||||
|
if (dataMap.TryGetValue(JobDataKeys.EmbyRecentlyAddedSearch, out var recentlyAddedObj))
|
||||||
|
{
|
||||||
|
recentlyAdded = Convert.ToBoolean(recentlyAddedObj);
|
||||||
|
}
|
||||||
|
|
||||||
|
await _notification.SendNotificationToAdmins(recentlyAdded ? "Emby Recently Added Started" : "Emby Content Sync Started");
|
||||||
|
|
||||||
|
|
||||||
|
var embySettings = await _settings.GetSettingsAsync();
|
||||||
|
if (!embySettings.Enable)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Api = _apiFactory.CreateClient(embySettings);
|
||||||
|
|
||||||
|
foreach (var server in embySettings.Servers)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await StartServerCache(server);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
await _notification.SendNotificationToAdmins("Emby Content Sync Failed");
|
||||||
|
_logger.LogError(e, "Exception when caching Emby for server {0}", server.Name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await _notification.SendNotificationToAdmins("Emby Content Sync Finished");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private async Task StartServerCache(EmbyServers server)
|
||||||
|
{
|
||||||
|
if (!ValidateSettings(server))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (server.EmbySelectedLibraries.Any() && server.EmbySelectedLibraries.Any(x => x.Enabled))
|
||||||
|
{
|
||||||
|
var movieLibsToFilter = server.EmbySelectedLibraries.Where(x => x.Enabled && x.CollectionType == "movies");
|
||||||
|
|
||||||
|
foreach (var movieParentIdFilder in movieLibsToFilter)
|
||||||
|
{
|
||||||
|
_logger.LogInformation($"Scanning Lib '{movieParentIdFilder.Title}'");
|
||||||
|
await ProcessMovies(server, movieParentIdFilder.Key);
|
||||||
|
}
|
||||||
|
|
||||||
|
var tvLibsToFilter = server.EmbySelectedLibraries.Where(x => x.Enabled && x.CollectionType == "tvshows");
|
||||||
|
foreach (var tvParentIdFilter in tvLibsToFilter)
|
||||||
|
{
|
||||||
|
_logger.LogInformation($"Scanning Lib '{tvParentIdFilter.Title}'");
|
||||||
|
await ProcessTv(server, tvParentIdFilter.Key);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var mixedLibs = server.EmbySelectedLibraries.Where(x => x.Enabled && x.CollectionType == "mixed");
|
||||||
|
foreach (var m in mixedLibs)
|
||||||
|
{
|
||||||
|
_logger.LogInformation($"Scanning Lib '{m.Title}'");
|
||||||
|
await ProcessTv(server, m.Key);
|
||||||
|
await ProcessMovies(server, m.Key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await ProcessMovies(server);
|
||||||
|
await ProcessTv(server);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract Task ProcessTv(EmbyServers server, string parentId = default);
|
||||||
|
|
||||||
|
protected abstract Task ProcessMovies(EmbyServers server, string parentId = default);
|
||||||
|
|
||||||
|
private bool ValidateSettings(EmbyServers server)
|
||||||
|
{
|
||||||
|
if (server?.Ip == null || string.IsNullOrEmpty(server?.ApiKey))
|
||||||
|
{
|
||||||
|
_logger.LogInformation(LoggingEvents.EmbyContentCacher, $"Server {server?.Name} is not configured correctly");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool _disposed;
|
||||||
|
protected virtual void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (_disposed)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (disposing)
|
||||||
|
{
|
||||||
|
//_settings?.Dispose();
|
||||||
|
}
|
||||||
|
_disposed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Dispose(true);
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
110
src/Ombi.Schedule/Jobs/Emby/EmbyPlayedSync.cs
Normal file
110
src/Ombi.Schedule/Jobs/Emby/EmbyPlayedSync.cs
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Ombi.Api.Emby;
|
||||||
|
using Ombi.Api.Emby.Models;
|
||||||
|
using Ombi.Api.Emby.Models.Movie;
|
||||||
|
using Ombi.Core.Authentication;
|
||||||
|
using Ombi.Core.Settings;
|
||||||
|
using Ombi.Core.Settings.Models.External;
|
||||||
|
using Ombi.Helpers;
|
||||||
|
using Ombi.Hubs;
|
||||||
|
using Ombi.Store.Entities;
|
||||||
|
using Ombi.Store.Repository;
|
||||||
|
|
||||||
|
namespace Ombi.Schedule.Jobs.Emby
|
||||||
|
{
|
||||||
|
public class EmbyPlayedSync : EmbyLibrarySync, IEmbyPlayedSync
|
||||||
|
{
|
||||||
|
public EmbyPlayedSync(ISettingsService<EmbySettings> settings, IEmbyApiFactory api, ILogger<EmbyContentSync> logger,
|
||||||
|
IUserPlayedMovieRepository repo, INotificationHubService notification, OmbiUserManager user) : base(settings, api, logger, notification)
|
||||||
|
{
|
||||||
|
_userManager = user;
|
||||||
|
_repo = repo;
|
||||||
|
}
|
||||||
|
private OmbiUserManager _userManager { get; }
|
||||||
|
|
||||||
|
private readonly IUserPlayedMovieRepository _repo;
|
||||||
|
|
||||||
|
protected override Task ProcessTv(EmbyServers server, string parentId = default)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async override Task ProcessMovies(EmbyServers server, string parentId = default)
|
||||||
|
{
|
||||||
|
|
||||||
|
var allUsers = await _userManager.Users.Where(x => x.UserType == UserType.EmbyUser || x.UserType == UserType.EmbyConnectUser).ToListAsync();
|
||||||
|
foreach (var user in allUsers)
|
||||||
|
{
|
||||||
|
await ProcessMoviesUser(server, user, parentId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private async Task ProcessMoviesUser(EmbyServers server, OmbiUser user, string parentId = default)
|
||||||
|
{
|
||||||
|
EmbyItemContainer<EmbyMovie> movies;
|
||||||
|
if (recentlyAdded)
|
||||||
|
{
|
||||||
|
var recentlyAddedAmountToTake = 5; // to be adjusted?
|
||||||
|
movies = await Api.GetMoviesPlayed(server.ApiKey, parentId, 0, recentlyAddedAmountToTake, user.ProviderUserId, server.FullUri);
|
||||||
|
// Setting this so we don't attempt to grab more than we need
|
||||||
|
if (movies.TotalRecordCount > recentlyAddedAmountToTake)
|
||||||
|
{
|
||||||
|
movies.TotalRecordCount = recentlyAddedAmountToTake;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
movies = await Api.GetMoviesPlayed(server.ApiKey, parentId, 0, AmountToTake, user.ProviderUserId, server.FullUri);
|
||||||
|
}
|
||||||
|
var totalCount = movies.TotalRecordCount;
|
||||||
|
var processed = 0;
|
||||||
|
var mediaToAdd = new HashSet<UserPlayedMovie>();
|
||||||
|
_logger.LogCritical($"Adding {totalCount.ToString()} for {user.UserName}");
|
||||||
|
while (processed < totalCount)
|
||||||
|
{
|
||||||
|
foreach (var movie in movies.Items)
|
||||||
|
{
|
||||||
|
await ProcessMovie(movie, user, mediaToAdd, server);
|
||||||
|
processed++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the next batch
|
||||||
|
// Recently Added should never be checked as the TotalRecords should equal the amount to take
|
||||||
|
if (!recentlyAdded)
|
||||||
|
{
|
||||||
|
movies = await Api.GetMoviesPlayed(server.ApiKey, parentId, processed, AmountToTake, user.ProviderUserId, server.FullUri);
|
||||||
|
}
|
||||||
|
await _repo.AddRange(mediaToAdd);
|
||||||
|
mediaToAdd.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task ProcessMovie(EmbyMovie movieInfo, OmbiUser user, ICollection<UserPlayedMovie> content, EmbyServers server)
|
||||||
|
{
|
||||||
|
if (movieInfo.ProviderIds.Tmdb.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
_logger.LogWarning($"Movie {movieInfo.Name} has no relevant metadata. Skipping.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var userPlayedMovie = new UserPlayedMovie()
|
||||||
|
{
|
||||||
|
TheMovieDbId = movieInfo.ProviderIds.Tmdb,
|
||||||
|
UserId = user.Id
|
||||||
|
};
|
||||||
|
// Check if it exists
|
||||||
|
var existingMovie = await _repo.Get(userPlayedMovie.TheMovieDbId, userPlayedMovie.UserId);
|
||||||
|
var alreadyGoingToAdd = content.Any(x => x.TheMovieDbId == userPlayedMovie.TheMovieDbId && x.UserId == userPlayedMovie.UserId);
|
||||||
|
if (existingMovie == null && !alreadyGoingToAdd)
|
||||||
|
{
|
||||||
|
content.Add(userPlayedMovie);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
6
src/Ombi.Schedule/Jobs/Emby/IEmbyPlayedSync.cs
Normal file
6
src/Ombi.Schedule/Jobs/Emby/IEmbyPlayedSync.cs
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
namespace Ombi.Schedule.Jobs.Emby
|
||||||
|
{
|
||||||
|
public interface IEmbyPlayedSync : IBaseJob
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
|
@ -98,6 +98,8 @@ namespace Ombi.Schedule
|
||||||
{
|
{
|
||||||
await OmbiQuartz.Instance.AddJob<IEmbyContentSync>(nameof(IEmbyContentSync), "Emby", JobSettingsHelper.EmbyContent(s));
|
await OmbiQuartz.Instance.AddJob<IEmbyContentSync>(nameof(IEmbyContentSync), "Emby", JobSettingsHelper.EmbyContent(s));
|
||||||
await OmbiQuartz.Instance.AddJob<IEmbyContentSync>(nameof(IEmbyContentSync) + "RecentlyAdded", "Emby", JobSettingsHelper.EmbyRecentlyAddedSync(s), new Dictionary<string, string> { { JobDataKeys.EmbyRecentlyAddedSearch, "true" } });
|
await OmbiQuartz.Instance.AddJob<IEmbyContentSync>(nameof(IEmbyContentSync) + "RecentlyAdded", "Emby", JobSettingsHelper.EmbyRecentlyAddedSync(s), new Dictionary<string, string> { { JobDataKeys.EmbyRecentlyAddedSearch, "true" } });
|
||||||
|
await OmbiQuartz.Instance.AddJob<IEmbyPlayedSync>(nameof(IEmbyPlayedSync), "Emby", JobSettingsHelper.EmbyContent(s));
|
||||||
|
await OmbiQuartz.Instance.AddJob<IEmbyPlayedSync>(nameof(IEmbyPlayedSync) + "RecentlyAdded", "Emby", JobSettingsHelper.EmbyRecentlyAddedSync(s), new Dictionary<string, string> { { JobDataKeys.EmbyRecentlyAddedSearch, "true" } });
|
||||||
await OmbiQuartz.Instance.AddJob<IEmbyEpisodeSync>(nameof(IEmbyEpisodeSync), "Emby", null);
|
await OmbiQuartz.Instance.AddJob<IEmbyEpisodeSync>(nameof(IEmbyEpisodeSync), "Emby", null);
|
||||||
await OmbiQuartz.Instance.AddJob<IEmbyAvaliabilityChecker>(nameof(IEmbyAvaliabilityChecker), "Emby", null);
|
await OmbiQuartz.Instance.AddJob<IEmbyAvaliabilityChecker>(nameof(IEmbyAvaliabilityChecker), "Emby", null);
|
||||||
await OmbiQuartz.Instance.AddJob<IEmbyUserImporter>(nameof(IEmbyUserImporter), "Emby", JobSettingsHelper.UserImporter(s));
|
await OmbiQuartz.Instance.AddJob<IEmbyUserImporter>(nameof(IEmbyUserImporter), "Emby", JobSettingsHelper.UserImporter(s));
|
||||||
|
|
|
@ -41,6 +41,7 @@ namespace Ombi.Store.Context
|
||||||
public DbSet<SonarrEpisodeCache> SonarrEpisodeCache { get; set; }
|
public DbSet<SonarrEpisodeCache> SonarrEpisodeCache { get; set; }
|
||||||
public DbSet<SickRageCache> SickRageCache { get; set; }
|
public DbSet<SickRageCache> SickRageCache { get; set; }
|
||||||
public DbSet<SickRageEpisodeCache> SickRageEpisodeCache { get; set; }
|
public DbSet<SickRageEpisodeCache> SickRageEpisodeCache { get; set; }
|
||||||
|
public DbSet<UserPlayedMovie> UserPlayedMovie { get; set; }
|
||||||
|
|
||||||
protected override void OnModelCreating(ModelBuilder builder)
|
protected override void OnModelCreating(ModelBuilder builder)
|
||||||
{
|
{
|
||||||
|
|
10
src/Ombi.Store/Entities/MovieUserPlayed.cs
Normal file
10
src/Ombi.Store/Entities/MovieUserPlayed.cs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
|
||||||
|
namespace Ombi.Store.Entities
|
||||||
|
{
|
||||||
|
public class UserPlayedMovie : Entity
|
||||||
|
{
|
||||||
|
public string TheMovieDbId { get; set; }
|
||||||
|
public string UserId { get; set; }
|
||||||
|
}
|
||||||
|
}
|
564
src/Ombi.Store/Migrations/ExternalSqlite/20230309182556_MovieUserPlayed.Designer.cs
generated
Normal file
564
src/Ombi.Store/Migrations/ExternalSqlite/20230309182556_MovieUserPlayed.Designer.cs
generated
Normal file
|
@ -0,0 +1,564 @@
|
||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
using Ombi.Store.Context.Sqlite;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Ombi.Store.Migrations.ExternalSqlite
|
||||||
|
{
|
||||||
|
[DbContext(typeof(ExternalSqliteContext))]
|
||||||
|
[Migration("20230309182556_MovieUserPlayed")]
|
||||||
|
partial class MovieUserPlayed
|
||||||
|
{
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder.HasAnnotation("ProductVersion", "6.0.9");
|
||||||
|
|
||||||
|
modelBuilder.Entity("Ombi.Store.Entities.CouchPotatoCache", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("TheMovieDbId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("CouchPotatoCache");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Ombi.Store.Entities.EmbyContent", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTime>("AddedAt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("EmbyId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<bool>("Has4K")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("ImdbId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("ProviderId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Quality")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("TheMovieDbId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Title")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("TvDbId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("Type")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Url")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("EmbyContent");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Ombi.Store.Entities.EmbyEpisode", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTime>("AddedAt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("EmbyId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("EpisodeNumber")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("ImdbId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("ParentId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("ProviderId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("SeasonNumber")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("TheMovieDbId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Title")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("TvDbId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ParentId");
|
||||||
|
|
||||||
|
b.ToTable("EmbyEpisode");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Ombi.Store.Entities.JellyfinContent", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTime>("AddedAt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<bool>("Has4K")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("ImdbId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("JellyfinId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("ProviderId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Quality")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("TheMovieDbId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Title")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("TvDbId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("Type")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Url")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("JellyfinContent");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Ombi.Store.Entities.JellyfinEpisode", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTime>("AddedAt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("EpisodeNumber")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("ImdbId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("JellyfinId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("ParentId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("ProviderId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("SeasonNumber")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("TheMovieDbId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Title")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("TvDbId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ParentId");
|
||||||
|
|
||||||
|
b.ToTable("JellyfinEpisode");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Ombi.Store.Entities.LidarrAlbumCache", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTime>("AddedAt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("ArtistId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("ForeignAlbumId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<bool>("Monitored")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<decimal>("PercentOfTracks")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime>("ReleaseDate")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Title")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("TrackCount")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("LidarrAlbumCache");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Ombi.Store.Entities.LidarrArtistCache", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("ArtistId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("ArtistName")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("ForeignArtistId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<bool>("Monitored")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("LidarrArtistCache");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Ombi.Store.Entities.PlexEpisode", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("EpisodeNumber")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("GrandparentKey")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Key")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("ParentKey")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("SeasonNumber")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Title")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("GrandparentKey");
|
||||||
|
|
||||||
|
b.ToTable("PlexEpisode");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Ombi.Store.Entities.PlexSeasonsContent", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("ParentKey")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("PlexContentId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int?>("PlexServerContentId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("SeasonKey")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("SeasonNumber")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("PlexServerContentId");
|
||||||
|
|
||||||
|
b.ToTable("PlexSeasonsContent");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Ombi.Store.Entities.PlexServerContent", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTime>("AddedAt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<bool>("Has4K")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("ImdbId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Key")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Quality")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("ReleaseYear")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int?>("RequestId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("TheMovieDbId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Title")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("TvDbId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("Type")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Url")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("PlexServerContent");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Ombi.Store.Entities.PlexWatchlistHistory", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("TmdbId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("PlexWatchlistHistory");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Ombi.Store.Entities.RadarrCache", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("Has4K")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("HasFile")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("HasRegular")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("TheMovieDbId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("RadarrCache");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Ombi.Store.Entities.SickRageCache", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("TvDbId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("SickRageCache");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Ombi.Store.Entities.SickRageEpisodeCache", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("EpisodeNumber")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("SeasonNumber")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("TvDbId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("SickRageEpisodeCache");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Ombi.Store.Entities.SonarrCache", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("TheMovieDbId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("TvDbId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("SonarrCache");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Ombi.Store.Entities.SonarrEpisodeCache", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("EpisodeNumber")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("HasFile")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("MovieDbId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("SeasonNumber")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("TvDbId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("SonarrEpisodeCache");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Ombi.Store.Entities.UserPlayedMovie", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("TheMovieDbId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("UserId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("UserPlayedMovie");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Ombi.Store.Entities.EmbyEpisode", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Ombi.Store.Entities.EmbyContent", "Series")
|
||||||
|
.WithMany("Episodes")
|
||||||
|
.HasForeignKey("ParentId")
|
||||||
|
.HasPrincipalKey("EmbyId");
|
||||||
|
|
||||||
|
b.Navigation("Series");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Ombi.Store.Entities.JellyfinEpisode", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Ombi.Store.Entities.JellyfinContent", "Series")
|
||||||
|
.WithMany("Episodes")
|
||||||
|
.HasForeignKey("ParentId")
|
||||||
|
.HasPrincipalKey("JellyfinId");
|
||||||
|
|
||||||
|
b.Navigation("Series");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Ombi.Store.Entities.PlexEpisode", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Ombi.Store.Entities.PlexServerContent", "Series")
|
||||||
|
.WithMany("Episodes")
|
||||||
|
.HasForeignKey("GrandparentKey")
|
||||||
|
.HasPrincipalKey("Key");
|
||||||
|
|
||||||
|
b.Navigation("Series");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Ombi.Store.Entities.PlexSeasonsContent", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Ombi.Store.Entities.PlexServerContent", null)
|
||||||
|
.WithMany("Seasons")
|
||||||
|
.HasForeignKey("PlexServerContentId");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Ombi.Store.Entities.EmbyContent", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Episodes");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Ombi.Store.Entities.JellyfinContent", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Episodes");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Ombi.Store.Entities.PlexServerContent", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Episodes");
|
||||||
|
|
||||||
|
b.Navigation("Seasons");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Ombi.Store.Migrations.ExternalSqlite
|
||||||
|
{
|
||||||
|
public partial class MovieUserPlayed : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "UserPlayedMovie",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||||
|
.Annotation("Sqlite:Autoincrement", true),
|
||||||
|
TheMovieDbId = table.Column<string>(type: "TEXT", nullable: true),
|
||||||
|
UserId = table.Column<string>(type: "TEXT", nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_UserPlayedMovie", x => x.Id);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "UserPlayedMovie");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,7 +15,7 @@ namespace Ombi.Store.Migrations.ExternalSqlite
|
||||||
protected override void BuildModel(ModelBuilder modelBuilder)
|
protected override void BuildModel(ModelBuilder modelBuilder)
|
||||||
{
|
{
|
||||||
#pragma warning disable 612, 618
|
#pragma warning disable 612, 618
|
||||||
modelBuilder.HasAnnotation("ProductVersion", "6.0.0");
|
modelBuilder.HasAnnotation("ProductVersion", "6.0.9");
|
||||||
|
|
||||||
modelBuilder.Entity("Ombi.Store.Entities.CouchPotatoCache", b =>
|
modelBuilder.Entity("Ombi.Store.Entities.CouchPotatoCache", b =>
|
||||||
{
|
{
|
||||||
|
@ -486,6 +486,23 @@ namespace Ombi.Store.Migrations.ExternalSqlite
|
||||||
b.ToTable("SonarrEpisodeCache");
|
b.ToTable("SonarrEpisodeCache");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Ombi.Store.Entities.UserPlayedMovie", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("TheMovieDbId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("UserId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("UserPlayedMovie");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Ombi.Store.Entities.EmbyEpisode", b =>
|
modelBuilder.Entity("Ombi.Store.Entities.EmbyEpisode", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("Ombi.Store.Entities.EmbyContent", "Series")
|
b.HasOne("Ombi.Store.Entities.EmbyContent", "Series")
|
||||||
|
|
13
src/Ombi.Store/Repository/IUserPlayedMovieRepository.cs
Normal file
13
src/Ombi.Store/Repository/IUserPlayedMovieRepository.cs
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Ombi.Store.Entities;
|
||||||
|
|
||||||
|
namespace Ombi.Store.Repository
|
||||||
|
{
|
||||||
|
public interface IUserPlayedMovieRepository : IExternalRepository<UserPlayedMovie>
|
||||||
|
{
|
||||||
|
Task<UserPlayedMovie> Get(string theMovieDbId, string userId);
|
||||||
|
}
|
||||||
|
}
|
27
src/Ombi.Store/Repository/UserPlayedMovieRepository.cs
Normal file
27
src/Ombi.Store/Repository/UserPlayedMovieRepository.cs
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Query;
|
||||||
|
using Ombi.Store.Context;
|
||||||
|
using Ombi.Store.Entities;
|
||||||
|
|
||||||
|
namespace Ombi.Store.Repository
|
||||||
|
{
|
||||||
|
public class UserPlayedMovieRepository : ExternalRepository<UserPlayedMovie>, IUserPlayedMovieRepository
|
||||||
|
{
|
||||||
|
protected ExternalContext Db { get; }
|
||||||
|
public UserPlayedMovieRepository(ExternalContext db) : base(db)
|
||||||
|
{
|
||||||
|
Db = db;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<UserPlayedMovie> Get(string theMovieDbId, string userId)
|
||||||
|
{
|
||||||
|
return await Db.UserPlayedMovie.FirstOrDefaultAsync(x => x.TheMovieDbId == theMovieDbId && x.UserId == userId);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -51,6 +51,10 @@ export class JobService extends ServiceHelpers {
|
||||||
return this.http.post<boolean>(`${this.url}embyrecentlyadded/`, {headers: this.headers});
|
return this.http.post<boolean>(`${this.url}embyrecentlyadded/`, {headers: this.headers});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public runEmbyRecentlyPlayedCacher(): Observable<boolean> {
|
||||||
|
return this.http.post<boolean>(`${this.url}embyrecentlyplayed/`, {headers: this.headers});
|
||||||
|
}
|
||||||
|
|
||||||
public clearMediaserverData(): Observable<boolean> {
|
public clearMediaserverData(): Observable<boolean> {
|
||||||
return this.http.post<boolean>(`${this.url}clearmediaserverdata/`, {headers: this.headers});
|
return this.http.post<boolean>(`${this.url}clearmediaserverdata/`, {headers: this.headers});
|
||||||
}
|
}
|
||||||
|
@ -59,6 +63,10 @@ export class JobService extends ServiceHelpers {
|
||||||
return this.http.post<boolean>(`${this.url}embycontentcacher/`, {headers: this.headers});
|
return this.http.post<boolean>(`${this.url}embycontentcacher/`, {headers: this.headers});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public runEmbyPlayedCacher(): Observable<boolean> {
|
||||||
|
return this.http.post<boolean>(`${this.url}embyplayedcacher/`, {headers: this.headers});
|
||||||
|
}
|
||||||
|
|
||||||
public runJellyfinCacher(): Observable<boolean> {
|
public runJellyfinCacher(): Observable<boolean> {
|
||||||
return this.http.post<boolean>(`${this.url}jellyfincontentcacher/`, {headers: this.headers});
|
return this.http.post<boolean>(`${this.url}jellyfincontentcacher/`, {headers: this.headers});
|
||||||
}
|
}
|
||||||
|
|
|
@ -115,6 +115,15 @@
|
||||||
class="mat-focus-indicator mat-stroked-button mat-button-base">Manually Run Recently
|
class="mat-focus-indicator mat-stroked-button mat-button-base">Manually Run Recently
|
||||||
Added Sync</button>
|
Added Sync</button>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div>
|
||||||
|
<button mat-raised-button (click)="runPlayedCacher()" type="button" id="playedSync" class="mat-focus-indicator mat-stroked-button mat-button-base">Manually Run Played Sync</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<button mat-raised-button (click)="runRecentlyPlayedCacher()" type="button" id="recentlyPlayedSync"
|
||||||
|
class="mat-focus-indicator mat-stroked-button mat-button-base">Manually Run Recently Played Sync</button>
|
||||||
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<button mat-raised-button (click)="clearDataAndResync()" type="button" id="clearData"
|
<button mat-raised-button (click)="clearDataAndResync()" type="button" id="clearData"
|
||||||
class="mat-focus-indicator mat-stroked-button mat-button-base">
|
class="mat-focus-indicator mat-stroked-button mat-button-base">
|
||||||
|
|
|
@ -102,6 +102,22 @@ export class EmbyComponent implements OnInit {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public runPlayedCacher(): void {
|
||||||
|
this.jobService.runEmbyPlayedCacher().subscribe(x => {
|
||||||
|
if(x) {
|
||||||
|
this.notificationService.success("Triggered the Emby Played Cacher");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public runRecentlyPlayedCacher(): void {
|
||||||
|
this.jobService.runEmbyRecentlyPlayedCacher().subscribe(x => {
|
||||||
|
if (x) {
|
||||||
|
this.notificationService.success("Triggered the Emby Recently Played Sync");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public clearDataAndResync(): void {
|
public clearDataAndResync(): void {
|
||||||
this.jobService.clearMediaserverData().subscribe(x => {
|
this.jobService.clearMediaserverData().subscribe(x => {
|
||||||
if (x) {
|
if (x) {
|
||||||
|
|
|
@ -167,6 +167,19 @@ namespace Ombi.Controllers.V1
|
||||||
await OmbiQuartz.Scheduler.TriggerJob(new JobKey(nameof(IEmbyContentSync), "Emby"), new JobDataMap(new Dictionary<string, string> { { JobDataKeys.EmbyRecentlyAddedSearch, "false" } }));
|
await OmbiQuartz.Scheduler.TriggerJob(new JobKey(nameof(IEmbyContentSync), "Emby"), new JobDataMap(new Dictionary<string, string> { { JobDataKeys.EmbyRecentlyAddedSearch, "false" } }));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpPost("embyplayedcacher")]
|
||||||
|
public async Task<bool> StartEmbyPlayedCacher()
|
||||||
|
{
|
||||||
|
await OmbiQuartz.Scheduler.TriggerJob(new JobKey(nameof(IEmbyPlayedSync), "Emby"), new JobDataMap(new Dictionary<string, string> { { JobDataKeys.EmbyRecentlyAddedSearch, "false" } }));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
[HttpPost("embyrecentlyplayed")]
|
||||||
|
public async Task<bool> StartEmbyRecentlyPlayedCacher()
|
||||||
|
{
|
||||||
|
await OmbiQuartz.Scheduler.TriggerJob(new JobKey(nameof(IEmbyPlayedSync), "Emby"), new JobDataMap(new Dictionary<string, string> { { JobDataKeys.EmbyRecentlyAddedSearch, "true" } }));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Runs a smaller version of the content cacher
|
/// Runs a smaller version of the content cacher
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue