You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Ombi/Ombi.Services/Jobs/PlexEpisodeCacher.cs

203 lines
7.7 KiB

#region Copyright
// /************************************************************************
// Copyright (c) 2016 Jamie Rees
// File: PlexEpisodeCacher.cs
// Created By: Jamie Rees
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// ************************************************************************/
#endregion
8 years ago
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using NLog;
8 years ago
using Ombi.Api.Interfaces;
using Ombi.Api.Models.Plex;
using Ombi.Core;
using Ombi.Core.SettingModels;
using Ombi.Helpers;
using Ombi.Services.Interfaces;
using Ombi.Store.Models;
8 years ago
using Ombi.Store.Models.Plex;
8 years ago
using Ombi.Store.Repository;
using Quartz;
8 years ago
using PlexMediaType = Ombi.Api.Models.Plex.PlexMediaType;
8 years ago
namespace Ombi.Services.Jobs
{
8 years ago
public class PlexEpisodeCacher : IJob, IPlexEpisodeCacher
{
public PlexEpisodeCacher(ISettingsService<PlexSettings> plexSettings, IPlexApi plex, ICacheProvider cache,
IJobRecord rec, IRepository<PlexEpisodes> repo, ISettingsService<ScheduledJobsSettings> jobs)
{
Plex = plexSettings;
PlexApi = plex;
Cache = cache;
Job = rec;
Repo = repo;
Jobs = jobs;
}
private ISettingsService<PlexSettings> Plex { get; }
private static Logger Log = LogManager.GetCurrentClassLogger();
private IPlexApi PlexApi { get; }
private ICacheProvider Cache { get; }
private IJobRecord Job { get; }
private IRepository<PlexEpisodes> Repo { get; }
private ISettingsService<ScheduledJobsSettings> Jobs { get; }
private const int ResultCount = 25;
private const string PlexType = "episode";
private const string TableName = "PlexEpisodes";
public void CacheEpisodes(PlexSettings settings)
{
var videoHashset = new HashSet<Video>();
// Ensure Plex is setup correctly
if (string.IsNullOrEmpty(settings.PlexAuthToken))
{
return;
}
// Get the librarys and then get the tv section
var sections = PlexApi.GetLibrarySections(settings.PlexAuthToken, settings.FullUri);
var tvSection = sections.Directories.FirstOrDefault(x => x.type.Equals(PlexMediaType.Show.ToString(), StringComparison.CurrentCultureIgnoreCase));
var tvSectionId = tvSection?.Key;
var currentPosition = 0;
int totalSize;
// Get the first 25 episodes (Paged)
var episodes = PlexApi.GetAllEpisodes(settings.PlexAuthToken, settings.FullUri, tvSectionId, currentPosition, ResultCount);
// Parse the total amount of episodes
int.TryParse(episodes.TotalSize, out totalSize);
// Get all of the episodes in batches until we them all (Got'a catch 'em all!)
while (currentPosition < totalSize)
{
videoHashset.UnionWith(PlexApi.GetAllEpisodes(settings.PlexAuthToken, settings.FullUri, tvSectionId, currentPosition, ResultCount).Video
.Where(x => x.Type.Equals(PlexType, StringComparison.InvariantCultureIgnoreCase)));
currentPosition += ResultCount;
}
var entities = new ConcurrentDictionary<PlexEpisodes, byte>();
Parallel.ForEach(videoHashset, video =>
{
// Get the individual episode Metadata (This is for us to get the TheTVDBId which also includes the episode number and season number)
var metadata = PlexApi.GetEpisodeMetaData(settings.PlexAuthToken, settings.FullUri, video.RatingKey);
// Loop through the metadata and create the model to insert into the DB
foreach (var metadataVideo in metadata.Video)
{
if(string.IsNullOrEmpty(metadataVideo.GrandparentTitle))
{
continue;
}
var epInfo = PlexHelper.GetSeasonsAndEpisodesFromPlexGuid(metadataVideo.Guid);
entities.TryAdd(
new PlexEpisodes
{
EpisodeNumber = epInfo.EpisodeNumber,
EpisodeTitle = metadataVideo.Title,
ProviderId = epInfo.ProviderId,
RatingKey = metadataVideo.RatingKey,
SeasonNumber = epInfo.SeasonNumber,
ShowTitle = metadataVideo.GrandparentTitle
},
1);
}
});
// Delete all of the current items
Repo.DeleteAll(TableName);
// Insert the new items
8 years ago
var result = Repo.BatchInsert(entities.Select(x => x.Key).ToList(), TableName);
if (!result)
{
Log.Error("Saving the Plex episodes to the DB Failed");
}
}
8 years ago
public void Start()
{
try
{
var s = Plex.GetSettings();
if (!s.EnableTvEpisodeSearching)
{
return;
}
8 years ago
Job.SetRunning(true, JobNames.EpisodeCacher);
CacheEpisodes(s);
}
catch (Exception e)
{
Log.Error(e);
}
finally
{
Job.Record(JobNames.EpisodeCacher);
Job.SetRunning(false, JobNames.EpisodeCacher);
}
}
public void Execute(IJobExecutionContext context)
{
try
{
var s = Plex.GetSettings();
if (!s.EnableTvEpisodeSearching)
{
return;
}
var jobs = Job.GetJobs();
var job = jobs.FirstOrDefault(x => x.Name.Equals(JobNames.EpisodeCacher, StringComparison.CurrentCultureIgnoreCase));
if (job != null)
{
if (job.LastRun > DateTime.Now.AddHours(-11)) // If it's been run in the last 11 hours
{
return;
}
}
Job.SetRunning(true, JobNames.EpisodeCacher);
CacheEpisodes(s);
}
catch (Exception e)
{
Log.Error(e);
}
finally
{
Job.Record(JobNames.EpisodeCacher);
Job.SetRunning(false, JobNames.EpisodeCacher);
}
}
}
}