mirror of
https://github.com/Ombi-app/Ombi.git
synced 2025-08-21 13:53:19 -07:00
The move!
This commit is contained in:
parent
1daf480b1b
commit
25526cc4d9
1147 changed files with 85 additions and 8524 deletions
61
Old/Ombi.Services/Interfaces/IAvailabilityChecker.cs
Normal file
61
Old/Ombi.Services/Interfaces/IAvailabilityChecker.cs
Normal file
|
@ -0,0 +1,61 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2016 Jamie Rees
|
||||
// File: IAvailabilityChecker.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
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Ombi.Store.Models;
|
||||
using Ombi.Store.Models.Plex;
|
||||
|
||||
namespace Ombi.Services.Interfaces
|
||||
{
|
||||
public interface IAvailabilityChecker
|
||||
{
|
||||
void Start();
|
||||
void CheckAndUpdateAll();
|
||||
IEnumerable<PlexContent> GetPlexMovies(IEnumerable<PlexContent> content);
|
||||
bool IsMovieAvailable(IEnumerable<PlexContent> plexMovies, string title, string year, string providerId = null);
|
||||
IEnumerable<PlexContent> GetPlexTvShows(IEnumerable<PlexContent> content);
|
||||
bool IsTvShowAvailable(IEnumerable<PlexContent> plexShows, string title, string year, string providerId = null, int[] seasons = null);
|
||||
IEnumerable<PlexContent> GetPlexAlbums(IEnumerable<PlexContent> content);
|
||||
bool IsAlbumAvailable(IEnumerable<PlexContent> plexAlbums, string title, string year, string artist);
|
||||
bool IsEpisodeAvailable(string theTvDbId, int season, int episode);
|
||||
PlexContent GetAlbum(IEnumerable<PlexContent> plexAlbums, string title, string year, string artist);
|
||||
PlexContent GetMovie(IEnumerable<PlexContent> plexMovies, string title, string year, string providerId = null);
|
||||
PlexContent GetTvShow(IEnumerable<PlexContent> plexShows, string title, string year, string providerId = null, int[] seasons = null);
|
||||
/// <summary>
|
||||
/// Gets the episode's stored in the cache.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task<IEnumerable<PlexEpisodes>> GetEpisodes();
|
||||
/// <summary>
|
||||
/// Gets the episode's stored in the cache and then filters on the TheTvDBId.
|
||||
/// </summary>
|
||||
/// <param name="theTvDbId">The tv database identifier.</param>
|
||||
/// <returns></returns>
|
||||
Task<IEnumerable<PlexEpisodes>> GetEpisodes(int theTvDbId);
|
||||
}
|
||||
}
|
8
Old/Ombi.Services/Interfaces/ICouchPotatoCacher.cs
Normal file
8
Old/Ombi.Services/Interfaces/ICouchPotatoCacher.cs
Normal file
|
@ -0,0 +1,8 @@
|
|||
namespace Ombi.Services.Interfaces
|
||||
{
|
||||
public interface ICouchPotatoCacher
|
||||
{
|
||||
void Queued();
|
||||
int[] QueuedIds();
|
||||
}
|
||||
}
|
6
Old/Ombi.Services/Interfaces/IEmbyNotificationEngine.cs
Normal file
6
Old/Ombi.Services/Interfaces/IEmbyNotificationEngine.cs
Normal file
|
@ -0,0 +1,6 @@
|
|||
namespace Ombi.Services.Interfaces
|
||||
{
|
||||
public interface IEmbyNotificationEngine : INotificationEngine
|
||||
{
|
||||
}
|
||||
}
|
36
Old/Ombi.Services/Interfaces/IIntervals.cs
Normal file
36
Old/Ombi.Services/Interfaces/IIntervals.cs
Normal file
|
@ -0,0 +1,36 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2016 Jamie Rees
|
||||
// File: IIntervals.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
|
||||
|
||||
using System;
|
||||
|
||||
namespace Ombi.Services.Interfaces
|
||||
{
|
||||
public interface IIntervals
|
||||
{
|
||||
TimeSpan Notification { get; } // notification interval for high load
|
||||
}
|
||||
}
|
41
Old/Ombi.Services/Interfaces/IJobRecord.cs
Normal file
41
Old/Ombi.Services/Interfaces/IJobRecord.cs
Normal file
|
@ -0,0 +1,41 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2016 Jamie Rees
|
||||
// File: IJobRecord.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
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Ombi.Store.Models;
|
||||
|
||||
namespace Ombi.Services.Interfaces
|
||||
{
|
||||
public interface IJobRecord
|
||||
{
|
||||
void Record(string jobName);
|
||||
Task<IEnumerable<ScheduledJobs>> GetJobsAsync();
|
||||
IEnumerable<ScheduledJobs> GetJobs();
|
||||
void SetRunning(bool running, string jobName);
|
||||
}
|
||||
}
|
12
Old/Ombi.Services/Interfaces/IMassEmail.cs
Normal file
12
Old/Ombi.Services/Interfaces/IMassEmail.cs
Normal file
|
@ -0,0 +1,12 @@
|
|||
using Quartz;
|
||||
|
||||
namespace Ombi.Services.Jobs
|
||||
{
|
||||
public interface IMassEmail
|
||||
{
|
||||
void Execute(IJobExecutionContext context);
|
||||
void MassEmailAdminTest(string html, string subject);
|
||||
void SendMassEmail(string html, string subject);
|
||||
|
||||
}
|
||||
}
|
47
Old/Ombi.Services/Interfaces/INotification.cs
Normal file
47
Old/Ombi.Services/Interfaces/INotification.cs
Normal file
|
@ -0,0 +1,47 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2016 Jamie Rees
|
||||
// File: INotification.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
|
||||
|
||||
using System.Threading.Tasks;
|
||||
using Ombi.Core.SettingModels;
|
||||
using Ombi.Services.Notification;
|
||||
|
||||
namespace Ombi.Services.Interfaces
|
||||
{
|
||||
public interface INotification
|
||||
{
|
||||
string NotificationName { get; }
|
||||
|
||||
Task NotifyAsync(NotificationModel model);
|
||||
/// <summary>
|
||||
/// Sends a notification to the user, this is usually for testing the settings.
|
||||
/// </summary>
|
||||
/// <param name="model">The model.</param>
|
||||
/// <param name="settings">The settings.</param>
|
||||
/// <returns></returns>
|
||||
Task NotifyAsync(NotificationModel model, Settings settings);
|
||||
}
|
||||
}
|
40
Old/Ombi.Services/Interfaces/INotificationEngine.cs
Normal file
40
Old/Ombi.Services/Interfaces/INotificationEngine.cs
Normal file
|
@ -0,0 +1,40 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2016 Jamie Rees
|
||||
// File: INotificationEngine.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
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Ombi.Core.Models;
|
||||
using Ombi.Store;
|
||||
|
||||
namespace Ombi.Services.Interfaces
|
||||
{
|
||||
public interface INotificationEngine
|
||||
{
|
||||
Task NotifyUsers(IEnumerable<RequestedModel> modelChanged, NotificationType type);
|
||||
Task NotifyUsers(RequestedModel modelChanged, NotificationType type);
|
||||
}
|
||||
}
|
54
Old/Ombi.Services/Interfaces/INotificationService.cs
Normal file
54
Old/Ombi.Services/Interfaces/INotificationService.cs
Normal file
|
@ -0,0 +1,54 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2016 Jamie Rees
|
||||
// File: INotificationService.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
|
||||
|
||||
using System.Threading.Tasks;
|
||||
using Ombi.Core.SettingModels;
|
||||
using Ombi.Services.Notification;
|
||||
|
||||
namespace Ombi.Services.Interfaces
|
||||
{
|
||||
public interface INotificationService
|
||||
{
|
||||
/// <summary>
|
||||
/// Sends a notification to the user. This one is used in normal notification scenarios
|
||||
/// </summary>
|
||||
/// <param name="model">The model.</param>
|
||||
/// <returns></returns>
|
||||
Task Publish(NotificationModel model);
|
||||
Task PublishTest(NotificationModel model, Settings settings, INotification type);
|
||||
/// <summary>
|
||||
/// Sends a notification to the user, this is usually for testing the settings.
|
||||
/// </summary>
|
||||
/// <param name="model">The model.</param>
|
||||
/// <param name="settings">The settings.</param>
|
||||
/// <returns></returns>
|
||||
Task Publish(NotificationModel model, Settings settings);
|
||||
void Subscribe(INotification notification);
|
||||
void UnSubscribe(INotification notification);
|
||||
|
||||
}
|
||||
}
|
10
Old/Ombi.Services/Interfaces/IPlexContentCacher.cs
Normal file
10
Old/Ombi.Services/Interfaces/IPlexContentCacher.cs
Normal file
|
@ -0,0 +1,10 @@
|
|||
using Quartz;
|
||||
|
||||
namespace Ombi.Services.Jobs
|
||||
{
|
||||
public interface IPlexContentCacher
|
||||
{
|
||||
void CacheContent();
|
||||
void Execute(IJobExecutionContext context);
|
||||
}
|
||||
}
|
6
Old/Ombi.Services/Interfaces/IPlexNotificationEngine.cs
Normal file
6
Old/Ombi.Services/Interfaces/IPlexNotificationEngine.cs
Normal file
|
@ -0,0 +1,6 @@
|
|||
namespace Ombi.Services.Interfaces
|
||||
{
|
||||
public interface IPlexNotificationEngine : INotificationEngine
|
||||
{
|
||||
}
|
||||
}
|
11
Old/Ombi.Services/Interfaces/IRadarrCacher.cs
Normal file
11
Old/Ombi.Services/Interfaces/IRadarrCacher.cs
Normal file
|
@ -0,0 +1,11 @@
|
|||
using System.Collections.Generic;
|
||||
using Ombi.Services.Models;
|
||||
|
||||
namespace Ombi.Services.Interfaces
|
||||
{
|
||||
public interface IRadarrCacher
|
||||
{
|
||||
void Queued();
|
||||
int[] QueuedIds();
|
||||
}
|
||||
}
|
11
Old/Ombi.Services/Interfaces/IRecentlyAdded.cs
Normal file
11
Old/Ombi.Services/Interfaces/IRecentlyAdded.cs
Normal file
|
@ -0,0 +1,11 @@
|
|||
using Quartz;
|
||||
|
||||
namespace Ombi.Services.Jobs
|
||||
{
|
||||
public interface IRecentlyAdded
|
||||
{
|
||||
void Execute(IJobExecutionContext context);
|
||||
void RecentlyAddedAdminTest();
|
||||
void StartNewsLetter();
|
||||
}
|
||||
}
|
8
Old/Ombi.Services/Interfaces/ISickRageCacher.cs
Normal file
8
Old/Ombi.Services/Interfaces/ISickRageCacher.cs
Normal file
|
@ -0,0 +1,8 @@
|
|||
namespace Ombi.Services.Interfaces
|
||||
{
|
||||
public interface ISickRageCacher
|
||||
{
|
||||
void Queued();
|
||||
int[] QueuedIds();
|
||||
}
|
||||
}
|
11
Old/Ombi.Services/Interfaces/ISonarrCacher.cs
Normal file
11
Old/Ombi.Services/Interfaces/ISonarrCacher.cs
Normal file
|
@ -0,0 +1,11 @@
|
|||
using System.Collections.Generic;
|
||||
using Ombi.Services.Models;
|
||||
|
||||
namespace Ombi.Services.Interfaces
|
||||
{
|
||||
public interface ISonarrCacher
|
||||
{
|
||||
void Queued();
|
||||
IEnumerable<SonarrCachedResult> QueuedIds();
|
||||
}
|
||||
}
|
10
Old/Ombi.Services/Interfaces/IStoreBackup.cs
Normal file
10
Old/Ombi.Services/Interfaces/IStoreBackup.cs
Normal file
|
@ -0,0 +1,10 @@
|
|||
using Quartz;
|
||||
|
||||
namespace Ombi.Services.Jobs
|
||||
{
|
||||
public interface IStoreBackup
|
||||
{
|
||||
void Start();
|
||||
void Execute(IJobExecutionContext context);
|
||||
}
|
||||
}
|
10
Old/Ombi.Services/Interfaces/IStoreCleanup.cs
Normal file
10
Old/Ombi.Services/Interfaces/IStoreCleanup.cs
Normal file
|
@ -0,0 +1,10 @@
|
|||
using Quartz;
|
||||
|
||||
namespace Ombi.Services.Jobs
|
||||
{
|
||||
public interface IStoreCleanup
|
||||
{
|
||||
void Execute(IJobExecutionContext context);
|
||||
void Start();
|
||||
}
|
||||
}
|
16
Old/Ombi.Services/Interfaces/IUserRequestLimitResetter.cs
Normal file
16
Old/Ombi.Services/Interfaces/IUserRequestLimitResetter.cs
Normal file
|
@ -0,0 +1,16 @@
|
|||
using System.Collections.Generic;
|
||||
using Ombi.Core.SettingModels;
|
||||
using Ombi.Store.Models;
|
||||
using Quartz;
|
||||
|
||||
namespace Ombi.Services.Jobs
|
||||
{
|
||||
public interface IUserRequestLimitResetter
|
||||
{
|
||||
void AlbumLimit(PlexRequestSettings s, IEnumerable<RequestLimit> allUsers);
|
||||
void Execute(IJobExecutionContext context);
|
||||
void MovieLimit(PlexRequestSettings s, IEnumerable<RequestLimit> allUsers);
|
||||
void Start();
|
||||
void TvLimit(PlexRequestSettings s, IEnumerable<RequestLimit> allUsers);
|
||||
}
|
||||
}
|
8
Old/Ombi.Services/Interfaces/IWatcherCacher.cs
Normal file
8
Old/Ombi.Services/Interfaces/IWatcherCacher.cs
Normal file
|
@ -0,0 +1,8 @@
|
|||
namespace Ombi.Services.Interfaces
|
||||
{
|
||||
public interface IWatcherCacher
|
||||
{
|
||||
void Queued();
|
||||
string[] QueuedIds();
|
||||
}
|
||||
}
|
113
Old/Ombi.Services/Jobs/CouchPotatoCacher.cs
Normal file
113
Old/Ombi.Services/Jobs/CouchPotatoCacher.cs
Normal file
|
@ -0,0 +1,113 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2016 Jamie Rees
|
||||
// File: PlexAvailabilityChecker.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
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using Ombi.Api.Interfaces;
|
||||
using Ombi.Api.Models.Movie;
|
||||
using Ombi.Core;
|
||||
using Ombi.Core.SettingModels;
|
||||
using Ombi.Helpers;
|
||||
using Ombi.Services.Interfaces;
|
||||
using Quartz;
|
||||
|
||||
namespace Ombi.Services.Jobs
|
||||
{
|
||||
public class CouchPotatoCacher : IJob, ICouchPotatoCacher
|
||||
{
|
||||
public CouchPotatoCacher(ISettingsService<CouchPotatoSettings> cpSettings, ICouchPotatoApi cpApi, ICacheProvider cache, IJobRecord rec)
|
||||
{
|
||||
CpSettings = cpSettings;
|
||||
CpApi = cpApi;
|
||||
Cache = cache;
|
||||
Job = rec;
|
||||
}
|
||||
|
||||
private ISettingsService<CouchPotatoSettings> CpSettings { get; }
|
||||
private ICacheProvider Cache { get; }
|
||||
private ICouchPotatoApi CpApi { get; }
|
||||
private IJobRecord Job { get; }
|
||||
|
||||
private static Logger Log = LogManager.GetCurrentClassLogger();
|
||||
|
||||
public void Queued()
|
||||
{
|
||||
Log.Trace("Getting the settings");
|
||||
|
||||
var settings = CpSettings.GetSettings();
|
||||
if (settings.Enabled)
|
||||
{
|
||||
Job.SetRunning(true, JobNames.CpCacher);
|
||||
Log.Trace("Getting all movies from CouchPotato");
|
||||
try
|
||||
{
|
||||
var movies = CpApi.GetMovies(settings.FullUri, settings.ApiKey, new[] { "active" });
|
||||
if (movies != null)
|
||||
{
|
||||
Cache.Set(CacheKeys.CouchPotatoQueued, movies, CacheKeys.TimeFrameMinutes.SchedulerCaching);
|
||||
}
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
Log.Error(ex, "Failed caching queued items from CouchPotato");
|
||||
}
|
||||
finally
|
||||
{
|
||||
Job.Record(JobNames.CpCacher);
|
||||
Job.SetRunning(false, JobNames.CpCacher);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// we do not want to set here...
|
||||
public int[] QueuedIds()
|
||||
{
|
||||
try
|
||||
{
|
||||
var movies = Cache.Get<CouchPotatoMovies>(CacheKeys.CouchPotatoQueued);
|
||||
|
||||
var items = movies?.movies?.Select(x => x.info?.tmdb_id);
|
||||
if(items != null)
|
||||
{
|
||||
return items.Cast<int>().ToArray();
|
||||
}
|
||||
return new int[] { };
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
return new int[] {};
|
||||
}
|
||||
}
|
||||
|
||||
public void Execute(IJobExecutionContext context)
|
||||
{
|
||||
Queued();
|
||||
}
|
||||
}
|
||||
}
|
362
Old/Ombi.Services/Jobs/EmbyAvailabilityChecker.cs
Normal file
362
Old/Ombi.Services/Jobs/EmbyAvailabilityChecker.cs
Normal file
|
@ -0,0 +1,362 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2016 Jamie Rees
|
||||
// File: PlexAvailabilityChecker.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
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Dapper;
|
||||
using NLog;
|
||||
using Ombi.Api.Interfaces;
|
||||
using Ombi.Api.Models.Plex;
|
||||
using Ombi.Core;
|
||||
using Ombi.Core.Models;
|
||||
using Ombi.Core.SettingModels;
|
||||
using Ombi.Helpers;
|
||||
using Ombi.Services.Interfaces;
|
||||
using Ombi.Services.Models;
|
||||
using Ombi.Store;
|
||||
using Ombi.Store.Models;
|
||||
using Ombi.Store.Models.Emby;
|
||||
using Ombi.Store.Models.Plex;
|
||||
using Ombi.Store.Repository;
|
||||
using Quartz;
|
||||
using PlexMediaType = Ombi.Api.Models.Plex.PlexMediaType;
|
||||
|
||||
namespace Ombi.Services.Jobs
|
||||
{
|
||||
public class EmbyAvailabilityChecker : IJob, IEmbyAvailabilityChecker
|
||||
{
|
||||
public EmbyAvailabilityChecker(ISettingsService<EmbySettings> embySettings, IRequestService request, IEmbyApi emby, ICacheProvider cache,
|
||||
INotificationService notify, IJobRecord rec, IRepository<UsersToNotify> users, IRepository<EmbyEpisodes> repo, IEmbyNotificationEngine e, IRepository<EmbyContent> content)
|
||||
{
|
||||
Emby = embySettings;
|
||||
RequestService = request;
|
||||
EmbyApi = emby;
|
||||
Cache = cache;
|
||||
Notification = notify;
|
||||
Job = rec;
|
||||
UserNotifyRepo = users;
|
||||
EpisodeRepo = repo;
|
||||
NotificationEngine = e;
|
||||
EmbyContent = content;
|
||||
}
|
||||
|
||||
private ISettingsService<EmbySettings> Emby { get; }
|
||||
private IRepository<EmbyEpisodes> EpisodeRepo { get; }
|
||||
private IRequestService RequestService { get; }
|
||||
private static Logger Log = LogManager.GetCurrentClassLogger();
|
||||
private IEmbyApi EmbyApi { get; }
|
||||
private ICacheProvider Cache { get; }
|
||||
private INotificationService Notification { get; }
|
||||
private IJobRecord Job { get; }
|
||||
private IRepository<UsersToNotify> UserNotifyRepo { get; }
|
||||
private INotificationEngine NotificationEngine { get; }
|
||||
private IRepository<EmbyContent> EmbyContent { get; }
|
||||
|
||||
public void CheckAndUpdateAll()
|
||||
{
|
||||
var embySettings = Emby.GetSettings();
|
||||
if (!embySettings.Enable)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!ValidateSettings(embySettings))
|
||||
{
|
||||
Log.Debug("Validation of the Emby settings failed.");
|
||||
return;
|
||||
}
|
||||
|
||||
var content = EmbyContent.GetAll().ToList();
|
||||
|
||||
var movies = GetEmbyMovies(content).ToArray();
|
||||
var shows = GetEmbyTvShows(content).ToArray();
|
||||
var albums = GetEmbyMusic(content).ToArray();
|
||||
|
||||
var requests = RequestService.GetAll();
|
||||
var requestedModels = requests as RequestedModel[] ?? requests.Where(x => !x.Available).ToArray();
|
||||
|
||||
if (!requestedModels.Any())
|
||||
{
|
||||
Log.Debug("There are no requests to check.");
|
||||
return;
|
||||
}
|
||||
|
||||
var modifiedModel = new List<RequestedModel>();
|
||||
foreach (var r in requestedModels)
|
||||
{
|
||||
var releaseDate = r.ReleaseDate == DateTime.MinValue ? string.Empty : r.ReleaseDate.ToString("yyyy");
|
||||
bool matchResult;
|
||||
|
||||
switch (r.Type)
|
||||
{
|
||||
case RequestType.Movie:
|
||||
matchResult = IsMovieAvailable(movies, r.Title, releaseDate, r.ImdbId);
|
||||
break;
|
||||
case RequestType.TvShow:
|
||||
if (!embySettings.EnableEpisodeSearching)
|
||||
{
|
||||
matchResult = IsTvShowAvailable(shows, r.Title, releaseDate, r.TvDbId, r.SeasonList);
|
||||
}
|
||||
else
|
||||
{
|
||||
matchResult = r.Episodes.Any() ?
|
||||
r.Episodes.All(x => IsEpisodeAvailable(r.TvDbId, x.SeasonNumber, x.EpisodeNumber)) :
|
||||
IsTvShowAvailable(shows, r.Title, releaseDate, r.TvDbId, r.SeasonList);
|
||||
}
|
||||
break;
|
||||
case RequestType.Album:
|
||||
//matchResult = IsAlbumAvailable(albums, r.Title, r.ReleaseDate.Year.ToString(), r.ArtistName); // TODO Emby
|
||||
matchResult = false;
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
|
||||
if (matchResult)
|
||||
{
|
||||
r.Available = true;
|
||||
modifiedModel.Add(r);
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Log.Debug("Requests that will be updated count {0}", modifiedModel.Count);
|
||||
|
||||
if (modifiedModel.Any())
|
||||
{
|
||||
NotificationEngine.NotifyUsers(modifiedModel, NotificationType.RequestAvailable);
|
||||
RequestService.BatchUpdate(modifiedModel);
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<EmbyContent> GetEmbyMovies(IEnumerable<EmbyContent> content)
|
||||
{
|
||||
return content.Where(x => x.Type == EmbyMediaType.Movie);
|
||||
}
|
||||
|
||||
public bool IsMovieAvailable(IEnumerable<EmbyContent> embyMovies, string title, string year, string providerId)
|
||||
{
|
||||
var movie = GetMovie(embyMovies, title, year, providerId);
|
||||
return movie != null;
|
||||
}
|
||||
|
||||
public EmbyContent GetMovie(IEnumerable<EmbyContent> embyMovies, string title, string year, string providerId)
|
||||
{
|
||||
if (embyMovies.Count() == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
foreach (var movie in embyMovies)
|
||||
{
|
||||
if (string.IsNullOrEmpty(movie.Title) || movie.PremierDate == DateTime.MinValue)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(movie.ProviderId) &&
|
||||
movie.ProviderId.Equals(providerId, StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
return movie;
|
||||
}
|
||||
|
||||
if (movie.Title.Equals(title, StringComparison.CurrentCultureIgnoreCase) &&
|
||||
movie.PremierDate.Year.ToString().Equals(year, StringComparison.CurrentCultureIgnoreCase))
|
||||
{
|
||||
return movie;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public IEnumerable<EmbyContent> GetEmbyTvShows(IEnumerable<EmbyContent> content)
|
||||
{
|
||||
return content.Where(x => x.Type == EmbyMediaType.Series);
|
||||
}
|
||||
|
||||
public bool IsTvShowAvailable(IEnumerable<EmbyContent> embyShows, string title, string year, string providerId, int[] seasons = null)
|
||||
{
|
||||
var show = GetTvShow(embyShows, title, year, providerId, seasons);
|
||||
return show != null;
|
||||
}
|
||||
|
||||
|
||||
public EmbyContent GetTvShow(IEnumerable<EmbyContent> embyShows, string title, string year, string providerId,
|
||||
int[] seasons = null)
|
||||
{
|
||||
foreach (var show in embyShows)
|
||||
{
|
||||
//if (show.ProviderId == providerId && seasons != null) // TODO Emby
|
||||
//{
|
||||
// var showSeasons = ByteConverterHelper.ReturnObject<int[]>(show.Seasons);
|
||||
// if (seasons.Any(season => showSeasons.Contains(season)))
|
||||
// {
|
||||
// return show;
|
||||
// }
|
||||
// return null;
|
||||
//}
|
||||
if (!string.IsNullOrEmpty(show.ProviderId) &&
|
||||
show.ProviderId.Equals(providerId, StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
return show;
|
||||
}
|
||||
|
||||
if (show.Title.Equals(title, StringComparison.CurrentCultureIgnoreCase) &&
|
||||
show.PremierDate.Year.ToString().Equals(year, StringComparison.CurrentCultureIgnoreCase))
|
||||
{
|
||||
return show;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool IsEpisodeAvailable(string theTvDbId, int season, int episode)
|
||||
{
|
||||
var ep = EpisodeRepo.Custom(
|
||||
connection =>
|
||||
{
|
||||
connection.Open();
|
||||
var result = connection.Query<EmbyEpisodes>("select * from EmbyEpisodes where ProviderId = @ProviderId", new { ProviderId = theTvDbId });
|
||||
|
||||
return result;
|
||||
}).ToList();
|
||||
|
||||
if (!ep.Any())
|
||||
{
|
||||
Log.Info("Episode cache info is not available. tvdbid: {0}, season: {1}, episode: {2}", theTvDbId, season, episode);
|
||||
return false;
|
||||
}
|
||||
foreach (var result in ep)
|
||||
{
|
||||
if (result.ProviderId.Equals(theTvDbId) && result.EpisodeNumber == episode && result.SeasonNumber == season)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the episode's db in the cache.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<IEnumerable<EmbyEpisodes>> GetEpisodes()
|
||||
{
|
||||
var episodes = await EpisodeRepo.GetAllAsync();
|
||||
if (episodes == null)
|
||||
{
|
||||
return new HashSet<EmbyEpisodes>();
|
||||
}
|
||||
return episodes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the episode's stored in the db and then filters on the TheTvDBId.
|
||||
/// </summary>
|
||||
/// <param name="theTvDbId">The tv database identifier.</param>
|
||||
/// <returns></returns>
|
||||
public async Task<IEnumerable<EmbyEpisodes>> GetEpisodes(int theTvDbId)
|
||||
{
|
||||
var ep = await EpisodeRepo.CustomAsync(async connection =>
|
||||
{
|
||||
connection.Open();
|
||||
var result = await connection.QueryAsync<EmbyEpisodes>(@"select ee.* from EmbyEpisodes ee inner join EmbyContent ec
|
||||
on ee.ParentId = ec.EmbyId
|
||||
where ec.ProviderId = @ProviderId", new { ProviderId = theTvDbId });
|
||||
|
||||
return result;
|
||||
});
|
||||
|
||||
var embyEpisodes = ep as EmbyEpisodes[] ?? ep.ToArray();
|
||||
if (!embyEpisodes.Any())
|
||||
{
|
||||
Log.Info("Episode db info is not available.");
|
||||
return new List<EmbyEpisodes>();
|
||||
}
|
||||
|
||||
return embyEpisodes;
|
||||
}
|
||||
|
||||
public IEnumerable<EmbyContent> GetEmbyMusic(IEnumerable<EmbyContent> content)
|
||||
{
|
||||
return content.Where(x => x.Type == EmbyMediaType.Music);
|
||||
}
|
||||
|
||||
|
||||
private bool ValidateSettings(EmbySettings emby)
|
||||
{
|
||||
if (emby.Enable)
|
||||
{
|
||||
if (string.IsNullOrEmpty(emby?.Ip) || string.IsNullOrEmpty(emby?.ApiKey) || string.IsNullOrEmpty(emby?.AdministratorId))
|
||||
{
|
||||
Log.Warn("A setting is null, Ensure Emby is configured correctly");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return emby.Enable;
|
||||
}
|
||||
|
||||
public void Execute(IJobExecutionContext context)
|
||||
{
|
||||
|
||||
Job.SetRunning(true, JobNames.EmbyChecker);
|
||||
try
|
||||
{
|
||||
CheckAndUpdateAll();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Job.Record(JobNames.EmbyChecker);
|
||||
Job.SetRunning(false, JobNames.EmbyChecker);
|
||||
}
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
Job.SetRunning(true, JobNames.EmbyChecker);
|
||||
try
|
||||
{
|
||||
CheckAndUpdateAll();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Job.Record(JobNames.EmbyChecker);
|
||||
Job.SetRunning(false, JobNames.EmbyChecker);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
298
Old/Ombi.Services/Jobs/EmbyContentCacher.cs
Normal file
298
Old/Ombi.Services/Jobs/EmbyContentCacher.cs
Normal file
|
@ -0,0 +1,298 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2016 Jamie Rees
|
||||
// File: PlexAvailabilityChecker.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
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Dapper;
|
||||
using NLog;
|
||||
using Ombi.Api.Interfaces;
|
||||
using Ombi.Api.Models.Emby;
|
||||
using Ombi.Core;
|
||||
using Ombi.Core.SettingModels;
|
||||
using Ombi.Helpers;
|
||||
using Ombi.Services.Interfaces;
|
||||
using Ombi.Services.Jobs.Interfaces;
|
||||
using Ombi.Store.Models.Emby;
|
||||
using Ombi.Store.Repository;
|
||||
using Quartz;
|
||||
using EmbyMediaType = Ombi.Api.Models.Emby.EmbyMediaType;
|
||||
|
||||
namespace Ombi.Services.Jobs
|
||||
{
|
||||
public class EmbyContentCacher : IJob, IEmbyContentCacher
|
||||
{
|
||||
public EmbyContentCacher(ISettingsService<EmbySettings> embySettings, IRequestService request, IEmbyApi emby, ICacheProvider cache,
|
||||
IJobRecord rec, IRepository<EmbyEpisodes> repo, IRepository<EmbyContent> content)
|
||||
{
|
||||
Emby = embySettings;
|
||||
RequestService = request;
|
||||
EmbyApi = emby;
|
||||
Cache = cache;
|
||||
Job = rec;
|
||||
EpisodeRepo = repo;
|
||||
EmbyContent = content;
|
||||
}
|
||||
|
||||
private ISettingsService<EmbySettings> Emby { get; }
|
||||
private IRepository<EmbyEpisodes> EpisodeRepo { get; }
|
||||
private IRequestService RequestService { get; }
|
||||
private static Logger Log = LogManager.GetCurrentClassLogger();
|
||||
private IEmbyApi EmbyApi { get; }
|
||||
private ICacheProvider Cache { get; }
|
||||
private IJobRecord Job { get; }
|
||||
private IRepository<EmbyContent> EmbyContent { get; }
|
||||
|
||||
public void CacheContent()
|
||||
{
|
||||
var embySettings = Emby.GetSettings();
|
||||
if (!embySettings.Enable)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!ValidateSettings(embySettings))
|
||||
{
|
||||
Log.Debug("Validation of emby settings failed.");
|
||||
return;
|
||||
}
|
||||
CachedLibraries(embySettings);
|
||||
}
|
||||
|
||||
|
||||
public List<EmbyMovieItem> GetMovies()
|
||||
{
|
||||
var settings = Emby.GetSettings();
|
||||
return EmbyApi.GetAllMovies(settings.ApiKey, settings.AdministratorId, settings.FullUri).Items;
|
||||
}
|
||||
|
||||
public List<EmbySeriesItem> GetTvShows()
|
||||
{
|
||||
var settings = Emby.GetSettings();
|
||||
return EmbyApi.GetAllShows(settings.ApiKey, settings.AdministratorId, settings.FullUri).Items;
|
||||
}
|
||||
|
||||
private void CachedLibraries(EmbySettings embySettings)
|
||||
{
|
||||
|
||||
if (!ValidateSettings(embySettings))
|
||||
{
|
||||
Log.Warn("The settings are not configured");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var movies = GetMovies();
|
||||
// Delete everything
|
||||
EmbyContent.Custom(connection =>
|
||||
{
|
||||
connection.Open();
|
||||
connection.Query("delete from EmbyContent where type = @type", new { type = 0 });
|
||||
return new List<EmbyContent>();
|
||||
});
|
||||
foreach (var m in movies)
|
||||
{
|
||||
if (m.Type.Equals("boxset", StringComparison.CurrentCultureIgnoreCase))
|
||||
{
|
||||
var info = EmbyApi.GetCollection(m.Id, embySettings.ApiKey,
|
||||
embySettings.AdministratorId, embySettings.FullUri);
|
||||
foreach (var item in info.Items)
|
||||
{
|
||||
var movieInfo = EmbyApi.GetInformation(item.Id, EmbyMediaType.Movie, embySettings.ApiKey,
|
||||
embySettings.AdministratorId, embySettings.FullUri).MovieInformation;
|
||||
ProcessMovies(movieInfo);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var movieInfo = EmbyApi.GetInformation(m.Id, EmbyMediaType.Movie, embySettings.ApiKey,
|
||||
embySettings.AdministratorId, embySettings.FullUri).MovieInformation;
|
||||
|
||||
ProcessMovies(movieInfo);
|
||||
}
|
||||
}
|
||||
|
||||
var tv = GetTvShows();
|
||||
// Delete everything
|
||||
EmbyContent.Custom(connection =>
|
||||
{
|
||||
connection.Open();
|
||||
connection.Query("delete from EmbyContent where type = @type", new { type = 1 });
|
||||
return new List<EmbyContent>();
|
||||
});
|
||||
foreach (var t in tv)
|
||||
{
|
||||
var tvInfo = EmbyApi.GetInformation(t.Id, EmbyMediaType.Series, embySettings.ApiKey,
|
||||
embySettings.AdministratorId, embySettings.FullUri).SeriesInformation;
|
||||
if (string.IsNullOrEmpty(tvInfo.ProviderIds?.Tvdb))
|
||||
{
|
||||
Log.Error("Provider Id on tv {0} is null", t.Name);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// Check if it exists
|
||||
var item = EmbyContent.Custom(connection =>
|
||||
{
|
||||
connection.Open();
|
||||
var media = connection.QueryFirstOrDefault<EmbyContent>("select * from EmbyContent where ProviderId = @ProviderId and type = @type", new { ProviderId = tvInfo.ProviderIds.Tvdb, type = 1 });
|
||||
connection.Dispose();
|
||||
return media;
|
||||
});
|
||||
if (item != null && item.EmbyId != t.Id)
|
||||
{
|
||||
// delete this item since the Id has changed
|
||||
EmbyContent.Delete(item);
|
||||
item = null;
|
||||
}
|
||||
|
||||
if (item == null)
|
||||
{
|
||||
EmbyContent.Insert(new EmbyContent
|
||||
{
|
||||
ProviderId = tvInfo.ProviderIds.Tvdb,
|
||||
PremierDate = tvInfo.PremiereDate,
|
||||
Title = tvInfo.Name,
|
||||
Type = Store.Models.Plex.EmbyMediaType.Series,
|
||||
EmbyId = t.Id,
|
||||
AddedAt = DateTime.UtcNow
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
//TODO Emby
|
||||
//var albums = GetPlexAlbums(results);
|
||||
//foreach (var a in albums)
|
||||
//{
|
||||
// if (string.IsNullOrEmpty(a.ProviderId))
|
||||
// {
|
||||
// Log.Error("Provider Id on album {0} is null", a.Title);
|
||||
// continue;
|
||||
// }
|
||||
|
||||
|
||||
// // Check if it exists
|
||||
// var item = EmbyContent.Custom(connection =>
|
||||
// {
|
||||
// connection.Open();
|
||||
// var media = connection.QueryFirstOrDefault<PlexContent>("select * from EmbyContent where ProviderId = @ProviderId and type = @type", new { a.ProviderId, type = 2 });
|
||||
// connection.Dispose();
|
||||
// return media;
|
||||
// });
|
||||
|
||||
// if (item == null)
|
||||
// {
|
||||
|
||||
// EmbyContent.Insert(new PlexContent
|
||||
// {
|
||||
// ProviderId = a.ProviderId,
|
||||
// ReleaseYear = a.ReleaseYear ?? string.Empty,
|
||||
// Title = a.Title,
|
||||
// Type = Store.Models.Plex.PlexMediaType.Artist,
|
||||
// Url = a.Url
|
||||
// });
|
||||
// }
|
||||
//}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "Failed to obtain Emby libraries");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private bool ValidateSettings(EmbySettings emby)
|
||||
{
|
||||
if (emby.Enable)
|
||||
{
|
||||
if (emby?.Ip == null || string.IsNullOrEmpty(emby?.ApiKey))
|
||||
{
|
||||
Log.Warn("A setting is null, Ensure Emby is configured correctly, and we have a Emby Auth token.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return emby.Enable;
|
||||
}
|
||||
|
||||
public void Execute(IJobExecutionContext context)
|
||||
{
|
||||
|
||||
Job.SetRunning(true, JobNames.EmbyCacher);
|
||||
try
|
||||
{
|
||||
CacheContent();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Job.Record(JobNames.EmbyCacher);
|
||||
Job.SetRunning(false, JobNames.EmbyCacher);
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessMovies(EmbyMovieInformation movieInfo)
|
||||
{
|
||||
if (string.IsNullOrEmpty(movieInfo.ProviderIds.Imdb))
|
||||
{
|
||||
Log.Error("Provider Id on movie {0} is null", movieInfo.Name);
|
||||
return;
|
||||
}
|
||||
// Check if it exists
|
||||
var item = EmbyContent.Custom(connection =>
|
||||
{
|
||||
connection.Open();
|
||||
var media = connection.QueryFirstOrDefault<EmbyContent>("select * from EmbyContent where ProviderId = @ProviderId and type = @type", new { ProviderId = movieInfo.ProviderIds.Imdb, type = 0 });
|
||||
connection.Dispose();
|
||||
return media;
|
||||
});
|
||||
|
||||
if (item != null && item.EmbyId != movieInfo.Id)
|
||||
{
|
||||
// delete this item since the Id has changed
|
||||
EmbyContent.Delete(item);
|
||||
item = null;
|
||||
}
|
||||
|
||||
if (item == null)
|
||||
{
|
||||
// Doesn't exist, insert it
|
||||
EmbyContent.Insert(new EmbyContent
|
||||
{
|
||||
ProviderId = movieInfo.ProviderIds.Imdb,
|
||||
PremierDate = movieInfo.PremiereDate,
|
||||
Title = movieInfo.Name,
|
||||
Type = Store.Models.Plex.EmbyMediaType.Movie,
|
||||
EmbyId = movieInfo.Id,
|
||||
AddedAt = DateTime.UtcNow
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
180
Old/Ombi.Services/Jobs/EmbyEpisodeCacher.cs
Normal file
180
Old/Ombi.Services/Jobs/EmbyEpisodeCacher.cs
Normal file
|
@ -0,0 +1,180 @@
|
|||
#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
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Dapper;
|
||||
using NLog;
|
||||
using Ombi.Api.Interfaces;
|
||||
using Ombi.Api.Models.Emby;
|
||||
using Ombi.Core;
|
||||
using Ombi.Core.SettingModels;
|
||||
using Ombi.Helpers;
|
||||
using Ombi.Services.Interfaces;
|
||||
using Ombi.Services.Jobs.Interfaces;
|
||||
using Ombi.Store.Models.Emby;
|
||||
using Ombi.Store.Repository;
|
||||
using Quartz;
|
||||
|
||||
namespace Ombi.Services.Jobs
|
||||
{
|
||||
public class EmbyEpisodeCacher : IJob, IEmbyEpisodeCacher
|
||||
{
|
||||
public EmbyEpisodeCacher(ISettingsService<EmbySettings> embySettings, IEmbyApi emby, ICacheProvider cache,
|
||||
IJobRecord rec, IRepository<EmbyEpisodes> repo, ISettingsService<ScheduledJobsSettings> jobs)
|
||||
{
|
||||
Emby = embySettings;
|
||||
EmbyApi = emby;
|
||||
Cache = cache;
|
||||
Job = rec;
|
||||
Repo = repo;
|
||||
Jobs = jobs;
|
||||
}
|
||||
|
||||
private ISettingsService<EmbySettings> Emby { get; }
|
||||
private static Logger Log = LogManager.GetCurrentClassLogger();
|
||||
private IEmbyApi EmbyApi { get; }
|
||||
private ICacheProvider Cache { get; }
|
||||
private IJobRecord Job { get; }
|
||||
private IRepository<EmbyEpisodes> Repo { get; }
|
||||
private ISettingsService<ScheduledJobsSettings> Jobs { get; }
|
||||
|
||||
private const string TableName = "EmbyEpisodes";
|
||||
|
||||
// Note, once an episode exists, we store it and it always exists.
|
||||
// We might want to look at checking if something has been removed from the server in the future.
|
||||
public void CacheEpisodes(EmbySettings settings)
|
||||
{
|
||||
var allEpisodes = EmbyApi.GetAllEpisodes(settings.ApiKey, settings.AdministratorId, settings.FullUri);
|
||||
var model = new List<EmbyEpisodes>();
|
||||
foreach (var ep in allEpisodes.Items)
|
||||
{
|
||||
var epInfo = EmbyApi.GetInformation(ep.Id, EmbyMediaType.Episode, settings.ApiKey,
|
||||
settings.AdministratorId, settings.FullUri);
|
||||
if (epInfo.EpisodeInformation?.ProviderIds?.Tvdb == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// Check it this episode exists
|
||||
var item = Repo.Custom(connection =>
|
||||
{
|
||||
connection.Open();
|
||||
var media =
|
||||
connection.QueryFirstOrDefault<EmbyEpisodes>(
|
||||
"select * from EmbyEpisodes where ProviderId = @ProviderId",
|
||||
new {ProviderId = epInfo.EpisodeInformation?.ProviderIds?.Tvdb});
|
||||
connection.Dispose();
|
||||
return media;
|
||||
});
|
||||
|
||||
if (item != null)
|
||||
{
|
||||
if (item.EmbyId != ep.Id) // The id's dont match, delete it
|
||||
{
|
||||
Repo.Delete(item);
|
||||
item = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (item == null)
|
||||
{
|
||||
// add it
|
||||
model.Add(new EmbyEpisodes
|
||||
{
|
||||
EmbyId = ep.Id,
|
||||
EpisodeNumber = ep.IndexNumber,
|
||||
SeasonNumber = ep.ParentIndexNumber,
|
||||
EpisodeTitle = ep.Name,
|
||||
ParentId = ep.SeriesId,
|
||||
ShowTitle = ep.SeriesName,
|
||||
ProviderId = epInfo.EpisodeInformation.ProviderIds.Tvdb,
|
||||
AddedAt = DateTime.UtcNow
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Insert the new items
|
||||
var result = Repo.BatchInsert(model, TableName);
|
||||
|
||||
if (!result)
|
||||
{
|
||||
Log.Error("Saving the emby episodes to the DB Failed");
|
||||
}
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
try
|
||||
{
|
||||
var s = Emby.GetSettings();
|
||||
if (!s.EnableEpisodeSearching)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Job.SetRunning(true, JobNames.EmbyEpisodeCacher);
|
||||
CacheEpisodes(s);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Job.Record(JobNames.EmbyEpisodeCacher);
|
||||
Job.SetRunning(false, JobNames.EmbyEpisodeCacher);
|
||||
}
|
||||
}
|
||||
public void Execute(IJobExecutionContext context)
|
||||
{
|
||||
|
||||
try
|
||||
{
|
||||
var s = Emby.GetSettings();
|
||||
if (!s.EnableEpisodeSearching)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Job.SetRunning(true, JobNames.EmbyEpisodeCacher);
|
||||
CacheEpisodes(s);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Job.Record(JobNames.EmbyEpisodeCacher);
|
||||
Job.SetRunning(false, JobNames.EmbyEpisodeCacher);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
136
Old/Ombi.Services/Jobs/EmbyUserChecker.cs
Normal file
136
Old/Ombi.Services/Jobs/EmbyUserChecker.cs
Normal file
|
@ -0,0 +1,136 @@
|
|||
#region Copyright
|
||||
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2016 Jamie Rees
|
||||
// File: StoreCleanup.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
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using Ombi.Api.Interfaces;
|
||||
using Ombi.Core;
|
||||
using Ombi.Core.SettingModels;
|
||||
using Ombi.Core.Users;
|
||||
using Ombi.Helpers.Permissions;
|
||||
using Ombi.Services.Interfaces;
|
||||
using Ombi.Store.Models.Emby;
|
||||
using Ombi.Store.Repository;
|
||||
using Quartz;
|
||||
|
||||
namespace Ombi.Services.Jobs
|
||||
{
|
||||
public class EmbyUserChecker : IJob, IEmbyUserChecker
|
||||
{
|
||||
private static readonly Logger Log = LogManager.GetCurrentClassLogger();
|
||||
|
||||
public EmbyUserChecker(IExternalUserRepository<EmbyUsers> plexUsers, IEmbyApi embyApi, IJobRecord rec, ISettingsService<EmbySettings> embyS, ISettingsService<PlexRequestSettings> prSettings, ISettingsService<UserManagementSettings> umSettings,
|
||||
IRequestService requestService, IUserRepository localUser)
|
||||
{
|
||||
Repo = plexUsers;
|
||||
JobRecord = rec;
|
||||
EmbyApi = embyApi;
|
||||
EmbySettings = embyS;
|
||||
PlexRequestSettings = prSettings;
|
||||
UserManagementSettings = umSettings;
|
||||
RequestService = requestService;
|
||||
LocalUserRepository = localUser;
|
||||
}
|
||||
|
||||
private IJobRecord JobRecord { get; }
|
||||
private IEmbyApi EmbyApi { get; }
|
||||
private IExternalUserRepository<EmbyUsers> Repo { get; }
|
||||
private ISettingsService<EmbySettings> EmbySettings { get; }
|
||||
private ISettingsService<PlexRequestSettings> PlexRequestSettings { get; }
|
||||
private ISettingsService<UserManagementSettings> UserManagementSettings { get; }
|
||||
private IRequestService RequestService { get; }
|
||||
private IUserRepository LocalUserRepository { get; }
|
||||
|
||||
public void Start()
|
||||
{
|
||||
JobRecord.SetRunning(true, JobNames.EmbyUserChecker);
|
||||
|
||||
try
|
||||
{
|
||||
var settings = EmbySettings.GetSettings();
|
||||
if (string.IsNullOrEmpty(settings.ApiKey) || !settings.Enable)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var embyUsers = EmbyApi.GetUsers(settings.FullUri, settings.ApiKey);
|
||||
var userManagementSettings = UserManagementSettings.GetSettings();
|
||||
|
||||
var dbUsers = Repo.GetAll().ToList();
|
||||
|
||||
// Regular users
|
||||
foreach (var user in embyUsers)
|
||||
{
|
||||
var dbUser = dbUsers.FirstOrDefault(x => x.EmbyUserId == user.Id);
|
||||
if (dbUser != null)
|
||||
{
|
||||
// we already have a user
|
||||
continue;
|
||||
}
|
||||
|
||||
// Looks like it's a new user!
|
||||
var m = new EmbyUsers
|
||||
{
|
||||
EmbyUserId = user.Id,
|
||||
Permissions = UserManagementHelper.GetPermissions(userManagementSettings),
|
||||
Features = UserManagementHelper.GetFeatures(userManagementSettings),
|
||||
UserAlias = string.Empty,
|
||||
Username = user.Name,
|
||||
LoginId = Guid.NewGuid().ToString()
|
||||
};
|
||||
|
||||
|
||||
// If it's the admin, give them the admin permission
|
||||
if (user.Policy.IsAdministrator)
|
||||
{
|
||||
if (!((Permissions) m.Permissions).HasFlag(Permissions.Administrator))
|
||||
{
|
||||
m.Permissions += (int)Permissions.Administrator;
|
||||
}
|
||||
}
|
||||
|
||||
Repo.Insert(m);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
JobRecord.SetRunning(false, JobNames.EmbyUserChecker);
|
||||
JobRecord.Record(JobNames.EmbyUserChecker);
|
||||
}
|
||||
}
|
||||
public void Execute(IJobExecutionContext context)
|
||||
{
|
||||
Start();
|
||||
}
|
||||
}
|
||||
}
|
337
Old/Ombi.Services/Jobs/FaultQueueHandler.cs
Normal file
337
Old/Ombi.Services/Jobs/FaultQueueHandler.cs
Normal file
|
@ -0,0 +1,337 @@
|
|||
#region Copyright
|
||||
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2016 Jamie Rees
|
||||
// File: UserRequestLimitResetter.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
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using Ombi.Api;
|
||||
using Ombi.Api.Interfaces;
|
||||
using Ombi.Core;
|
||||
using Ombi.Core.SettingModels;
|
||||
using Ombi.Helpers;
|
||||
using Ombi.Helpers.Permissions;
|
||||
using Ombi.Services.Interfaces;
|
||||
using Ombi.Store;
|
||||
using Ombi.Store.Models;
|
||||
using Ombi.Store.Repository;
|
||||
using Quartz;
|
||||
|
||||
namespace Ombi.Services.Jobs
|
||||
{
|
||||
public class FaultQueueHandler : IJob, IFaultQueueHandler
|
||||
{
|
||||
private static readonly Logger Log = LogManager.GetCurrentClassLogger();
|
||||
|
||||
public FaultQueueHandler(IJobRecord record, IRepository<RequestQueue> repo, ISonarrApi sonarrApi,
|
||||
ISickRageApi srApi, ISettingsService<SonarrSettings> sonarrSettings, ISettingsService<SickRageSettings> srSettings,
|
||||
ICouchPotatoApi cpApi, ISettingsService<CouchPotatoSettings> cpsettings, IRequestService requestService,
|
||||
ISettingsService<HeadphonesSettings> hpSettings, IHeadphonesApi headphonesApi, ISettingsService<PlexRequestSettings> prSettings,
|
||||
ISecurityExtensions security, IMovieSender movieSender, ICacheProvider cache)
|
||||
{
|
||||
Record = record;
|
||||
Repo = repo;
|
||||
SonarrApi = sonarrApi;
|
||||
SrApi = srApi;
|
||||
CpApi = cpApi;
|
||||
HpApi = headphonesApi;
|
||||
|
||||
RequestService = requestService;
|
||||
|
||||
SickrageSettings = srSettings;
|
||||
SonarrSettings = sonarrSettings;
|
||||
CpSettings = cpsettings;
|
||||
HeadphoneSettings = hpSettings;
|
||||
Security = security;
|
||||
PrSettings = prSettings.GetSettings();
|
||||
MovieSender = movieSender;
|
||||
|
||||
Cache = cache;
|
||||
}
|
||||
|
||||
private IMovieSender MovieSender { get; }
|
||||
private IRepository<RequestQueue> Repo { get; }
|
||||
private IJobRecord Record { get; }
|
||||
private ISonarrApi SonarrApi { get; }
|
||||
private ISickRageApi SrApi { get; }
|
||||
private ICacheProvider Cache { get; }
|
||||
private ICouchPotatoApi CpApi { get; }
|
||||
private IHeadphonesApi HpApi { get; }
|
||||
private IRequestService RequestService { get; }
|
||||
private PlexRequestSettings PrSettings { get; }
|
||||
private ISettingsService<SonarrSettings> SonarrSettings { get; }
|
||||
private ISettingsService<SickRageSettings> SickrageSettings { get; }
|
||||
private ISettingsService<CouchPotatoSettings> CpSettings { get; }
|
||||
private ISettingsService<HeadphonesSettings> HeadphoneSettings { get; }
|
||||
private ISecurityExtensions Security { get; }
|
||||
|
||||
public void Start()
|
||||
{
|
||||
Record.SetRunning(true, JobNames.CpCacher);
|
||||
try
|
||||
{
|
||||
var faultedRequests = Repo.GetAll().ToList();
|
||||
|
||||
var missingInfo = faultedRequests.Where(x => x.FaultType == FaultType.MissingInformation).ToList();
|
||||
ProcessMissingInformation(missingInfo);
|
||||
|
||||
var transientErrors = faultedRequests.Where(x => x.FaultType == FaultType.RequestFault).ToList();
|
||||
ProcessTransientErrors(transientErrors);
|
||||
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Record.Record(JobNames.FaultQueueHandler);
|
||||
Record.SetRunning(false, JobNames.CpCacher);
|
||||
}
|
||||
}
|
||||
public void Execute(IJobExecutionContext context)
|
||||
{
|
||||
|
||||
Start();
|
||||
}
|
||||
|
||||
|
||||
private void ProcessMissingInformation(List<RequestQueue> requests)
|
||||
{
|
||||
if (!requests.Any())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var sonarrSettings = SonarrSettings.GetSettings();
|
||||
var sickrageSettings = SickrageSettings.GetSettings();
|
||||
|
||||
var tv = requests.Where(x => x.Type == RequestType.TvShow);
|
||||
|
||||
// TV
|
||||
var tvApi = new TvMazeApi();
|
||||
foreach (var t in tv)
|
||||
{
|
||||
var providerId = int.Parse(t.PrimaryIdentifier);
|
||||
var showInfo = tvApi.ShowLookup(providerId);
|
||||
|
||||
if (showInfo.externals?.thetvdb != null)
|
||||
{
|
||||
// We now have the info
|
||||
var tvModel = ByteConverterHelper.ReturnObject<RequestedModel>(t.Content);
|
||||
tvModel.ProviderId = showInfo.externals.thetvdb.Value;
|
||||
var result = ProcessTvShow(tvModel, sonarrSettings, sickrageSettings);
|
||||
|
||||
if (!result)
|
||||
{
|
||||
// we now have the info but couldn't add it, so add it back into the queue but with a different fault
|
||||
t.Content = ByteConverterHelper.ReturnBytes(tvModel);
|
||||
t.FaultType = FaultType.RequestFault;
|
||||
t.LastRetry = DateTime.UtcNow;
|
||||
Repo.Update(t);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Make sure it's been requested
|
||||
var existingRequests = RequestService.GetAll();
|
||||
var thisItem = existingRequests.Any(x => x.Title.Equals(tvModel.Title));
|
||||
if (!thisItem)
|
||||
{
|
||||
tvModel.Approved = true;
|
||||
RequestService.AddRequest(tvModel);
|
||||
}
|
||||
|
||||
// Successful, remove from the fault queue
|
||||
Repo.Delete(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool ProcessTvShow(RequestedModel tvModel, SonarrSettings sonarr, SickRageSettings sickrage)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
var sender = new TvSenderOld(SonarrApi, SrApi, Cache);
|
||||
if (sonarr.Enabled)
|
||||
{
|
||||
var task = sender.SendToSonarr(sonarr, tvModel, sonarr.QualityProfile);
|
||||
var a = task.Result;
|
||||
if (string.IsNullOrEmpty(a?.title))
|
||||
{
|
||||
// Couldn't send it
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (sickrage.Enabled)
|
||||
{
|
||||
var result = sender.SendToSickRage(sickrage, tvModel);
|
||||
if (result?.result != "success")
|
||||
{
|
||||
// Couldn't send it
|
||||
return false;
|
||||
}
|
||||
|
||||
// Approve it
|
||||
tvModel.Approved = true;
|
||||
RequestService.UpdateRequest(tvModel);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
return false; // It fails so it will get added back into the queue
|
||||
}
|
||||
}
|
||||
|
||||
private bool ProcessMovies(RequestedModel model)
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = MovieSender.Send(model).Result;
|
||||
if (result.Result)
|
||||
{
|
||||
// Approve it now
|
||||
model.Approved = true;
|
||||
RequestService.UpdateRequest(model);
|
||||
return true;
|
||||
};
|
||||
|
||||
return false;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
return false; // It fails so it will get added back into the queue
|
||||
}
|
||||
}
|
||||
|
||||
private bool ProcessAlbums(RequestedModel model, HeadphonesSettings hp)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (hp.Enabled)
|
||||
{
|
||||
var sender = new HeadphonesSender(HpApi, hp, RequestService);
|
||||
var result = sender.AddAlbum(model).Result;
|
||||
|
||||
if (result)
|
||||
{
|
||||
|
||||
if (ShouldAutoApprove(model.Type, PrSettings, model.RequestedUsers))
|
||||
// Approve it now
|
||||
model.Approved = true;
|
||||
RequestService.UpdateRequest(model);
|
||||
};
|
||||
|
||||
return result;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
return false; // It fails so it will get added back into the queue
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessTransientErrors(List<RequestQueue> requests)
|
||||
{
|
||||
var sonarrSettings = SonarrSettings.GetSettings();
|
||||
var sickrageSettings = SickrageSettings.GetSettings();
|
||||
var hpSettings = HeadphoneSettings.GetSettings();
|
||||
|
||||
if (!requests.Any())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var request in requests)
|
||||
{
|
||||
var model = ByteConverterHelper.ReturnObject<RequestedModel>(request.Content);
|
||||
bool result;
|
||||
switch (request.Type)
|
||||
{
|
||||
case RequestType.Movie:
|
||||
result = ProcessMovies(model);
|
||||
break;
|
||||
case RequestType.TvShow:
|
||||
result = ProcessTvShow(model, sonarrSettings, sickrageSettings);
|
||||
break;
|
||||
case RequestType.Album:
|
||||
result = ProcessAlbums(model, hpSettings);
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
if (!result)
|
||||
{
|
||||
// we now have the info but couldn't add it, so do nothing now.
|
||||
request.LastRetry = DateTime.UtcNow;
|
||||
Repo.Update(request);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Successful, remove from the fault queue
|
||||
Repo.Delete(request);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool ShouldAutoApprove(RequestType requestType, PlexRequestSettings prSettings, List<string> username)
|
||||
{
|
||||
foreach (var user in username)
|
||||
{
|
||||
var admin = Security.HasPermissions(user, Permissions.Administrator);
|
||||
// if the user is an admin or they are whitelisted, they go ahead and allow auto-approval
|
||||
if (admin) return true;
|
||||
|
||||
// check by request type if the category requires approval or not
|
||||
switch (requestType)
|
||||
{
|
||||
case RequestType.Movie:
|
||||
return Security.HasPermissions(user, Permissions.AutoApproveMovie);
|
||||
case RequestType.TvShow:
|
||||
return Security.HasPermissions(user, Permissions.AutoApproveTv);
|
||||
case RequestType.Album:
|
||||
return Security.HasPermissions(user, Permissions.AutoApproveAlbum);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
69
Old/Ombi.Services/Jobs/HtmlTemplateGenerator.cs
Normal file
69
Old/Ombi.Services/Jobs/HtmlTemplateGenerator.cs
Normal file
|
@ -0,0 +1,69 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2016 Jamie Rees
|
||||
// File: HtmlTemplateGenerator.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
|
||||
|
||||
using System.Text;
|
||||
|
||||
namespace Ombi.Services.Jobs
|
||||
{
|
||||
public abstract class HtmlTemplateGenerator
|
||||
{
|
||||
protected virtual void AddParagraph(StringBuilder stringBuilder, string text, int fontSize = 14, string fontWeight = "normal")
|
||||
{
|
||||
stringBuilder.AppendFormat("<p style=\"font-family: sans-serif; font-size: {1}px; font-weight: {2}; margin: 0; Margin-bottom: 15px;\">{0}</p>", text, fontSize, fontWeight);
|
||||
}
|
||||
|
||||
protected virtual void AddImageInsideTable(StringBuilder sb, string url)
|
||||
{
|
||||
sb.Append("<tr>");
|
||||
sb.Append("<td align=\"center\">");
|
||||
sb.AppendFormat(
|
||||
"<img src=\"{0}\" width=\"400px\" text-align=\"center\" />",
|
||||
url);
|
||||
sb.Append("</td>");
|
||||
sb.Append("</tr>");
|
||||
}
|
||||
|
||||
protected virtual void Href(StringBuilder sb, string url)
|
||||
{
|
||||
sb.AppendFormat("<a href=\"{0}\">", url);
|
||||
}
|
||||
|
||||
protected virtual void EndTag(StringBuilder sb, string tag)
|
||||
{
|
||||
sb.AppendFormat("</{0}>", tag);
|
||||
}
|
||||
|
||||
protected virtual void Header(StringBuilder sb, int size, string text, string fontWeight = "normal")
|
||||
{
|
||||
sb.AppendFormat(
|
||||
"<h{0} style=\"font-family: sans-serif; font-weight: {2}; margin: 0; Margin-bottom: 15px;\">{1}</h{0}>",
|
||||
size, text, fontWeight);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
10
Old/Ombi.Services/Jobs/IEmbyUserChecker.cs
Normal file
10
Old/Ombi.Services/Jobs/IEmbyUserChecker.cs
Normal file
|
@ -0,0 +1,10 @@
|
|||
using Quartz;
|
||||
|
||||
namespace Ombi.Services.Jobs
|
||||
{
|
||||
public interface IEmbyUserChecker
|
||||
{
|
||||
void Execute(IJobExecutionContext context);
|
||||
void Start();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Ombi.Store.Models.Emby;
|
||||
using Quartz;
|
||||
|
||||
namespace Ombi.Services.Jobs
|
||||
{
|
||||
public interface IEmbyAvailabilityChecker
|
||||
{
|
||||
void CheckAndUpdateAll();
|
||||
void Execute(IJobExecutionContext context);
|
||||
IEnumerable<EmbyContent> GetEmbyMovies(IEnumerable<EmbyContent> content);
|
||||
IEnumerable<EmbyContent> GetEmbyMusic(IEnumerable<EmbyContent> content);
|
||||
IEnumerable<EmbyContent> GetEmbyTvShows(IEnumerable<EmbyContent> content);
|
||||
Task<IEnumerable<EmbyEpisodes>> GetEpisodes();
|
||||
Task<IEnumerable<EmbyEpisodes>> GetEpisodes(int theTvDbId);
|
||||
EmbyContent GetMovie(IEnumerable<EmbyContent> embyMovies, string title, string year, string providerId);
|
||||
EmbyContent GetTvShow(IEnumerable<EmbyContent> embyShows, string title, string year, string providerId, int[] seasons = null);
|
||||
bool IsEpisodeAvailable(string theTvDbId, int season, int episode);
|
||||
bool IsMovieAvailable(IEnumerable<EmbyContent> embyMovies, string title, string year, string providerId);
|
||||
bool IsTvShowAvailable(IEnumerable<EmbyContent> embyShows, string title, string year, string providerId, int[] seasons = null);
|
||||
void Start();
|
||||
}
|
||||
}
|
14
Old/Ombi.Services/Jobs/Interfaces/IEmbyContentCacher.cs
Normal file
14
Old/Ombi.Services/Jobs/Interfaces/IEmbyContentCacher.cs
Normal file
|
@ -0,0 +1,14 @@
|
|||
using System.Collections.Generic;
|
||||
using Ombi.Api.Models.Emby;
|
||||
using Quartz;
|
||||
|
||||
namespace Ombi.Services.Jobs.Interfaces
|
||||
{
|
||||
public interface IEmbyContentCacher
|
||||
{
|
||||
void CacheContent();
|
||||
void Execute(IJobExecutionContext context);
|
||||
List<EmbyMovieItem> GetMovies();
|
||||
List<EmbySeriesItem> GetTvShows();
|
||||
}
|
||||
}
|
12
Old/Ombi.Services/Jobs/Interfaces/IEmbyEpisodeCacher.cs
Normal file
12
Old/Ombi.Services/Jobs/Interfaces/IEmbyEpisodeCacher.cs
Normal file
|
@ -0,0 +1,12 @@
|
|||
using Ombi.Core.SettingModels;
|
||||
using Quartz;
|
||||
|
||||
namespace Ombi.Services.Jobs.Interfaces
|
||||
{
|
||||
public interface IEmbyEpisodeCacher
|
||||
{
|
||||
void CacheEpisodes(EmbySettings settings);
|
||||
void Execute(IJobExecutionContext context);
|
||||
void Start();
|
||||
}
|
||||
}
|
14
Old/Ombi.Services/Jobs/Interfaces/IFaultQueueHandler.cs
Normal file
14
Old/Ombi.Services/Jobs/Interfaces/IFaultQueueHandler.cs
Normal file
|
@ -0,0 +1,14 @@
|
|||
using System.Collections.Generic;
|
||||
using Ombi.Core.SettingModels;
|
||||
using Ombi.Store;
|
||||
using Quartz;
|
||||
|
||||
namespace Ombi.Services.Jobs
|
||||
{
|
||||
public interface IFaultQueueHandler
|
||||
{
|
||||
void Execute(IJobExecutionContext context);
|
||||
bool ShouldAutoApprove(RequestType requestType, PlexRequestSettings prSettings, List<string> username);
|
||||
void Start();
|
||||
}
|
||||
}
|
12
Old/Ombi.Services/Jobs/Interfaces/IPlexEpisodeCacher.cs
Normal file
12
Old/Ombi.Services/Jobs/Interfaces/IPlexEpisodeCacher.cs
Normal file
|
@ -0,0 +1,12 @@
|
|||
using Ombi.Core.SettingModels;
|
||||
using Quartz;
|
||||
|
||||
namespace Ombi.Services.Jobs
|
||||
{
|
||||
public interface IPlexEpisodeCacher
|
||||
{
|
||||
void CacheEpisodes(PlexSettings settings);
|
||||
void Execute(IJobExecutionContext context);
|
||||
void Start();
|
||||
}
|
||||
}
|
10
Old/Ombi.Services/Jobs/Interfaces/IPlexUserChecker.cs
Normal file
10
Old/Ombi.Services/Jobs/Interfaces/IPlexUserChecker.cs
Normal file
|
@ -0,0 +1,10 @@
|
|||
using Quartz;
|
||||
|
||||
namespace Ombi.Services.Jobs
|
||||
{
|
||||
public interface IPlexUserChecker
|
||||
{
|
||||
void Execute(IJobExecutionContext context);
|
||||
void Start();
|
||||
}
|
||||
}
|
51
Old/Ombi.Services/Jobs/JobNames.cs
Normal file
51
Old/Ombi.Services/Jobs/JobNames.cs
Normal file
|
@ -0,0 +1,51 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2016 Jamie Rees
|
||||
// File: JobNames.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
|
||||
namespace Ombi.Services.Jobs
|
||||
{
|
||||
public static class JobNames
|
||||
{
|
||||
public const string StoreBackup = "Database Backup";
|
||||
public const string CpCacher = "CouchPotato Cacher";
|
||||
public const string WatcherCacher = "Watcher Cacher";
|
||||
public const string SonarrCacher = "Sonarr Cacher";
|
||||
public const string RadarrCacher = "Radarr Cacher";
|
||||
public const string SrCacher = "SickRage Cacher";
|
||||
public const string PlexChecker = "Plex Availability Cacher";
|
||||
public const string EmbyChecker = "Emby Availability Cacher";
|
||||
public const string PlexCacher = "Plex Cacher";
|
||||
public const string EmbyCacher = "Emby Cacher";
|
||||
public const string StoreCleanup = "Database Cleanup";
|
||||
public const string RequestLimitReset = "Request Limit Reset";
|
||||
public const string EpisodeCacher = "Plex Episode Cacher";
|
||||
public const string EmbyEpisodeCacher = "Emby Episode Cacher";
|
||||
public const string RecentlyAddedEmail = "Recently Added Email Notification";
|
||||
public const string FaultQueueHandler = "Request Fault Queue Handler";
|
||||
public const string PlexUserChecker = "Plex User Checker";
|
||||
public const string EmbyUserChecker = "Emby User Checker";
|
||||
|
||||
}
|
||||
}
|
90
Old/Ombi.Services/Jobs/JobRecord.cs
Normal file
90
Old/Ombi.Services/Jobs/JobRecord.cs
Normal file
|
@ -0,0 +1,90 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2016 Jamie Rees
|
||||
// File: JobRecord.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
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Ombi.Services.Interfaces;
|
||||
using Ombi.Store.Models;
|
||||
using Ombi.Store.Repository;
|
||||
|
||||
namespace Ombi.Services.Jobs
|
||||
{
|
||||
public class JobRecord : IJobRecord
|
||||
{
|
||||
public JobRecord(IRepository<ScheduledJobs> repo)
|
||||
{
|
||||
Repo = repo;
|
||||
}
|
||||
|
||||
private IRepository<ScheduledJobs> Repo { get; }
|
||||
|
||||
public void Record(string jobName)
|
||||
{
|
||||
var allJobs = Repo.GetAll();
|
||||
var storeJob = allJobs.FirstOrDefault(x => x.Name == jobName);
|
||||
if (storeJob != null)
|
||||
{
|
||||
storeJob.LastRun = DateTime.UtcNow;
|
||||
Repo.Update(storeJob);
|
||||
}
|
||||
else
|
||||
{
|
||||
var job = new ScheduledJobs { LastRun = DateTime.UtcNow, Name = jobName };
|
||||
Repo.Insert(job);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetRunning(bool running, string jobName)
|
||||
{
|
||||
var allJobs = Repo.GetAll();
|
||||
var storeJob = allJobs.FirstOrDefault(x => x.Name == jobName);
|
||||
if (storeJob != null)
|
||||
{
|
||||
storeJob.Running = running;
|
||||
Repo.Update(storeJob);
|
||||
}
|
||||
else
|
||||
{
|
||||
var job = new ScheduledJobs { Running = running, Name = jobName };
|
||||
Repo.Insert(job);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public async Task<IEnumerable<ScheduledJobs>> GetJobsAsync()
|
||||
{
|
||||
return await Repo.GetAllAsync();
|
||||
}
|
||||
|
||||
public IEnumerable<ScheduledJobs> GetJobs()
|
||||
{
|
||||
return Repo.GetAll();
|
||||
}
|
||||
}
|
||||
}
|
503
Old/Ombi.Services/Jobs/PlexAvailabilityChecker.cs
Normal file
503
Old/Ombi.Services/Jobs/PlexAvailabilityChecker.cs
Normal file
|
@ -0,0 +1,503 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2016 Jamie Rees
|
||||
// File: PlexAvailabilityChecker.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
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Dapper;
|
||||
using NLog;
|
||||
using Ombi.Api.Interfaces;
|
||||
using Ombi.Api.Models.Plex;
|
||||
using Ombi.Core;
|
||||
using Ombi.Core.Models;
|
||||
using Ombi.Core.SettingModels;
|
||||
using Ombi.Helpers;
|
||||
using Ombi.Services.Interfaces;
|
||||
using Ombi.Services.Models;
|
||||
using Ombi.Store;
|
||||
using Ombi.Store.Models;
|
||||
using Ombi.Store.Models.Plex;
|
||||
using Ombi.Store.Repository;
|
||||
using Quartz;
|
||||
using PlexMediaType = Ombi.Api.Models.Plex.PlexMediaType;
|
||||
|
||||
namespace Ombi.Services.Jobs
|
||||
{
|
||||
public class PlexAvailabilityChecker : IJob, IAvailabilityChecker
|
||||
{
|
||||
public PlexAvailabilityChecker(ISettingsService<PlexSettings> plexSettings, IRequestService request, IPlexApi plex, ICacheProvider cache,
|
||||
INotificationService notify, IJobRecord rec, IRepository<UsersToNotify> users, IRepository<PlexEpisodes> repo, IPlexNotificationEngine e, IRepository<PlexContent> content)
|
||||
{
|
||||
Plex = plexSettings;
|
||||
RequestService = request;
|
||||
PlexApi = plex;
|
||||
Cache = cache;
|
||||
Notification = notify;
|
||||
Job = rec;
|
||||
UserNotifyRepo = users;
|
||||
EpisodeRepo = repo;
|
||||
NotificationEngine = e;
|
||||
PlexContent = content;
|
||||
}
|
||||
|
||||
private ISettingsService<PlexSettings> Plex { get; }
|
||||
private IRepository<PlexEpisodes> EpisodeRepo { get; }
|
||||
private IRequestService RequestService { get; }
|
||||
private static Logger Log = LogManager.GetCurrentClassLogger();
|
||||
private IPlexApi PlexApi { get; }
|
||||
private ICacheProvider Cache { get; }
|
||||
private INotificationService Notification { get; }
|
||||
private IJobRecord Job { get; }
|
||||
private IRepository<UsersToNotify> UserNotifyRepo { get; }
|
||||
private INotificationEngine NotificationEngine { get; }
|
||||
private IRepository<PlexContent> PlexContent { get; }
|
||||
|
||||
public void CheckAndUpdateAll()
|
||||
{
|
||||
|
||||
var plexSettings = Plex.GetSettings();
|
||||
|
||||
if (!plexSettings.Enable)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ValidateSettings(plexSettings))
|
||||
{
|
||||
Log.Debug("Validation of the plex settings failed.");
|
||||
return;
|
||||
}
|
||||
//var libraries = CachedLibraries(plexSettings, true); //force setting the cache (10 min intervals via scheduler)
|
||||
|
||||
//if (libraries == null || !libraries.Any())
|
||||
//{
|
||||
// Log.Debug("Did not find any libraries in Plex.");
|
||||
// return;
|
||||
//}
|
||||
var content = PlexContent.GetAll().ToList();
|
||||
var movies = GetPlexMovies(content).ToArray();
|
||||
var shows = GetPlexTvShows(content).ToArray();
|
||||
var albums = GetPlexAlbums(content).ToArray();
|
||||
|
||||
var requests = RequestService.GetAll();
|
||||
var requestedModels = requests as RequestedModel[] ?? requests.Where(x => !x.Available).ToArray();
|
||||
|
||||
if (!requestedModels.Any())
|
||||
{
|
||||
Log.Debug("There are no requests to check.");
|
||||
return;
|
||||
}
|
||||
|
||||
var modifiedModel = new List<RequestedModel>();
|
||||
foreach (var r in requestedModels)
|
||||
{
|
||||
var releaseDate = r.ReleaseDate == DateTime.MinValue ? string.Empty : r.ReleaseDate.ToString("yyyy");
|
||||
bool matchResult;
|
||||
|
||||
switch (r.Type)
|
||||
{
|
||||
case RequestType.Movie:
|
||||
matchResult = IsMovieAvailable(movies, r.Title, releaseDate, r.ImdbId);
|
||||
break;
|
||||
case RequestType.TvShow:
|
||||
if (!plexSettings.EnableTvEpisodeSearching)
|
||||
{
|
||||
matchResult = IsTvShowAvailable(shows, r.Title, releaseDate, r.TvDbId, r.SeasonList);
|
||||
}
|
||||
else
|
||||
{
|
||||
matchResult = r.Episodes.Any() ?
|
||||
r.Episodes.All(x => IsEpisodeAvailable(r.TvDbId, x.SeasonNumber, x.EpisodeNumber)) :
|
||||
IsTvShowAvailable(shows, r.Title, releaseDate, r.TvDbId, r.SeasonList);
|
||||
}
|
||||
break;
|
||||
case RequestType.Album:
|
||||
matchResult = IsAlbumAvailable(albums, r.Title, r.ReleaseDate.Year.ToString(), r.ArtistName);
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
|
||||
if (matchResult)
|
||||
{
|
||||
r.Available = true;
|
||||
modifiedModel.Add(r);
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Log.Debug("Requests that will be updated count {0}", modifiedModel.Count);
|
||||
|
||||
if (modifiedModel.Any())
|
||||
{
|
||||
NotificationEngine.NotifyUsers(modifiedModel, NotificationType.RequestAvailable);
|
||||
RequestService.BatchUpdate(modifiedModel);
|
||||
}
|
||||
}
|
||||
|
||||
public List<PlexMovie> GetPlexMoviesOld()
|
||||
{
|
||||
var settings = Plex.GetSettings();
|
||||
var movies = new List<PlexMovie>();
|
||||
var libs = Cache.Get<List<PlexSearch>>(CacheKeys.PlexLibaries);
|
||||
if (libs != null)
|
||||
{
|
||||
var movieLibs = libs.Where(x =>
|
||||
x.Video.Any(y =>
|
||||
y.Type.Equals(PlexMediaType.Movie.ToString(), StringComparison.CurrentCultureIgnoreCase)
|
||||
)
|
||||
).ToArray();
|
||||
|
||||
foreach (var lib in movieLibs)
|
||||
{
|
||||
movies.AddRange(lib.Video.Select(video => new PlexMovie
|
||||
{
|
||||
ReleaseYear = video.Year,
|
||||
Title = video.Title,
|
||||
ProviderId = video.ProviderId,
|
||||
Url = PlexHelper.GetPlexMediaUrl(settings.MachineIdentifier, video.RatingKey)
|
||||
}));
|
||||
}
|
||||
}
|
||||
return movies;
|
||||
}
|
||||
|
||||
public IEnumerable<PlexContent> GetPlexMovies(IEnumerable<PlexContent> content)
|
||||
{
|
||||
return content.Where(x => x.Type == Store.Models.Plex.PlexMediaType.Movie);
|
||||
}
|
||||
|
||||
public bool IsMovieAvailable(IEnumerable<PlexContent> plexMovies, string title, string year, string providerId = null)
|
||||
{
|
||||
var movie = GetMovie(plexMovies, title, year, providerId);
|
||||
return movie != null;
|
||||
}
|
||||
|
||||
public PlexContent GetMovie(IEnumerable<PlexContent> plexMovies, string title, string year, string providerId = null)
|
||||
{
|
||||
if (plexMovies.Count() == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
var advanced = !string.IsNullOrEmpty(providerId);
|
||||
foreach (var movie in plexMovies)
|
||||
{
|
||||
if (string.IsNullOrEmpty(movie.Title) || string.IsNullOrEmpty(movie.ReleaseYear))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (advanced)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(movie.ProviderId) &&
|
||||
movie.ProviderId.Equals(providerId, StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
return movie;
|
||||
}
|
||||
}
|
||||
if (movie.Title.Equals(title, StringComparison.CurrentCultureIgnoreCase) &&
|
||||
movie.ReleaseYear.Equals(year, StringComparison.CurrentCultureIgnoreCase))
|
||||
{
|
||||
return movie;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public IEnumerable<PlexContent> GetPlexTvShows(IEnumerable<PlexContent> content)
|
||||
{
|
||||
return content.Where(x => x.Type == Store.Models.Plex.PlexMediaType.Show);
|
||||
}
|
||||
|
||||
public bool IsTvShowAvailable(IEnumerable<PlexContent> plexShows, string title, string year, string providerId = null, int[] seasons = null)
|
||||
{
|
||||
var show = GetTvShow(plexShows, title, year, providerId, seasons);
|
||||
return show != null;
|
||||
}
|
||||
|
||||
|
||||
public PlexContent GetTvShow(IEnumerable<PlexContent> plexShows, string title, string year, string providerId = null,
|
||||
int[] seasons = null)
|
||||
{
|
||||
var advanced = !string.IsNullOrEmpty(providerId);
|
||||
foreach (var show in plexShows)
|
||||
{
|
||||
if (advanced)
|
||||
{
|
||||
if (show.ProviderId == providerId && seasons != null)
|
||||
{
|
||||
var showSeasons = ByteConverterHelper.ReturnObject<int[]>(show.Seasons);
|
||||
if (seasons.Any(season => showSeasons.Contains(season)))
|
||||
{
|
||||
return show;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
if (!string.IsNullOrEmpty(show.ProviderId) &&
|
||||
show.ProviderId.Equals(providerId, StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
return show;
|
||||
}
|
||||
}
|
||||
if (show.Title.Equals(title, StringComparison.CurrentCultureIgnoreCase) &&
|
||||
show.ReleaseYear.Equals(year, StringComparison.CurrentCultureIgnoreCase))
|
||||
{
|
||||
return show;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool IsEpisodeAvailable(string theTvDbId, int season, int episode)
|
||||
{
|
||||
var ep = EpisodeRepo.Custom(
|
||||
connection =>
|
||||
{
|
||||
connection.Open();
|
||||
var result = connection.Query<PlexEpisodes>("select * from PlexEpisodes where ProviderId = @ProviderId", new { ProviderId = theTvDbId });
|
||||
|
||||
return result;
|
||||
}).ToList();
|
||||
|
||||
if (!ep.Any())
|
||||
{
|
||||
Log.Info("Episode cache info is not available. tvdbid: {0}, season: {1}, episode: {2}", theTvDbId, season, episode);
|
||||
return false;
|
||||
}
|
||||
foreach (var result in ep)
|
||||
{
|
||||
if (result.ProviderId.Equals(theTvDbId) && result.EpisodeNumber == episode && result.SeasonNumber == season)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the episode's db in the cache.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<IEnumerable<PlexEpisodes>> GetEpisodes()
|
||||
{
|
||||
var episodes = await EpisodeRepo.GetAllAsync();
|
||||
if (episodes == null)
|
||||
{
|
||||
return new HashSet<PlexEpisodes>();
|
||||
}
|
||||
return episodes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the episode's stored in the db and then filters on the TheTvDBId.
|
||||
/// </summary>
|
||||
/// <param name="theTvDbId">The tv database identifier.</param>
|
||||
/// <returns></returns>
|
||||
public async Task<IEnumerable<PlexEpisodes>> GetEpisodes(int theTvDbId)
|
||||
{
|
||||
var ep = await EpisodeRepo.CustomAsync(async connection =>
|
||||
{
|
||||
connection.Open();
|
||||
var result = await connection.QueryAsync<PlexEpisodes>("select * from PlexEpisodes where ProviderId = @ProviderId", new { ProviderId = theTvDbId });
|
||||
|
||||
return result;
|
||||
});
|
||||
|
||||
var plexEpisodeses = ep as PlexEpisodes[] ?? ep.ToArray();
|
||||
if (!plexEpisodeses.Any())
|
||||
{
|
||||
Log.Info("Episode db info is not available.");
|
||||
return new List<PlexEpisodes>();
|
||||
}
|
||||
|
||||
return plexEpisodeses;
|
||||
}
|
||||
|
||||
public IEnumerable<PlexContent> GetPlexAlbums(IEnumerable<PlexContent> content)
|
||||
{
|
||||
return content.Where(x => x.Type == Store.Models.Plex.PlexMediaType.Artist);
|
||||
}
|
||||
|
||||
public bool IsAlbumAvailable(IEnumerable<PlexContent> plexAlbums, string title, string year, string artist)
|
||||
{
|
||||
return plexAlbums.Any(x =>
|
||||
x.Title.Contains(title) &&
|
||||
x.Artist.Equals(artist, StringComparison.CurrentCultureIgnoreCase));
|
||||
}
|
||||
|
||||
public PlexContent GetAlbum(IEnumerable<PlexContent> plexAlbums, string title, string year, string artist)
|
||||
{
|
||||
return plexAlbums.FirstOrDefault(x =>
|
||||
x.Title.Contains(title) &&
|
||||
x.Artist.Equals(artist, StringComparison.CurrentCultureIgnoreCase));
|
||||
}
|
||||
|
||||
private List<PlexSearch> CachedLibraries(PlexSettings plexSettings, bool setCache)
|
||||
{
|
||||
var results = new List<PlexSearch>();
|
||||
|
||||
if (!ValidateSettings(plexSettings))
|
||||
{
|
||||
Log.Warn("The settings are not configured");
|
||||
return results; // don't error out here, just let it go! let it goo!!!
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
// TODO what the fuck was I thinking
|
||||
if (setCache)
|
||||
{
|
||||
results = GetLibraries(plexSettings);
|
||||
if (plexSettings.AdvancedSearch)
|
||||
{
|
||||
foreach (PlexSearch t in results)
|
||||
{
|
||||
foreach (Directory1 t1 in t.Directory)
|
||||
{
|
||||
var currentItem = t1;
|
||||
var metaData = PlexApi.GetMetadata(plexSettings.PlexAuthToken, plexSettings.FullUri,
|
||||
currentItem.RatingKey);
|
||||
|
||||
// Get the seasons for each show
|
||||
if (currentItem.Type.Equals(PlexMediaType.Show.ToString(), StringComparison.CurrentCultureIgnoreCase))
|
||||
{
|
||||
var seasons = PlexApi.GetSeasons(plexSettings.PlexAuthToken, plexSettings.FullUri,
|
||||
currentItem.RatingKey);
|
||||
|
||||
// We do not want "all episodes" this as a season
|
||||
var filtered = seasons.Directory.Where(x => !x.Title.Equals("All episodes", StringComparison.CurrentCultureIgnoreCase));
|
||||
|
||||
t1.Seasons.AddRange(filtered);
|
||||
}
|
||||
|
||||
var providerId = PlexHelper.GetProviderIdFromPlexGuid(metaData.Directory.Guid);
|
||||
t1.ProviderId = providerId;
|
||||
}
|
||||
foreach (Video t1 in t.Video)
|
||||
{
|
||||
var currentItem = t1;
|
||||
var metaData = PlexApi.GetMetadata(plexSettings.PlexAuthToken, plexSettings.FullUri,
|
||||
currentItem.RatingKey);
|
||||
var providerId = PlexHelper.GetProviderIdFromPlexGuid(metaData.Video.Guid);
|
||||
t1.ProviderId = providerId;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (results != null)
|
||||
{
|
||||
Cache.Set(CacheKeys.PlexLibaries, results, CacheKeys.TimeFrameMinutes.SchedulerCaching);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
results = Cache.GetOrSet(CacheKeys.PlexLibaries, () =>
|
||||
GetLibraries(plexSettings), CacheKeys.TimeFrameMinutes.SchedulerCaching);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "Failed to obtain Plex libraries");
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
private List<PlexSearch> GetLibraries(PlexSettings plexSettings)
|
||||
{
|
||||
var sections = PlexApi.GetLibrarySections(plexSettings.PlexAuthToken, plexSettings.FullUri);
|
||||
|
||||
var libs = new List<PlexSearch>();
|
||||
if (sections != null)
|
||||
{
|
||||
foreach (var dir in sections.Directories ?? new List<Directory>())
|
||||
{
|
||||
var lib = PlexApi.GetLibrary(plexSettings.PlexAuthToken, plexSettings.FullUri, dir.Key);
|
||||
if (lib != null)
|
||||
{
|
||||
libs.Add(lib);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return libs;
|
||||
}
|
||||
|
||||
private bool ValidateSettings(PlexSettings plex)
|
||||
{
|
||||
if (plex.Enable)
|
||||
{
|
||||
if (plex?.Ip == null || plex?.PlexAuthToken == null)
|
||||
{
|
||||
Log.Warn("A setting is null, Ensure Plex is configured correctly, and we have a Plex Auth token.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return plex.Enable;
|
||||
}
|
||||
|
||||
public void Execute(IJobExecutionContext context)
|
||||
{
|
||||
|
||||
Job.SetRunning(true, JobNames.PlexChecker);
|
||||
try
|
||||
{
|
||||
CheckAndUpdateAll();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Job.Record(JobNames.PlexChecker);
|
||||
Job.SetRunning(false, JobNames.PlexChecker);
|
||||
}
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
Job.SetRunning(true, JobNames.PlexChecker);
|
||||
try
|
||||
{
|
||||
CheckAndUpdateAll();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Job.Record(JobNames.PlexChecker);
|
||||
Job.SetRunning(false, JobNames.PlexChecker);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
438
Old/Ombi.Services/Jobs/PlexContentCacher.cs
Normal file
438
Old/Ombi.Services/Jobs/PlexContentCacher.cs
Normal file
|
@ -0,0 +1,438 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2016 Jamie Rees
|
||||
// File: PlexAvailabilityChecker.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
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Dapper;
|
||||
using NLog;
|
||||
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.Services.Models;
|
||||
using Ombi.Store.Models;
|
||||
using Ombi.Store.Models.Plex;
|
||||
using Ombi.Store.Repository;
|
||||
using Quartz;
|
||||
using PlexMediaType = Ombi.Api.Models.Plex.PlexMediaType;
|
||||
|
||||
namespace Ombi.Services.Jobs
|
||||
{
|
||||
public class PlexContentCacher : IJob, IPlexContentCacher
|
||||
{
|
||||
public PlexContentCacher(ISettingsService<PlexSettings> plexSettings, IRequestService request, IPlexApi plex, ICacheProvider cache,
|
||||
INotificationService notify, IJobRecord rec, IRepository<UsersToNotify> users, IRepository<PlexEpisodes> repo, IPlexNotificationEngine e, IRepository<PlexContent> content)
|
||||
{
|
||||
Plex = plexSettings;
|
||||
RequestService = request;
|
||||
PlexApi = plex;
|
||||
Cache = cache;
|
||||
Notification = notify;
|
||||
Job = rec;
|
||||
UserNotifyRepo = users;
|
||||
EpisodeRepo = repo;
|
||||
NotificationEngine = e;
|
||||
PlexContent = content;
|
||||
}
|
||||
|
||||
private ISettingsService<PlexSettings> Plex { get; }
|
||||
private IRepository<PlexEpisodes> EpisodeRepo { get; }
|
||||
private IRequestService RequestService { get; }
|
||||
private static Logger Log = LogManager.GetCurrentClassLogger();
|
||||
private IPlexApi PlexApi { get; }
|
||||
private ICacheProvider Cache { get; }
|
||||
private INotificationService Notification { get; }
|
||||
private IJobRecord Job { get; }
|
||||
private IRepository<UsersToNotify> UserNotifyRepo { get; }
|
||||
private INotificationEngine NotificationEngine { get; }
|
||||
private IRepository<PlexContent> PlexContent { get; }
|
||||
|
||||
public void CacheContent()
|
||||
{
|
||||
var plexSettings = Plex.GetSettings();
|
||||
if (!plexSettings.Enable)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!ValidateSettings(plexSettings))
|
||||
{
|
||||
Log.Debug("Validation of the plex settings failed.");
|
||||
return;
|
||||
}
|
||||
var libraries = CachedLibraries(plexSettings);
|
||||
|
||||
if (libraries == null || !libraries.Any())
|
||||
{
|
||||
Log.Debug("Did not find any libraries in Plex.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public List<PlexMovie> GetPlexMovies(List<PlexSearch> libs)
|
||||
{
|
||||
var settings = Plex.GetSettings();
|
||||
var movies = new List<PlexMovie>();
|
||||
if (libs != null)
|
||||
{
|
||||
var movieLibs = libs.Where(x =>
|
||||
x.Video.Any(y =>
|
||||
y.Type.Equals(PlexMediaType.Movie.ToString(), StringComparison.CurrentCultureIgnoreCase)
|
||||
)
|
||||
).ToArray();
|
||||
|
||||
foreach (var lib in movieLibs)
|
||||
{
|
||||
movies.AddRange(lib.Video.Select(video => new PlexMovie
|
||||
{
|
||||
ReleaseYear = video.Year,
|
||||
Title = video.Title,
|
||||
ProviderId = video.ProviderId,
|
||||
Url = PlexHelper.GetPlexMediaUrl(settings.MachineIdentifier, video.RatingKey),
|
||||
ItemId = video.RatingKey
|
||||
}));
|
||||
}
|
||||
}
|
||||
return movies;
|
||||
}
|
||||
|
||||
public List<PlexTvShow> GetPlexTvShows(List<PlexSearch> libs)
|
||||
{
|
||||
var settings = Plex.GetSettings();
|
||||
var shows = new List<PlexTvShow>();
|
||||
if (libs != null)
|
||||
{
|
||||
var withDir = libs.Where(x => x.Directory != null);
|
||||
var tvLibs = withDir.Where(x =>
|
||||
x.Directory.Any(y =>
|
||||
y.Type.Equals(PlexMediaType.Show.ToString(), StringComparison.CurrentCultureIgnoreCase)
|
||||
)
|
||||
).ToArray();
|
||||
|
||||
foreach (var lib in tvLibs)
|
||||
{
|
||||
|
||||
shows.AddRange(lib.Directory.Select(x => new PlexTvShow // shows are in the directory list
|
||||
{
|
||||
Title = x.Title,
|
||||
ReleaseYear = x.Year,
|
||||
ProviderId = x.ProviderId,
|
||||
Seasons = x.Seasons?.Select(d => PlexHelper.GetSeasonNumberFromTitle(d.Title)).ToArray(),
|
||||
Url = PlexHelper.GetPlexMediaUrl(settings.MachineIdentifier, x.RatingKey),
|
||||
ItemId= x.RatingKey
|
||||
|
||||
}));
|
||||
}
|
||||
}
|
||||
return shows;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public List<PlexAlbum> GetPlexAlbums(List<PlexSearch> libs)
|
||||
{
|
||||
var settings = Plex.GetSettings();
|
||||
var albums = new List<PlexAlbum>();
|
||||
if (libs != null)
|
||||
{
|
||||
var albumLibs = libs.Where(x =>
|
||||
x.Directory.Any(y =>
|
||||
y.Type.Equals(PlexMediaType.Artist.ToString(), StringComparison.CurrentCultureIgnoreCase)
|
||||
)
|
||||
).ToArray();
|
||||
|
||||
foreach (var lib in albumLibs)
|
||||
{
|
||||
albums.AddRange(lib.Directory.Select(x => new PlexAlbum()
|
||||
{
|
||||
Title = x.Title,
|
||||
ProviderId = x.ProviderId,
|
||||
ReleaseYear = x.Year,
|
||||
Artist = x.ParentTitle,
|
||||
Url = PlexHelper.GetPlexMediaUrl(settings.MachineIdentifier, x.RatingKey)
|
||||
}));
|
||||
}
|
||||
}
|
||||
return albums;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private List<PlexSearch> CachedLibraries(PlexSettings plexSettings)
|
||||
{
|
||||
var results = new List<PlexSearch>();
|
||||
|
||||
if (!ValidateSettings(plexSettings))
|
||||
{
|
||||
Log.Warn("The settings are not configured");
|
||||
return results; // don't error out here, just let it go! let it goo!!!
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
results = GetLibraries(plexSettings);
|
||||
if (plexSettings.AdvancedSearch)
|
||||
{
|
||||
Log.Debug("Going through all the items now");
|
||||
Log.Debug($"Item count {results.Count}");
|
||||
foreach (PlexSearch t in results)
|
||||
{
|
||||
foreach (Directory1 t1 in t.Directory)
|
||||
{
|
||||
var currentItem = t1;
|
||||
var metaData = PlexApi.GetMetadata(plexSettings.PlexAuthToken, plexSettings.FullUri,
|
||||
currentItem.RatingKey);
|
||||
|
||||
// Get the seasons for each show
|
||||
if (currentItem.Type.Equals(PlexMediaType.Show.ToString(), StringComparison.CurrentCultureIgnoreCase))
|
||||
{
|
||||
var seasons = PlexApi.GetSeasons(plexSettings.PlexAuthToken, plexSettings.FullUri,
|
||||
currentItem.RatingKey);
|
||||
|
||||
// We do not want "all episodes" this as a season
|
||||
var filtered = seasons.Directory.Where(x => !x.Title.Equals("All episodes", StringComparison.CurrentCultureIgnoreCase));
|
||||
|
||||
t1.Seasons.AddRange(filtered);
|
||||
}
|
||||
|
||||
var providerId = PlexHelper.GetProviderIdFromPlexGuid(metaData.Directory.Guid);
|
||||
t1.ProviderId = providerId;
|
||||
}
|
||||
foreach (Video t1 in t.Video)
|
||||
{
|
||||
var currentItem = t1;
|
||||
var metaData = PlexApi.GetMetadata(plexSettings.PlexAuthToken, plexSettings.FullUri,
|
||||
currentItem.RatingKey);
|
||||
var providerId = PlexHelper.GetProviderIdFromPlexGuid(metaData.Video.Guid);
|
||||
t1.ProviderId = providerId;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (results != null)
|
||||
{
|
||||
Log.Debug("done all that, moving onto the DB now");
|
||||
var movies = GetPlexMovies(results);
|
||||
|
||||
// Time to destroy the plex movies from the DB
|
||||
PlexContent.Custom(connection =>
|
||||
{
|
||||
connection.Open();
|
||||
connection.Query("delete from PlexContent where type = @type", new { type = 0 });
|
||||
return new List<PlexContent>();
|
||||
});
|
||||
|
||||
foreach (var m in movies)
|
||||
{
|
||||
if (string.IsNullOrEmpty(m.ProviderId))
|
||||
{
|
||||
Log.Error("Provider Id on movie {0} is null",m.Title);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if it exists
|
||||
var item = PlexContent.Custom(connection =>
|
||||
{
|
||||
connection.Open();
|
||||
var media = connection.QueryFirstOrDefault<PlexContent>("select * from PlexContent where ProviderId = @ProviderId and type = @type", new { m.ProviderId, type = 0 });
|
||||
connection.Dispose();
|
||||
return media;
|
||||
});
|
||||
|
||||
if (item == null && !string.IsNullOrEmpty(m.ItemId))
|
||||
{
|
||||
// Doesn't exist, insert it
|
||||
PlexContent.Insert(new PlexContent
|
||||
{
|
||||
ProviderId = m.ProviderId,
|
||||
ReleaseYear = m.ReleaseYear ?? string.Empty,
|
||||
Title = m.Title,
|
||||
Type = Store.Models.Plex.PlexMediaType.Movie,
|
||||
Url = m.Url,
|
||||
ItemId = m.ItemId,
|
||||
AddedAt = DateTime.UtcNow,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Log.Debug("Done movies");
|
||||
var tv = GetPlexTvShows(results);
|
||||
// Time to destroy the plex tv from the DB
|
||||
PlexContent.Custom(connection =>
|
||||
{
|
||||
connection.Open();
|
||||
connection.Query("delete from PlexContent where type = @type", new { type = 1 });
|
||||
return new List<PlexContent>();
|
||||
});
|
||||
foreach (var t in tv)
|
||||
{
|
||||
if (string.IsNullOrEmpty(t.ProviderId))
|
||||
{
|
||||
Log.Error("Provider Id on tv {0} is null", t.Title);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// Check if it exists
|
||||
var item = PlexContent.Custom(connection =>
|
||||
{
|
||||
connection.Open();
|
||||
var media = connection.QueryFirstOrDefault<PlexContent>("select * from PlexContent where ProviderId = @ProviderId and type = @type", new { t.ProviderId, type = 1 });
|
||||
connection.Dispose();
|
||||
return media;
|
||||
});
|
||||
|
||||
if (item == null && !string.IsNullOrEmpty(t.ItemId))
|
||||
{
|
||||
PlexContent.Insert(new PlexContent
|
||||
{
|
||||
ProviderId = t.ProviderId,
|
||||
ReleaseYear = t.ReleaseYear ?? string.Empty,
|
||||
Title = t.Title,
|
||||
Type = Store.Models.Plex.PlexMediaType.Show,
|
||||
Url = t.Url,
|
||||
Seasons = ByteConverterHelper.ReturnBytes(t.Seasons),
|
||||
ItemId = t.ItemId,
|
||||
AddedAt = DateTime.UtcNow,
|
||||
});
|
||||
}
|
||||
}
|
||||
Log.Debug("Done TV");
|
||||
var albums = GetPlexAlbums(results);
|
||||
// Time to destroy the plex movies from the DB
|
||||
PlexContent.Custom(connection =>
|
||||
{
|
||||
connection.Open();
|
||||
connection.Query("delete from PlexContent where type = @type", new { type = 2 });
|
||||
return new List<PlexContent>();
|
||||
});
|
||||
|
||||
foreach (var a in albums)
|
||||
{
|
||||
if (string.IsNullOrEmpty(a.ProviderId))
|
||||
{
|
||||
Log.Error("Provider Id on album {0} is null", a.Title);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// Check if it exists
|
||||
var item = PlexContent.Custom(connection =>
|
||||
{
|
||||
connection.Open();
|
||||
var media = connection.QueryFirstOrDefault<PlexContent>("select * from PlexContent where ProviderId = @ProviderId and type = @type", new { a.ProviderId, type = 2 });
|
||||
connection.Dispose();
|
||||
return media;
|
||||
});
|
||||
|
||||
if (item == null)
|
||||
{
|
||||
|
||||
PlexContent.Insert(new PlexContent
|
||||
{
|
||||
ProviderId = a.ProviderId,
|
||||
ReleaseYear = a.ReleaseYear ?? string.Empty,
|
||||
Title = a.Title,
|
||||
Type = Store.Models.Plex.PlexMediaType.Artist,
|
||||
Url = a.Url,
|
||||
ItemId = "album",
|
||||
AddedAt = DateTime.UtcNow,
|
||||
});
|
||||
}
|
||||
}
|
||||
Log.Debug("Done albums");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Debug("Exception:");
|
||||
Log.Debug(ex);
|
||||
Log.Error(ex, "Failed to obtain Plex libraries");
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
private List<PlexSearch> GetLibraries(PlexSettings plexSettings)
|
||||
{
|
||||
Log.Debug("Getting Lib sections");
|
||||
var sections = PlexApi.GetLibrarySections(plexSettings.PlexAuthToken, plexSettings.FullUri);
|
||||
|
||||
Log.Debug("Going through sections now");
|
||||
var libs = new List<PlexSearch>();
|
||||
if (sections != null)
|
||||
{
|
||||
foreach (var dir in sections.Directories ?? new List<Directory>())
|
||||
{
|
||||
var lib = PlexApi.GetLibrary(plexSettings.PlexAuthToken, plexSettings.FullUri, dir.Key);
|
||||
if (lib != null)
|
||||
{
|
||||
Log.Debug("adding lib");
|
||||
libs.Add(lib);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return libs;
|
||||
}
|
||||
|
||||
private bool ValidateSettings(PlexSettings plex)
|
||||
{
|
||||
if (plex.Enable)
|
||||
{
|
||||
if (plex?.Ip == null || plex?.PlexAuthToken == null)
|
||||
{
|
||||
Log.Warn("A setting is null, Ensure Plex is configured correctly, and we have a Plex Auth token.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return plex.Enable;
|
||||
}
|
||||
|
||||
public void Execute(IJobExecutionContext context)
|
||||
{
|
||||
|
||||
Job.SetRunning(true, JobNames.PlexCacher);
|
||||
try
|
||||
{
|
||||
CacheContent();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Job.Record(JobNames.PlexCacher);
|
||||
Job.SetRunning(false, JobNames.PlexCacher);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
203
Old/Ombi.Services/Jobs/PlexEpisodeCacher.cs
Normal file
203
Old/Ombi.Services/Jobs/PlexEpisodeCacher.cs
Normal file
|
@ -0,0 +1,203 @@
|
|||
#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
|
||||
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using NLog;
|
||||
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;
|
||||
using Ombi.Store.Models.Plex;
|
||||
using Ombi.Store.Repository;
|
||||
using Quartz;
|
||||
using PlexMediaType = Ombi.Api.Models.Plex.PlexMediaType;
|
||||
|
||||
namespace Ombi.Services.Jobs
|
||||
{
|
||||
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 ?? new List<Video>())
|
||||
{
|
||||
if(string.IsNullOrEmpty(metadataVideo.GrandparentTitle))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
var epInfo = PlexHelper.GetSeasonsAndEpisodesFromPlexGuid(metadataVideo.Guid);
|
||||
entities.TryAdd(
|
||||
new PlexEpisodes
|
||||
{
|
||||
EpisodeNumber = epInfo?.EpisodeNumber ?? 0,
|
||||
EpisodeTitle = metadataVideo.Title,
|
||||
ProviderId = epInfo?.ProviderId ?? "",
|
||||
RatingKey = metadataVideo.RatingKey,
|
||||
SeasonNumber = epInfo?.SeasonNumber ?? 0,
|
||||
ShowTitle = metadataVideo.GrandparentTitle
|
||||
},
|
||||
1);
|
||||
}
|
||||
});
|
||||
|
||||
// Delete all of the current items
|
||||
Repo.DeleteAll(TableName);
|
||||
|
||||
// Insert the new items
|
||||
var result = Repo.BatchInsert(entities.Select(x => x.Key).ToList(), TableName);
|
||||
|
||||
if (!result)
|
||||
{
|
||||
Log.Error("Saving the Plex episodes to the DB Failed");
|
||||
}
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
try
|
||||
{
|
||||
var s = Plex.GetSettings();
|
||||
if (!s.EnableTvEpisodeSearching)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
215
Old/Ombi.Services/Jobs/PlexUserChecker.cs
Normal file
215
Old/Ombi.Services/Jobs/PlexUserChecker.cs
Normal file
|
@ -0,0 +1,215 @@
|
|||
#region Copyright
|
||||
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2016 Jamie Rees
|
||||
// File: StoreCleanup.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
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using Ombi.Api.Interfaces;
|
||||
using Ombi.Api.Models.Plex;
|
||||
using Ombi.Core;
|
||||
using Ombi.Core.SettingModels;
|
||||
using Ombi.Core.Users;
|
||||
using Ombi.Helpers.Permissions;
|
||||
using Ombi.Services.Interfaces;
|
||||
using Ombi.Store.Models;
|
||||
using Ombi.Store.Models.Plex;
|
||||
using Ombi.Store.Repository;
|
||||
using Quartz;
|
||||
|
||||
namespace Ombi.Services.Jobs
|
||||
{
|
||||
public class PlexUserChecker : IJob, IPlexUserChecker
|
||||
{
|
||||
private static readonly Logger Log = LogManager.GetCurrentClassLogger();
|
||||
|
||||
public PlexUserChecker(IExternalUserRepository<PlexUsers> plexUsers, IPlexApi plexAPi, IJobRecord rec, ISettingsService<PlexSettings> plexSettings, ISettingsService<PlexRequestSettings> prSettings, ISettingsService<UserManagementSettings> umSettings,
|
||||
IRequestService requestService, IUserRepository localUser)
|
||||
{
|
||||
Repo = plexUsers;
|
||||
JobRecord = rec;
|
||||
PlexApi = plexAPi;
|
||||
PlexSettings = plexSettings;
|
||||
PlexRequestSettings = prSettings;
|
||||
UserManagementSettings = umSettings;
|
||||
RequestService = requestService;
|
||||
LocalUserRepository = localUser;
|
||||
}
|
||||
|
||||
private IJobRecord JobRecord { get; }
|
||||
private IPlexApi PlexApi { get; }
|
||||
private IExternalUserRepository<PlexUsers> Repo { get; }
|
||||
private ISettingsService<PlexSettings> PlexSettings { get; }
|
||||
private ISettingsService<PlexRequestSettings> PlexRequestSettings { get; }
|
||||
private ISettingsService<UserManagementSettings> UserManagementSettings { get; }
|
||||
private IRequestService RequestService { get; }
|
||||
private IUserRepository LocalUserRepository { get; }
|
||||
|
||||
public void Start()
|
||||
{
|
||||
JobRecord.SetRunning(true, JobNames.PlexUserChecker);
|
||||
|
||||
try
|
||||
{
|
||||
var settings = PlexSettings.GetSettings();
|
||||
if (string.IsNullOrEmpty(settings.PlexAuthToken) || !settings.Enable)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var plexUsers = PlexApi.GetUsers(settings.PlexAuthToken);
|
||||
var userManagementSettings = UserManagementSettings.GetSettings();
|
||||
var mainPlexAccount = PlexApi.GetAccount(settings.PlexAuthToken);
|
||||
var requests = RequestService.GetAll().ToList();
|
||||
|
||||
var dbUsers = Repo.GetAll().ToList();
|
||||
var localUsers = LocalUserRepository.GetAll().ToList();
|
||||
|
||||
// Regular users
|
||||
foreach (var user in plexUsers?.User ?? new UserFriends[]{})
|
||||
{
|
||||
var dbUser = dbUsers.FirstOrDefault(x => x.PlexUserId == user.Id);
|
||||
if (dbUser != null)
|
||||
{
|
||||
// We already have the user, let's check if they have updated any of their info.
|
||||
var needToUpdate = false;
|
||||
var usernameChanged = false;
|
||||
|
||||
if (!string.IsNullOrEmpty(user.Username)) // If true then this is a managed user, we do not want to update the email since Managed Users do not have email addresses
|
||||
{
|
||||
// Do we need up update any info?
|
||||
if (!dbUser.EmailAddress.Equals(user.Email, StringComparison.CurrentCultureIgnoreCase))
|
||||
{
|
||||
dbUser.EmailAddress = user.Email;
|
||||
needToUpdate = true;
|
||||
}
|
||||
}
|
||||
if (!dbUser.Username.Equals(user.Title, StringComparison.CurrentCultureIgnoreCase))
|
||||
{
|
||||
needToUpdate = true;
|
||||
usernameChanged = true;
|
||||
}
|
||||
|
||||
if (needToUpdate)
|
||||
{
|
||||
if (usernameChanged)
|
||||
{
|
||||
// The username has changed, let's check if the username matches any local users
|
||||
var localUser = localUsers.FirstOrDefault(x => x.UserName.Equals(user.Title, StringComparison.CurrentCultureIgnoreCase));
|
||||
dbUser.Username = user.Title;
|
||||
if (localUser != null)
|
||||
{
|
||||
// looks like we have a local user with the same name...
|
||||
// We should delete the local user and the Plex user will become the master,
|
||||
// I am not going to update the Plex Users permissions as that could end up leading to a security vulnerability
|
||||
// Where anyone could change their Plex Username to the PR.Net server admins name and get all the admin permissions.
|
||||
|
||||
LocalUserRepository.Delete(localUser);
|
||||
}
|
||||
|
||||
// Since the username has changed, we need to update all requests with that username (unless we are using the alias! Since the alias won't change)
|
||||
if (string.IsNullOrEmpty(dbUser.UserAlias))
|
||||
{
|
||||
// Update all requests
|
||||
var requestsWithThisUser = requests.Where(x => x.RequestedUsers.Contains(user.Username)).ToList();
|
||||
foreach (var r in requestsWithThisUser)
|
||||
{
|
||||
r.RequestedUsers.Remove(user.Title); // Remove old
|
||||
r.RequestedUsers.Add(dbUser.Username); // Add new
|
||||
}
|
||||
|
||||
if (requestsWithThisUser.Any())
|
||||
{
|
||||
RequestService.BatchUpdate(requestsWithThisUser);
|
||||
}
|
||||
}
|
||||
}
|
||||
Repo.Update(dbUser);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Looks like it's a new user!
|
||||
var m = new PlexUsers
|
||||
{
|
||||
PlexUserId = user.Id,
|
||||
Permissions = UserManagementHelper.GetPermissions(userManagementSettings),
|
||||
Features = UserManagementHelper.GetFeatures(userManagementSettings),
|
||||
UserAlias = string.Empty,
|
||||
EmailAddress = user.Email,
|
||||
Username = user.Title,
|
||||
LoginId = Guid.NewGuid().ToString()
|
||||
};
|
||||
|
||||
Repo.Insert(m);
|
||||
}
|
||||
|
||||
// Main Plex user
|
||||
var dbMainAcc = dbUsers.FirstOrDefault(x => x.Username.Equals(mainPlexAccount.Username, StringComparison.CurrentCulture));
|
||||
var localMainAcc = localUsers.FirstOrDefault(x => x.UserName.Equals(mainPlexAccount.Username, StringComparison.CurrentCulture));
|
||||
|
||||
// TODO if admin acc does exist, check if we need to update it
|
||||
|
||||
|
||||
// Create the local admin account if it doesn't already exist
|
||||
if (dbMainAcc == null && localMainAcc == null)
|
||||
{
|
||||
var a = new PlexUsers
|
||||
{
|
||||
PlexUserId = mainPlexAccount.Id,
|
||||
Permissions = UserManagementHelper.GetPermissions(userManagementSettings),
|
||||
Features = UserManagementHelper.GetFeatures(userManagementSettings),
|
||||
UserAlias = string.Empty,
|
||||
EmailAddress = mainPlexAccount.Email,
|
||||
Username = mainPlexAccount.Username,
|
||||
LoginId = Guid.NewGuid().ToString()
|
||||
};
|
||||
|
||||
a.Permissions += (int)Permissions.Administrator; // Make admin
|
||||
|
||||
Repo.Insert(a);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
JobRecord.SetRunning(false, JobNames.PlexUserChecker);
|
||||
JobRecord.Record(JobNames.PlexUserChecker);
|
||||
}
|
||||
}
|
||||
public void Execute(IJobExecutionContext context)
|
||||
{
|
||||
Start();
|
||||
}
|
||||
}
|
||||
}
|
114
Old/Ombi.Services/Jobs/RadarrCacher.cs
Normal file
114
Old/Ombi.Services/Jobs/RadarrCacher.cs
Normal file
|
@ -0,0 +1,114 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2016 Jamie Rees
|
||||
// File: PlexAvailabilityChecker.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
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using Ombi.Api.Interfaces;
|
||||
using Ombi.Api.Models.Radarr;
|
||||
using Ombi.Core;
|
||||
using Ombi.Core.SettingModels;
|
||||
using Ombi.Helpers;
|
||||
using Ombi.Services.Interfaces;
|
||||
using Quartz;
|
||||
|
||||
namespace Ombi.Services.Jobs
|
||||
{
|
||||
public class RadarrCacher : IJob, IRadarrCacher
|
||||
{
|
||||
public RadarrCacher(ISettingsService<RadarrSettings> radarrService, IRadarrApi radarrApi, ICacheProvider cache, IJobRecord rec)
|
||||
{
|
||||
RadarrSettings = radarrService;
|
||||
RadarrApi = radarrApi;
|
||||
Job = rec;
|
||||
Cache = cache;
|
||||
}
|
||||
|
||||
private ISettingsService<RadarrSettings> RadarrSettings { get; }
|
||||
private ICacheProvider Cache { get; }
|
||||
private IRadarrApi RadarrApi { get; }
|
||||
private IJobRecord Job { get; }
|
||||
|
||||
private static Logger Log = LogManager.GetCurrentClassLogger();
|
||||
|
||||
public void Queued()
|
||||
{
|
||||
var settings = RadarrSettings.GetSettings();
|
||||
if (settings.Enabled)
|
||||
{
|
||||
Job.SetRunning(true, JobNames.RadarrCacher);
|
||||
try
|
||||
{
|
||||
var movies = RadarrApi.GetMovies(settings.ApiKey, settings.FullUri);
|
||||
if (movies != null)
|
||||
{
|
||||
var movieIds = new List<int>();
|
||||
foreach (var m in movies)
|
||||
{
|
||||
if (m.tmdbId > 0)
|
||||
{
|
||||
movieIds.Add(m.tmdbId);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Error("TMDBId is not > 0 for movie {0}", m.title);
|
||||
}
|
||||
}
|
||||
//var movieIds = movies.Select(x => x.tmdbId).ToList();
|
||||
Cache.Set(CacheKeys.RadarrMovies, movieIds, CacheKeys.TimeFrameMinutes.SchedulerCaching);
|
||||
}
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
Log.Error(ex, "Failed caching queued items from Radarr");
|
||||
}
|
||||
finally
|
||||
{
|
||||
Job.Record(JobNames.RadarrCacher);
|
||||
Job.SetRunning(false, JobNames.RadarrCacher);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// we do not want to set here...
|
||||
public int[] QueuedIds()
|
||||
{
|
||||
var retVal = new List<int>();
|
||||
var movies = Cache.Get<List<int>>(CacheKeys.RadarrMovies);
|
||||
if (movies != null)
|
||||
{
|
||||
retVal.AddRange(movies);
|
||||
}
|
||||
return retVal.ToArray();
|
||||
}
|
||||
|
||||
public void Execute(IJobExecutionContext context)
|
||||
{
|
||||
Queued();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,454 @@
|
|||
#region Copyright
|
||||
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2016 Jamie Rees
|
||||
// File: RecentlyAddedModel.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
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using Newtonsoft.Json;
|
||||
using NLog;
|
||||
using Ombi.Api;
|
||||
using Ombi.Api.Interfaces;
|
||||
using Ombi.Api.Models.Emby;
|
||||
using Ombi.Core;
|
||||
using Ombi.Core.SettingModels;
|
||||
using Ombi.Services.Jobs.Templates;
|
||||
using Ombi.Store.Models;
|
||||
using Ombi.Store.Models.Emby;
|
||||
using Ombi.Store.Repository;
|
||||
using TMDbLib.Objects.Exceptions;
|
||||
using EmbyMediaType = Ombi.Store.Models.Plex.EmbyMediaType;
|
||||
using Polly;
|
||||
|
||||
namespace Ombi.Services.Jobs.RecentlyAddedNewsletter
|
||||
{
|
||||
public class EmbyAddedNewsletter : HtmlTemplateGenerator, IEmbyAddedNewsletter
|
||||
{
|
||||
public EmbyAddedNewsletter(IEmbyApi api, ISettingsService<EmbySettings> embySettings,
|
||||
ISettingsService<EmailNotificationSettings> email,
|
||||
ISettingsService<NewletterSettings> newsletter, IRepository<RecentlyAddedLog> log,
|
||||
IRepository<EmbyContent> embyContent, IRepository<EmbyEpisodes> episodes)
|
||||
{
|
||||
Api = api;
|
||||
EmbySettings = embySettings;
|
||||
EmailSettings = email;
|
||||
NewsletterSettings = newsletter;
|
||||
Content = embyContent;
|
||||
MovieApi = new TheMovieDbApi();
|
||||
TvApi = new TvMazeApi();
|
||||
Episodes = episodes;
|
||||
RecentlyAddedLog = log;
|
||||
}
|
||||
|
||||
private IEmbyApi Api { get; }
|
||||
private TheMovieDbApi MovieApi { get; }
|
||||
private TvMazeApi TvApi { get; }
|
||||
private ISettingsService<EmbySettings> EmbySettings { get; }
|
||||
private ISettingsService<EmailNotificationSettings> EmailSettings { get; }
|
||||
private ISettingsService<NewletterSettings> NewsletterSettings { get; }
|
||||
private IRepository<EmbyContent> Content { get; }
|
||||
private IRepository<EmbyEpisodes> Episodes { get; }
|
||||
private IRepository<RecentlyAddedLog> RecentlyAddedLog { get; }
|
||||
|
||||
private static readonly Logger Log = LogManager.GetCurrentClassLogger();
|
||||
|
||||
public Newsletter GetNewsletter(bool test)
|
||||
{
|
||||
try
|
||||
{
|
||||
return GetHtml(test);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private class EmbyRecentlyAddedModel
|
||||
{
|
||||
public EmbyInformation EmbyInformation { get; set; }
|
||||
public EmbyContent EmbyContent { get; set; }
|
||||
public List<EmbyEpisodeInformation> EpisodeInformation { get; set; }
|
||||
}
|
||||
|
||||
private Newsletter GetHtml(bool test)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
var newsletter = new Newsletter();
|
||||
|
||||
var embySettings = EmbySettings.GetSettings();
|
||||
var embyContent = Content.GetAll().ToList();
|
||||
|
||||
var series = embyContent.Where(x => x.Type == EmbyMediaType.Series).ToList();
|
||||
var episodes = Episodes.GetAll().ToList();
|
||||
var movie = embyContent.Where(x => x.Type == EmbyMediaType.Movie).ToList();
|
||||
|
||||
var recentlyAdded = RecentlyAddedLog.GetAll().ToList();
|
||||
|
||||
var firstRun = !recentlyAdded.Any();
|
||||
|
||||
var filteredMovies = movie.Where(m => recentlyAdded.All(x => x.ProviderId != m.EmbyId)).ToList();
|
||||
var filteredEp = episodes.Where(m => recentlyAdded.All(x => x.ProviderId != m.EmbyId)).ToList();
|
||||
var filteredSeries = series.Where(m => recentlyAdded.All(x => x.ProviderId != m.EmbyId)).ToList();
|
||||
|
||||
var info = new List<EmbyRecentlyAddedModel>();
|
||||
foreach (var m in filteredMovies.OrderByDescending(x => x.AddedAt))
|
||||
{
|
||||
var policy = RetryHandler.RetryAndWaitPolicy((exception, timespan) =>
|
||||
Log.Error(exception, "Exception thrown when processing an emby movie for the newsletter, Retrying {0}", timespan));
|
||||
var result = policy.Execute(() =>
|
||||
{
|
||||
var i = Api.GetInformation(m.EmbyId, Ombi.Api.Models.Emby.EmbyMediaType.Movie,
|
||||
embySettings.ApiKey, embySettings.AdministratorId, embySettings.FullUri);
|
||||
|
||||
return new EmbyRecentlyAddedModel
|
||||
{
|
||||
EmbyInformation = i,
|
||||
EmbyContent = m
|
||||
};
|
||||
});
|
||||
info.Add(result);
|
||||
}
|
||||
GenerateMovieHtml(info, sb);
|
||||
newsletter.MovieCount = info.Count;
|
||||
|
||||
info.Clear();
|
||||
|
||||
// Check if there are any epiosdes, then get the series info.
|
||||
// Otherwise then just add the series to the newsletter
|
||||
if (test && !filteredEp.Any() && episodes.Any())
|
||||
{
|
||||
// if this is a test make sure we show something
|
||||
filteredEp = episodes.Take(5).ToList();
|
||||
}
|
||||
if (filteredEp.Any())
|
||||
{
|
||||
var recentlyAddedModel = new List<EmbyRecentlyAddedModel>();
|
||||
foreach (var embyEpisodes in filteredEp)
|
||||
{
|
||||
try
|
||||
{
|
||||
var policy = RetryHandler.RetryAndWaitPolicy((exception, timespan) =>
|
||||
Log.Error(exception, "Exception thrown when processing an emby episode for the newsletter, Retrying {0}", timespan));
|
||||
|
||||
policy.Execute(() =>
|
||||
{
|
||||
// Find related series item
|
||||
var relatedSeries = series.FirstOrDefault(x => x.EmbyId == embyEpisodes.ParentId);
|
||||
|
||||
if (relatedSeries == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Get series information
|
||||
var i = Api.GetInformation(relatedSeries.EmbyId, Ombi.Api.Models.Emby.EmbyMediaType.Series,
|
||||
embySettings.ApiKey, embySettings.AdministratorId, embySettings.FullUri);
|
||||
|
||||
Thread.Sleep(200);
|
||||
var episodeInfo = Api.GetInformation(embyEpisodes.EmbyId,
|
||||
Ombi.Api.Models.Emby.EmbyMediaType.Episode,
|
||||
embySettings.ApiKey, embySettings.AdministratorId, embySettings.FullUri);
|
||||
|
||||
// Check if we already have this series
|
||||
var existingSeries = recentlyAddedModel.FirstOrDefault(x =>
|
||||
x.EmbyInformation.SeriesInformation.Id.Equals(i.SeriesInformation.Id,
|
||||
StringComparison.CurrentCultureIgnoreCase));
|
||||
|
||||
if (existingSeries != null)
|
||||
{
|
||||
existingSeries.EpisodeInformation.Add(episodeInfo.EpisodeInformation);
|
||||
}
|
||||
else
|
||||
{
|
||||
recentlyAddedModel.Add(new EmbyRecentlyAddedModel
|
||||
{
|
||||
EmbyInformation = i,
|
||||
EpisodeInformation = new List<EmbyEpisodeInformation>() { episodeInfo.EpisodeInformation },
|
||||
EmbyContent = relatedSeries
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
catch (JsonReaderException)
|
||||
{
|
||||
Log.Error("Failed getting information from Emby, we may have overloaded Emby's api... Waiting and we will skip this one and go to the next");
|
||||
Thread.Sleep(1000);
|
||||
}
|
||||
}
|
||||
|
||||
info.AddRange(recentlyAddedModel);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var t in filteredSeries.OrderByDescending(x => x.AddedAt))
|
||||
{
|
||||
|
||||
|
||||
var policy = RetryHandler.RetryAndWaitPolicy((exception, timespan) =>
|
||||
Log.Error(exception, "Exception thrown when processing an emby series for the newsletter, Retrying {0}", timespan));
|
||||
var item = policy.Execute(() =>
|
||||
{
|
||||
var i = Api.GetInformation(t.EmbyId, Ombi.Api.Models.Emby.EmbyMediaType.Series,
|
||||
embySettings.ApiKey, embySettings.AdministratorId, embySettings.FullUri);
|
||||
var model = new EmbyRecentlyAddedModel
|
||||
{
|
||||
EmbyContent = t,
|
||||
EmbyInformation = i,
|
||||
};
|
||||
return model;
|
||||
});
|
||||
info.Add(item);
|
||||
}
|
||||
}
|
||||
GenerateTvHtml(info, sb);
|
||||
newsletter.TvCount = info.Count;
|
||||
|
||||
|
||||
var template = new RecentlyAddedTemplate();
|
||||
var html = template.LoadTemplate(sb.ToString());
|
||||
Log.Debug("Loaded the template");
|
||||
|
||||
if (!test || firstRun)
|
||||
{
|
||||
foreach (var a in filteredMovies)
|
||||
{
|
||||
RecentlyAddedLog.Insert(new RecentlyAddedLog
|
||||
{
|
||||
ProviderId = a.EmbyId,
|
||||
AddedAt = DateTime.UtcNow
|
||||
});
|
||||
}
|
||||
foreach (var a in filteredEp)
|
||||
{
|
||||
RecentlyAddedLog.Insert(new RecentlyAddedLog
|
||||
{
|
||||
ProviderId = a.EmbyId,
|
||||
AddedAt = DateTime.UtcNow
|
||||
});
|
||||
}
|
||||
foreach (var s in filteredSeries)
|
||||
{
|
||||
RecentlyAddedLog.Insert(new RecentlyAddedLog
|
||||
{
|
||||
ProviderId = s.EmbyId,
|
||||
AddedAt = DateTime.UtcNow
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var escapedHtml = new string(html.Where(c => !char.IsControl(c)).ToArray());
|
||||
Log.Debug(escapedHtml);
|
||||
newsletter.Html = escapedHtml;
|
||||
return newsletter;
|
||||
|
||||
}
|
||||
|
||||
private void GenerateMovieHtml(IEnumerable<EmbyRecentlyAddedModel> recentlyAddedMovies, StringBuilder sb)
|
||||
{
|
||||
var movies = recentlyAddedMovies?.ToList() ?? new List<EmbyRecentlyAddedModel>();
|
||||
if (!movies.Any())
|
||||
{
|
||||
return;
|
||||
}
|
||||
var orderedMovies = movies.OrderByDescending(x => x.EmbyContent.AddedAt).Select(x => x.EmbyInformation.MovieInformation).ToList();
|
||||
sb.Append("<h1>New Movies:</h1><br /><br />");
|
||||
sb.Append(
|
||||
"<table border=\"0\" cellpadding=\"0\" align=\"center\" cellspacing=\"0\" style=\"border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%;\" width=\"100%\">");
|
||||
foreach (var movie in orderedMovies)
|
||||
{
|
||||
// We have a try within a try so we can catch the rate limit without ending the loop (finally block)
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
var imdbId = movie.ProviderIds.Imdb;
|
||||
var info = MovieApi.GetMovieInformation(imdbId).Result;
|
||||
if (info == null)
|
||||
{
|
||||
throw new Exception($"Movie with Imdb id {imdbId} returned null from the MovieApi");
|
||||
}
|
||||
AddImageInsideTable(sb, $"https://image.tmdb.org/t/p/w500{info.BackdropPath}");
|
||||
|
||||
sb.Append("<tr>");
|
||||
sb.Append(
|
||||
"<td align=\"center\" style=\"font-family: sans-serif; font-size: 14px; vertical-align: top;\" valign=\"top\">");
|
||||
|
||||
Href(sb, $"https://www.imdb.com/title/{info.ImdbId}/");
|
||||
Header(sb, 3, $"{info.Title} {info.ReleaseDate?.ToString("yyyy") ?? string.Empty}");
|
||||
EndTag(sb, "a");
|
||||
|
||||
if (info.Genres.Any())
|
||||
{
|
||||
AddParagraph(sb,
|
||||
$"Genre: {string.Join(", ", info.Genres.Select(x => x.Name.ToString()).ToArray())}");
|
||||
}
|
||||
|
||||
AddParagraph(sb, info.Overview);
|
||||
}
|
||||
catch (Exception limit)
|
||||
{
|
||||
// We have hit a limit, we need to now wait.
|
||||
Thread.Sleep(TimeSpan.FromSeconds(10));
|
||||
Log.Info(limit);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
Log.Error("Error for movie with IMDB Id = {0}", movie.ProviderIds.Imdb);
|
||||
}
|
||||
finally
|
||||
{
|
||||
EndLoopHtml(sb);
|
||||
}
|
||||
|
||||
}
|
||||
sb.Append("</table><br /><br />");
|
||||
}
|
||||
|
||||
private class TvModel
|
||||
{
|
||||
public EmbySeriesInformation Series { get; set; }
|
||||
public List<EmbyEpisodeInformation> Episodes { get; set; }
|
||||
}
|
||||
private void GenerateTvHtml(IEnumerable<EmbyRecentlyAddedModel> recenetlyAddedTv, StringBuilder sb)
|
||||
{
|
||||
var tv = recenetlyAddedTv?.ToList() ?? new List<EmbyRecentlyAddedModel>();
|
||||
|
||||
if (!tv.Any())
|
||||
{
|
||||
return;
|
||||
}
|
||||
var orderedTv = tv.OrderByDescending(x => x.EmbyContent.AddedAt).ToList();
|
||||
|
||||
// TV
|
||||
sb.Append("<h1>New Episodes:</h1><br /><br />");
|
||||
sb.Append(
|
||||
"<table border=\"0\" cellpadding=\"0\" align=\"center\" cellspacing=\"0\" style=\"border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%;\" width=\"100%\">");
|
||||
foreach (var t in orderedTv)
|
||||
{
|
||||
var seriesItem = t.EmbyInformation.SeriesInformation;
|
||||
var relatedEpisodes = t.EpisodeInformation;
|
||||
var endLoop = false;
|
||||
|
||||
try
|
||||
{
|
||||
var info = TvApi.ShowLookupByTheTvDbId(int.Parse(seriesItem.ProviderIds.Tvdb));
|
||||
if (info == null) continue;
|
||||
|
||||
var banner = info.image?.original;
|
||||
if (!string.IsNullOrEmpty(banner))
|
||||
{
|
||||
banner = banner.Replace("http", "https"); // Always use the Https banners
|
||||
}
|
||||
AddImageInsideTable(sb, banner);
|
||||
|
||||
sb.Append("<tr>");
|
||||
sb.Append(
|
||||
"<td align=\"center\" style=\"font-family: sans-serif; font-size: 14px; vertical-align: top;\" valign=\"top\">");
|
||||
|
||||
var title = $"{seriesItem.Name} {seriesItem.PremiereDate.Year}";
|
||||
|
||||
Href(sb, $"https://www.imdb.com/title/{info.externals.imdb}/");
|
||||
Header(sb, 3, title);
|
||||
EndTag(sb, "a");
|
||||
|
||||
if (relatedEpisodes != null)
|
||||
{
|
||||
var results = relatedEpisodes.GroupBy(p => p.ParentIndexNumber,
|
||||
(key, g) => new
|
||||
{
|
||||
ParentIndexNumber = key,
|
||||
IndexNumber = g.ToList()
|
||||
}
|
||||
);
|
||||
// Group the episodes
|
||||
foreach (var embyEpisodeInformation in results.OrderBy(x => x.ParentIndexNumber))
|
||||
{
|
||||
var epSb = new StringBuilder();
|
||||
var orderedEpisodes = embyEpisodeInformation.IndexNumber.OrderBy(x => x.IndexNumber).ToList();
|
||||
for (var i = 0; i < orderedEpisodes.Count; i++)
|
||||
{
|
||||
var ep = orderedEpisodes[i];
|
||||
if (i < embyEpisodeInformation.IndexNumber.Count - 1)
|
||||
{
|
||||
epSb.Append($"{ep.IndexNumber},");
|
||||
}
|
||||
else
|
||||
{
|
||||
epSb.Append(ep.IndexNumber);
|
||||
}
|
||||
}
|
||||
AddParagraph(sb, $"Season: {embyEpisodeInformation.ParentIndexNumber}, Episode: {epSb}");
|
||||
}
|
||||
}
|
||||
|
||||
if (info.genres.Any())
|
||||
{
|
||||
AddParagraph(sb, $"Genre: {string.Join(", ", info.genres.Select(x => x.ToString()).ToArray())}");
|
||||
}
|
||||
|
||||
AddParagraph(sb, string.IsNullOrEmpty(seriesItem.Overview) ? info.summary : seriesItem.Overview);
|
||||
endLoop = true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (endLoop)
|
||||
EndLoopHtml(sb);
|
||||
}
|
||||
}
|
||||
sb.Append("</table><br /><br />");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private void EndLoopHtml(StringBuilder sb)
|
||||
{
|
||||
//NOTE: BR have to be in TD's as per html spec or it will be put outside of the table...
|
||||
//Source: http://stackoverflow.com/questions/6588638/phantom-br-tag-rendered-by-browsers-prior-to-table-tag
|
||||
sb.Append("<hr />");
|
||||
sb.Append("<br />");
|
||||
sb.Append("<br />");
|
||||
sb.Append("</td>");
|
||||
sb.Append("</tr>");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
namespace Ombi.Services.Jobs.RecentlyAddedNewsletter
|
||||
{
|
||||
public interface IEmbyAddedNewsletter
|
||||
{
|
||||
Newsletter GetNewsletter(bool test);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
namespace Ombi.Services.Jobs.RecentlyAddedNewsletter
|
||||
{
|
||||
public interface IPlexNewsletter
|
||||
{
|
||||
Newsletter GetNewsletter(bool test);
|
||||
}
|
||||
}
|
37
Old/Ombi.Services/Jobs/RecentlyAddedNewsletter/Newsletter.cs
Normal file
37
Old/Ombi.Services/Jobs/RecentlyAddedNewsletter/Newsletter.cs
Normal file
|
@ -0,0 +1,37 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2017 Jamie Rees
|
||||
// File: Newsletter.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
|
||||
namespace Ombi.Services.Jobs.RecentlyAddedNewsletter
|
||||
{
|
||||
public class Newsletter
|
||||
{
|
||||
public string Html { get; set; }
|
||||
public int MovieCount { get; set; }
|
||||
public int TvCount { get; set; }
|
||||
|
||||
public bool Send => MovieCount > 0 || TvCount > 0;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,425 @@
|
|||
#region Copyright
|
||||
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2016 Jamie Rees
|
||||
// File: RecentlyAddedModel.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
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using NLog;
|
||||
using Ombi.Api;
|
||||
using Ombi.Api.Interfaces;
|
||||
using Ombi.Api.Models.Emby;
|
||||
using Ombi.Api.Models.Plex;
|
||||
using Ombi.Core;
|
||||
using Ombi.Core.SettingModels;
|
||||
using Ombi.Helpers;
|
||||
using Ombi.Services.Jobs.Templates;
|
||||
using Ombi.Store.Models;
|
||||
using Ombi.Store.Models.Plex;
|
||||
using Ombi.Store.Repository;
|
||||
using TMDbLib.Objects.Exceptions;
|
||||
using PlexMediaType = Ombi.Store.Models.Plex.PlexMediaType;
|
||||
|
||||
namespace Ombi.Services.Jobs.RecentlyAddedNewsletter
|
||||
{
|
||||
public class
|
||||
PlexRecentlyAddedNewsletter : HtmlTemplateGenerator, IPlexNewsletter
|
||||
{
|
||||
public PlexRecentlyAddedNewsletter(IPlexApi api, ISettingsService<PlexSettings> plexSettings,
|
||||
ISettingsService<EmailNotificationSettings> email,
|
||||
ISettingsService<NewletterSettings> newsletter, IRepository<RecentlyAddedLog> log,
|
||||
IRepository<PlexContent> embyContent, IRepository<PlexEpisodes> episodes)
|
||||
{
|
||||
Api = api;
|
||||
PlexSettings = plexSettings;
|
||||
EmailSettings = email;
|
||||
NewsletterSettings = newsletter;
|
||||
Content = embyContent;
|
||||
MovieApi = new TheMovieDbApi();
|
||||
TvApi = new TvMazeApi();
|
||||
Episodes = episodes;
|
||||
RecentlyAddedLog = log;
|
||||
}
|
||||
|
||||
private IPlexApi Api { get; }
|
||||
private TheMovieDbApi MovieApi { get; }
|
||||
private TvMazeApi TvApi { get; }
|
||||
private ISettingsService<PlexSettings> PlexSettings { get; }
|
||||
private ISettingsService<EmailNotificationSettings> EmailSettings { get; }
|
||||
private ISettingsService<NewletterSettings> NewsletterSettings { get; }
|
||||
private IRepository<PlexContent> Content { get; }
|
||||
private IRepository<PlexEpisodes> Episodes { get; }
|
||||
private IRepository<RecentlyAddedLog> RecentlyAddedLog { get; }
|
||||
|
||||
private static readonly Logger Log = LogManager.GetCurrentClassLogger();
|
||||
|
||||
public Newsletter GetNewsletter(bool test)
|
||||
{
|
||||
try
|
||||
{
|
||||
return GetHtml(test);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private class PlexRecentlyAddedModel
|
||||
{
|
||||
public PlexMetadata Metadata { get; set; }
|
||||
public PlexContent Content { get; set; }
|
||||
public List<PlexEpisodeMetadata> EpisodeMetadata { get; set; }
|
||||
}
|
||||
|
||||
private Newsletter GetHtml(bool test)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
var newsletter = new Newsletter();
|
||||
var plexSettings = PlexSettings.GetSettings();
|
||||
|
||||
var plexContent = Content.GetAll().ToList();
|
||||
|
||||
var series = plexContent.Where(x => x.Type == PlexMediaType.Show).ToList();
|
||||
var episodes = Episodes.GetAll().ToList();
|
||||
var movie = plexContent.Where(x => x.Type == PlexMediaType.Movie).ToList();
|
||||
|
||||
var recentlyAdded = RecentlyAddedLog.GetAll().ToList();
|
||||
|
||||
var firstRun = !recentlyAdded.Any();
|
||||
|
||||
var filteredMovies = movie.Where(m => recentlyAdded.All(x => x.ProviderId != m.ProviderId)).ToList();
|
||||
var filteredEp = episodes.Where(m => recentlyAdded.All(x => x.ProviderId != m.RatingKey)).ToList();
|
||||
var filteredSeries = series.Where(x => recentlyAdded.All(c => c.ProviderId != x.ProviderId)).ToList();
|
||||
|
||||
var info = new List<PlexRecentlyAddedModel>();
|
||||
|
||||
if (test && !filteredMovies.Any())
|
||||
{
|
||||
// if this is a test make sure we show something
|
||||
filteredMovies = movie.Take(5).ToList();
|
||||
}
|
||||
foreach (var m in filteredMovies.OrderByDescending(x => x.AddedAt))
|
||||
{
|
||||
var i = Api.GetMetadata(plexSettings.PlexAuthToken, plexSettings.FullUri, m.ItemId);
|
||||
if (i.Video == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
info.Add(new PlexRecentlyAddedModel
|
||||
{
|
||||
Metadata = i,
|
||||
Content = m
|
||||
});
|
||||
}
|
||||
GenerateMovieHtml(info, sb);
|
||||
newsletter.MovieCount = info.Count;
|
||||
|
||||
info.Clear();
|
||||
if (test && !filteredEp.Any() && episodes.Any())
|
||||
{
|
||||
// if this is a test make sure we show something
|
||||
filteredEp = episodes.Take(5).ToList();
|
||||
}
|
||||
if (filteredEp.Any())
|
||||
{
|
||||
var recentlyAddedModel = new List<PlexRecentlyAddedModel>();
|
||||
foreach (var plexEpisodes in filteredEp)
|
||||
{
|
||||
// Find related series item
|
||||
var relatedSeries = series.FirstOrDefault(x => x.ProviderId == plexEpisodes.ProviderId);
|
||||
|
||||
if (relatedSeries == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get series information
|
||||
var i = Api.GetMetadata(plexSettings.PlexAuthToken, plexSettings.FullUri, relatedSeries.ItemId);
|
||||
|
||||
var episodeInfo = Api.GetEpisodeMetaData(plexSettings.PlexAuthToken, plexSettings.FullUri, plexEpisodes.RatingKey);
|
||||
// Check if we already have this series
|
||||
var existingSeries = recentlyAddedModel.FirstOrDefault(x =>
|
||||
x.Metadata.Directory.RatingKey == i.Directory.RatingKey);
|
||||
|
||||
if (existingSeries != null)
|
||||
{
|
||||
existingSeries.EpisodeMetadata.Add(episodeInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
recentlyAddedModel.Add(new PlexRecentlyAddedModel
|
||||
{
|
||||
Metadata = i,
|
||||
EpisodeMetadata = new List<PlexEpisodeMetadata>() { episodeInfo },
|
||||
Content = relatedSeries
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
info.AddRange(recentlyAddedModel);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (test && !filteredSeries.Any())
|
||||
{
|
||||
// if this is a test make sure we show something
|
||||
filteredSeries = series.Take(5).ToList();
|
||||
}
|
||||
foreach (var t in filteredSeries.OrderByDescending(x => x.AddedAt))
|
||||
{
|
||||
var i = Api.GetMetadata(plexSettings.PlexAuthToken, plexSettings.FullUri, t.ItemId);
|
||||
if (i.Directory == null)
|
||||
{
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
info.Add(new PlexRecentlyAddedModel
|
||||
{
|
||||
Metadata = i,
|
||||
Content = t
|
||||
});
|
||||
}
|
||||
}
|
||||
GenerateTvHtml(info, sb);
|
||||
newsletter.TvCount = info.Count;
|
||||
|
||||
var template = new RecentlyAddedTemplate();
|
||||
var html = template.LoadTemplate(sb.ToString());
|
||||
Log.Debug("Loaded the template");
|
||||
|
||||
if (!test || firstRun)
|
||||
{
|
||||
foreach (var a in filteredMovies)
|
||||
{
|
||||
RecentlyAddedLog.Insert(new RecentlyAddedLog
|
||||
{
|
||||
ProviderId = a.ProviderId,
|
||||
AddedAt = DateTime.UtcNow
|
||||
});
|
||||
}
|
||||
foreach (var a in filteredEp)
|
||||
{
|
||||
RecentlyAddedLog.Insert(new RecentlyAddedLog
|
||||
{
|
||||
ProviderId = a.RatingKey,
|
||||
AddedAt = DateTime.UtcNow
|
||||
});
|
||||
}
|
||||
foreach (var a in filteredSeries)
|
||||
{
|
||||
RecentlyAddedLog.Insert(new RecentlyAddedLog
|
||||
{
|
||||
ProviderId = a.ProviderId,
|
||||
AddedAt = DateTime.UtcNow
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
var escapedHtml = new string(html.Where(c => !char.IsControl(c)).ToArray());
|
||||
Log.Debug(escapedHtml);
|
||||
newsletter.Html = escapedHtml;
|
||||
return newsletter;
|
||||
}
|
||||
|
||||
private void GenerateMovieHtml(IEnumerable<PlexRecentlyAddedModel> recentlyAddedMovies, StringBuilder sb)
|
||||
{
|
||||
var movies = recentlyAddedMovies?.ToList() ?? new List<PlexRecentlyAddedModel>();
|
||||
if (!movies.Any())
|
||||
{
|
||||
return;
|
||||
}
|
||||
var orderedMovies = movies.OrderByDescending(x => x.Content.AddedAt).ToList();
|
||||
sb.Append("<h1>New Movies:</h1><br /><br />");
|
||||
sb.Append(
|
||||
"<table border=\"0\" cellpadding=\"0\" align=\"center\" cellspacing=\"0\" style=\"border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%;\" width=\"100%\">");
|
||||
foreach (var movie in orderedMovies)
|
||||
{
|
||||
// We have a try within a try so we can catch the rate limit without ending the loop (finally block)
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
var imdbId = PlexHelper.GetProviderIdFromPlexGuid(movie.Metadata.Video.Guid);
|
||||
var info = MovieApi.GetMovieInformation(imdbId).Result;
|
||||
if (info == null)
|
||||
{
|
||||
throw new Exception($"Movie with Imdb id {imdbId} returned null from the MovieApi");
|
||||
}
|
||||
AddImageInsideTable(sb, $"https://image.tmdb.org/t/p/w500{info.BackdropPath}");
|
||||
|
||||
sb.Append("<tr>");
|
||||
sb.Append(
|
||||
"<td align=\"center\" style=\"font-family: sans-serif; font-size: 14px; vertical-align: top;\" valign=\"top\">");
|
||||
|
||||
Href(sb, $"https://www.imdb.com/title/{info.ImdbId}/");
|
||||
Header(sb, 3, $"{info.Title} {info.ReleaseDate?.ToString("yyyy") ?? string.Empty}");
|
||||
EndTag(sb, "a");
|
||||
|
||||
if (info.Genres.Any())
|
||||
{
|
||||
AddParagraph(sb,
|
||||
$"Genre: {string.Join(", ", info.Genres.Select(x => x.Name.ToString()).ToArray())}");
|
||||
}
|
||||
|
||||
AddParagraph(sb, info.Overview);
|
||||
}
|
||||
catch (RequestLimitExceededException limit)
|
||||
{
|
||||
// We have hit a limit, we need to now wait.
|
||||
Thread.Sleep(TimeSpan.FromSeconds(10));
|
||||
Log.Info(limit);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
Log.Error("Error for movie with IMDB Id = {0}", movie.Metadata.Video.Guid);
|
||||
}
|
||||
finally
|
||||
{
|
||||
EndLoopHtml(sb);
|
||||
}
|
||||
|
||||
}
|
||||
sb.Append("</table><br /><br />");
|
||||
}
|
||||
|
||||
private class TvModel
|
||||
{
|
||||
public EmbySeriesInformation Series { get; set; }
|
||||
public List<EmbyEpisodeInformation> Episodes { get; set; }
|
||||
}
|
||||
private void GenerateTvHtml(IEnumerable<PlexRecentlyAddedModel> recenetlyAddedTv, StringBuilder sb)
|
||||
{
|
||||
var tv = recenetlyAddedTv?.ToList() ?? new List<PlexRecentlyAddedModel>();
|
||||
|
||||
if (!tv.Any())
|
||||
{
|
||||
return;
|
||||
}
|
||||
var orderedTv = tv.OrderByDescending(x => x.Content.AddedAt).ToList();
|
||||
|
||||
// TV
|
||||
sb.Append("<h1>New Episodes:</h1><br /><br />");
|
||||
sb.Append(
|
||||
"<table border=\"0\" cellpadding=\"0\" align=\"center\" cellspacing=\"0\" style=\"border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%;\" width=\"100%\">");
|
||||
foreach (var t in orderedTv)
|
||||
{
|
||||
var relatedEpisodes = t.EpisodeMetadata ?? new List<PlexEpisodeMetadata>();
|
||||
|
||||
try
|
||||
{
|
||||
var info = TvApi.ShowLookupByTheTvDbId(int.Parse(PlexHelper.GetProviderIdFromPlexGuid(t?.Metadata?.Directory?.Guid ?? string.Empty)));
|
||||
|
||||
var banner = info.image?.original;
|
||||
if (!string.IsNullOrEmpty(banner))
|
||||
{
|
||||
banner = banner.Replace("http", "https"); // Always use the Https banners
|
||||
}
|
||||
AddImageInsideTable(sb, banner);
|
||||
|
||||
sb.Append("<tr>");
|
||||
sb.Append(
|
||||
"<td align=\"center\" style=\"font-family: sans-serif; font-size: 14px; vertical-align: top;\" valign=\"top\">");
|
||||
|
||||
var title = $"{t.Content.Title} {t.Content.ReleaseYear}";
|
||||
|
||||
Href(sb, $"https://www.imdb.com/title/{info.externals.imdb}/");
|
||||
Header(sb, 3, title);
|
||||
EndTag(sb, "a");
|
||||
|
||||
// Group by the ParentIndex (season number)
|
||||
var results = relatedEpisodes.GroupBy(p => p.Video.FirstOrDefault()?.ParentIndex,
|
||||
(key, g) => new
|
||||
{
|
||||
ParentIndexNumber = key,
|
||||
IndexNumber = g.ToList()
|
||||
}
|
||||
);
|
||||
// Group the episodes
|
||||
foreach (var epInformation in results.OrderBy(x => x.ParentIndexNumber))
|
||||
{
|
||||
var orderedEpisodes = epInformation.IndexNumber.OrderBy(x => Convert.ToInt32(x.Video.FirstOrDefault().Index)).ToList();
|
||||
var epSb = new StringBuilder();
|
||||
for (var i = 0; i < orderedEpisodes.Count; i++)
|
||||
{
|
||||
var ep = orderedEpisodes[i];
|
||||
if (i < orderedEpisodes.Count - 1)
|
||||
{
|
||||
epSb.Append($"{ep.Video.FirstOrDefault().Index},");
|
||||
}
|
||||
else
|
||||
{
|
||||
epSb.Append($"{ep.Video.FirstOrDefault().Index}");
|
||||
}
|
||||
|
||||
}
|
||||
AddParagraph(sb, $"Season: {epInformation.ParentIndexNumber}, Episode: {epSb}");
|
||||
}
|
||||
|
||||
if (info.genres.Any())
|
||||
{
|
||||
AddParagraph(sb, $"Genre: {string.Join(", ", info.genres.Select(x => x.ToString()).ToArray())}");
|
||||
}
|
||||
|
||||
AddParagraph(sb, string.IsNullOrEmpty(t.Metadata.Directory.Summary) ? t.Metadata.Directory.Summary : info.summary);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
EndLoopHtml(sb);
|
||||
}
|
||||
}
|
||||
sb.Append("</table><br /><br />");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private void EndLoopHtml(StringBuilder sb)
|
||||
{
|
||||
//NOTE: BR have to be in TD's as per html spec or it will be put outside of the table...
|
||||
//Source: http://stackoverflow.com/questions/6588638/phantom-br-tag-rendered-by-browsers-prior-to-table-tag
|
||||
sb.Append("<hr />");
|
||||
sb.Append("<br />");
|
||||
sb.Append("<br />");
|
||||
sb.Append("</td>");
|
||||
sb.Append("</tr>");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,284 @@
|
|||
#region Copyright
|
||||
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2016 Jamie Rees
|
||||
// File: RecentlyAddedModel.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
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using MailKit.Net.Smtp;
|
||||
using MimeKit;
|
||||
using NLog;
|
||||
using Ombi.Api;
|
||||
using Ombi.Api.Interfaces;
|
||||
using Ombi.Api.Models.Plex;
|
||||
using Ombi.Core;
|
||||
using Ombi.Core.SettingModels;
|
||||
using Ombi.Core.Users;
|
||||
using Ombi.Helpers;
|
||||
using Ombi.Helpers.Permissions;
|
||||
using Ombi.Services.Interfaces;
|
||||
using Ombi.Services.Jobs.Templates;
|
||||
using Quartz;
|
||||
|
||||
namespace Ombi.Services.Jobs.RecentlyAddedNewsletter
|
||||
{
|
||||
public class RecentlyAddedNewsletter : HtmlTemplateGenerator, IJob, IRecentlyAdded, IMassEmail
|
||||
{
|
||||
public RecentlyAddedNewsletter(IPlexApi api, ISettingsService<PlexSettings> plexSettings,
|
||||
ISettingsService<EmailNotificationSettings> email, IJobRecord rec,
|
||||
ISettingsService<NewletterSettings> newsletter,
|
||||
IUserHelper userHelper, IEmbyAddedNewsletter embyNews,
|
||||
ISettingsService<EmbySettings> embyS,
|
||||
IPlexNewsletter plex)
|
||||
{
|
||||
JobRecord = rec;
|
||||
Api = api;
|
||||
PlexSettings = plexSettings;
|
||||
EmailSettings = email;
|
||||
NewsletterSettings = newsletter;
|
||||
UserHelper = userHelper;
|
||||
EmbyNewsletter = embyNews;
|
||||
EmbySettings = embyS;
|
||||
PlexNewsletter = plex;
|
||||
}
|
||||
|
||||
private IPlexApi Api { get; }
|
||||
private TvMazeApi TvApi = new TvMazeApi();
|
||||
private readonly TheMovieDbApi _movieApi = new TheMovieDbApi();
|
||||
private ISettingsService<PlexSettings> PlexSettings { get; }
|
||||
private ISettingsService<EmbySettings> EmbySettings { get; }
|
||||
private ISettingsService<EmailNotificationSettings> EmailSettings { get; }
|
||||
private ISettingsService<NewletterSettings> NewsletterSettings { get; }
|
||||
private IJobRecord JobRecord { get; }
|
||||
private IUserHelper UserHelper { get; }
|
||||
private IEmbyAddedNewsletter EmbyNewsletter { get; }
|
||||
private IPlexNewsletter PlexNewsletter { get; }
|
||||
|
||||
private static readonly Logger Log = LogManager.GetCurrentClassLogger();
|
||||
|
||||
public void StartNewsLetter()
|
||||
{
|
||||
try
|
||||
{
|
||||
var settings = NewsletterSettings.GetSettings();
|
||||
if (!settings.SendRecentlyAddedEmail)
|
||||
{
|
||||
return;
|
||||
}
|
||||
JobRecord.SetRunning(true, JobNames.RecentlyAddedEmail);
|
||||
StartNewsLetter(settings);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
JobRecord.Record(JobNames.RecentlyAddedEmail);
|
||||
JobRecord.SetRunning(false, JobNames.RecentlyAddedEmail);
|
||||
}
|
||||
}
|
||||
public void Execute(IJobExecutionContext context)
|
||||
{
|
||||
StartNewsLetter();
|
||||
}
|
||||
|
||||
public void RecentlyAddedAdminTest()
|
||||
{
|
||||
Log.Debug("Starting Recently Added Newsletter Test");
|
||||
var settings = NewsletterSettings.GetSettings();
|
||||
StartNewsLetter(settings, true);
|
||||
}
|
||||
|
||||
public void MassEmailAdminTest(string html, string subject)
|
||||
{
|
||||
Log.Debug("Starting Mass Email Test");
|
||||
var template = new MassEmailTemplate();
|
||||
var body = template.LoadTemplate(html);
|
||||
SendMassEmail(body, subject, true);
|
||||
}
|
||||
|
||||
public void SendMassEmail(string html, string subject)
|
||||
{
|
||||
Log.Debug("Starting Mass Email Test");
|
||||
var template = new MassEmailTemplate();
|
||||
var body = template.LoadTemplate(html);
|
||||
SendMassEmail(body, subject, false);
|
||||
}
|
||||
|
||||
private void StartNewsLetter(NewletterSettings newletterSettings, bool testEmail = false)
|
||||
{
|
||||
var embySettings = EmbySettings.GetSettings();
|
||||
if (embySettings.Enable)
|
||||
{
|
||||
var letter = EmbyNewsletter.GetNewsletter(testEmail) ?? new Newsletter();
|
||||
if (letter.Send || testEmail)
|
||||
{
|
||||
SendNewsletter(newletterSettings, letter.Html, testEmail, "New Content On Emby!");
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Warn("There is no new content to send the newsletter");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var plexSettings = PlexSettings.GetSettings();
|
||||
if (plexSettings.Enable)
|
||||
{
|
||||
var letter = PlexNewsletter.GetNewsletter(testEmail) ?? new Newsletter();
|
||||
if (letter.Send || testEmail)
|
||||
{
|
||||
SendNewsletter(newletterSettings, letter.Html, testEmail);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SendMassEmail(string html, string subject, bool testEmail)
|
||||
{
|
||||
var settings = EmailSettings.GetSettings();
|
||||
|
||||
if (!settings.Enabled || string.IsNullOrEmpty(settings.EmailHost))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var body = new BodyBuilder { HtmlBody = html, TextBody = "This email is only available on devices that support HTML." };
|
||||
|
||||
var message = new MimeMessage
|
||||
{
|
||||
Body = body.ToMessageBody(),
|
||||
Subject = subject
|
||||
};
|
||||
Log.Debug("Created Plain/HTML MIME body");
|
||||
|
||||
if (!testEmail)
|
||||
{
|
||||
var users = UserHelper.GetUsers(); // Get all users
|
||||
if (users != null)
|
||||
{
|
||||
foreach (var user in users)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(user.EmailAddress))
|
||||
{
|
||||
message.Bcc.Add(new MailboxAddress(user.Username, user.EmailAddress)); // BCC everyone
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
message.Bcc.Add(new MailboxAddress(settings.EmailUsername, settings.RecipientEmail)); // Include the admin
|
||||
|
||||
message.From.Add(new MailboxAddress(settings.EmailUsername, settings.EmailSender));
|
||||
SendMail(settings, message);
|
||||
}
|
||||
|
||||
|
||||
private void SendNewsletter(NewletterSettings newletterSettings, string html, bool testEmail = false, string subject = "New Content on Plex!")
|
||||
{
|
||||
Log.Debug("Entering SendNewsletter");
|
||||
var settings = EmailSettings.GetSettings();
|
||||
|
||||
if (!settings.Enabled || string.IsNullOrEmpty(settings.EmailHost))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var body = new BodyBuilder { HtmlBody = html, TextBody = "This email is only available on devices that support HTML." };
|
||||
|
||||
var message = new MimeMessage
|
||||
{
|
||||
Body = body.ToMessageBody(),
|
||||
Subject = subject
|
||||
};
|
||||
Log.Debug("Created Plain/HTML MIME body");
|
||||
|
||||
if (!testEmail)
|
||||
{
|
||||
var users = UserHelper.GetUsersWithFeature(Features.Newsletter);
|
||||
if (users != null)
|
||||
{
|
||||
foreach (var user in users)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(user.EmailAddress))
|
||||
{
|
||||
message.Bcc.Add(new MailboxAddress(user.Username, user.EmailAddress));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (newletterSettings.CustomUsersEmailAddresses != null
|
||||
&& newletterSettings.CustomUsersEmailAddresses.Any())
|
||||
{
|
||||
foreach (var user in newletterSettings.CustomUsersEmailAddresses)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(user))
|
||||
{
|
||||
message.Bcc.Add(new MailboxAddress(user, user));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
message.Bcc.Add(new MailboxAddress(settings.EmailUsername, settings.RecipientEmail)); // Include the admin
|
||||
|
||||
message.From.Add(new MailboxAddress(settings.EmailUsername, settings.EmailSender));
|
||||
SendMail(settings, message);
|
||||
}
|
||||
|
||||
private void SendMail(EmailNotificationSettings settings, MimeMessage message)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var client = new SmtpClient())
|
||||
{
|
||||
client.Connect(settings.EmailHost, settings.EmailPort); // Let MailKit figure out the correct SecureSocketOptions.
|
||||
|
||||
// Note: since we don't have an OAuth2 token, disable
|
||||
// the XOAUTH2 authentication mechanism.
|
||||
client.AuthenticationMechanisms.Remove("XOAUTH2");
|
||||
|
||||
if (settings.Authentication)
|
||||
{
|
||||
client.Authenticate(settings.EmailUsername, settings.EmailPassword);
|
||||
}
|
||||
Log.Info("sending message to {0} \r\n from: {1}\r\n Are we authenticated: {2}", message.To, message.From, client.IsAuthenticated);
|
||||
Log.Debug("Sending");
|
||||
client.Send(message);
|
||||
Log.Debug("Sent");
|
||||
client.Disconnect(true);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
100
Old/Ombi.Services/Jobs/SickRageCacher.cs
Normal file
100
Old/Ombi.Services/Jobs/SickRageCacher.cs
Normal file
|
@ -0,0 +1,100 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2016 Jamie Rees
|
||||
// File: PlexAvailabilityChecker.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
|
||||
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using Ombi.Api.Interfaces;
|
||||
using Ombi.Api.Models.SickRage;
|
||||
using Ombi.Core;
|
||||
using Ombi.Core.SettingModels;
|
||||
using Ombi.Helpers;
|
||||
using Ombi.Services.Interfaces;
|
||||
using Quartz;
|
||||
|
||||
namespace Ombi.Services.Jobs
|
||||
{
|
||||
public class SickRageCacher : IJob, ISickRageCacher
|
||||
{
|
||||
public SickRageCacher(ISettingsService<SickRageSettings> srSettings, ISickRageApi srApi, ICacheProvider cache, IJobRecord rec)
|
||||
{
|
||||
SrSettings = srSettings;
|
||||
SrApi = srApi;
|
||||
Cache = cache;
|
||||
Job = rec;
|
||||
}
|
||||
|
||||
private ISettingsService<SickRageSettings> SrSettings { get; }
|
||||
private ICacheProvider Cache { get; }
|
||||
private ISickRageApi SrApi { get; }
|
||||
|
||||
private static Logger Log = LogManager.GetCurrentClassLogger();
|
||||
private IJobRecord Job { get; }
|
||||
|
||||
public void Queued()
|
||||
{
|
||||
Log.Trace("Getting the settings");
|
||||
|
||||
var settings = SrSettings.GetSettings();
|
||||
if (settings.Enabled)
|
||||
{
|
||||
|
||||
Job.SetRunning(true, JobNames.SrCacher);
|
||||
|
||||
Log.Trace("Getting all shows from SickRage");
|
||||
try
|
||||
{
|
||||
var shows = SrApi.GetShows(settings.ApiKey, settings.FullUri);
|
||||
if (shows != null)
|
||||
{
|
||||
Cache.Set(CacheKeys.SickRageQueued, shows.Result, CacheKeys.TimeFrameMinutes.SchedulerCaching);
|
||||
}
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
Log.Error(ex, "Failed caching queued items from SickRage");
|
||||
}
|
||||
finally
|
||||
{
|
||||
Job.Record(JobNames.SrCacher);
|
||||
Job.SetRunning(false, JobNames.SrCacher);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// we do not want to set here...
|
||||
public int[] QueuedIds()
|
||||
{
|
||||
var tv = Cache.Get<SickrageShows>(CacheKeys.SickRageQueued);
|
||||
return tv?.data?.Values.Select(x => x.tvdbid).ToArray() ?? new int[] { };
|
||||
}
|
||||
|
||||
public void Execute(IJobExecutionContext context)
|
||||
{
|
||||
Queued();
|
||||
}
|
||||
}
|
||||
}
|
115
Old/Ombi.Services/Jobs/SonarrCacher.cs
Normal file
115
Old/Ombi.Services/Jobs/SonarrCacher.cs
Normal file
|
@ -0,0 +1,115 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2016 Jamie Rees
|
||||
// File: PlexAvailabilityChecker.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
|
||||
|
||||
using System.Collections.Generic;
|
||||
using NLog;
|
||||
using Ombi.Api.Interfaces;
|
||||
using Ombi.Api.Models.Sonarr;
|
||||
using Ombi.Core;
|
||||
using Ombi.Core.SettingModels;
|
||||
using Ombi.Helpers;
|
||||
using Ombi.Services.Interfaces;
|
||||
using Ombi.Services.Models;
|
||||
using Quartz;
|
||||
|
||||
namespace Ombi.Services.Jobs
|
||||
{
|
||||
public class SonarrCacher : IJob, ISonarrCacher
|
||||
{
|
||||
public SonarrCacher(ISettingsService<SonarrSettings> sonarrSettings, ISonarrApi sonarrApi, ICacheProvider cache, IJobRecord rec)
|
||||
{
|
||||
SonarrSettings = sonarrSettings;
|
||||
SonarrApi = sonarrApi;
|
||||
Job = rec;
|
||||
Cache = cache;
|
||||
}
|
||||
|
||||
private ISettingsService<SonarrSettings> SonarrSettings { get; }
|
||||
private ICacheProvider Cache { get; }
|
||||
private ISonarrApi SonarrApi { get; }
|
||||
private IJobRecord Job { get; }
|
||||
|
||||
private static Logger Log = LogManager.GetCurrentClassLogger();
|
||||
|
||||
public void Queued()
|
||||
{
|
||||
var settings = SonarrSettings.GetSettings();
|
||||
if (settings.Enabled)
|
||||
{
|
||||
Job.SetRunning(true, JobNames.SonarrCacher);
|
||||
try
|
||||
{
|
||||
var series = SonarrApi.GetSeries(settings.ApiKey, settings.FullUri);
|
||||
if (series != null)
|
||||
{
|
||||
Cache.Set(CacheKeys.SonarrQueued, series, CacheKeys.TimeFrameMinutes.SchedulerCaching);
|
||||
}
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
Log.Error(ex, "Failed caching queued items from Sonarr");
|
||||
}
|
||||
finally
|
||||
{
|
||||
Job.Record(JobNames.SonarrCacher);
|
||||
Job.SetRunning(false, JobNames.SonarrCacher);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// we do not want to set here...
|
||||
public IEnumerable<SonarrCachedResult> QueuedIds()
|
||||
{
|
||||
var result = new List<SonarrCachedResult>();
|
||||
|
||||
var series = Cache.Get<List<Series>>(CacheKeys.SonarrQueued);
|
||||
if (series != null)
|
||||
{
|
||||
foreach (var s in series)
|
||||
{
|
||||
var cached = new SonarrCachedResult {TvdbId = s.tvdbId};
|
||||
foreach (var season in s.seasons)
|
||||
{
|
||||
cached.Seasons.Add(new SonarrSeasons
|
||||
{
|
||||
SeasonNumber = season.seasonNumber,
|
||||
Monitored = season.monitored
|
||||
});
|
||||
}
|
||||
|
||||
result.Add(cached);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public void Execute(IJobExecutionContext context)
|
||||
{
|
||||
Queued();
|
||||
}
|
||||
}
|
||||
}
|
168
Old/Ombi.Services/Jobs/StoreBackup.cs
Normal file
168
Old/Ombi.Services/Jobs/StoreBackup.cs
Normal file
|
@ -0,0 +1,168 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2016 Jamie Rees
|
||||
// File: StoreBackup.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
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using Ombi.Services.Interfaces;
|
||||
using Ombi.Store;
|
||||
using Quartz;
|
||||
|
||||
namespace Ombi.Services.Jobs
|
||||
{
|
||||
public class StoreBackup : IJob, IStoreBackup
|
||||
{
|
||||
public StoreBackup(ISqliteConfiguration sql, IJobRecord rec)
|
||||
{
|
||||
Sql = sql;
|
||||
JobRecord = rec;
|
||||
}
|
||||
|
||||
private ISqliteConfiguration Sql { get; }
|
||||
private IJobRecord JobRecord { get; }
|
||||
|
||||
private static Logger Log = LogManager.GetCurrentClassLogger();
|
||||
|
||||
public void Start()
|
||||
{
|
||||
JobRecord.SetRunning(true, JobNames.CpCacher);
|
||||
TakeBackup();
|
||||
Cleanup();
|
||||
}
|
||||
|
||||
public void Execute(IJobExecutionContext context)
|
||||
{
|
||||
JobRecord.SetRunning(true, JobNames.CpCacher);
|
||||
TakeBackup();
|
||||
Cleanup();
|
||||
}
|
||||
|
||||
private void TakeBackup()
|
||||
{
|
||||
Log.Trace("Starting DB Backup");
|
||||
var dbPath = Sql.CurrentPath;
|
||||
var dir = Path.GetDirectoryName(dbPath);
|
||||
if (dir == null)
|
||||
{
|
||||
Log.Warn("We couldn't find the DB path. We cannot backup.");
|
||||
return;
|
||||
}
|
||||
var backupDir = Directory.CreateDirectory(Path.Combine(dir, "Backup"));
|
||||
|
||||
|
||||
if (string.IsNullOrEmpty(dbPath))
|
||||
{
|
||||
Log.Warn("Could not find the actual database. We cannot backup.");
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (DoWeNeedToBackup(backupDir.FullName))
|
||||
{
|
||||
File.Copy(dbPath, Path.Combine(backupDir.FullName, $"PlexRequests.sqlite_{DateTime.Now.ToString("yyyy-MM-dd hh.mm.ss")}.bak"));
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Warn(e);
|
||||
Log.Warn("Exception when trying to copy the backup.");
|
||||
}
|
||||
finally
|
||||
{
|
||||
JobRecord.Record(JobNames.StoreBackup);
|
||||
JobRecord.SetRunning(false, JobNames.CpCacher);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void Cleanup()
|
||||
{
|
||||
Log.Trace("Starting DB Cleanup");
|
||||
var dbPath = Sql.CurrentPath;
|
||||
var dir = Path.GetDirectoryName(dbPath);
|
||||
if (dir == null)
|
||||
{
|
||||
Log.Warn("We couldn't find the DB path. We cannot backup.");
|
||||
return;
|
||||
}
|
||||
var backupDir = Directory.CreateDirectory(Path.Combine(dir, "Backup"));
|
||||
|
||||
var files = backupDir.GetFiles();
|
||||
|
||||
foreach (var file in files)
|
||||
{
|
||||
var dt = ParseName(file.Name);
|
||||
if (dt < DateTime.Now.AddDays(-7))
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
File.Delete(file.FullName);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private bool DoWeNeedToBackup(string backupPath)
|
||||
{
|
||||
var files = Directory.GetFiles(backupPath);
|
||||
var last = files.LastOrDefault();
|
||||
if (!string.IsNullOrEmpty(last))
|
||||
{
|
||||
var dt = ParseName(Path.GetFileName(last));
|
||||
if (dt < DateTime.Now.AddHours(-1))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// We don't have a backup
|
||||
return true;
|
||||
}
|
||||
|
||||
private DateTime ParseName(string fileName)
|
||||
{
|
||||
var names = fileName.Split(new[] { '_', '.', ' ' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
if (names.Length > 1)
|
||||
{
|
||||
DateTime parsed;
|
||||
DateTime.TryParse(names[2], out parsed);
|
||||
return parsed;
|
||||
|
||||
}
|
||||
return DateTime.MinValue;
|
||||
}
|
||||
}
|
||||
}
|
95
Old/Ombi.Services/Jobs/StoreCleanup.cs
Normal file
95
Old/Ombi.Services/Jobs/StoreCleanup.cs
Normal file
|
@ -0,0 +1,95 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2016 Jamie Rees
|
||||
// File: StoreCleanup.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
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using Ombi.Services.Interfaces;
|
||||
using Ombi.Store.Models;
|
||||
using Ombi.Store.Repository;
|
||||
using Quartz;
|
||||
|
||||
namespace Ombi.Services.Jobs
|
||||
{
|
||||
public class StoreCleanup : IJob, IStoreCleanup
|
||||
{
|
||||
private static readonly Logger Log = LogManager.GetCurrentClassLogger();
|
||||
|
||||
public StoreCleanup(IRepository<LogEntity> repo, IJobRecord rec)
|
||||
{
|
||||
Repo = repo;
|
||||
JobRecord = rec;
|
||||
}
|
||||
|
||||
private IJobRecord JobRecord { get; }
|
||||
|
||||
private IRepository<LogEntity> Repo { get; }
|
||||
|
||||
private const int ItemsToDelete = 1000;
|
||||
|
||||
private void Cleanup()
|
||||
{
|
||||
try
|
||||
{
|
||||
var items = Repo.GetAll();
|
||||
var ordered = items.OrderByDescending(x => x.Date).ToList();
|
||||
var itemsToDelete = new List<LogEntity>();
|
||||
if (ordered.Count > ItemsToDelete)
|
||||
{
|
||||
itemsToDelete = ordered.Skip(ItemsToDelete).ToList();
|
||||
}
|
||||
|
||||
foreach (var o in itemsToDelete)
|
||||
{
|
||||
Repo.Delete(o);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
JobRecord.Record(JobNames.StoreCleanup);
|
||||
JobRecord.SetRunning(false, JobNames.CpCacher);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
JobRecord.SetRunning(true, JobNames.CpCacher);
|
||||
Cleanup();
|
||||
}
|
||||
public void Execute(IJobExecutionContext context)
|
||||
{
|
||||
JobRecord.SetRunning(true, JobNames.CpCacher);
|
||||
Cleanup();
|
||||
}
|
||||
}
|
||||
}
|
58
Old/Ombi.Services/Jobs/Templates/MassEmailTemplate.cs
Normal file
58
Old/Ombi.Services/Jobs/Templates/MassEmailTemplate.cs
Normal file
|
@ -0,0 +1,58 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2016 Jamie Rees
|
||||
// File: RecentlyAddedTemplate.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
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
using NLog;
|
||||
|
||||
namespace Ombi.Services.Jobs.Templates
|
||||
{
|
||||
public class MassEmailTemplate
|
||||
{
|
||||
public string TemplateLocation => Path.Combine(Path.GetDirectoryName(Application.ExecutablePath) ?? string.Empty, "Jobs", "Templates", "MassEmailTemplate.html");
|
||||
private static readonly Logger Log = LogManager.GetCurrentClassLogger();
|
||||
|
||||
private const string RecentlyAddedKey = "{@MASSEMAIL}";
|
||||
|
||||
public string LoadTemplate(string html)
|
||||
{
|
||||
try
|
||||
{
|
||||
var sb = new StringBuilder(File.ReadAllText(TemplateLocation));
|
||||
sb.Replace(RecentlyAddedKey, html);
|
||||
return sb.ToString();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
181
Old/Ombi.Services/Jobs/Templates/MassEmailTemplate.html
Normal file
181
Old/Ombi.Services/Jobs/Templates/MassEmailTemplate.html
Normal file
|
@ -0,0 +1,181 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<title>Ombi</title>
|
||||
<style media="all" type="text/css">
|
||||
@media all {
|
||||
.btn-primary table td:hover {
|
||||
background-color: #34495e !important;
|
||||
}
|
||||
|
||||
.btn-primary a:hover {
|
||||
background-color: #34495e !important;
|
||||
border-color: #34495e !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media all {
|
||||
.btn-secondary a:hover {
|
||||
border-color: #34495e !important;
|
||||
color: #34495e !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 620px) {
|
||||
table[class=body] h1 {
|
||||
font-size: 28px !important;
|
||||
margin-bottom: 10px !important;
|
||||
}
|
||||
|
||||
table[class=body] h2 {
|
||||
font-size: 22px !important;
|
||||
margin-bottom: 10px !important;
|
||||
}
|
||||
|
||||
table[class=body] h3 {
|
||||
font-size: 16px !important;
|
||||
margin-bottom: 10px !important;
|
||||
}
|
||||
|
||||
table[class=body] p,
|
||||
table[class=body] ul,
|
||||
table[class=body] ol,
|
||||
table[class=body] td,
|
||||
table[class=body] span,
|
||||
table[class=body] a {
|
||||
font-size: 16px !important;
|
||||
}
|
||||
|
||||
table[class=body] .wrapper,
|
||||
table[class=body] .article {
|
||||
padding: 10px !important;
|
||||
}
|
||||
|
||||
table[class=body] .content {
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
table[class=body] .container {
|
||||
padding: 0 !important;
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
table[class=body] .header {
|
||||
margin-bottom: 10px !important;
|
||||
}
|
||||
|
||||
table[class=body] .main {
|
||||
border-left-width: 0 !important;
|
||||
border-radius: 0 !important;
|
||||
border-right-width: 0 !important;
|
||||
}
|
||||
|
||||
table[class=body] .btn table {
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
table[class=body] .btn a {
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
table[class=body] .img-responsive {
|
||||
height: auto !important;
|
||||
max-width: 100% !important;
|
||||
width: auto !important;
|
||||
}
|
||||
|
||||
table[class=body] .alert td {
|
||||
border-radius: 0 !important;
|
||||
padding: 10px !important;
|
||||
}
|
||||
|
||||
table[class=body] .span-2,
|
||||
table[class=body] .span-3 {
|
||||
max-width: none !important;
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
table[class=body] .receipt {
|
||||
width: 100% !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media all {
|
||||
.ExternalClass {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.ExternalClass,
|
||||
.ExternalClass p,
|
||||
.ExternalClass span,
|
||||
.ExternalClass font,
|
||||
.ExternalClass td,
|
||||
.ExternalClass div {
|
||||
line-height: 100%;
|
||||
}
|
||||
|
||||
.apple-link a {
|
||||
color: inherit !important;
|
||||
font-family: inherit !important;
|
||||
font-size: inherit !important;
|
||||
font-weight: inherit !important;
|
||||
line-height: inherit !important;
|
||||
text-decoration: none !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="" style="font-family: sans-serif; -webkit-font-smoothing: antialiased; font-size: 14px; line-height: 1.4; -ms-text-size-adjust: 100%; -webkit-text-size-adjust: 100%; background-color: #f6f6f6; margin: 0; padding: 0;">
|
||||
<table border="0" cellpadding="0" cellspacing="0" class="body" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; background-color: #f6f6f6;" width="100%" bgcolor="#f6f6f6">
|
||||
<tr>
|
||||
<td style="font-family: sans-serif; font-size: 14px; vertical-align: top;" valign="top"> </td>
|
||||
<td class="container" style="font-family: sans-serif; font-size: 14px; vertical-align: top; display: block; Margin: 0 auto !important; max-width: 580px; padding: 10px; width: 580px;" width="580" valign="top">
|
||||
<div class="content" style="box-sizing: border-box; display: block; Margin: 0 auto; max-width: 580px; padding: 10px;">
|
||||
|
||||
<!-- START CENTERED WHITE CONTAINER -->
|
||||
<span class="preheader" style="color: transparent; display: none; height: 0; max-height: 0; max-width: 0; opacity: 0; overflow: hidden; mso-hide: all; visibility: hidden; width: 0;">Ombi Recently Added</span>
|
||||
<table class="main" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; background: #fff; border-radius: 3px;" width="100%">
|
||||
|
||||
<!-- START MAIN CONTENT AREA -->
|
||||
<tr>
|
||||
<td class="wrapper" style="font-family: sans-serif; font-size: 14px; vertical-align: top; box-sizing: border-box; padding: 20px;" valign="top">
|
||||
<table border="0" cellpadding="0" cellspacing="0" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%;" width="100%">
|
||||
<tr>
|
||||
<td align="center">
|
||||
<img src="http://i.imgur.com/qQsN78U.png" width="400px" text-align="center" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left">
|
||||
{@MASSEMAIL}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- END MAIN CONTENT AREA -->
|
||||
</table>
|
||||
|
||||
<!-- START FOOTER -->
|
||||
<div class="footer" style="clear: both; padding-top: 10px; text-align: center; width: 100%;">
|
||||
<table border="0" cellpadding="0" cellspacing="0" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%;" width="100%">
|
||||
<tr>
|
||||
<td class="content-block powered-by" style="font-family: sans-serif; vertical-align: top; padding-top: 10px; padding-bottom: 10px; font-size: 12px; color: #999999; text-align: center;" valign="top" align="center">
|
||||
Powered by <a href="https://github.com/tidusjar/Ombi" style="color: #999999; font-size: 12px; text-align: center; text-decoration: underline;">Ombi</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- END FOOTER -->
|
||||
<!-- END CENTERED WHITE CONTAINER -->
|
||||
</div>
|
||||
</td>
|
||||
<td style="font-family: sans-serif; font-size: 14px; vertical-align: top;" valign="top"> </td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
58
Old/Ombi.Services/Jobs/Templates/RecentlyAddedTemplate.cs
Normal file
58
Old/Ombi.Services/Jobs/Templates/RecentlyAddedTemplate.cs
Normal file
|
@ -0,0 +1,58 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2016 Jamie Rees
|
||||
// File: RecentlyAddedTemplate.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
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
using NLog;
|
||||
|
||||
namespace Ombi.Services.Jobs.Templates
|
||||
{
|
||||
public class RecentlyAddedTemplate
|
||||
{
|
||||
public string TemplateLocation => Path.Combine(Path.GetDirectoryName(Application.ExecutablePath) ?? string.Empty, "Jobs", "Templates", "RecentlyAddedTemplate.html");
|
||||
private static readonly Logger Log = LogManager.GetCurrentClassLogger();
|
||||
|
||||
private const string RecentlyAddedKey = "{@RECENTLYADDED}";
|
||||
|
||||
public string LoadTemplate(string html)
|
||||
{
|
||||
try
|
||||
{
|
||||
var sb = new StringBuilder(File.ReadAllText(TemplateLocation));
|
||||
sb.Replace(RecentlyAddedKey, html);
|
||||
return sb.ToString();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
187
Old/Ombi.Services/Jobs/Templates/RecentlyAddedTemplate.html
Normal file
187
Old/Ombi.Services/Jobs/Templates/RecentlyAddedTemplate.html
Normal file
|
@ -0,0 +1,187 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<title>Ombi</title>
|
||||
<style media="all" type="text/css">
|
||||
@media all {
|
||||
.btn-primary table td:hover {
|
||||
background-color: #34495e !important;
|
||||
}
|
||||
|
||||
.btn-primary a:hover {
|
||||
background-color: #34495e !important;
|
||||
border-color: #34495e !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media all {
|
||||
.btn-secondary a:hover {
|
||||
border-color: #34495e !important;
|
||||
color: #34495e !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 620px) {
|
||||
table[class=body] h1 {
|
||||
font-size: 28px !important;
|
||||
margin-bottom: 10px !important;
|
||||
}
|
||||
|
||||
table[class=body] h2 {
|
||||
font-size: 22px !important;
|
||||
margin-bottom: 10px !important;
|
||||
}
|
||||
|
||||
table[class=body] h3 {
|
||||
font-size: 16px !important;
|
||||
margin-bottom: 10px !important;
|
||||
}
|
||||
|
||||
table[class=body] p,
|
||||
table[class=body] ul,
|
||||
table[class=body] ol,
|
||||
table[class=body] td,
|
||||
table[class=body] span,
|
||||
table[class=body] a {
|
||||
font-size: 16px !important;
|
||||
}
|
||||
|
||||
table[class=body] .wrapper,
|
||||
table[class=body] .article {
|
||||
padding: 10px !important;
|
||||
}
|
||||
|
||||
table[class=body] .content {
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
table[class=body] .container {
|
||||
padding: 0 !important;
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
table[class=body] .header {
|
||||
margin-bottom: 10px !important;
|
||||
}
|
||||
|
||||
table[class=body] .main {
|
||||
border-left-width: 0 !important;
|
||||
border-radius: 0 !important;
|
||||
border-right-width: 0 !important;
|
||||
}
|
||||
|
||||
table[class=body] .btn table {
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
table[class=body] .btn a {
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
table[class=body] .img-responsive {
|
||||
height: auto !important;
|
||||
max-width: 100% !important;
|
||||
width: auto !important;
|
||||
}
|
||||
|
||||
table[class=body] .alert td {
|
||||
border-radius: 0 !important;
|
||||
padding: 10px !important;
|
||||
}
|
||||
|
||||
table[class=body] .span-2,
|
||||
table[class=body] .span-3 {
|
||||
max-width: none !important;
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
table[class=body] .receipt {
|
||||
width: 100% !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media all {
|
||||
.ExternalClass {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.ExternalClass,
|
||||
.ExternalClass p,
|
||||
.ExternalClass span,
|
||||
.ExternalClass font,
|
||||
.ExternalClass td,
|
||||
.ExternalClass div {
|
||||
line-height: 100%;
|
||||
}
|
||||
|
||||
.apple-link a {
|
||||
color: inherit !important;
|
||||
font-family: inherit !important;
|
||||
font-size: inherit !important;
|
||||
font-weight: inherit !important;
|
||||
line-height: inherit !important;
|
||||
text-decoration: none !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="" style="font-family: sans-serif; -webkit-font-smoothing: antialiased; font-size: 14px; line-height: 1.4; -ms-text-size-adjust: 100%; -webkit-text-size-adjust: 100%; background-color: #f6f6f6; margin: 0; padding: 0;">
|
||||
<table border="0" cellpadding="0" cellspacing="0" class="body" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; background-color: #f6f6f6;" width="100%" bgcolor="#f6f6f6">
|
||||
<tr>
|
||||
<td style="font-family: sans-serif; font-size: 14px; vertical-align: top;" valign="top"> </td>
|
||||
<td class="container" style="font-family: sans-serif; font-size: 14px; vertical-align: top; display: block; Margin: 0 auto !important; max-width: 580px; padding: 10px; width: 580px;" width="580" valign="top">
|
||||
<div class="content" style="box-sizing: border-box; display: block; Margin: 0 auto; max-width: 580px; padding: 10px;">
|
||||
|
||||
<!-- START CENTERED WHITE CONTAINER -->
|
||||
<span class="preheader" style="color: transparent; display: none; height: 0; max-height: 0; max-width: 0; opacity: 0; overflow: hidden; mso-hide: all; visibility: hidden; width: 0;">Ombi Recently Added</span>
|
||||
<table class="main" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; background: #fff; border-radius: 3px;" width="100%">
|
||||
|
||||
<!-- START MAIN CONTENT AREA -->
|
||||
<tr>
|
||||
<td class="wrapper" style="font-family: sans-serif; font-size: 14px; vertical-align: top; box-sizing: border-box; padding: 20px;" valign="top">
|
||||
<table border="0" cellpadding="0" cellspacing="0" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%;" width="100%">
|
||||
<tr>
|
||||
<td align="center">
|
||||
<img src="http://i.imgur.com/qQsN78U.png" width="400px" text-align="center" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="font-family: sans-serif; font-size: 14px; vertical-align: top;" valign="top">
|
||||
<br />
|
||||
<br />
|
||||
<p style="font-family: sans-serif; font-size: 20px; font-weight: normal; margin: 0; Margin-bottom: 15px;">Here is a list of Movies and TV Shows that have recently been added!</p>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
{@RECENTLYADDED}
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- END MAIN CONTENT AREA -->
|
||||
</table>
|
||||
|
||||
<!-- START FOOTER -->
|
||||
<div class="footer" style="clear: both; padding-top: 10px; text-align: center; width: 100%;">
|
||||
<table border="0" cellpadding="0" cellspacing="0" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%;" width="100%">
|
||||
<tr>
|
||||
<td class="content-block powered-by" style="font-family: sans-serif; vertical-align: top; padding-top: 10px; padding-bottom: 10px; font-size: 12px; color: #999999; text-align: center;" valign="top" align="center">
|
||||
Powered by <a href="https://github.com/tidusjar/Ombi" style="color: #999999; font-size: 12px; text-align: center; text-decoration: underline;">Ombi</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- END FOOTER -->
|
||||
<!-- END CENTERED WHITE CONTAINER -->
|
||||
</div>
|
||||
</td>
|
||||
<td style="font-family: sans-serif; font-size: 14px; vertical-align: top;" valign="top"> </td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
146
Old/Ombi.Services/Jobs/UserRequestLimitResetter.cs
Normal file
146
Old/Ombi.Services/Jobs/UserRequestLimitResetter.cs
Normal file
|
@ -0,0 +1,146 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2016 Jamie Rees
|
||||
// File: UserRequestLimitResetter.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
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using Ombi.Core;
|
||||
using Ombi.Core.SettingModels;
|
||||
using Ombi.Services.Interfaces;
|
||||
using Ombi.Store;
|
||||
using Ombi.Store.Models;
|
||||
using Ombi.Store.Repository;
|
||||
using Quartz;
|
||||
|
||||
namespace Ombi.Services.Jobs
|
||||
{
|
||||
public class UserRequestLimitResetter : IJob, IUserRequestLimitResetter
|
||||
{
|
||||
private static readonly Logger Log = LogManager.GetCurrentClassLogger();
|
||||
|
||||
public UserRequestLimitResetter(IJobRecord record, IRepository<RequestLimit> repo, ISettingsService<PlexRequestSettings> settings)
|
||||
{
|
||||
Record = record;
|
||||
Repo = repo;
|
||||
Settings = settings;
|
||||
}
|
||||
|
||||
private IJobRecord Record { get; }
|
||||
private IRepository<RequestLimit> Repo { get; }
|
||||
private ISettingsService<PlexRequestSettings> Settings { get; }
|
||||
|
||||
public void AlbumLimit(PlexRequestSettings s, IEnumerable<RequestLimit> allUsers)
|
||||
{
|
||||
if (s.AlbumWeeklyRequestLimit == 0)
|
||||
{
|
||||
return; // The limit has not been set
|
||||
}
|
||||
CheckAndDelete(allUsers, RequestType.Album);
|
||||
}
|
||||
|
||||
public void MovieLimit(PlexRequestSettings s, IEnumerable<RequestLimit> allUsers)
|
||||
{
|
||||
if (s.MovieWeeklyRequestLimit == 0)
|
||||
{
|
||||
return; // The limit has not been set
|
||||
}
|
||||
CheckAndDelete(allUsers, RequestType.Movie);
|
||||
}
|
||||
|
||||
public void TvLimit(PlexRequestSettings s, IEnumerable<RequestLimit> allUsers)
|
||||
{
|
||||
if (s.TvWeeklyRequestLimit == 0)
|
||||
{
|
||||
return; // The limit has not been set
|
||||
}
|
||||
CheckAndDelete(allUsers, RequestType.TvShow);
|
||||
}
|
||||
|
||||
private void CheckAndDelete(IEnumerable<RequestLimit> allUsers, RequestType type)
|
||||
{
|
||||
var users = allUsers.Where(x => x.RequestType == type);
|
||||
foreach (var u in users)
|
||||
{
|
||||
var daysDiff = (u.FirstRequestDate - DateTime.UtcNow.AddDays(-7)).TotalDays;
|
||||
if (daysDiff <= 0)
|
||||
{
|
||||
Repo.Delete(u);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void Start()
|
||||
{
|
||||
Record.SetRunning(true, JobNames.CpCacher);
|
||||
try
|
||||
{
|
||||
var settings = Settings.GetSettings();
|
||||
var users = Repo.GetAll();
|
||||
var requestLimits = users as RequestLimit[] ?? users.ToArray();
|
||||
|
||||
MovieLimit(settings, requestLimits);
|
||||
TvLimit(settings, requestLimits);
|
||||
AlbumLimit(settings, requestLimits);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Record.Record(JobNames.RequestLimitReset);
|
||||
Record.SetRunning(false, JobNames.CpCacher);
|
||||
}
|
||||
}
|
||||
|
||||
public void Execute(IJobExecutionContext context)
|
||||
{
|
||||
Record.SetRunning(true, JobNames.CpCacher);
|
||||
try
|
||||
{
|
||||
var settings = Settings.GetSettings();
|
||||
var users = Repo.GetAll();
|
||||
var requestLimits = users as RequestLimit[] ?? users.ToArray();
|
||||
|
||||
MovieLimit(settings, requestLimits);
|
||||
TvLimit(settings, requestLimits);
|
||||
AlbumLimit(settings, requestLimits);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Record.Record(JobNames.RequestLimitReset);
|
||||
Record.SetRunning(false, JobNames.CpCacher);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
132
Old/Ombi.Services/Jobs/WatcherCacher.cs
Normal file
132
Old/Ombi.Services/Jobs/WatcherCacher.cs
Normal file
|
@ -0,0 +1,132 @@
|
|||
#region Copyright
|
||||
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2016 Jamie Rees
|
||||
// File: PlexAvailabilityChecker.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
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using Ombi.Api.Interfaces;
|
||||
using Ombi.Api.Models.Movie;
|
||||
using Ombi.Core;
|
||||
using Ombi.Core.SettingModels;
|
||||
using Ombi.Helpers;
|
||||
using Ombi.Services.Interfaces;
|
||||
using Quartz;
|
||||
|
||||
namespace Ombi.Services.Jobs
|
||||
{
|
||||
public class WatcherCacher : IJob, IWatcherCacher
|
||||
{
|
||||
public WatcherCacher(
|
||||
ISettingsService<WatcherSettings> watcher,
|
||||
IWatcherApi watcherApi, ICacheProvider cache, IJobRecord rec)
|
||||
{
|
||||
WatcherSettings = watcher;
|
||||
WatcherApi = watcherApi;
|
||||
Cache = cache;
|
||||
Job = rec;
|
||||
}
|
||||
|
||||
private ISettingsService<WatcherSettings> WatcherSettings { get; }
|
||||
private ICacheProvider Cache { get; }
|
||||
private IWatcherApi WatcherApi { get; }
|
||||
private IJobRecord Job { get; }
|
||||
|
||||
private static Logger Log = LogManager.GetCurrentClassLogger();
|
||||
|
||||
public void Queued()
|
||||
{
|
||||
Log.Trace("Getting the settings");
|
||||
|
||||
var watcherSettings = WatcherSettings.GetSettings();
|
||||
|
||||
Job.SetRunning(true, JobNames.WatcherCacher);
|
||||
try
|
||||
{
|
||||
if (watcherSettings.Enabled)
|
||||
{
|
||||
var movies = WatcherApi.ListMovies(watcherSettings.ApiKey, watcherSettings.FullUri);
|
||||
if (movies.Error)
|
||||
{
|
||||
Log.Error("Error when trying to get Watchers movies");
|
||||
Log.Error(movies.ErrorMessage);
|
||||
}
|
||||
var wantedMovies =
|
||||
movies?.Movies?.Where(x => x.status.Equals("Wanted", StringComparison.CurrentCultureIgnoreCase));
|
||||
if (wantedMovies != null && wantedMovies.Any())
|
||||
{
|
||||
Cache.Set(CacheKeys.WatcherQueued, movies.Movies.Select(x => x.imdbid).ToArray(), CacheKeys.TimeFrameMinutes.SchedulerCaching);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Job.Record(JobNames.WatcherCacher);
|
||||
Job.SetRunning(false, JobNames.WatcherCacher);
|
||||
}
|
||||
}
|
||||
|
||||
// we do not want to set here...
|
||||
public string[] QueuedIds()
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
var watcherSettings = WatcherSettings.GetSettings();
|
||||
|
||||
if (watcherSettings.Enabled)
|
||||
{
|
||||
var movies = Cache.Get<string[]>(CacheKeys.WatcherQueued);
|
||||
|
||||
if (movies != null)
|
||||
{
|
||||
return movies;
|
||||
}
|
||||
return new string[] {};
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
return new string[] { };
|
||||
}
|
||||
return new string[] {};
|
||||
}
|
||||
|
||||
public void Execute(IJobExecutionContext context)
|
||||
{
|
||||
Queued();
|
||||
}
|
||||
}
|
||||
}
|
12
Old/Ombi.Services/Models/PlexAlbum.cs
Normal file
12
Old/Ombi.Services/Models/PlexAlbum.cs
Normal file
|
@ -0,0 +1,12 @@
|
|||
namespace Ombi.Services.Models
|
||||
{
|
||||
public class PlexAlbum
|
||||
{
|
||||
public string Title { get; set; }
|
||||
public string Artist { get; set; }
|
||||
public string ReleaseYear { get; set; }
|
||||
public string Url { get; set; }
|
||||
public string ProviderId { get; set; }
|
||||
public string Id { get; set; }
|
||||
}
|
||||
}
|
41
Old/Ombi.Services/Models/PlexEpisodeModel.cs
Normal file
41
Old/Ombi.Services/Models/PlexEpisodeModel.cs
Normal file
|
@ -0,0 +1,41 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2016 Jamie Rees
|
||||
// File: PlexEpisodeModel.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
|
||||
|
||||
using Ombi.Helpers;
|
||||
|
||||
namespace Ombi.Services.Models
|
||||
{
|
||||
public class PlexEpisodeModel
|
||||
{
|
||||
public EpisodeModelHelper Episodes => PlexHelper.GetSeasonsAndEpisodesFromPlexGuid(Guid);
|
||||
public string Guid { get; set; }
|
||||
public string RatingKey { get; set; }
|
||||
public string EpisodeTitle { get; set; }
|
||||
public string ShowTitle { get; set; }
|
||||
|
||||
}
|
||||
}
|
12
Old/Ombi.Services/Models/PlexMovie.cs
Normal file
12
Old/Ombi.Services/Models/PlexMovie.cs
Normal file
|
@ -0,0 +1,12 @@
|
|||
namespace Ombi.Services.Models
|
||||
{
|
||||
public class PlexMovie
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public string Title { get; set; }
|
||||
public string ReleaseYear { get; set; }
|
||||
public string ProviderId { get; set; }
|
||||
public string Url { get; set; }
|
||||
public string ItemId { get; set; }
|
||||
}
|
||||
}
|
13
Old/Ombi.Services/Models/PlexTvShow.cs
Normal file
13
Old/Ombi.Services/Models/PlexTvShow.cs
Normal file
|
@ -0,0 +1,13 @@
|
|||
namespace Ombi.Services.Models
|
||||
{
|
||||
public class PlexTvShow
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public string Title { get; set; }
|
||||
public string ReleaseYear { get; set; }
|
||||
public string ProviderId { get; set; }
|
||||
public int[] Seasons { get; set; }
|
||||
public string Url { get; set; }
|
||||
public string ItemId { get; set; }
|
||||
}
|
||||
}
|
47
Old/Ombi.Services/Models/SonarrCachedResult.cs
Normal file
47
Old/Ombi.Services/Models/SonarrCachedResult.cs
Normal file
|
@ -0,0 +1,47 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2016 Jamie Rees
|
||||
// File: SonarrCachedResult.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
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ombi.Services.Models
|
||||
{
|
||||
public class SonarrCachedResult
|
||||
{
|
||||
public SonarrCachedResult()
|
||||
{
|
||||
Seasons = new List<SonarrSeasons>( );
|
||||
}
|
||||
public List<SonarrSeasons> Seasons { get; set; }
|
||||
public int TvdbId { get; set; }
|
||||
}
|
||||
|
||||
public class SonarrSeasons
|
||||
{
|
||||
public int SeasonNumber { get; set; }
|
||||
public bool Monitored { get; set; }
|
||||
}
|
||||
}
|
123
Old/Ombi.Services/Notification/BaseNotification.cs
Normal file
123
Old/Ombi.Services/Notification/BaseNotification.cs
Normal file
|
@ -0,0 +1,123 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2017 Jamie Rees
|
||||
// File: BaseNotification.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
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using NLog;
|
||||
using Ombi.Core;
|
||||
using Ombi.Core.Models;
|
||||
using Ombi.Core.SettingModels;
|
||||
using Ombi.Services.Interfaces;
|
||||
|
||||
namespace Ombi.Services.Notification
|
||||
{
|
||||
public abstract class BaseNotification<T> : INotification where T : Settings, new()
|
||||
{
|
||||
protected BaseNotification(ISettingsService<T> settings)
|
||||
{
|
||||
Settings = settings;
|
||||
}
|
||||
|
||||
private static readonly Logger Log = LogManager.GetCurrentClassLogger();
|
||||
protected ISettingsService<T> Settings { get; }
|
||||
public abstract string NotificationName { get; }
|
||||
|
||||
public async Task NotifyAsync(NotificationModel model)
|
||||
{
|
||||
var configuration = GetConfiguration();
|
||||
await NotifyAsync(model, configuration);
|
||||
}
|
||||
|
||||
public async Task NotifyAsync(NotificationModel model, Settings settings)
|
||||
{
|
||||
if (settings == null) await NotifyAsync(model);
|
||||
|
||||
var notificationSettings = (T)settings;
|
||||
|
||||
if (!ValidateConfiguration(notificationSettings))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
switch (model.NotificationType)
|
||||
{
|
||||
case NotificationType.NewRequest:
|
||||
await NewRequest(model, notificationSettings);
|
||||
break;
|
||||
case NotificationType.Issue:
|
||||
await Issue(model, notificationSettings);
|
||||
break;
|
||||
case NotificationType.RequestAvailable:
|
||||
await AvailableRequest(model, notificationSettings);
|
||||
break;
|
||||
case NotificationType.RequestApproved:
|
||||
await RequestApproved(model, notificationSettings);
|
||||
break;
|
||||
case NotificationType.AdminNote:
|
||||
throw new NotImplementedException();
|
||||
|
||||
case NotificationType.Test:
|
||||
await Test(model, notificationSettings);
|
||||
break;
|
||||
case NotificationType.RequestDeclined:
|
||||
await RequestDeclined(model, notificationSettings);
|
||||
break;
|
||||
case NotificationType.ItemAddedToFaultQueue:
|
||||
await AddedToRequestQueue(model, notificationSettings);
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
catch (NotImplementedException)
|
||||
{
|
||||
// Do nothing, it's not implimented meaning it might not be ready or even used
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private T GetConfiguration()
|
||||
{
|
||||
var settings = Settings.GetSettings();
|
||||
return settings;
|
||||
}
|
||||
|
||||
|
||||
protected abstract bool ValidateConfiguration(T settings);
|
||||
protected abstract Task NewRequest(NotificationModel model, T settings);
|
||||
protected abstract Task Issue(NotificationModel model, T settings);
|
||||
protected abstract Task AddedToRequestQueue(NotificationModel model, T settings);
|
||||
protected abstract Task RequestDeclined(NotificationModel model, T settings);
|
||||
protected abstract Task RequestApproved(NotificationModel model, T settings);
|
||||
protected abstract Task AvailableRequest(NotificationModel model, T settings);
|
||||
protected abstract Task Send(NotificationMessage model, T settings);
|
||||
protected abstract Task Test(NotificationModel model, T settings);
|
||||
|
||||
}
|
||||
}
|
144
Old/Ombi.Services/Notification/DiscordNotification.cs
Normal file
144
Old/Ombi.Services/Notification/DiscordNotification.cs
Normal file
|
@ -0,0 +1,144 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2016 Jamie Rees
|
||||
// File: SlackNotification.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
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using NLog;
|
||||
using Ombi.Api.Interfaces;
|
||||
using Ombi.Core;
|
||||
using Ombi.Core.SettingModels;
|
||||
|
||||
namespace Ombi.Services.Notification
|
||||
{
|
||||
public class DiscordNotification : BaseNotification<DiscordNotificationSettings>
|
||||
{
|
||||
public DiscordNotification(IDiscordApi api, ISettingsService<DiscordNotificationSettings> sn) : base(sn)
|
||||
{
|
||||
Api = api;
|
||||
}
|
||||
|
||||
public override string NotificationName => "DiscordNotification";
|
||||
|
||||
private IDiscordApi Api { get; }
|
||||
private static readonly Logger Log = LogManager.GetCurrentClassLogger();
|
||||
|
||||
protected override bool ValidateConfiguration(DiscordNotificationSettings settings)
|
||||
{
|
||||
if (!settings.Enabled)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (string.IsNullOrEmpty(settings.WebhookUrl))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
try
|
||||
{
|
||||
var a = settings.Token;
|
||||
var b = settings.WebookId;
|
||||
}
|
||||
catch (IndexOutOfRangeException)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override async Task NewRequest(NotificationModel model, DiscordNotificationSettings settings)
|
||||
{
|
||||
var message = $"{model.Title} has been requested by user: {model.User}";
|
||||
|
||||
var notification = new NotificationMessage
|
||||
{
|
||||
Message = message,
|
||||
};
|
||||
await Send(notification, settings);
|
||||
}
|
||||
|
||||
protected override async Task Issue(NotificationModel model, DiscordNotificationSettings settings)
|
||||
{
|
||||
var message = $"A new issue: {model.Body} has been reported by user: {model.User} for the title: {model.Title}";
|
||||
var notification = new NotificationMessage
|
||||
{
|
||||
Message = message,
|
||||
};
|
||||
await Send(notification, settings);
|
||||
}
|
||||
|
||||
protected override async Task AddedToRequestQueue(NotificationModel model, DiscordNotificationSettings settings)
|
||||
{
|
||||
var message = $"Hello! The user '{model.User}' has requested {model.Title} but it could not be added. This has been added into the requests queue and will keep retrying";
|
||||
var notification = new NotificationMessage
|
||||
{
|
||||
Message = message,
|
||||
};
|
||||
await Send(notification, settings);
|
||||
}
|
||||
|
||||
protected override async Task RequestDeclined(NotificationModel model, DiscordNotificationSettings settings)
|
||||
{
|
||||
var message = $"Hello! Your request for {model.Title} has been declined, Sorry!";
|
||||
var notification = new NotificationMessage
|
||||
{
|
||||
Message = message,
|
||||
};
|
||||
await Send(notification, settings);
|
||||
}
|
||||
|
||||
protected override Task RequestApproved(NotificationModel model, DiscordNotificationSettings settings)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
protected override Task AvailableRequest(NotificationModel model, DiscordNotificationSettings settings)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
protected override async Task Send(NotificationMessage model, DiscordNotificationSettings settings)
|
||||
{
|
||||
try
|
||||
{
|
||||
await Api.SendMessageAsync(model.Message, settings.WebookId, settings.Token, settings.Username);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
protected override async Task Test(NotificationModel model, DiscordNotificationSettings settings)
|
||||
{
|
||||
var message = $"This is a test from Ombi, if you can see this then we have successfully pushed a notification!";
|
||||
var notification = new NotificationMessage
|
||||
{
|
||||
Message = message,
|
||||
};
|
||||
await Send(notification, settings);
|
||||
}
|
||||
}
|
||||
}
|
253
Old/Ombi.Services/Notification/EmailMessageNotification.cs
Normal file
253
Old/Ombi.Services/Notification/EmailMessageNotification.cs
Normal file
|
@ -0,0 +1,253 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2016 Jamie Rees
|
||||
// File: EmailMessageNotification.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
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using MimeKit;
|
||||
using NLog;
|
||||
using Ombi.Core;
|
||||
using Ombi.Core.Notification.Templates;
|
||||
using Ombi.Core.SettingModels;
|
||||
using Ombi.Store;
|
||||
using SmtpClient = MailKit.Net.Smtp.SmtpClient;
|
||||
|
||||
namespace Ombi.Services.Notification
|
||||
{
|
||||
public class EmailMessageNotification : BaseNotification<EmailNotificationSettings>
|
||||
{
|
||||
public EmailMessageNotification(ISettingsService<EmailNotificationSettings> settings) : base(settings)
|
||||
{
|
||||
}
|
||||
|
||||
private static readonly Logger Log = LogManager.GetCurrentClassLogger();
|
||||
public override string NotificationName => "EmailMessageNotification";
|
||||
|
||||
protected override bool ValidateConfiguration(EmailNotificationSettings settings)
|
||||
{
|
||||
if (settings.Authentication)
|
||||
{
|
||||
if (string.IsNullOrEmpty(settings.EmailUsername) || string.IsNullOrEmpty(settings.EmailPassword))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (string.IsNullOrEmpty(settings.EmailHost) || string.IsNullOrEmpty(settings.RecipientEmail) || string.IsNullOrEmpty(settings.EmailPort.ToString()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override async Task NewRequest(NotificationModel model, EmailNotificationSettings settings)
|
||||
{
|
||||
var email = new EmailBasicTemplate();
|
||||
var html = email.LoadTemplate(
|
||||
$"Ombi: New {model.RequestType.GetString()?.ToLower()} request for {model.Title}!",
|
||||
$"Hello! The user '{model.User}' has requested the {model.RequestType.GetString()?.ToLower()} '{model.Title}'! Please log in to approve this request. Request Date: {model.DateTime.ToString("f")}",
|
||||
model.ImgSrc);
|
||||
|
||||
|
||||
var message = new NotificationMessage
|
||||
{
|
||||
Message = html,
|
||||
Subject = $"Ombi: New {model.RequestType.GetString()?.ToLower()} request for {model.Title}!",
|
||||
To = settings.RecipientEmail,
|
||||
};
|
||||
|
||||
message.Other.Add("PlainTextBody", $"Hello! The user '{model.User}' has requested the {model.RequestType.GetString()?.ToLower()} '{model.Title}'! Please log in to approve this request. Request Date: {model.DateTime.ToString("f")}");
|
||||
|
||||
await Send(message, settings);
|
||||
}
|
||||
|
||||
protected override async Task Issue(NotificationModel model, EmailNotificationSettings settings)
|
||||
{
|
||||
var email = new EmailBasicTemplate();
|
||||
var html = email.LoadTemplate(
|
||||
$"Ombi: New issue for {model.Title}!",
|
||||
$"Hello! The user '{model.User}' has reported a new issue {model.Body} for the title {model.Title}!",
|
||||
model.ImgSrc);
|
||||
|
||||
var message = new NotificationMessage
|
||||
{
|
||||
Message = html,
|
||||
Subject = $"Ombi: New issue for {model.Title}!",
|
||||
To = settings.RecipientEmail,
|
||||
};
|
||||
|
||||
message.Other.Add("PlainTextBody", $"Hello! The user '{model.User}' has reported a new issue {model.Body} for the title {model.Title}!");
|
||||
|
||||
|
||||
|
||||
await Send(message, settings);
|
||||
}
|
||||
|
||||
protected override async Task AddedToRequestQueue(NotificationModel model, EmailNotificationSettings settings)
|
||||
{
|
||||
var email = new EmailBasicTemplate();
|
||||
var html = email.LoadTemplate(
|
||||
"Ombi: A request could not be added.",
|
||||
$"Hello! The user '{model.User}' has requested {model.Title} but it could not be added. This has been added into the requests queue and will keep retrying",
|
||||
model.ImgSrc);
|
||||
|
||||
var message = new NotificationMessage
|
||||
{
|
||||
Message = html,
|
||||
Subject = $"Ombi: A request could not be added",
|
||||
To = settings.RecipientEmail,
|
||||
};
|
||||
|
||||
message.Other.Add("PlainTextBody", $"Hello! The user '{model.User}' has requested {model.Title} but it could not be added. This has been added into the requests queue and will keep retrying");
|
||||
|
||||
|
||||
await Send(message, settings);
|
||||
}
|
||||
|
||||
protected override async Task RequestDeclined(NotificationModel model, EmailNotificationSettings settings)
|
||||
{
|
||||
var email = new EmailBasicTemplate();
|
||||
var html = email.LoadTemplate(
|
||||
"Ombi: Your request has been declined",
|
||||
$"Hello! Your request for {model.Title} has been declined, Sorry!",
|
||||
model.ImgSrc);
|
||||
|
||||
var message = new NotificationMessage
|
||||
{
|
||||
Message = html,
|
||||
Subject = $"Ombi: Your request has been declined",
|
||||
To = model.UserEmail,
|
||||
};
|
||||
|
||||
message.Other.Add("PlainTextBody", $"Hello! Your request for {model.Title} has been declined, Sorry!");
|
||||
|
||||
|
||||
await Send(message, settings);
|
||||
}
|
||||
|
||||
protected override async Task RequestApproved(NotificationModel model, EmailNotificationSettings settings)
|
||||
{
|
||||
var email = new EmailBasicTemplate();
|
||||
var html = email.LoadTemplate(
|
||||
"Ombi: Your request has been approved!",
|
||||
$"Hello! Your request for {model.Title} has been approved!",
|
||||
model.ImgSrc);
|
||||
|
||||
var message = new NotificationMessage
|
||||
{
|
||||
Message = html,
|
||||
Subject = $"Ombi: Your request has been approved!",
|
||||
To = model.UserEmail,
|
||||
};
|
||||
|
||||
message.Other.Add("PlainTextBody", $"Hello! Your request for {model.Title} has been approved!");
|
||||
|
||||
await Send(message, settings);
|
||||
}
|
||||
|
||||
protected override async Task AvailableRequest(NotificationModel model, EmailNotificationSettings settings)
|
||||
{
|
||||
var email = new EmailBasicTemplate();
|
||||
var html = email.LoadTemplate(
|
||||
$"Ombi: {model.Title} is now available!",
|
||||
$"Hello! You requested {model.Title} on Ombi! This is now available on Plex! :)",
|
||||
model.ImgSrc);
|
||||
|
||||
|
||||
var message = new NotificationMessage
|
||||
{
|
||||
Message = html,
|
||||
Subject = $"Ombi: {model.Title} is now available!",
|
||||
To = model.UserEmail,
|
||||
};
|
||||
|
||||
message.Other.Add("PlainTextBody", $"Hello! You requested {model.Title} on Ombi! This is now available on Plex! :)");
|
||||
|
||||
await Send(message, settings);
|
||||
}
|
||||
|
||||
protected override async Task Send(NotificationMessage model, EmailNotificationSettings settings)
|
||||
{
|
||||
try
|
||||
{
|
||||
var body = new BodyBuilder
|
||||
{
|
||||
HtmlBody = model.Message,
|
||||
TextBody = model.Other["PlainTextBody"]
|
||||
};
|
||||
|
||||
var message = new MimeMessage
|
||||
{
|
||||
Body = body.ToMessageBody(),
|
||||
Subject = model.Subject
|
||||
};
|
||||
message.From.Add(new MailboxAddress(settings.EmailSender, settings.EmailSender));
|
||||
message.To.Add(new MailboxAddress(model.To, model.To));
|
||||
|
||||
using (var client = new SmtpClient())
|
||||
{
|
||||
client.Connect(settings.EmailHost, settings.EmailPort); // Let MailKit figure out the correct SecureSocketOptions.
|
||||
|
||||
// Note: since we don't have an OAuth2 token, disable
|
||||
// the XOAUTH2 authentication mechanism.
|
||||
client.AuthenticationMechanisms.Remove("XOAUTH2");
|
||||
|
||||
if (settings.Authentication)
|
||||
{
|
||||
client.Authenticate(settings.EmailUsername, settings.EmailPassword);
|
||||
}
|
||||
Log.Info("sending message to {0} \r\n from: {1}\r\n Are we authenticated: {2}", message.To, message.From, client.IsAuthenticated);
|
||||
await client.SendAsync(message);
|
||||
await client.DisconnectAsync(true);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
throw new InvalidOperationException(e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
protected override async Task Test(NotificationModel model, EmailNotificationSettings settings)
|
||||
{
|
||||
var email = new EmailBasicTemplate();
|
||||
var html = email.LoadTemplate(
|
||||
"Test Message",
|
||||
"This is just a test! Success!",
|
||||
model.ImgSrc);
|
||||
var message = new NotificationMessage
|
||||
{
|
||||
Message = html,
|
||||
Subject = $"Ombi: Test",
|
||||
To = settings.RecipientEmail,
|
||||
};
|
||||
|
||||
message.Other.Add("PlainTextBody", "This is just a test! Success!");
|
||||
|
||||
await Send(message, settings);
|
||||
}
|
||||
}
|
||||
}
|
219
Old/Ombi.Services/Notification/EmbyNotificationEngine.cs
Normal file
219
Old/Ombi.Services/Notification/EmbyNotificationEngine.cs
Normal file
|
@ -0,0 +1,219 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using NLog;
|
||||
using Ombi.Api.Interfaces;
|
||||
using Ombi.Core;
|
||||
using Ombi.Core.Models;
|
||||
using Ombi.Core.SettingModels;
|
||||
using Ombi.Core.Users;
|
||||
using Ombi.Helpers.Permissions;
|
||||
using Ombi.Services.Interfaces;
|
||||
using Ombi.Store;
|
||||
using Ombi.Store.Models;
|
||||
using Ombi.Store.Models.Emby;
|
||||
using Ombi.Store.Repository;
|
||||
|
||||
namespace Ombi.Services.Notification
|
||||
{
|
||||
public class EmbyNotificationEngine : IEmbyNotificationEngine
|
||||
{
|
||||
public EmbyNotificationEngine(IEmbyApi p, IRepository<UsersToNotify> repo, ISettingsService<EmbySettings> embySettings, INotificationService service, IUserHelper userHelper, IExternalUserRepository<EmbyUsers> embyUsers)
|
||||
{
|
||||
EmbyApi = p;
|
||||
UserNotifyRepo = repo;
|
||||
Notification = service;
|
||||
UserHelper = userHelper;
|
||||
EmbySettings = embySettings;
|
||||
EmbyUserRepo = embyUsers;
|
||||
}
|
||||
|
||||
private IEmbyApi EmbyApi { get; }
|
||||
private IRepository<UsersToNotify> UserNotifyRepo { get; }
|
||||
private static Logger Log = LogManager.GetCurrentClassLogger();
|
||||
private INotificationService Notification { get; }
|
||||
private IUserHelper UserHelper { get; }
|
||||
private ISettingsService<EmbySettings> EmbySettings { get; }
|
||||
private IExternalUserRepository<EmbyUsers> EmbyUserRepo { get; }
|
||||
|
||||
public async Task NotifyUsers(IEnumerable<RequestedModel> modelChanged, NotificationType type)
|
||||
{
|
||||
try
|
||||
{
|
||||
var embySettings = await EmbySettings.GetSettingsAsync();
|
||||
var embyUsers = EmbyApi.GetUsers(embySettings.FullUri, embySettings.ApiKey);
|
||||
var userAccount = embyUsers.FirstOrDefault(x => x.Policy.IsAdministrator);
|
||||
|
||||
var adminUsername = userAccount?.Name ?? string.Empty;
|
||||
|
||||
var users = UserHelper.GetUsersWithFeature(Features.RequestAddedNotification).ToList();
|
||||
Log.Debug("Notifying Users Count {0}", users.Count);
|
||||
foreach (var model in modelChanged)
|
||||
{
|
||||
var selectedUsers = new List<string>();
|
||||
|
||||
foreach (var u in users)
|
||||
{
|
||||
var requestUser = model.RequestedUsers.FirstOrDefault(
|
||||
x => x.Equals(u.Username, StringComparison.CurrentCultureIgnoreCase) || x.Equals(u.UserAlias, StringComparison.CurrentCultureIgnoreCase));
|
||||
if (string.IsNullOrEmpty(requestUser))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Make sure we do not already have the user
|
||||
if (!selectedUsers.Contains(requestUser))
|
||||
{
|
||||
selectedUsers.Add(requestUser);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var user in selectedUsers)
|
||||
{
|
||||
var localUser =
|
||||
users.FirstOrDefault(x =>
|
||||
x.Username.Equals(user, StringComparison.CurrentCultureIgnoreCase) ||
|
||||
x.UserAlias.Equals(user, StringComparison.CurrentCultureIgnoreCase));
|
||||
Log.Info("Notifying user {0}", user);
|
||||
if (user.Equals(adminUsername, StringComparison.CurrentCultureIgnoreCase))
|
||||
{
|
||||
Log.Info("This user is the Plex server owner");
|
||||
await PublishUserNotification(userAccount?.Name, localUser?.EmailAddress, model.Title, model.PosterPath, type, model.Type);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// So if the request was from an alias, then we need to use the local user (since that contains the alias).
|
||||
// If we do not have a local user, then we should be using the Emby user if that user exists.
|
||||
// This will execute most of the time since Emby and Local users will most always be in the database.
|
||||
if (localUser != null)
|
||||
{
|
||||
if (string.IsNullOrEmpty(localUser?.EmailAddress))
|
||||
{
|
||||
Log.Info("There is no email address for this Local user ({0}), cannot send notification", localUser.Username);
|
||||
continue;
|
||||
}
|
||||
|
||||
Log.Info("Sending notification to: {0} at: {1}, for : {2}", localUser, localUser.EmailAddress, model.Title);
|
||||
await PublishUserNotification(localUser.Username, localUser.EmailAddress, model.Title, model.PosterPath, type, model.Type);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
var embyUser = EmbyUserRepo.GetUserByUsername(user);
|
||||
var email = embyUsers.FirstOrDefault(x => x.Name.Equals(user, StringComparison.CurrentCultureIgnoreCase));
|
||||
if (string.IsNullOrEmpty(embyUser?.EmailAddress)) // TODO this needs to be the email
|
||||
{
|
||||
Log.Info("There is no email address for this Emby user ({0}), cannot send notification", email?.Name);
|
||||
// We do not have a plex user that requested this!
|
||||
continue;
|
||||
}
|
||||
|
||||
Log.Info("Sending notification to: {0} at: {1}, for : {2}", embyUser?.Username, embyUser?.EmailAddress, model.Title);
|
||||
await PublishUserNotification(email?.Name, embyUser?.EmailAddress, model.Title, model.PosterPath, type, model.Type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task NotifyUsers(RequestedModel model, NotificationType type)
|
||||
{
|
||||
try
|
||||
{
|
||||
var embySettings = await EmbySettings.GetSettingsAsync();
|
||||
var embyUsers = EmbyApi.GetUsers(embySettings.FullUri, embySettings.ApiKey);
|
||||
var userAccount = embyUsers.FirstOrDefault(x => x.Policy.IsAdministrator);
|
||||
var localUsers = UserHelper.GetUsers().ToList();
|
||||
|
||||
var adminUsername = userAccount.Name ?? string.Empty;
|
||||
|
||||
var users = UserHelper.GetUsersWithFeature(Features.RequestAddedNotification).ToList();
|
||||
Log.Debug("Notifying Users Count {0}", users.Count);
|
||||
|
||||
// Get the usernames or alias depending if they have an alias
|
||||
var userNamesWithFeature = users.Select(x => x.UsernameOrAlias).ToList();
|
||||
Log.Debug("Users with the feature count {0}", userNamesWithFeature.Count);
|
||||
Log.Debug("Usernames: ");
|
||||
foreach (var u in userNamesWithFeature)
|
||||
{
|
||||
Log.Debug(u);
|
||||
}
|
||||
|
||||
Log.Debug("Users in the requested model count: {0}", model.AllUsers.Count);
|
||||
Log.Debug("usernames from model: ");
|
||||
foreach (var modelAllUser in model.AllUsers)
|
||||
{
|
||||
Log.Debug(modelAllUser);
|
||||
}
|
||||
|
||||
if (model.AllUsers == null || !model.AllUsers.Any())
|
||||
{
|
||||
Log.Debug("There are no users in the model.AllUsers, no users to notify");
|
||||
return;
|
||||
}
|
||||
var usersToNotify = userNamesWithFeature.Intersect(model.AllUsers, StringComparer.CurrentCultureIgnoreCase).ToList();
|
||||
|
||||
if (!usersToNotify.Any())
|
||||
{
|
||||
Log.Debug("Could not find any users after the .Intersect()");
|
||||
}
|
||||
|
||||
Log.Debug("Users being notified for this request count {0}", users.Count);
|
||||
foreach (var user in usersToNotify)
|
||||
{
|
||||
var embyUser = EmbyUserRepo.GetUserByUsername(user);
|
||||
Log.Info("Notifying user {0}", user);
|
||||
if (user.Equals(adminUsername, StringComparison.CurrentCultureIgnoreCase))
|
||||
{
|
||||
Log.Info("This user is the Emby server owner");
|
||||
await PublishUserNotification(userAccount.Name, embyUser.EmailAddress, model.Title, model.PosterPath, type, model.Type);
|
||||
return;
|
||||
}
|
||||
|
||||
var email = embyUsers.FirstOrDefault(x => x.Name.Equals(user, StringComparison.CurrentCultureIgnoreCase));
|
||||
if (email == null)
|
||||
{
|
||||
// Local User?
|
||||
var local = localUsers.FirstOrDefault(x => x.UsernameOrAlias.Equals(user));
|
||||
if (local != null)
|
||||
{
|
||||
|
||||
Log.Info("Sending notification to: {0} at: {1}, for title: {2}", local.UsernameOrAlias, local.EmailAddress, model.Title);
|
||||
await PublishUserNotification(local.UsernameOrAlias, local.EmailAddress, model.Title, model.PosterPath, type, model.Type);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
Log.Info("Sending notification to: {0} at: {1}, for title: {2}", email.Name, embyUser.EmailAddress, model.Title);
|
||||
await PublishUserNotification(email.Name, embyUser.EmailAddress, model.Title, model.PosterPath, type, model.Type);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task PublishUserNotification(string username, string email, string title, string img, NotificationType type, RequestType requestType)
|
||||
{
|
||||
var notificationModel = new NotificationModel
|
||||
{
|
||||
User = username,
|
||||
UserEmail = email,
|
||||
NotificationType = type,
|
||||
Title = title,
|
||||
ImgSrc = requestType == RequestType.Movie ? $"https://image.tmdb.org/t/p/w300/{img}" : img
|
||||
};
|
||||
|
||||
// Send the notification to the user.
|
||||
await Notification.Publish(notificationModel);
|
||||
}
|
||||
}
|
||||
}
|
40
Old/Ombi.Services/Notification/NotificationMessage.cs
Normal file
40
Old/Ombi.Services/Notification/NotificationMessage.cs
Normal file
|
@ -0,0 +1,40 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2017 Jamie Rees
|
||||
// File: NotificationMessage.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
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ombi.Services.Notification
|
||||
{
|
||||
public class NotificationMessage
|
||||
{
|
||||
public string Subject { get; set; }
|
||||
public string Message { get; set; }
|
||||
public string To { get; set; }
|
||||
|
||||
public Dictionary<string,string> Other { get; set; } = new Dictionary<string, string>();
|
||||
}
|
||||
}
|
45
Old/Ombi.Services/Notification/NotificationModel.cs
Normal file
45
Old/Ombi.Services/Notification/NotificationModel.cs
Normal file
|
@ -0,0 +1,45 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2016 Jamie Rees
|
||||
// File: NotificationModel.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
|
||||
|
||||
using System;
|
||||
using Ombi.Core.Models;
|
||||
using Ombi.Store;
|
||||
|
||||
namespace Ombi.Services.Notification
|
||||
{
|
||||
public class NotificationModel
|
||||
{
|
||||
public string Title { get; set; }
|
||||
public string Body { get; set; }
|
||||
public DateTime DateTime { get; set; }
|
||||
public NotificationType NotificationType { get; set; }
|
||||
public string User { get; set; }
|
||||
public string UserEmail { get; set; }
|
||||
public RequestType RequestType { get; set; }
|
||||
public string ImgSrc { get; set; }
|
||||
}
|
||||
}
|
109
Old/Ombi.Services/Notification/NotificationService.cs
Normal file
109
Old/Ombi.Services/Notification/NotificationService.cs
Normal file
|
@ -0,0 +1,109 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2016 Jamie Rees
|
||||
// File: NotificationService.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
|
||||
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using NLog;
|
||||
using Ombi.Core.SettingModels;
|
||||
using Ombi.Services.Interfaces;
|
||||
|
||||
namespace Ombi.Services.Notification
|
||||
{
|
||||
public class NotificationService : INotificationService
|
||||
{
|
||||
private static Logger Log = LogManager.GetCurrentClassLogger();
|
||||
public ConcurrentDictionary<string, INotification> Observers { get; } = new ConcurrentDictionary<string, INotification>();
|
||||
|
||||
/// <summary>
|
||||
/// Sends a notification to the user. This one is used in normal notification scenarios
|
||||
/// </summary>
|
||||
/// <param name="model">The model.</param>
|
||||
/// <returns></returns>
|
||||
public async Task Publish(NotificationModel model)
|
||||
{
|
||||
var notificationTasks = Observers.Values.Select(notification => NotifyAsync(notification, model));
|
||||
|
||||
await Task.WhenAll(notificationTasks).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends a notification to the user, this is usually for testing the settings.
|
||||
/// </summary>
|
||||
/// <param name="model">The model.</param>
|
||||
/// <param name="settings">The settings.</param>
|
||||
/// <returns></returns>
|
||||
public async Task Publish(NotificationModel model, Settings settings)
|
||||
{
|
||||
var notificationTasks = Observers.Values.Select(notification => NotifyAsync(notification, model, settings));
|
||||
|
||||
await Task.WhenAll(notificationTasks).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public void Subscribe(INotification notification)
|
||||
{
|
||||
Observers.TryAdd(notification.NotificationName, notification);
|
||||
}
|
||||
|
||||
public void UnSubscribe(INotification notification)
|
||||
{
|
||||
Observers.TryRemove(notification.NotificationName, out notification);
|
||||
}
|
||||
|
||||
private async Task NotifyAsync(INotification notification, NotificationModel model)
|
||||
{
|
||||
try
|
||||
{
|
||||
await notification.NotifyAsync(model).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, $"Notification '{notification.NotificationName}' failed with exception");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private async Task NotifyAsync(INotification notification, NotificationModel model, Settings settings)
|
||||
{
|
||||
try
|
||||
{
|
||||
await notification.NotifyAsync(model, settings).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, $"Notification '{notification.NotificationName}' failed with exception");
|
||||
throw new InvalidOperationException(ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task PublishTest(NotificationModel model, Settings settings, INotification type)
|
||||
{
|
||||
await type.NotifyAsync(model, settings);
|
||||
}
|
||||
}
|
||||
}
|
262
Old/Ombi.Services/Notification/PlexNotificationEngine.cs
Normal file
262
Old/Ombi.Services/Notification/PlexNotificationEngine.cs
Normal file
|
@ -0,0 +1,262 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2016 Jamie Rees
|
||||
// File: PlexNotificationEngine.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
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using NLog;
|
||||
using Ombi.Api.Interfaces;
|
||||
using Ombi.Core;
|
||||
using Ombi.Core.Models;
|
||||
using Ombi.Core.SettingModels;
|
||||
using Ombi.Core.Users;
|
||||
using Ombi.Helpers.Permissions;
|
||||
using Ombi.Services.Interfaces;
|
||||
using Ombi.Store;
|
||||
using Ombi.Store.Models;
|
||||
using Ombi.Store.Repository;
|
||||
|
||||
namespace Ombi.Services.Notification
|
||||
{
|
||||
public class PlexNotificationEngine : IPlexNotificationEngine
|
||||
{
|
||||
public PlexNotificationEngine(IPlexApi p, IRepository<UsersToNotify> repo, INotificationService service, IUserHelper userHelper, ISettingsService<PlexSettings> ps)
|
||||
{
|
||||
PlexApi = p;
|
||||
UserNotifyRepo = repo;
|
||||
Notification = service;
|
||||
UserHelper = userHelper;
|
||||
PlexSettings = ps;
|
||||
}
|
||||
|
||||
private IPlexApi PlexApi { get; }
|
||||
private IRepository<UsersToNotify> UserNotifyRepo { get; }
|
||||
private static Logger Log = LogManager.GetCurrentClassLogger();
|
||||
private INotificationService Notification { get; }
|
||||
private IUserHelper UserHelper { get; }
|
||||
private ISettingsService<PlexSettings> PlexSettings { get; }
|
||||
|
||||
public async Task NotifyUsers(IEnumerable<RequestedModel> modelChanged, NotificationType type)
|
||||
{
|
||||
try
|
||||
{
|
||||
var settings = await PlexSettings.GetSettingsAsync();
|
||||
var plexUser = PlexApi.GetUsers(settings.PlexAuthToken);
|
||||
var userAccount = PlexApi.GetAccount(settings.PlexAuthToken);
|
||||
|
||||
var adminUsername = userAccount.Username ?? string.Empty;
|
||||
|
||||
var users = UserHelper.GetUsersWithFeature(Features.RequestAddedNotification).ToList();
|
||||
Log.Debug("Notifying Users Count {0}", users.Count);
|
||||
foreach (var model in modelChanged)
|
||||
{
|
||||
var selectedUsers = new List<string>();
|
||||
|
||||
foreach (var u in users)
|
||||
{
|
||||
var requestUser = model.RequestedUsers.FirstOrDefault(
|
||||
x => x.Equals(u.Username, StringComparison.CurrentCultureIgnoreCase) || x.Equals(u.UserAlias, StringComparison.CurrentCultureIgnoreCase));
|
||||
if (string.IsNullOrEmpty(requestUser))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Make sure we do not already have the user
|
||||
if (!selectedUsers.Contains(requestUser))
|
||||
{
|
||||
selectedUsers.Add(requestUser);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var user in selectedUsers)
|
||||
{
|
||||
Log.Info("Notifying user {0}", user);
|
||||
if (user.Equals(adminUsername, StringComparison.CurrentCultureIgnoreCase))
|
||||
{
|
||||
Log.Info("This user is the Plex server owner");
|
||||
await PublishUserNotification(userAccount.Username, userAccount.Email, model.Title, model.PosterPath, type, model.Type);
|
||||
return;
|
||||
}
|
||||
|
||||
UserHelperModel localUser = null;
|
||||
//users.FirstOrDefault( x =>
|
||||
// x.Username.Equals(user, StringComparison.CurrentCultureIgnoreCase) ||
|
||||
// x.UserAlias.Equals(user, StringComparison.CurrentCultureIgnoreCase));
|
||||
|
||||
foreach (var userHelperModel in users)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(userHelperModel.Username))
|
||||
{
|
||||
if (userHelperModel.Username.Equals(user, StringComparison.CurrentCultureIgnoreCase))
|
||||
{
|
||||
localUser = userHelperModel;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!string.IsNullOrEmpty(userHelperModel.UserAlias))
|
||||
{
|
||||
if (userHelperModel.UserAlias.Equals(user, StringComparison.CurrentCultureIgnoreCase))
|
||||
{
|
||||
localUser = userHelperModel;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// So if the request was from an alias, then we need to use the local user (since that contains the alias).
|
||||
// If we do not have a local user, then we should be using the Plex user if that user exists.
|
||||
// This will execute most of the time since Plex and Local users will most always be in the database.
|
||||
if (localUser != null)
|
||||
{
|
||||
if (string.IsNullOrEmpty(localUser?.EmailAddress))
|
||||
{
|
||||
Log.Info("There is no email address for this Local user ({0}), cannot send notification", localUser.Username);
|
||||
continue;
|
||||
}
|
||||
|
||||
Log.Info("Sending notification to: {0} at: {1}, for : {2}", localUser, localUser.EmailAddress, model.Title);
|
||||
await PublishUserNotification(localUser.Username, localUser.EmailAddress, model.Title, model.PosterPath, type, model.Type);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
var email = plexUser.User.FirstOrDefault(x => x.Username.Equals(user, StringComparison.CurrentCultureIgnoreCase));
|
||||
if (string.IsNullOrEmpty(email?.Email))
|
||||
{
|
||||
Log.Info("There is no email address for this Plex user ({0}), cannot send notification", email?.Username);
|
||||
// We do not have a plex user that requested this!
|
||||
continue;
|
||||
}
|
||||
|
||||
Log.Info("Sending notification to: {0} at: {1}, for : {2}", email.Username, email.Email, model.Title);
|
||||
await PublishUserNotification(email.Username, email.Email, model.Title, model.PosterPath, type, model.Type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task NotifyUsers(RequestedModel model, NotificationType type)
|
||||
{
|
||||
try
|
||||
{
|
||||
var settings = await PlexSettings.GetSettingsAsync();
|
||||
|
||||
var plexUser = PlexApi.GetUsers(settings.PlexAuthToken); // TODO emby
|
||||
var userAccount = PlexApi.GetAccount(settings.PlexAuthToken);
|
||||
var localUsers = UserHelper.GetUsers().ToList();
|
||||
|
||||
var adminUsername = userAccount.Username ?? string.Empty;
|
||||
|
||||
var users = UserHelper.GetUsersWithFeature(Features.RequestAddedNotification).ToList();
|
||||
Log.Debug("Notifying Users Count {0}", users.Count);
|
||||
|
||||
// Get the usernames or alias depending if they have an alias
|
||||
var userNamesWithFeature = users.Select(x => x.UsernameOrAlias).ToList();
|
||||
Log.Debug("Users with the feature count {0}", userNamesWithFeature.Count);
|
||||
Log.Debug("Usernames: ");
|
||||
foreach (var u in userNamesWithFeature)
|
||||
{
|
||||
Log.Debug(u);
|
||||
}
|
||||
|
||||
Log.Debug("Users in the requested model count: {0}", model.AllUsers.Count);
|
||||
Log.Debug("usernames from model: ");
|
||||
foreach (var modelAllUser in model.AllUsers)
|
||||
{
|
||||
Log.Debug(modelAllUser);
|
||||
}
|
||||
|
||||
if (model.AllUsers == null || !model.AllUsers.Any())
|
||||
{
|
||||
Log.Debug("There are no users in the model.AllUsers, no users to notify");
|
||||
return;
|
||||
}
|
||||
var usersToNotify = userNamesWithFeature.Intersect(model.AllUsers, StringComparer.CurrentCultureIgnoreCase).ToList();
|
||||
|
||||
if (!usersToNotify.Any())
|
||||
{
|
||||
Log.Debug("Could not find any users after the .Intersect()");
|
||||
}
|
||||
|
||||
Log.Debug("Users being notified for this request count {0}", users.Count);
|
||||
foreach (var user in usersToNotify)
|
||||
{
|
||||
Log.Info("Notifying user {0}", user);
|
||||
if (user.Equals(adminUsername, StringComparison.CurrentCultureIgnoreCase))
|
||||
{
|
||||
Log.Info("This user is the Plex server owner");
|
||||
await PublishUserNotification(userAccount.Username, userAccount.Email, model.Title, model.PosterPath, type, model.Type);
|
||||
return;
|
||||
}
|
||||
|
||||
var email = plexUser.User.FirstOrDefault(x => x.Username.Equals(user, StringComparison.CurrentCultureIgnoreCase));
|
||||
if (email == null) // This is not a Plex User
|
||||
{
|
||||
// Local User?
|
||||
var local = localUsers.FirstOrDefault(x => x.UsernameOrAlias.Equals(user));
|
||||
if (local != null)
|
||||
{
|
||||
|
||||
Log.Info("Sending notification to: {0} at: {1}, for title: {2}", local.UsernameOrAlias, local.EmailAddress, model.Title);
|
||||
await PublishUserNotification(local.UsernameOrAlias, local.EmailAddress, model.Title, model.PosterPath, type, model.Type);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
Log.Info("Sending notification to: {0} at: {1}, for title: {2}", email.Username, email.Email, model.Title);
|
||||
await PublishUserNotification(email.Username, email.Email, model.Title, model.PosterPath, type, model.Type);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task PublishUserNotification(string username, string email, string title, string img, NotificationType type, RequestType requestType)
|
||||
{
|
||||
var notificationModel = new NotificationModel
|
||||
{
|
||||
User = username,
|
||||
UserEmail = email,
|
||||
NotificationType = type,
|
||||
Title = title,
|
||||
ImgSrc = requestType == RequestType.Movie ? $"https://image.tmdb.org/t/p/w300/{img}" : img
|
||||
};
|
||||
|
||||
// Send the notification to the user.
|
||||
await Notification.Publish(notificationModel);
|
||||
}
|
||||
}
|
||||
}
|
144
Old/Ombi.Services/Notification/PushbulletNotification.cs
Normal file
144
Old/Ombi.Services/Notification/PushbulletNotification.cs
Normal file
|
@ -0,0 +1,144 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2016 Jamie Rees
|
||||
// File: PushbulletNotification.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
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using NLog;
|
||||
using Ombi.Api.Interfaces;
|
||||
using Ombi.Core;
|
||||
using Ombi.Core.SettingModels;
|
||||
using Ombi.Store;
|
||||
|
||||
namespace Ombi.Services.Notification
|
||||
{
|
||||
public class PushbulletNotification : BaseNotification<PushbulletNotificationSettings>
|
||||
{
|
||||
public PushbulletNotification(IPushbulletApi pushbulletApi, ISettingsService<PushbulletNotificationSettings> settings) : base(settings)
|
||||
{
|
||||
PushbulletApi = pushbulletApi;
|
||||
}
|
||||
private IPushbulletApi PushbulletApi { get; }
|
||||
private ISettingsService<PushbulletNotificationSettings> SettingsService { get; }
|
||||
|
||||
private static readonly Logger Log = LogManager.GetCurrentClassLogger();
|
||||
public override string NotificationName => "PushbulletNotification";
|
||||
|
||||
protected override bool ValidateConfiguration(PushbulletNotificationSettings settings)
|
||||
{
|
||||
if (!settings.Enabled)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (string.IsNullOrEmpty(settings.AccessToken))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override async Task NewRequest(NotificationModel model, PushbulletNotificationSettings settings)
|
||||
{
|
||||
var message = $"The {model.RequestType.GetString()?.ToLower()} '{model.Title}' has been requested by user: {model.User}";
|
||||
var pushTitle = $"Ombi: The {model.RequestType.GetString()?.ToLower()} {model.Title} has been requested!";
|
||||
var notification = new NotificationMessage
|
||||
{
|
||||
Message = message,
|
||||
Subject = pushTitle
|
||||
};
|
||||
await Send(notification, settings);
|
||||
}
|
||||
|
||||
|
||||
protected override async Task Issue(NotificationModel model, PushbulletNotificationSettings settings)
|
||||
{
|
||||
var message = $"A new issue: {model.Body} has been reported by user: {model.User} for the title: {model.Title}";
|
||||
var pushTitle = $"Ombi: A new issue has been reported for {model.Title}";
|
||||
var notification = new NotificationMessage
|
||||
{
|
||||
Message = message,
|
||||
Subject = pushTitle
|
||||
};
|
||||
await Send(notification, settings);
|
||||
}
|
||||
|
||||
protected override async Task AddedToRequestQueue(NotificationModel model, PushbulletNotificationSettings settings)
|
||||
{
|
||||
|
||||
var message = $"Hello!The user '{model.User}' has requested { model.Title} but it could not be added. This has been added into the requests queue and will keep retrying";
|
||||
var pushTitle = $"Ombi: A request could not be added.";
|
||||
var notification = new NotificationMessage
|
||||
{
|
||||
Message = message,
|
||||
Subject = pushTitle
|
||||
};
|
||||
await Send(notification, settings);
|
||||
}
|
||||
|
||||
protected override Task RequestDeclined(NotificationModel model, PushbulletNotificationSettings settings)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
protected override Task RequestApproved(NotificationModel model, PushbulletNotificationSettings settings)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
protected override Task AvailableRequest(NotificationModel model, PushbulletNotificationSettings settings)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
protected override async Task Send(NotificationMessage model, PushbulletNotificationSettings settings)
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = await PushbulletApi.PushAsync(settings.AccessToken, model.Subject, model.Message, settings.DeviceIdentifier);
|
||||
if (result != null)
|
||||
{
|
||||
Log.Error("Pushbullet api returned a null value, the notification did not get pushed");
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
protected override async Task Test(NotificationModel model, PushbulletNotificationSettings settings)
|
||||
{
|
||||
var message = "This is just a test! Success!";
|
||||
var pushTitle = "Ombi: Test Message!";
|
||||
var notification = new NotificationMessage
|
||||
{
|
||||
Message = message,
|
||||
Subject = pushTitle
|
||||
};
|
||||
await Send(notification,settings);
|
||||
}
|
||||
}
|
||||
}
|
136
Old/Ombi.Services/Notification/PushoverNotification.cs
Normal file
136
Old/Ombi.Services/Notification/PushoverNotification.cs
Normal file
|
@ -0,0 +1,136 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2016 Jamie Rees
|
||||
// File: PushbulletNotification.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
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using NLog;
|
||||
using Ombi.Api.Interfaces;
|
||||
using Ombi.Core;
|
||||
using Ombi.Core.SettingModels;
|
||||
using Ombi.Store;
|
||||
|
||||
namespace Ombi.Services.Notification
|
||||
{
|
||||
public class PushoverNotification : BaseNotification<PushoverNotificationSettings>
|
||||
{
|
||||
public PushoverNotification(IPushoverApi pushoverApi, ISettingsService<PushoverNotificationSettings> settings) : base(settings)
|
||||
{
|
||||
PushoverApi = pushoverApi;
|
||||
}
|
||||
private IPushoverApi PushoverApi { get; }
|
||||
|
||||
private static Logger Log = LogManager.GetCurrentClassLogger();
|
||||
public override string NotificationName => "PushoverNotification";
|
||||
|
||||
|
||||
protected override bool ValidateConfiguration(PushoverNotificationSettings settings)
|
||||
{
|
||||
if (!settings.Enabled)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (string.IsNullOrEmpty(settings.AccessToken) || string.IsNullOrEmpty(settings.UserToken))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override async Task NewRequest(NotificationModel model, PushoverNotificationSettings settings)
|
||||
{
|
||||
var message = $"Ombi: The {model.RequestType.GetString()?.ToLower()} '{model.Title}' has been requested by user: {model.User}";
|
||||
var notification = new NotificationMessage
|
||||
{
|
||||
Message = message,
|
||||
};
|
||||
await Send(notification, settings);
|
||||
}
|
||||
|
||||
protected override async Task Issue(NotificationModel model, PushoverNotificationSettings settings)
|
||||
{
|
||||
var message = $"Ombi: A new issue: {model.Body} has been reported by user: {model.User} for the title: {model.Title}";
|
||||
var notification = new NotificationMessage
|
||||
{
|
||||
Message = message,
|
||||
};
|
||||
await Send(notification, settings);
|
||||
}
|
||||
|
||||
protected override async Task AddedToRequestQueue(NotificationModel model, PushoverNotificationSettings settings)
|
||||
{
|
||||
var message = $"Hello! The user '{model.User}' has requested {model.Title} but it could not be added. This has been added into the requests queue and will keep retrying";
|
||||
|
||||
var notification = new NotificationMessage
|
||||
{
|
||||
Message = message,
|
||||
};
|
||||
await Send(notification, settings);
|
||||
}
|
||||
|
||||
protected override Task RequestDeclined(NotificationModel model, PushoverNotificationSettings settings)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
protected override Task RequestApproved(NotificationModel model, PushoverNotificationSettings settings)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
protected override Task AvailableRequest(NotificationModel model, PushoverNotificationSettings settings)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
protected override async Task Send(NotificationMessage model, PushoverNotificationSettings settings)
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = await PushoverApi.PushAsync(settings.AccessToken, model.Message, settings.UserToken);
|
||||
if (result?.status != 1)
|
||||
{
|
||||
Log.Error("Pushover api returned a status that was not 1, the notification did not get pushed");
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
protected override async Task Test(NotificationModel model, PushoverNotificationSettings settings)
|
||||
{
|
||||
|
||||
var message = $"Ombi: Test Message!";
|
||||
var notification = new NotificationMessage
|
||||
{
|
||||
Message = message,
|
||||
};
|
||||
await Send(notification, settings);
|
||||
}
|
||||
}
|
||||
}
|
149
Old/Ombi.Services/Notification/SlackNotification.cs
Normal file
149
Old/Ombi.Services/Notification/SlackNotification.cs
Normal file
|
@ -0,0 +1,149 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2016 Jamie Rees
|
||||
// File: SlackNotification.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
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using NLog;
|
||||
using Ombi.Api.Interfaces;
|
||||
using Ombi.Api.Models.Notifications;
|
||||
using Ombi.Core;
|
||||
using Ombi.Core.SettingModels;
|
||||
|
||||
namespace Ombi.Services.Notification
|
||||
{
|
||||
public class SlackNotification : BaseNotification<SlackNotificationSettings>
|
||||
{
|
||||
public SlackNotification(ISlackApi api, ISettingsService<SlackNotificationSettings> sn) : base(sn)
|
||||
{
|
||||
Api = api;
|
||||
}
|
||||
|
||||
public override string NotificationName => "SlackNotification";
|
||||
|
||||
private ISlackApi Api { get; }
|
||||
private static readonly Logger Log = LogManager.GetCurrentClassLogger();
|
||||
|
||||
|
||||
protected override bool ValidateConfiguration(SlackNotificationSettings settings)
|
||||
{
|
||||
if (!settings.Enabled)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (string.IsNullOrEmpty(settings.WebhookUrl))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
try
|
||||
{
|
||||
var a = settings.Team;
|
||||
var b = settings.Service;
|
||||
var c = settings.Token;
|
||||
}
|
||||
catch (IndexOutOfRangeException)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override async Task NewRequest(NotificationModel model, SlackNotificationSettings settings)
|
||||
{
|
||||
var message = $"{model.Title} has been requested by user: {model.User}";
|
||||
var notification = new NotificationMessage
|
||||
{
|
||||
Message = message,
|
||||
};
|
||||
await Send(notification, settings);
|
||||
}
|
||||
|
||||
protected override async Task Issue(NotificationModel model, SlackNotificationSettings settings)
|
||||
{
|
||||
var message = $"A new issue: {model.Body} has been reported by user: {model.User} for the title: {model.Title}";
|
||||
var notification = new NotificationMessage
|
||||
{
|
||||
Message = message,
|
||||
};
|
||||
await Send(notification, settings);
|
||||
}
|
||||
|
||||
protected override async Task AddedToRequestQueue(NotificationModel model, SlackNotificationSettings settings)
|
||||
{
|
||||
var message = $"Hello! The user '{model.User}' has requested {model.Title} but it could not be added. This has been added into the requests queue and will keep retrying";
|
||||
|
||||
var notification = new NotificationMessage
|
||||
{
|
||||
Message = message,
|
||||
};
|
||||
await Send(notification, settings);
|
||||
}
|
||||
|
||||
protected override Task RequestDeclined(NotificationModel model, SlackNotificationSettings settings)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
protected override Task RequestApproved(NotificationModel model, SlackNotificationSettings settings)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
protected override Task AvailableRequest(NotificationModel model, SlackNotificationSettings settings)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
protected override async Task Send(NotificationMessage model, SlackNotificationSettings config)
|
||||
{
|
||||
try
|
||||
{
|
||||
var notification = new SlackNotificationBody { username = config.Username, channel = config.Channel ?? string.Empty, text = model.Message };
|
||||
|
||||
var result = await Api.PushAsync(config.Team, config.Token, config.Service, notification);
|
||||
if (!result.Equals("ok"))
|
||||
{
|
||||
Log.Error("Slack returned a message that was not 'ok', the notification did not get pushed");
|
||||
Log.Error($"Message that slack returned: {result}");
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
protected override async Task Test(NotificationModel model, SlackNotificationSettings settings)
|
||||
{
|
||||
var message = $"This is a test from Ombi, if you can see this then we have successfully pushed a notification!";
|
||||
var notification = new NotificationMessage
|
||||
{
|
||||
Message = message,
|
||||
};
|
||||
await Send(notification, settings);
|
||||
}
|
||||
}
|
||||
}
|
208
Old/Ombi.Services/Ombi.Services.csproj
Normal file
208
Old/Ombi.Services/Ombi.Services.csproj
Normal file
|
@ -0,0 +1,208 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{566EFA49-68F8-4716-9693-A6B3F2624DEA}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>Ombi.Services</RootNamespace>
|
||||
<AssemblyName>Ombi.Services</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<TargetFrameworkProfile />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Dapper, Version=1.50.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Dapper.1.50.0-beta8\lib\net45\Dapper.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Build.Framework" />
|
||||
<Reference Include="Nancy, Version=1.4.2.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Nancy.1.4.3\lib\net40\Nancy.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Newtonsoft.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\NLog.4.3.6\lib\net45\NLog.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Polly, Version=4.3.0.0, Culture=neutral, PublicKeyToken=c8a3ffc3f8f825cc" />
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Security" />
|
||||
<Reference Include="System.Web" />
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="BouncyCastle, Version=1.8.1.0, Culture=neutral, PublicKeyToken=0e99375e54769942">
|
||||
<HintPath>..\packages\MimeKit.1.2.22\lib\net45\BouncyCastle.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Common.Logging, Version=3.0.0.0, Culture=neutral, PublicKeyToken=af08829b84f0328e">
|
||||
<HintPath>..\packages\Common.Logging.3.0.0\lib\net40\Common.Logging.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Common.Logging.Core, Version=3.0.0.0, Culture=neutral, PublicKeyToken=af08829b84f0328e">
|
||||
<HintPath>..\packages\Common.Logging.Core.3.0.0\lib\net40\Common.Logging.Core.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="MailKit, Version=1.2.0.0, Culture=neutral, PublicKeyToken=4e064fe7c44a8f1b">
|
||||
<HintPath>..\packages\MailKit.1.2.21\lib\net451\MailKit.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="MimeKit, Version=1.2.0.0, Culture=neutral, PublicKeyToken=bede1c8a46c66814">
|
||||
<HintPath>..\packages\MimeKit.1.2.22\lib\net45\MimeKit.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Mono.Data.Sqlite">
|
||||
<HintPath>..\Assemblies\Mono.Data.Sqlite.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Quartz, Version=2.3.3.0, Culture=neutral, PublicKeyToken=f6b8c98a402cc8a4">
|
||||
<HintPath>..\packages\Quartz.2.3.3\lib\net40\Quartz.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="TMDbLib, Version=0.9.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\TMDbLib.0.9.0.0-alpha\lib\net45\TMDbLib.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Interfaces\IEmbyNotificationEngine.cs" />
|
||||
<Compile Include="Interfaces\IMassEmail.cs" />
|
||||
<Compile Include="Interfaces\IPlexNotificationEngine.cs" />
|
||||
<Compile Include="Interfaces\IRadarrCacher.cs" />
|
||||
<Compile Include="Interfaces\IWatcherCacher.cs" />
|
||||
<Compile Include="Interfaces\IJobRecord.cs" />
|
||||
<Compile Include="Interfaces\INotificationEngine.cs" />
|
||||
<Compile Include="Interfaces\IStoreBackup.cs" />
|
||||
<Compile Include="Interfaces\IStoreCleanup.cs" />
|
||||
<Compile Include="Interfaces\IUserRequestLimitResetter.cs" />
|
||||
<Compile Include="Jobs\IEmbyUserChecker.cs" />
|
||||
<Compile Include="Jobs\Interfaces\IEmbyEpisodeCacher.cs" />
|
||||
<Compile Include="Jobs\Interfaces\IEmbyContentCacher.cs" />
|
||||
<Compile Include="Jobs\Interfaces\IEmbyAvailabilityChecker.cs" />
|
||||
<Compile Include="Jobs\Interfaces\IFaultQueueHandler.cs" />
|
||||
<Compile Include="Jobs\Interfaces\IPlexEpisodeCacher.cs" />
|
||||
<Compile Include="Jobs\Interfaces\IPlexUserChecker.cs" />
|
||||
<Compile Include="Jobs\EmbyAvailabilityChecker.cs" />
|
||||
<Compile Include="Jobs\EmbyContentCacher.cs" />
|
||||
<Compile Include="Jobs\EmbyEpisodeCacher.cs" />
|
||||
<Compile Include="Jobs\EmbyUserChecker.cs" />
|
||||
<Compile Include="Jobs\RadarrCacher.cs" />
|
||||
<Compile Include="Jobs\RecentlyAddedNewsletter\Newsletter.cs" />
|
||||
<Compile Include="Jobs\RecentlyAddedNewsletter\PlexRecentlyAddedNewsletter.cs" />
|
||||
<Compile Include="Jobs\RecentlyAddedNewsletter\EmbyRecentlyAddedNewsletter.cs" />
|
||||
<Compile Include="Jobs\RecentlyAddedNewsletter\IPlexNewsletter.cs" />
|
||||
<Compile Include="Jobs\RecentlyAddedNewsletter\IEmbyAddedNewsletter.cs" />
|
||||
<Compile Include="Jobs\Templates\MassEmailTemplate.cs" />
|
||||
<Compile Include="Jobs\WatcherCacher.cs" />
|
||||
<Compile Include="Jobs\HtmlTemplateGenerator.cs" />
|
||||
<Compile Include="Interfaces\IPlexContentCacher.cs" />
|
||||
<Compile Include="Interfaces\IRecentlyAdded.cs" />
|
||||
<Compile Include="Jobs\JobRecord.cs" />
|
||||
<Compile Include="Jobs\JobNames.cs" />
|
||||
<Compile Include="Jobs\PlexContentCacher.cs" />
|
||||
<Compile Include="Jobs\PlexEpisodeCacher.cs" />
|
||||
<Compile Include="Jobs\RecentlyAddedNewsletter\RecentlyAddedNewsletter.cs" />
|
||||
<Compile Include="Jobs\StoreBackup.cs" />
|
||||
<Compile Include="Jobs\PlexUserChecker.cs" />
|
||||
<Compile Include="Jobs\StoreCleanup.cs" />
|
||||
<Compile Include="Jobs\CouchPotatoCacher.cs" />
|
||||
<Compile Include="Jobs\PlexAvailabilityChecker.cs" />
|
||||
<Compile Include="Jobs\SickRageCacher.cs" />
|
||||
<Compile Include="Jobs\SonarrCacher.cs" />
|
||||
<Compile Include="Jobs\Templates\RecentlyAddedTemplate.cs" />
|
||||
<Compile Include="Jobs\FaultQueueHandler.cs" />
|
||||
<Compile Include="Jobs\UserRequestLimitResetter.cs" />
|
||||
<Compile Include="Models\PlexAlbum.cs" />
|
||||
<Compile Include="Models\PlexEpisodeModel.cs" />
|
||||
<Compile Include="Models\PlexMovie.cs" />
|
||||
<Compile Include="Models\PlexTvShow.cs" />
|
||||
<Compile Include="Interfaces\ISickRageCacher.cs" />
|
||||
<Compile Include="Interfaces\ISonarrCacher.cs" />
|
||||
<Compile Include="Interfaces\ICouchPotatoCacher.cs" />
|
||||
<Compile Include="Interfaces\IAvailabilityChecker.cs" />
|
||||
<Compile Include="Interfaces\IIntervals.cs" />
|
||||
<Compile Include="Interfaces\INotification.cs" />
|
||||
<Compile Include="Interfaces\INotificationService.cs" />
|
||||
<Compile Include="Models\SonarrCachedResult.cs" />
|
||||
<Compile Include="Notification\BaseNotification.cs" />
|
||||
<Compile Include="Notification\EmailMessageNotification.cs" />
|
||||
<Compile Include="Notification\EmbyNotificationEngine.cs" />
|
||||
<Compile Include="Notification\NotificationMessage.cs" />
|
||||
<Compile Include="Notification\PlexNotificationEngine.cs" />
|
||||
<Compile Include="Notification\NotificationModel.cs" />
|
||||
<Compile Include="Notification\NotificationService.cs" />
|
||||
<Compile Include="Notification\PushoverNotification.cs" />
|
||||
<Compile Include="Notification\PushbulletNotification.cs" />
|
||||
<Compile Include="Notification\DiscordNotification.cs" />
|
||||
<Compile Include="Notification\SlackNotification.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="app.config" />
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Ombi.Api.Interfaces\Ombi.Api.Interfaces.csproj">
|
||||
<Project>{95834072-A675-415D-AA8F-877C91623810}</Project>
|
||||
<Name>Ombi.Api.Interfaces</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Ombi.Api.Models\Ombi.Api.Models.csproj">
|
||||
<Project>{CB37A5F8-6DFC-4554-99D3-A42B502E4591}</Project>
|
||||
<Name>Ombi.Api.Models</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Ombi.Api\Ombi.Api.csproj">
|
||||
<Project>{8CB8D235-2674-442D-9C6A-35FCAEEB160D}</Project>
|
||||
<Name>Ombi.Api</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Ombi.Core\Ombi.Core.csproj">
|
||||
<Project>{DD7DC444-D3BF-4027-8AB9-EFC71F5EC581}</Project>
|
||||
<Name>Ombi.Core</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Ombi.Helpers\Ombi.Helpers.csproj">
|
||||
<Project>{1252336D-42A3-482A-804C-836E60173DFA}</Project>
|
||||
<Name>Ombi.Helpers</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Ombi.Store\Ombi.Store.csproj">
|
||||
<Project>{92433867-2B7B-477B-A566-96C382427525}</Project>
|
||||
<Name>Ombi.Store</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="Jobs\Templates\MassEmailTemplate.html">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Jobs\Templates\RecentlyAddedTemplate.html">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
37
Old/Ombi.Services/Properties/AssemblyInfo.cs
Normal file
37
Old/Ombi.Services/Properties/AssemblyInfo.cs
Normal file
|
@ -0,0 +1,37 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("Ombi.Services")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("Ombi.Services")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2016")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("566efa49-68f8-4716-9693-a6b3f2624dea")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
[assembly: AssemblyInformationalVersionAttribute("1.0.0.0")]
|
11
Old/Ombi.Services/app.config
Normal file
11
Old/Ombi.Services/app.config
Normal file
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<runtime>
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-9.0.0.0" newVersion="9.0.0.0" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" /></startup></configuration>
|
11
Old/Ombi.Services/packages.config
Normal file
11
Old/Ombi.Services/packages.config
Normal file
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Common.Logging" version="3.0.0" targetFramework="net45" />
|
||||
<package id="Common.Logging.Core" version="3.0.0" targetFramework="net45" />
|
||||
<package id="Dapper" version="1.50.0-beta8" targetFramework="net45" />
|
||||
<package id="MailKit" version="1.2.21" targetFramework="net45" requireReinstallation="True" />
|
||||
<package id="MimeKit" version="1.2.22" targetFramework="net45" />
|
||||
<package id="Nancy" version="1.4.3" targetFramework="net45" />
|
||||
<package id="NLog" version="4.3.6" targetFramework="net45" />
|
||||
<package id="Quartz" version="2.3.3" targetFramework="net45" />
|
||||
</packages>
|
Loading…
Add table
Add a link
Reference in a new issue