mirror of
https://github.com/Ombi-app/Ombi.git
synced 2025-08-19 12:59:39 -07:00
Added Tv watchlist import
This commit is contained in:
parent
268e31c019
commit
0329c2b9d9
7 changed files with 185 additions and 20 deletions
|
@ -188,7 +188,7 @@ namespace Ombi.Core.Engine
|
||||||
(await tvBuilder
|
(await tvBuilder
|
||||||
.GetShowInfo(tv.TheMovieDbId, tv.languageCode))
|
.GetShowInfo(tv.TheMovieDbId, tv.languageCode))
|
||||||
.CreateTvList(tv)
|
.CreateTvList(tv)
|
||||||
.CreateChild(tv, canRequestOnBehalf ? tv.RequestOnBehalf : user.Id);
|
.CreateChild(tv, canRequestOnBehalf ? tv.RequestOnBehalf : user.Id, tv.Source);
|
||||||
|
|
||||||
await tvBuilder.BuildEpisodes(tv);
|
await tvBuilder.BuildEpisodes(tv);
|
||||||
|
|
||||||
|
|
|
@ -53,7 +53,7 @@ namespace Ombi.Core.Helpers
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TvShowRequestBuilderV2 CreateChild(TvRequestViewModelV2 model, string userId)
|
public TvShowRequestBuilderV2 CreateChild(TvRequestViewModelV2 model, string userId, RequestSource source)
|
||||||
{
|
{
|
||||||
var animationGenre = TheMovieDbRecord.genres?.Any(s => s.name.Equals("Animation", StringComparison.InvariantCultureIgnoreCase)) ?? false;
|
var animationGenre = TheMovieDbRecord.genres?.Any(s => s.name.Equals("Animation", StringComparison.InvariantCultureIgnoreCase)) ?? false;
|
||||||
var animeKeyword = TheMovieDbRecord.Keywords?.KeywordsValue?.Any(s => s.Name.Equals("Anime", StringComparison.InvariantCultureIgnoreCase)) ?? false;
|
var animeKeyword = TheMovieDbRecord.Keywords?.KeywordsValue?.Any(s => s.Name.Equals("Anime", StringComparison.InvariantCultureIgnoreCase)) ?? false;
|
||||||
|
@ -68,7 +68,8 @@ namespace Ombi.Core.Helpers
|
||||||
Title = TheMovieDbRecord.name,
|
Title = TheMovieDbRecord.name,
|
||||||
ReleaseYear = FirstAir,
|
ReleaseYear = FirstAir,
|
||||||
RequestedByAlias = model.RequestedByAlias,
|
RequestedByAlias = model.RequestedByAlias,
|
||||||
SeriesType = animationGenre && animeKeyword ? SeriesType.Anime : SeriesType.Standard
|
SeriesType = animationGenre && animeKeyword ? SeriesType.Anime : SeriesType.Standard,
|
||||||
|
Source = source
|
||||||
};
|
};
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
using Ombi.Store.Entities.Requests;
|
||||||
|
|
||||||
namespace Ombi.Core.Models.Requests
|
namespace Ombi.Core.Models.Requests
|
||||||
{
|
{
|
||||||
|
@ -7,5 +8,6 @@ namespace Ombi.Core.Models.Requests
|
||||||
{
|
{
|
||||||
public int TheMovieDbId { get; set; }
|
public int TheMovieDbId { get; set; }
|
||||||
public string languageCode { get; set; } = "en";
|
public string languageCode { get; set; } = "en";
|
||||||
|
public RequestSource Source { get; set; } = RequestSource.Ombi;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -136,6 +136,54 @@ namespace Ombi.Schedule.Tests
|
||||||
_mocker.Verify<IMovieRequestEngine>(x => x.SetUser(It.Is<OmbiUser>(x => x.Id == "abc")), Times.Once);
|
_mocker.Verify<IMovieRequestEngine>(x => x.SetUser(It.Is<OmbiUser>(x => x.Id == "abc")), Times.Once);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task TvRequestFromWatchList_NoGuid()
|
||||||
|
{
|
||||||
|
_mocker.Setup<ISettingsService<PlexSettings>, Task<PlexSettings>>(x => x.GetSettingsAsync()).ReturnsAsync(new PlexSettings { Enable = true, EnableWatchlistImport = true });
|
||||||
|
_mocker.Setup<IPlexApi, Task<PlexWatchlistContainer>>(x => x.GetWatchlist(It.IsAny<string>(), It.IsAny<CancellationToken>())).ReturnsAsync(new PlexWatchlistContainer
|
||||||
|
{
|
||||||
|
MediaContainer = new PlexWatchlist
|
||||||
|
{
|
||||||
|
Metadata = new List<Metadata>
|
||||||
|
{
|
||||||
|
new Metadata
|
||||||
|
{
|
||||||
|
type = "show",
|
||||||
|
ratingKey = "abc"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
_mocker.Setup<IPlexApi, Task<PlexWatchlistMetadataContainer>>(x => x.GetWatchlistMetadata("abc", It.IsAny<string>(), It.IsAny<CancellationToken>()))
|
||||||
|
.ReturnsAsync(new PlexWatchlistMetadataContainer
|
||||||
|
{
|
||||||
|
MediaContainer = new PlexWatchlistMetadata
|
||||||
|
{
|
||||||
|
Metadata = new WatchlistMetadata[]
|
||||||
|
{
|
||||||
|
new WatchlistMetadata
|
||||||
|
{
|
||||||
|
Guid = new List<PlexGuids>
|
||||||
|
{
|
||||||
|
new PlexGuids
|
||||||
|
{
|
||||||
|
Id = "tmdb://123"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
_mocker.Setup<ITvRequestEngine, Task<RequestEngineResult>>(x => x.RequestTvShow(It.IsAny<TvRequestViewModelV2>()))
|
||||||
|
.ReturnsAsync(new RequestEngineResult { RequestId = 1 });
|
||||||
|
await _subject.Execute(_context.Object);
|
||||||
|
_mocker.Verify<ITvRequestEngine>(x => x.RequestTvShow(It.Is<TvRequestViewModelV2>(x => x.TheMovieDbId == 123)), Times.Once);
|
||||||
|
_mocker.Verify<IPlexApi>(x => x.GetWatchlistMetadata("abc", It.IsAny<string>(), It.IsAny<CancellationToken>()), Times.Once);
|
||||||
|
_mocker.Verify<ITvRequestEngine>(x => x.SetUser(It.Is<OmbiUser>(x => x.Id == "abc")), Times.Once);
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public async Task MovieRequestFromWatchList_AlreadyRequested()
|
public async Task MovieRequestFromWatchList_AlreadyRequested()
|
||||||
{
|
{
|
||||||
|
@ -183,6 +231,53 @@ namespace Ombi.Schedule.Tests
|
||||||
_mocker.Verify<IMovieRequestEngine>(x => x.SetUser(It.Is<OmbiUser>(x => x.Id == "abc")), Times.Once);
|
_mocker.Verify<IMovieRequestEngine>(x => x.SetUser(It.Is<OmbiUser>(x => x.Id == "abc")), Times.Once);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task TvRequestFromWatchList_AlreadyRequested()
|
||||||
|
{
|
||||||
|
_mocker.Setup<ISettingsService<PlexSettings>, Task<PlexSettings>>(x => x.GetSettingsAsync()).ReturnsAsync(new PlexSettings { Enable = true, EnableWatchlistImport = true });
|
||||||
|
_mocker.Setup<IPlexApi, Task<PlexWatchlistContainer>>(x => x.GetWatchlist(It.IsAny<string>(), It.IsAny<CancellationToken>())).ReturnsAsync(new PlexWatchlistContainer
|
||||||
|
{
|
||||||
|
MediaContainer = new PlexWatchlist
|
||||||
|
{
|
||||||
|
Metadata = new List<Metadata>
|
||||||
|
{
|
||||||
|
new Metadata
|
||||||
|
{
|
||||||
|
type = "show",
|
||||||
|
ratingKey = "abc"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
_mocker.Setup<IPlexApi, Task<PlexWatchlistMetadataContainer>>(x => x.GetWatchlistMetadata("abc", It.IsAny<string>(), It.IsAny<CancellationToken>()))
|
||||||
|
.ReturnsAsync(new PlexWatchlistMetadataContainer
|
||||||
|
{
|
||||||
|
MediaContainer = new PlexWatchlistMetadata
|
||||||
|
{
|
||||||
|
Metadata = new WatchlistMetadata[]
|
||||||
|
{
|
||||||
|
new WatchlistMetadata
|
||||||
|
{
|
||||||
|
Guid = new List<PlexGuids>
|
||||||
|
{
|
||||||
|
new PlexGuids
|
||||||
|
{
|
||||||
|
Id = "tmdb://123"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
_mocker.Setup<ITvRequestEngine, Task<RequestEngineResult>>(x => x.RequestTvShow(It.IsAny<TvRequestViewModelV2>()))
|
||||||
|
.ReturnsAsync(new RequestEngineResult { ErrorCode = ErrorCode.AlreadyRequested, ErrorMessage = "Requested" });
|
||||||
|
await _subject.Execute(_context.Object);
|
||||||
|
_mocker.Verify<ITvRequestEngine>(x => x.RequestTvShow(It.Is<TvRequestViewModelV2>(x => x.TheMovieDbId == 123)), Times.Once);
|
||||||
|
_mocker.Verify<IPlexApi>(x => x.GetWatchlistMetadata("abc", It.IsAny<string>(), It.IsAny<CancellationToken>()), Times.Once);
|
||||||
|
_mocker.Verify<ITvRequestEngine>(x => x.SetUser(It.Is<OmbiUser>(x => x.Id == "abc")), Times.Once);
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public async Task MovieRequestFromWatchList_NoTmdbGuid()
|
public async Task MovieRequestFromWatchList_NoTmdbGuid()
|
||||||
{
|
{
|
||||||
|
@ -229,5 +324,52 @@ namespace Ombi.Schedule.Tests
|
||||||
_mocker.Verify<IPlexApi>(x => x.GetWatchlistMetadata("abc", It.IsAny<string>(), It.IsAny<CancellationToken>()), Times.Once);
|
_mocker.Verify<IPlexApi>(x => x.GetWatchlistMetadata("abc", It.IsAny<string>(), It.IsAny<CancellationToken>()), Times.Once);
|
||||||
_mocker.Verify<IMovieRequestEngine>(x => x.SetUser(It.Is<OmbiUser>(x => x.Id == "abc")), Times.Never);
|
_mocker.Verify<IMovieRequestEngine>(x => x.SetUser(It.Is<OmbiUser>(x => x.Id == "abc")), Times.Never);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task TvRequestFromWatchList_NoTmdbGuid()
|
||||||
|
{
|
||||||
|
_mocker.Setup<ISettingsService<PlexSettings>, Task<PlexSettings>>(x => x.GetSettingsAsync()).ReturnsAsync(new PlexSettings { Enable = true, EnableWatchlistImport = true });
|
||||||
|
_mocker.Setup<IPlexApi, Task<PlexWatchlistContainer>>(x => x.GetWatchlist(It.IsAny<string>(), It.IsAny<CancellationToken>())).ReturnsAsync(new PlexWatchlistContainer
|
||||||
|
{
|
||||||
|
MediaContainer = new PlexWatchlist
|
||||||
|
{
|
||||||
|
Metadata = new List<Metadata>
|
||||||
|
{
|
||||||
|
new Metadata
|
||||||
|
{
|
||||||
|
type = "movie",
|
||||||
|
ratingKey = "abc"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
_mocker.Setup<IPlexApi, Task<PlexWatchlistMetadataContainer>>(x => x.GetWatchlistMetadata("abc", It.IsAny<string>(), It.IsAny<CancellationToken>()))
|
||||||
|
.ReturnsAsync(new PlexWatchlistMetadataContainer
|
||||||
|
{
|
||||||
|
MediaContainer = new PlexWatchlistMetadata
|
||||||
|
{
|
||||||
|
Metadata = new WatchlistMetadata[]
|
||||||
|
{
|
||||||
|
new WatchlistMetadata
|
||||||
|
{
|
||||||
|
Guid = new List<PlexGuids>
|
||||||
|
{
|
||||||
|
new PlexGuids
|
||||||
|
{
|
||||||
|
Id = "imdb://123"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
_mocker.Setup<ITvRequestEngine, Task<RequestEngineResult>>(x => x.RequestTvShow(It.IsAny<TvRequestViewModelV2>()))
|
||||||
|
.ReturnsAsync(new RequestEngineResult { RequestId = 1 });
|
||||||
|
await _subject.Execute(_context.Object);
|
||||||
|
_mocker.Verify<ITvRequestEngine>(x => x.RequestTvShow(It.IsAny<TvRequestViewModelV2>()), Times.Never);
|
||||||
|
_mocker.Verify<IPlexApi>(x => x.GetWatchlistMetadata("abc", It.IsAny<string>(), It.IsAny<CancellationToken>()), Times.Once);
|
||||||
|
_mocker.Verify<ITvRequestEngine>(x => x.SetUser(It.Is<OmbiUser>(x => x.Id == "abc")), Times.Never);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ using Ombi.Api.Plex.Models;
|
||||||
using Ombi.Core.Authentication;
|
using Ombi.Core.Authentication;
|
||||||
using Ombi.Core.Engine;
|
using Ombi.Core.Engine;
|
||||||
using Ombi.Core.Engine.Interfaces;
|
using Ombi.Core.Engine.Interfaces;
|
||||||
|
using Ombi.Core.Models.Requests;
|
||||||
using Ombi.Core.Settings;
|
using Ombi.Core.Settings;
|
||||||
using Ombi.Core.Settings.Models.External;
|
using Ombi.Core.Settings.Models.External;
|
||||||
using Ombi.Helpers;
|
using Ombi.Helpers;
|
||||||
|
@ -23,16 +24,18 @@ namespace Ombi.Schedule.Jobs.Plex
|
||||||
private readonly ISettingsService<PlexSettings> _settings;
|
private readonly ISettingsService<PlexSettings> _settings;
|
||||||
private readonly OmbiUserManager _ombiUserManager;
|
private readonly OmbiUserManager _ombiUserManager;
|
||||||
private readonly IMovieRequestEngine _movieRequestEngine;
|
private readonly IMovieRequestEngine _movieRequestEngine;
|
||||||
|
private readonly ITvRequestEngine _tvRequestEngine;
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
|
|
||||||
public PlexWatchlistImport(IPlexApi plexApi, ISettingsService<PlexSettings> settings, OmbiUserManager ombiUserManager,
|
public PlexWatchlistImport(IPlexApi plexApi, ISettingsService<PlexSettings> settings, OmbiUserManager ombiUserManager,
|
||||||
IMovieRequestEngine movieRequestEngine,
|
IMovieRequestEngine movieRequestEngine, ITvRequestEngine tvRequestEngine,
|
||||||
ILogger<PlexWatchlistImport> logger)
|
ILogger<PlexWatchlistImport> logger)
|
||||||
{
|
{
|
||||||
_plexApi = plexApi;
|
_plexApi = plexApi;
|
||||||
_settings = settings;
|
_settings = settings;
|
||||||
_ombiUserManager = ombiUserManager;
|
_ombiUserManager = ombiUserManager;
|
||||||
_movieRequestEngine = movieRequestEngine;
|
_movieRequestEngine = movieRequestEngine;
|
||||||
|
_tvRequestEngine = tvRequestEngine;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,29 +59,48 @@ namespace Ombi.Schedule.Jobs.Plex
|
||||||
var items = watchlist.MediaContainer.Metadata;
|
var items = watchlist.MediaContainer.Metadata;
|
||||||
foreach (var item in items)
|
foreach (var item in items)
|
||||||
{
|
{
|
||||||
|
var providerIds = await GetProviderIds(user.MediaServerToken, item, context?.CancellationToken ?? CancellationToken.None);
|
||||||
|
if (!providerIds.TheMovieDb.HasValue())
|
||||||
|
{
|
||||||
|
// We need a MovieDbId to support this;
|
||||||
|
return;
|
||||||
|
}
|
||||||
switch (item.type)
|
switch (item.type)
|
||||||
{
|
{
|
||||||
case "show":
|
case "show":
|
||||||
await ProcessShow(item);
|
await ProcessShow(int.Parse(providerIds.TheMovieDb), user, context?.CancellationToken ?? CancellationToken.None);
|
||||||
break;
|
break;
|
||||||
case "movie":
|
case "movie":
|
||||||
await ProcessMovie(user.MediaServerToken, item, user, context?.CancellationToken ?? CancellationToken.None);
|
await ProcessMovie(int.Parse(providerIds.TheMovieDb), user, context?.CancellationToken ?? CancellationToken.None);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task ProcessMovie(string authToken, Metadata movie, OmbiUser user, CancellationToken cancellationToken)
|
private async Task ProcessMovie(int theMovieDbId, OmbiUser user, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var providerIds = await GetProviderIds(authToken, movie, cancellationToken);
|
|
||||||
if (!providerIds.TheMovieDb.HasValue())
|
|
||||||
{
|
|
||||||
// We need a MovieDbId to support this;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_movieRequestEngine.SetUser(user);
|
_movieRequestEngine.SetUser(user);
|
||||||
var response = await _movieRequestEngine.RequestMovie(new() { TheMovieDbId = int.Parse(providerIds.TheMovieDb), Source = RequestSource.PlexWatchlist});
|
var response = await _movieRequestEngine.RequestMovie(new() { TheMovieDbId = theMovieDbId, Source = RequestSource.PlexWatchlist});
|
||||||
|
if (response.IsError)
|
||||||
|
{
|
||||||
|
if (response.ErrorCode == ErrorCode.AlreadyRequested)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_logger.LogInformation($"Error adding title from PlexWatchlist for user '{user.UserName}'. Message: '{response.ErrorMessage}'");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.LogInformation($"Added title from PlexWatchlist for user '{user.UserName}'. {response.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private async Task ProcessShow(int theMovieDbId, OmbiUser user, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
_tvRequestEngine.SetUser(user);
|
||||||
|
var response = await _tvRequestEngine.RequestTvShow(new TvRequestViewModelV2 { RequestAll = true, TheMovieDbId = theMovieDbId, Source = RequestSource.PlexWatchlist });
|
||||||
if (response.IsError)
|
if (response.IsError)
|
||||||
{
|
{
|
||||||
if (response.ErrorCode == ErrorCode.AlreadyRequested)
|
if (response.ErrorCode == ErrorCode.AlreadyRequested)
|
||||||
|
@ -122,11 +144,6 @@ namespace Ombi.Schedule.Jobs.Plex
|
||||||
return providerIds;
|
return providerIds;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task ProcessShow(Metadata metadata)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose() { }
|
public void Dispose() { }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
user: request.requestedUser.userAlias,
|
user: request.requestedUser.userAlias,
|
||||||
date: request.requestedDate | amLocal | amUserLocale | amDateFormat: 'LL' } }}
|
date: request.requestedDate | amLocal | amUserLocale | amDateFormat: 'LL' } }}
|
||||||
<span *ngIf="request.denied"> - {{request.deniedReason}}</span>
|
<span *ngIf="request.denied"> - {{request.deniedReason}}</span>
|
||||||
|
<span *ngIf="request.source !== RequestSource.Ombi">{{'MediaDetails.RequestSource' | translate }} {{RequestSource[request.source]}}</span>
|
||||||
</mat-panel-description>
|
</mat-panel-description>
|
||||||
</mat-expansion-panel-header>
|
</mat-expansion-panel-header>
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { Component, Input } from "@angular/core";
|
import { Component, Input } from "@angular/core";
|
||||||
import { IChildRequests, RequestType } from "../../../../../interfaces";
|
import { IChildRequests, RequestSource, RequestType } from "../../../../../interfaces";
|
||||||
|
|
||||||
import { DenyDialogComponent } from "../../../shared/deny-dialog/deny-dialog.component";
|
import { DenyDialogComponent } from "../../../shared/deny-dialog/deny-dialog.component";
|
||||||
import { MatDialog } from "@angular/material/dialog";
|
import { MatDialog } from "@angular/material/dialog";
|
||||||
|
@ -17,6 +17,8 @@ export class TvRequestsPanelComponent {
|
||||||
@Input() public isAdmin: boolean;
|
@Input() public isAdmin: boolean;
|
||||||
@Input() public manageOwnRequests: boolean;
|
@Input() public manageOwnRequests: boolean;
|
||||||
|
|
||||||
|
public RequestSource = RequestSource;
|
||||||
|
|
||||||
public displayedColumns: string[] = ['number', 'title', 'airDate', 'status'];
|
public displayedColumns: string[] = ['number', 'title', 'airDate', 'status'];
|
||||||
|
|
||||||
constructor(private requestService: RequestService,
|
constructor(private requestService: RequestService,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue