Finished the Plex Content Cacher. Need to do the episodes part but things are now showing as available! #865

This commit is contained in:
tidusjar 2017-05-21 00:13:07 +01:00
parent b4789363e8
commit df5f0fc691
13 changed files with 143 additions and 75 deletions

View file

@ -13,13 +13,15 @@ using Ombi.Core.Requests.Models;
using Ombi.Core.Settings; using Ombi.Core.Settings;
using Ombi.Core.Settings.Models.External; using Ombi.Core.Settings.Models.External;
using Ombi.Store.Entities; using Ombi.Store.Entities;
using Ombi.Store.Repository;
namespace Ombi.Core.Engine namespace Ombi.Core.Engine
{ {
public class MovieSearchEngine : BaseMediaEngine, IMovieEngine public class MovieSearchEngine : BaseMediaEngine, IMovieEngine
{ {
public MovieSearchEngine(IPrincipal identity, IRequestServiceMain service, IMovieDbApi movApi, IMapper mapper, ISettingsService<PlexSettings> plexSettings, ISettingsService<EmbySettings> embySettings, public MovieSearchEngine(IPrincipal identity, IRequestServiceMain service, IMovieDbApi movApi, IMapper mapper, ISettingsService<PlexSettings> plexSettings,
ISettingsService<EmbySettings> embySettings, IPlexContentRepository repo,
ILogger<MovieSearchEngine> logger) ILogger<MovieSearchEngine> logger)
: base(identity, service) : base(identity, service)
{ {
@ -28,6 +30,7 @@ namespace Ombi.Core.Engine
PlexSettings = plexSettings; PlexSettings = plexSettings;
EmbySettings = embySettings; EmbySettings = embySettings;
Logger = logger; Logger = logger;
PlexContentRepo = repo;
} }
private IMovieDbApi MovieApi { get; } private IMovieDbApi MovieApi { get; }
@ -35,6 +38,7 @@ namespace Ombi.Core.Engine
private ISettingsService<PlexSettings> PlexSettings { get; } private ISettingsService<PlexSettings> PlexSettings { get; }
private ISettingsService<EmbySettings> EmbySettings { get; } private ISettingsService<EmbySettings> EmbySettings { get; }
private ILogger<MovieSearchEngine> Logger { get; } private ILogger<MovieSearchEngine> Logger { get; }
private IPlexContentRepository PlexContentRepo { get; }
public async Task<IEnumerable<SearchMovieViewModel>> LookupImdbInformation(IEnumerable<SearchMovieViewModel> movies) public async Task<IEnumerable<SearchMovieViewModel>> LookupImdbInformation(IEnumerable<SearchMovieViewModel> movies)
{ {
@ -136,8 +140,17 @@ namespace Ombi.Core.Engine
private async Task<SearchMovieViewModel> ProcessSingleMovie(SearchMovieViewModel viewMovie, private async Task<SearchMovieViewModel> ProcessSingleMovie(SearchMovieViewModel viewMovie,
Dictionary<int, MovieRequestModel> existingRequests, PlexSettings plexSettings, EmbySettings embySettings) Dictionary<int, MovieRequestModel> existingRequests, PlexSettings plexSettings, EmbySettings embySettings)
{ {
var showInfo = await MovieApi.GetMovieInformation(viewMovie.Id);
if (plexSettings.Enable) if (plexSettings.Enable)
{ {
var item = await PlexContentRepo.Get(showInfo.ImdbId.ToString());
if(item != null)
{
viewMovie.Available = true;
viewMovie.PlexUrl = item.Url;
}
// var content = PlexContentRepository.GetAll(); // var content = PlexContentRepository.GetAll();
// var plexMovies = PlexChecker.GetPlexMovies(content); // var plexMovies = PlexChecker.GetPlexMovies(content);

View file

@ -14,6 +14,7 @@ using Ombi.Core.Requests.Models;
using Ombi.Core.Settings; using Ombi.Core.Settings;
using Ombi.Core.Settings.Models.External; using Ombi.Core.Settings.Models.External;
using Ombi.Store.Entities; using Ombi.Store.Entities;
using Ombi.Store.Repository;
namespace Ombi.Core.Engine namespace Ombi.Core.Engine
{ {
@ -21,13 +22,14 @@ namespace Ombi.Core.Engine
{ {
public TvSearchEngine(IPrincipal identity, IRequestServiceMain service, ITvMazeApi tvMaze, IMapper mapper, ISettingsService<PlexSettings> plexSettings, public TvSearchEngine(IPrincipal identity, IRequestServiceMain service, ITvMazeApi tvMaze, IMapper mapper, ISettingsService<PlexSettings> plexSettings,
ISettingsService<EmbySettings> embySettings) ISettingsService<EmbySettings> embySettings, IPlexContentRepository repo)
: base(identity, service) : base(identity, service)
{ {
TvMazeApi = tvMaze; TvMazeApi = tvMaze;
Mapper = mapper; Mapper = mapper;
PlexSettings = plexSettings; PlexSettings = plexSettings;
EmbySettings = embySettings; EmbySettings = embySettings;
PlexContentRepo = repo;
//TraktApi = trakt; //TraktApi = trakt;
} }
@ -35,6 +37,7 @@ namespace Ombi.Core.Engine
private IMapper Mapper { get; } private IMapper Mapper { get; }
private ISettingsService<PlexSettings> PlexSettings { get; } private ISettingsService<PlexSettings> PlexSettings { get; }
private ISettingsService<EmbySettings> EmbySettings { get; } private ISettingsService<EmbySettings> EmbySettings { get; }
private IPlexContentRepository PlexContentRepo { get; }
//private ITraktApi TraktApi { get; } //private ITraktApi TraktApi { get; }
@ -91,7 +94,7 @@ namespace Ombi.Core.Engine
var existingRequests = await GetTvRequests(); var existingRequests = await GetTvRequests();
var plexSettings = await PlexSettings.GetSettingsAsync(); var plexSettings = await PlexSettings.GetSettingsAsync();
var embySettings = await EmbySettings.GetSettingsAsync(); var embySettings = await EmbySettings.GetSettingsAsync();
return ProcessResult(mapped, existingRequests, plexSettings, embySettings); return await ProcessResult(mapped, existingRequests, plexSettings, embySettings);
} }
//public async Task<IEnumerable<SearchTvShowViewModel>> Popular() //public async Task<IEnumerable<SearchTvShowViewModel>> Popular()
@ -127,12 +130,12 @@ namespace Ombi.Core.Engine
foreach (var tvMazeSearch in items) foreach (var tvMazeSearch in items)
{ {
var viewT = Mapper.Map<SearchTvShowViewModel>(tvMazeSearch); var viewT = Mapper.Map<SearchTvShowViewModel>(tvMazeSearch);
retVal.Add(ProcessResult(viewT, existingRequests, plexSettings, embySettings)); retVal.Add(await ProcessResult(viewT, existingRequests, plexSettings, embySettings));
} }
return retVal; return retVal;
} }
private SearchTvShowViewModel ProcessResult(SearchTvShowViewModel item, Dictionary<int, TvRequestModel> existingRequests, PlexSettings plexSettings, EmbySettings embySettings) private async Task<SearchTvShowViewModel> ProcessResult(SearchTvShowViewModel item, Dictionary<int, TvRequestModel> existingRequests, PlexSettings plexSettings, EmbySettings embySettings)
{ {
if (embySettings.Enable) if (embySettings.Enable)
{ {
@ -144,6 +147,13 @@ namespace Ombi.Core.Engine
} }
if (plexSettings.Enable) if (plexSettings.Enable)
{ {
var content = await PlexContentRepo.Get(item.Id.ToString());
if (content != null)
{
item.Available = true;
item.PlexUrl = content.Url;
}
//var plexShow = PlexChecker.GetTvShow(plexTvShows.ToArray(), t.show.name, t.show.premiered?.Substring(0, 4), //var plexShow = PlexChecker.GetTvShow(plexTvShows.ToArray(), t.show.name, t.show.premiered?.Substring(0, 4),
// providerId); // providerId);
//if (plexShow != null) //if (plexShow != null)
@ -155,6 +165,8 @@ namespace Ombi.Core.Engine
if (item.Id > 0 && item.Available) if (item.Id > 0 && item.Available)
{ {
// TODO need to check if the episodes are available
var tvdbid = item.Id; var tvdbid = item.Id;
if (existingRequests.ContainsKey(tvdbid)) if (existingRequests.ContainsKey(tvdbid))
{ {

View file

@ -14,7 +14,7 @@ namespace Ombi.Schedule
private IPlexContentCacher Cacher { get; } private IPlexContentCacher Cacher { get; }
public void Setup() public void Setup()
{ {
RecurringJob.AddOrUpdate(() => Cacher.CacheContent(), Cron.Minutely); RecurringJob.AddOrUpdate(() => Cacher.CacheContent(), Cron.Hourly);
} }
} }
} }

View file

@ -126,17 +126,16 @@ namespace Ombi.Schedule.Jobs
var allContent = GetAllContent(servers); var allContent = GetAllContent(servers);
// Let's now process this. // Let's now process this.
var contentToAdd = new List<PlexContent>(); var contentToAdd = new List<PlexContent>();
foreach (var content in allContent) foreach (var content in allContent)
{ {
if (content.viewGroup.Equals(PlexMediaType.Show.ToString(), StringComparison.CurrentCultureIgnoreCase)) if (content.viewGroup.Equals(PlexMediaType.Show.ToString(), StringComparison.CurrentCultureIgnoreCase))
{ {
// Process Shows // Process Shows
foreach (var metadata in content.Metadata) foreach (var show in content.Metadata)
{ {
var seasonList = await PlexApi.GetSeasons(servers.PlexAuthToken, servers.FullUri, var seasonList = await PlexApi.GetSeasons(servers.PlexAuthToken, servers.FullUri,
metadata.ratingKey); show.ratingKey);
var seasonsContent = new List<SeasonsContent>(); var seasonsContent = new List<SeasonsContent>();
foreach (var season in seasonList.MediaContainer.Metadata) foreach (var season in seasonList.MediaContainer.Metadata)
{ {
@ -149,45 +148,82 @@ namespace Ombi.Schedule.Jobs
} }
// Do we already have this item? // Do we already have this item?
var existingContent = await Repo.GetByKey(metadata.key); var existingContent = await Repo.GetByKey(show.ratingKey);
if (existingContent != null) if (existingContent != null)
{ {
// Ok so we have it, let's check if there are any new seasons // Ok so we have it, let's check if there are any new seasons
var seasonDifference = seasonsContent.Except(existingContent.Seasons).ToList(); var itemAdded = false;
if (seasonDifference.Any()) foreach (var season in seasonsContent)
{ {
// We have new seasons on Plex, let's add them back into the entity var seasonExists = existingContent.Seasons.Where(x => x.SeasonKey == season.SeasonKey);
existingContent.Seasons.AddRange(seasonDifference);
await Repo.Update(existingContent); if (seasonExists != null)
{
// We already have this season
continue; continue;
} }
else else
{ {
// No changes, no need to do anything existingContent.Seasons.Add(season);
continue; itemAdded = true;
} }
} }
if (itemAdded) await Repo.Update(existingContent);
}
else
{
// Get the show metadata... This sucks since the `metadata` var contains all information about the show // Get the show metadata... This sucks since the `metadata` var contains all information about the show
// But it does not contain the `guid` property that we need to pull out thetvdb id... // But it does not contain the `guid` property that we need to pull out thetvdb id...
var showMetadata = await PlexApi.GetMetadata(servers.PlexAuthToken, servers.FullUri, var showMetadata = await PlexApi.GetMetadata(servers.PlexAuthToken, servers.FullUri,
metadata.ratingKey); show.ratingKey);
var item = new PlexContent var item = new PlexContent
{ {
AddedAt = DateTime.Now, AddedAt = DateTime.Now,
Key = metadata.ratingKey, Key = show.ratingKey,
ProviderId = PlexHelper.GetProviderIdFromPlexGuid(showMetadata.MediaContainer.Metadata ProviderId = PlexHelper.GetProviderIdFromPlexGuid(showMetadata.MediaContainer.Metadata
.FirstOrDefault() .FirstOrDefault()
.guid), .guid),
ReleaseYear = metadata.year.ToString(), ReleaseYear = show.year.ToString(),
Type = PlexMediaTypeEntity.Show, Type = PlexMediaTypeEntity.Show,
Title = metadata.title, Title = show.title,
Url = PlexHelper.GetPlexMediaUrl(servers.MachineIdentifier, metadata.ratingKey), Url = PlexHelper.GetPlexMediaUrl(servers.MachineIdentifier, show.ratingKey),
Seasons = new List<SeasonsContent>() Seasons = new List<SeasonsContent>()
}; };
item.Seasons.ToList().AddRange(seasonsContent);
item.Seasons.AddRange(seasonsContent); contentToAdd.Add(item);
}
}
}
if (content.viewGroup.Equals(PlexMediaType.Movie.ToString(), StringComparison.CurrentCultureIgnoreCase))
{
foreach (var movie in content.Metadata)
{
// Let's check if we have this movie
var existing = await Repo.GetByKey(movie.ratingKey);
if(existing != null)
{
continue;
}
var metaData = await PlexApi.GetMetadata(servers.PlexAuthToken, servers.FullUri,
movie.ratingKey);
var item = new PlexContent
{
AddedAt = DateTime.Now,
Key = movie.ratingKey,
ProviderId = PlexHelper.GetProviderIdFromPlexGuid(metaData.MediaContainer.Metadata
.FirstOrDefault()
.guid),
ReleaseYear = movie.year.ToString(),
Type = PlexMediaTypeEntity.Movie,
Title = movie.title,
Url = PlexHelper.GetPlexMediaUrl(servers.MachineIdentifier, movie.ratingKey),
Seasons = new List<SeasonsContent>()
};
contentToAdd.Add(item); contentToAdd.Add(item);
} }
@ -196,7 +232,8 @@ namespace Ombi.Schedule.Jobs
if (contentToAdd.Any()) if (contentToAdd.Any())
{ {
await Repo.AddRange(contentToAdd);
contentToAdd.ForEach(async x => await Repo.Add(x));
} }
} }

View file

@ -15,8 +15,7 @@ namespace Ombi.Store.Context
DbSet<GlobalSettings> Settings { get; set; } DbSet<GlobalSettings> Settings { get; set; }
DbSet<PlexContent> PlexContent { get; set; } DbSet<PlexContent> PlexContent { get; set; }
DbSet<User> Users { get; set; } DbSet<User> Users { get; set; }
EntityEntry<GlobalSettings> Entry(GlobalSettings settings); EntityEntry<T> Entry<T>(T entry) where T : class;
EntityEntry<User> Entry(User settings);
EntityEntry<TEntity> Attach<TEntity>(TEntity entity) where TEntity : class; EntityEntry<TEntity> Attach<TEntity>(TEntity entity) where TEntity : class;
} }
} }

View file

@ -37,14 +37,9 @@ namespace Ombi.Store.Context
public DbSet<PlexContent> PlexContent { get; set; } public DbSet<PlexContent> PlexContent { get; set; }
public EntityEntry<GlobalSettings> Entry(GlobalSettings settings) public EntityEntry<T> Entry<T>(T entry) where T : class
{ {
return base.Entry(settings); return base.Entry(entry);
}
public EntityEntry<User> Entry(User settings)
{
return base.Entry(settings);
} }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)

View file

@ -44,7 +44,7 @@ namespace Ombi.Store.Entities
/// <summary> /// <summary>
/// Only used for TV Shows /// Only used for TV Shows
/// </summary> /// </summary>
public List<SeasonsContent> Seasons { get; set; } public virtual ICollection<SeasonsContent> Seasons { get; set; }
/// <summary> /// <summary>
/// Plex's internal ID for this item /// Plex's internal ID for this item
@ -55,6 +55,7 @@ namespace Ombi.Store.Entities
public class SeasonsContent : Entity public class SeasonsContent : Entity
{ {
public int PlexContentId { get; set; }
public int SeasonNumber { get; set; } public int SeasonNumber { get; set; }
public int SeasonKey { get; set; } public int SeasonKey { get; set; }
public int ParentKey { get; set; } public int ParentKey { get; set; }

View file

@ -50,7 +50,7 @@ namespace Ombi.Store.Repository
public async Task AddRange(IEnumerable<PlexContent> content) public async Task AddRange(IEnumerable<PlexContent> content)
{ {
await Db.PlexContent.AddRangeAsync(content); Db.PlexContent.AddRange(content);
await Db.SaveChangesAsync(); await Db.SaveChangesAsync();
} }
@ -73,7 +73,7 @@ namespace Ombi.Store.Repository
public async Task<PlexContent> GetByKey(string key) public async Task<PlexContent> GetByKey(string key)
{ {
return await Db.PlexContent.FirstOrDefaultAsync(x => x.Key == key); return await Db.PlexContent.Include(x => x.Seasons).FirstOrDefaultAsync(x => x.Key == key);
} }
public async Task Update(PlexContent existingContent) public async Task Update(PlexContent existingContent)

View file

@ -36,27 +36,37 @@ namespace Ombi.Controllers.External
if (!string.IsNullOrEmpty(result.user?.authentication_token)) if (!string.IsNullOrEmpty(result.user?.authentication_token))
{ {
var server = await PlexApi.GetServer(result.user.authentication_token); var server = await PlexApi.GetServer(result.user.authentication_token);
var servers = server.Server; var servers = server.Server.FirstOrDefault();
settings.Servers = new List<PlexServers>(); settings.Enable = true;
var serverNumber = 0; settings.Servers = new List<PlexServers> { new PlexServers{
foreach (var s in servers)
{
if (string.IsNullOrEmpty(s.LocalAddresses) || string.IsNullOrEmpty(s.Port))
{
continue;
}
settings.Servers.Add(new PlexServers
{
PlexAuthToken = result.user.authentication_token, PlexAuthToken = result.user.authentication_token,
Id = new Random().Next(), Id = new Random().Next(),
Ip = s.LocalAddresses.Split(new []{','}, StringSplitOptions.RemoveEmptyEntries).FirstOrDefault(), Ip = servers.LocalAddresses.Split(new []{','}, StringSplitOptions.RemoveEmptyEntries).FirstOrDefault(),
MachineIdentifier = s.MachineIdentifier, MachineIdentifier = servers.MachineIdentifier,
Port = int.Parse(s.Port), Port = int.Parse(servers.Port),
Ssl = s.Scheme != "http", Ssl = servers.Scheme != "http",
Name = $"Server{serverNumber++}" Name = $"Server 1",
});
} }
};
//var serverNumber = 0;
//foreach (var s in servers)
//{
// if (string.IsNullOrEmpty(s.LocalAddresses) || string.IsNullOrEmpty(s.Port))
// {
// continue;
// }
// settings.Servers.Add(new PlexServers
// {
// PlexAuthToken = result.user.authentication_token,
// Id = new Random().Next(),
// Ip = s.LocalAddresses.Split(new []{','}, StringSplitOptions.RemoveEmptyEntries).FirstOrDefault(),
// MachineIdentifier = s.MachineIdentifier,
// Port = int.Parse(s.Port),
// Ssl = s.Scheme != "http",
// Name = $"Server{serverNumber++}"
// });
//}
await PlexSettings.SaveSettingsAsync(settings); await PlexSettings.SaveSettingsAsync(settings);
} }

View file

@ -85,6 +85,7 @@
</div> </div>
</div> </div>
<div *ngIf="!result.available">
<div *ngIf="result.requested; then requestedBtn else notRequestedBtn"></div> <div *ngIf="result.requested; then requestedBtn else notRequestedBtn"></div>
<template #requestedBtn> <template #requestedBtn>
<button style="text-align: right" class="btn btn-primary-outline disabled" [disabled]><i class="fa fa-check"></i> Requested</button> <button style="text-align: right" class="btn btn-primary-outline disabled" [disabled]><i class="fa fa-check"></i> Requested</button>
@ -92,7 +93,7 @@
<template #notRequestedBtn> <template #notRequestedBtn>
<button id="{{result.id}}" style="text-align: right" class="btn btn-primary-outline" (click)="request(result)"><i class="fa fa-plus"></i> Request</button> <button id="{{result.id}}" style="text-align: right" class="btn btn-primary-outline" (click)="request(result)"><i class="fa fa-plus"></i> Request</button>
</template> </template>
</div>
<!--{{#if_eq type "tv"}} <!--{{#if_eq type "tv"}}
{{#if_eq tvFullyAvailable true}} {{#if_eq tvFullyAvailable true}}
@*//TODO Not used yet*@ @*//TODO Not used yet*@

View file

@ -7,7 +7,7 @@ import { Observable } from 'rxjs/Rx';
import { ServiceAuthHelpers } from '../service.helpers'; import { ServiceAuthHelpers } from '../service.helpers';
import { IPlexAuthentication, IPlexLibraries } from '../../interfaces/IPlex'; import { IPlexAuthentication, IPlexLibraries } from '../../interfaces/IPlex';
import { IPlexSettings } from '../../interfaces/ISettings'; import { IPlexServer } from '../../interfaces/ISettings';
@Injectable() @Injectable()
@ -20,7 +20,7 @@ export class PlexService extends ServiceAuthHelpers {
return this.regularHttp.post(`${this.url}`, JSON.stringify({ login: login, password:password}), { headers: this.headers }).map(this.extractData); return this.regularHttp.post(`${this.url}`, JSON.stringify({ login: login, password:password}), { headers: this.headers }).map(this.extractData);
} }
getLibraries(plexSettings: IPlexSettings): Observable<IPlexLibraries> { getLibraries(plexSettings: IPlexServer): Observable<IPlexLibraries> {
return this.http.post(`${this.url}Libraries`, JSON.stringify(plexSettings), { headers: this.headers }).map(this.extractData); return this.http.post(`${this.url}Libraries`, JSON.stringify(plexSettings), { headers: this.headers }).map(this.extractData);
} }

View file

@ -44,7 +44,7 @@
<div class="form-group"> <div class="form-group">
<label for="portNumber" class="control-label">Port</label> <label for="portNumber" class="control-label">Port</label>
<div> <div>
<input type="text" [(ngModel)]="settings.port" class="form-control form-control-custom " id="portNumber" name="Port" placeholder="Port Number" value="{{server.port}}"> <input type="text" [(ngModel)]="server.port" class="form-control form-control-custom " id="portNumber" name="Port" placeholder="Port Number" value="{{server.port}}">
</div> </div>
</div> </div>
@ -103,7 +103,7 @@
<label>Please select the libraries you want Ombi to look in for content</label> <label>Please select the libraries you want Ombi to look in for content</label>
<div class="form-group"> <div class="form-group">
<div> <div>
<button (click)="loadLibraries()" class="btn btn-primary-outline">Load Libraries <i class="fa fa-film"></i></button> <button (click)="loadLibraries(server)" class="btn btn-primary-outline">Load Libraries <i class="fa fa-film"></i></button>
</div> </div>
</div> </div>
<div *ngIf="server.plexSelectedLibraries"> <div *ngIf="server.plexSelectedLibraries">

View file

@ -51,7 +51,7 @@ export class PlexComponent implements OnInit {
} }
loadLibraries(server:IPlexServer) { loadLibraries(server:IPlexServer) {
this.plexService.getLibraries(this.settings).subscribe(x => { this.plexService.getLibraries(server).subscribe(x => {
server.plexSelectedLibraries = []; server.plexSelectedLibraries = [];
x.mediaContainer.directory.forEach((item, index) => { x.mediaContainer.directory.forEach((item, index) => {