1
0
mirror of https://github.com/Radarr/Radarr.git synced 2024-11-20 01:42:35 +01:00

New: Update matching movie path in Jellyfin/Emby library

(cherry picked from commit ad0dc01cf7ed16ccfa8260717111ad8a44675221)

Closes #8898
This commit is contained in:
Jendrik Weise 2023-07-29 03:40:30 +02:00 committed by Bogdan
parent 358ff0c130
commit a1104b8263
5 changed files with 143 additions and 10 deletions

View File

@ -35,7 +35,7 @@ public override void OnDownload(DownloadMessage message)
if (Settings.UpdateLibrary) if (Settings.UpdateLibrary)
{ {
_mediaBrowserService.UpdateMovies(Settings, message.Movie, "Created"); _mediaBrowserService.Update(Settings, message.Movie, "Created");
} }
} }
@ -43,7 +43,7 @@ public override void OnMovieRename(Movie movie, List<RenamedMovieFile> renamedFi
{ {
if (Settings.UpdateLibrary) if (Settings.UpdateLibrary)
{ {
_mediaBrowserService.UpdateMovies(Settings, movie, "Modified"); _mediaBrowserService.Update(Settings, movie, "Modified");
} }
} }
@ -82,7 +82,7 @@ public override void OnMovieDelete(MovieDeleteMessage deleteMessage)
if (Settings.UpdateLibrary) if (Settings.UpdateLibrary)
{ {
_mediaBrowserService.UpdateMovies(Settings, deleteMessage.Movie, "Deleted"); _mediaBrowserService.Update(Settings, deleteMessage.Movie, "Deleted");
} }
} }
} }
@ -96,7 +96,7 @@ public override void OnMovieFileDelete(MovieFileDeleteMessage deleteMessage)
if (Settings.UpdateLibrary) if (Settings.UpdateLibrary)
{ {
_mediaBrowserService.UpdateMovies(Settings, deleteMessage.Movie, "Deleted"); _mediaBrowserService.Update(Settings, deleteMessage.Movie, "Deleted");
} }
} }

View File

@ -0,0 +1,30 @@
using System.Collections.Generic;
namespace NzbDrone.Core.Notifications.Emby
{
public class MediaBrowserItems
{
public List<MediaBrowserItem> Items { get; set; }
}
public class MediaBrowserItem
{
public string Name { get; set; }
public string Path { get; set; }
public MediaBrowserProviderIds ProviderIds { get; set; }
}
public class MediaBrowserProviderIds
{
public string Imdb { get; set; }
public int Tmdb { get; set; }
}
public enum MediaBrowserMatchQuality
{
Id = 0,
Name = 1,
None = 2
}
}

View File

@ -1,6 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using NLog; using NLog;
using NzbDrone.Common.Http; using NzbDrone.Common.Http;
using NzbDrone.Common.Serializer; using NzbDrone.Common.Serializer;
using NzbDrone.Core.Movies;
namespace NzbDrone.Core.Notifications.Emby namespace NzbDrone.Core.Notifications.Emby
{ {
@ -31,7 +35,62 @@ public void Notify(MediaBrowserSettings settings, string title, string message)
ProcessRequest(request, settings); ProcessRequest(request, settings);
} }
public void UpdateMovies(MediaBrowserSettings settings, string moviePath, string updateType) public HashSet<string> GetPaths(MediaBrowserSettings settings, Movie movie)
{
var path = "/Items";
var url = GetUrl(settings);
// NameStartsWith uses the sort title, which is not the movie title
var request = new HttpRequestBuilder(url)
.Resource(path)
.AddQueryParam("recursive", "true")
.AddQueryParam("includeItemTypes", "Movie")
.AddQueryParam("fields", "Path,ProviderIds")
.AddQueryParam("years", movie.Year)
.Build();
try
{
var paths = ProcessGetRequest<MediaBrowserItems>(request, settings).Items.GroupBy(item =>
{
if (item is { ProviderIds.Tmdb: int tmdbid } && tmdbid != 0 && tmdbid == movie.TmdbId)
{
return MediaBrowserMatchQuality.Id;
}
if (item is { ProviderIds.Imdb: string imdbid } && imdbid == movie.ImdbId)
{
return MediaBrowserMatchQuality.Id;
}
if (item is { Name: var name } && name == movie.Title)
{
return MediaBrowserMatchQuality.Name;
}
return MediaBrowserMatchQuality.None;
}, item => item.Path).OrderBy(group => (int)group.Key).First();
if (paths.Key == MediaBrowserMatchQuality.None)
{
_logger.Trace("Could not find movie by name");
return new HashSet<string>();
}
_logger.Trace("Found movie by name/id: {0}", string.Join(" ", paths));
return paths.ToHashSet();
}
catch (InvalidOperationException)
{
_logger.Trace("Could not find movie by name.");
return new HashSet<string>();
}
}
public void Update(MediaBrowserSettings settings, string moviePath, string updateType)
{ {
var path = "/Library/Media/Updated"; var path = "/Library/Media/Updated";
var request = BuildRequest(path, settings); var request = BuildRequest(path, settings);
@ -52,6 +111,19 @@ public void UpdateMovies(MediaBrowserSettings settings, string moviePath, string
ProcessRequest(request, settings); ProcessRequest(request, settings);
} }
private T ProcessGetRequest<T>(HttpRequest request, MediaBrowserSettings settings)
where T : new()
{
request.Headers.Add("X-MediaBrowser-Token", settings.ApiKey);
var response = _httpClient.Get<T>(request);
_logger.Trace("Response: {0}", response.Content);
CheckForError(response);
return response.Resource;
}
private string ProcessRequest(HttpRequest request, MediaBrowserSettings settings) private string ProcessRequest(HttpRequest request, MediaBrowserSettings settings)
{ {
request.Headers.Add("X-MediaBrowser-Token", settings.ApiKey); request.Headers.Add("X-MediaBrowser-Token", settings.ApiKey);
@ -64,10 +136,15 @@ private string ProcessRequest(HttpRequest request, MediaBrowserSettings settings
return response.Content; return response.Content;
} }
private HttpRequest BuildRequest(string path, MediaBrowserSettings settings) private string GetUrl(MediaBrowserSettings settings)
{ {
var scheme = settings.UseSsl ? "https" : "http"; var scheme = settings.UseSsl ? "https" : "http";
var url = $@"{scheme}://{settings.Address}/mediabrowser"; return $@"{scheme}://{settings.Address}";
}
private HttpRequest BuildRequest(string path, MediaBrowserSettings settings)
{
var url = GetUrl(settings);
return new HttpRequestBuilder(url).Resource(path).Build(); return new HttpRequestBuilder(url).Resource(path).Build();
} }

View File

@ -3,6 +3,8 @@
using System.Net; using System.Net;
using FluentValidation.Results; using FluentValidation.Results;
using NLog; using NLog;
using NzbDrone.Common.Disk;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http; using NzbDrone.Common.Http;
using NzbDrone.Core.Localization; using NzbDrone.Core.Localization;
using NzbDrone.Core.Movies; using NzbDrone.Core.Movies;
@ -12,7 +14,7 @@ namespace NzbDrone.Core.Notifications.Emby
public interface IMediaBrowserService public interface IMediaBrowserService
{ {
void Notify(MediaBrowserSettings settings, string title, string message); void Notify(MediaBrowserSettings settings, string title, string message);
void UpdateMovies(MediaBrowserSettings settings, Movie movie, string updateType); void Update(MediaBrowserSettings settings, Movie movie, string updateType);
ValidationFailure Test(MediaBrowserSettings settings); ValidationFailure Test(MediaBrowserSettings settings);
} }
@ -34,9 +36,23 @@ public void Notify(MediaBrowserSettings settings, string title, string message)
_proxy.Notify(settings, title, message); _proxy.Notify(settings, title, message);
} }
public void UpdateMovies(MediaBrowserSettings settings, Movie movie, string updateType) public void Update(MediaBrowserSettings settings, Movie movie, string updateType)
{ {
_proxy.UpdateMovies(settings, movie.Path, updateType); var paths = _proxy.GetPaths(settings, movie);
var mappedPath = new OsPath(movie.Path);
if (settings.MapTo.IsNotNullOrWhiteSpace())
{
mappedPath = new OsPath(settings.MapTo) + (mappedPath - new OsPath(settings.MapFrom));
}
paths.Add(mappedPath.ToString());
foreach (var path in paths)
{
_proxy.Update(settings, path, updateType);
}
} }
public ValidationFailure Test(MediaBrowserSettings settings) public ValidationFailure Test(MediaBrowserSettings settings)

View File

@ -13,6 +13,8 @@ public MediaBrowserSettingsValidator()
RuleFor(c => c.Host).ValidHost(); RuleFor(c => c.Host).ValidHost();
RuleFor(c => c.ApiKey).NotEmpty(); RuleFor(c => c.ApiKey).NotEmpty();
RuleFor(c => c.UrlBase).ValidUrlBase(); RuleFor(c => c.UrlBase).ValidUrlBase();
RuleFor(c => c.MapFrom).NotEmpty().Unless(c => c.MapTo.IsNullOrWhiteSpace());
RuleFor(c => c.MapTo).NotEmpty().Unless(c => c.MapFrom.IsNullOrWhiteSpace());
} }
} }
@ -49,6 +51,14 @@ public MediaBrowserSettings()
[FieldDefinition(6, Label = "NotificationsSettingsUpdateLibrary", HelpText = "NotificationsEmbySettingsUpdateLibraryHelpText", Type = FieldType.Checkbox)] [FieldDefinition(6, Label = "NotificationsSettingsUpdateLibrary", HelpText = "NotificationsEmbySettingsUpdateLibraryHelpText", Type = FieldType.Checkbox)]
public bool UpdateLibrary { get; set; } public bool UpdateLibrary { get; set; }
[FieldDefinition(7, Label = "NotificationsSettingsUpdateMapPathsFrom", HelpText = "NotificationsSettingsUpdateMapPathsFromHelpText", Type = FieldType.Textbox, Advanced = true)]
[FieldToken(TokenField.HelpText, "NotificationsSettingsUpdateMapPathsFrom", "serviceName", "Emby/Jellyfin")]
public string MapFrom { get; set; }
[FieldDefinition(8, Label = "NotificationsSettingsUpdateMapPathsTo", HelpText = "NotificationsSettingsUpdateMapPathsToHelpText", Type = FieldType.Textbox, Advanced = true)]
[FieldToken(TokenField.HelpText, "NotificationsSettingsUpdateMapPathsTo", "serviceName", "Emby/Jellyfin")]
public string MapTo { get; set; }
[JsonIgnore] [JsonIgnore]
public string Address => $"{Host.ToUrlHost()}:{Port}{UrlBase}"; public string Address => $"{Host.ToUrlHost()}:{Port}{UrlBase}";