/// <returns>The index of the last image, or -1 if there are no images of imageType, or null otherwise.</returns> public async Task <int?> GetMaxImageIndex(ImageType imageType, IMovieIdentifier movieIdentifier) { await SemSlim.WaitAsync(); try { Logger.Log(Severity.Info, $"Querying the index of last {imageType} image."); var imageInfos = await Repository.GetImageInfosAsync(Client, movieIdentifier.Id); var imageInfosOfType = imageInfos .Where(x => x.ImageType == imageType) .ToArray(); if (imageInfosOfType.Any() == false) { return(-1); } return(imageInfosOfType .Select(x => x.ImageIndex ?? 0) .Max()); } catch (Exception ex) { LogException(ex, $"Failed to query the index of last {imageType} image:"); return(null); } finally { SemSlim.Release(); } }
public async Task <bool> TryAddImageToMovieAsync(ImageType imageType, Uri imageUrl, IMovieIdentifier movieIdentifier) { await SemSlim.WaitAsync(); if (imageUrl == null) { Logger.Log(Severity.Warn, $"No {imageType} image available."); return(true); } try { Logger.Log(Severity.Info, $"Adding {imageType} image."); await Repository.AddImageToMovieAsync(Client, imageType, imageUrl, movieIdentifier.Id); return(true); } catch (Exception ex) { LogException(ex, $"Failed to add {imageType} image:"); return(false); } finally { SemSlim.Release(); } }
public async Task <string> GetMovieDetailsAsync(IMovieIdentifier movieIdentifier, IWebProxy proxy) { string baseUrl = _configurationValues.ApiBaseUrl; string apiKey = _configurationValues.ApiKey; string url = baseUrl + string.Format(Endpoints.GetMovieByMovieId, movieIdentifier.Id); Dictionary <string, string> queryParams = new Dictionary <string, string> { { "api_key", apiKey }, }; string queryString = "?"; foreach (var param in queryParams) { if (queryString.Length > 1) { queryString += "&"; } queryString += $"{WebUtility.UrlEncode(param.Key)}={WebUtility.UrlEncode(param.Value)}"; } url += queryString; string json = await _httpDownloader.GetStringAsync(url, new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase) { { "Content-Type", "application/json" } }, proxy); return(json); }
private async Task <bool> AddMovieToCollectionsAsync(IReadOnlyCollection <ICollectionIdentifier> allCollections, IMovieIdentifier embyMovieIdentifier) { var addMovieToCollectionsTasks = allCollections .Select(x => _collectionService.TryAddMovieToCollectionAsync(embyMovieIdentifier, x)); var addMovieToCollectionsResults = await Task.WhenAll(addMovieToCollectionsTasks); return(addMovieToCollectionsResults.All(x => x)); }
public virtual async Task <Movie> GetMovieDetailsAsync(IMovieIdentifier movieIdentifier, IWebProxy proxy) { string json = await _apiDownloader.GetMovieDetailsAsync(movieIdentifier, proxy); var movieResponse = Deserialize <Models.Movie>(json); Movie movie = Adapt(movieResponse); return(movie); }
public async Task <bool> RunAsync(IPlexMovieMetadata plexMovieMetadata, IMovieIdentifier embyMovieIdentifier) { var importableImages = new[] { new ImportableImage { SourceUri = plexMovieMetadata.ThumbUri, ImageType = ImageType.Primary }, new ImportableImage { SourceUri = plexMovieMetadata.ArtUri, ImageType = ImageType.Backdrop }, }; return(await AddImagesToMovieWithDelete(importableImages, embyMovieIdentifier)); }
public async Task <bool> UpdateWatchedStatusAsync(IPlexMovieMetadata plexMovieMetadata, IMovieIdentifier movieIdentifier) { await SemSlim.WaitAsync(); try { Logger.Log(Severity.Info, "Determining Watched/Unwatched status."); var playCount = plexMovieMetadata.ViewCount ?? 0; var lastPlayedDate = plexMovieMetadata.LastViewedAt == null ? default(DateTime?) : new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc) .AddSeconds(Convert.ToDouble(plexMovieMetadata.LastViewedAt)); Logger.Log(Severity.Info, "Setting as 'Unwatched'."); await Repository.SetMovieAsUnwatchedAsync(Client, movieIdentifier.Id); if (playCount > 0) { if (lastPlayedDate == null) { throw new Exception("LastPlayedDate is null and PlayCount greater than 0."); } Logger.Log(Severity.Info, $"Setting as 'Watched' with playcount '{playCount}'."); for (var i = 0; i < playCount; i++) { await Repository.SetMovieAsWatchedAsync(Client, lastPlayedDate.Value, movieIdentifier.Id); } } return(true); } catch (Exception ex) { LogException(ex, "Failed to update Watched/Unwatched:"); return(false); } finally { SemSlim.Release(); } }
public async Task <bool> RunAsync(IPlexMovieMetadata plexMovieMetadata, IMovieIdentifier embyMovieIdentifier) { var retval = true; await SemSlim.WaitAsync(); try { _logger.Log(Severity.Info, $"Processing '{plexMovieMetadata.Title}'"); // Add movie to all collections (create if necessary). var embyImportMovieCollectionsLogic = _logicFactory.CreateLogic <IEmbyImportMovieCollectionsLogic>(); if (await embyImportMovieCollectionsLogic.RunAsync(plexMovieMetadata.Collections, embyMovieIdentifier) == false) { var msg = $"Failed to update Emby collections for '{plexMovieMetadata.Title}'."; _logger.Log(Severity.Warn, msg); retval = false; } // Add images to movie. var embyImportMovieImagesLogic = _logicFactory.CreateLogic <IEmbyImportMovieImagesLogic>(); if (await embyImportMovieImagesLogic.RunAsync(plexMovieMetadata, embyMovieIdentifier) == false) { _logger.Log(Severity.Warn, $"One or more images could not be properly added to '{plexMovieMetadata.Title}'."); retval = false; } // Update movie metadata. var embyImportMovieMetadataLogic = _logicFactory.CreateLogic <IEmbyImportMovieMetadataLogic>(); if (await embyImportMovieMetadataLogic.RunAsync(plexMovieMetadata, embyMovieIdentifier) == false) { _logger.Log(Severity.Warn, $"Metadata could not be updated on '{plexMovieMetadata.Title}'."); retval = false; } return(retval); } finally { OnItemProcessed(); SemSlim.Release(); } }
public async Task <bool> TryAddMovieToCollectionAsync(IMovieIdentifier movieIdentifier, ICollectionIdentifier collectionIdentifier) { await SemSlim.WaitAsync(); try { Logger.Log(Severity.Info, $"Adding movie to collection '{collectionIdentifier.Name}'."); await Repository.AddMovieToCollectionAsync(Client, movieIdentifier.Id, collectionIdentifier.Id); return(true); } catch (Exception ex) { LogException(ex, $"Failed to add movie to collection '{collectionIdentifier.Name}':"); return(false); } finally { SemSlim.Release(); } }
public async Task <bool> RunAsync(IPlexMovieMetadata plexMovieMetadata, IMovieIdentifier movieIdentifier) { var retval = true; var metadataService = _serviceFactory.CreateService <IEmbyMetadataService>(); // Update Watched/Unwatched. if (await metadataService.UpdateWatchedStatusAsync(plexMovieMetadata, movieIdentifier) == false) { _logger.Log(Severity.Warn, $"Failed to update Watched/Unwatched for '{movieIdentifier.Filename}'."); retval = false; } // Update other metadata. if (await metadataService.UpdateMetadataAsync(plexMovieMetadata, movieIdentifier) == false) { _logger.Log(Severity.Warn, $"Failed to update metadata for '{movieIdentifier.Filename}'."); retval = false; } return(retval); }
public async Task <bool> TryDeleteImageFromMovieAsync(ImageType imageType, int imageIndex, IMovieIdentifier movieIdentifier) { await SemSlim.WaitAsync(); try { Logger.Log(Severity.Info, $"Deleting {imageType} image at index {imageIndex}."); await Repository.DeleteImageFromMovieAsync(Client, imageType, imageIndex, movieIdentifier.Id); return(true); } catch (Exception ex) { LogException(ex, $"Failed to delete {imageType} image at index {imageIndex}:"); return(false); } finally { SemSlim.Release(); } }
/// <remarks> /// There is no way to tell the server to display the added image. One has to /// assume that the added image is the one with the highest index. See /// https://emby.media/community/index.php?/topic/50676-how-to-re-index-a-new-remoteimage-of-an-item/ /// Unfortunatelly reindexing does not work reliably, see /// https://emby.media/community/index.php?/topic/50794-apiclient-server-3230-cannot-reindex-the-backdrop-image-of-a-movie/ /// </remarks> public async Task <bool> ReindexImageOfMovieAsync(ImageType imageType, int currentIndex, int newIndex, IMovieIdentifier movieIdentifier) { await SemSlim.WaitAsync(); try { Logger.Log(Severity.Info, $"Reindexing {imageType} image from index {currentIndex} to index {newIndex}."); await Repository.ReindexImageOfMovieAsync(Client, imageType, currentIndex, newIndex, movieIdentifier.Id); return(true); } catch (Exception ex) { LogException(ex, $"Failed to reindex {imageType} image:"); return(false); } finally { SemSlim.Release(); } }
/// <remarks> /// Unfortunatelly reindexing does not work reliably, see /// https://emby.media/community/index.php?/topic/50794-apiclient-server-3230-cannot-reindex-the-backdrop-image-of-a-movie/ /// </remarks> private async Task <bool> AddImagesToMovieWithReindex(IReadOnlyCollection <ImportableImage> importableImages, IMovieIdentifier embyMovieIdentifier) { var service = _serviceFactory.CreateService <IEmbyImageService>(); var retval = true; foreach (var importableImage in importableImages) { // Add image. if (await service.TryAddImageToMovieAsync(importableImage.ImageType, importableImage.SourceUri, embyMovieIdentifier) == false) { _logger.Log(Severity.Warn, $"{importableImage.ImageType} image from {importableImage.SourceUri} was not imported."); retval = false; continue; } // Get the index of the last image (of the just added type). var maxImageIndex = await service.GetMaxImageIndex(importableImage.ImageType, embyMovieIdentifier); if (maxImageIndex == null) { _logger.Log(Severity.Warn, $"The added {importableImage.ImageType} image might not be diplayed."); retval = false; continue; } // Do not reindex if there is only one (or none) image. if (maxImageIndex.Value < 1) { continue; } if (await service.ReindexImageOfMovieAsync(importableImage.ImageType, maxImageIndex.Value, 0, embyMovieIdentifier) == false) { _logger.Log(Severity.Warn, $"The added {importableImage.ImageType} will not be diplayed."); retval = false; } } return(retval); }
private async Task <bool> AddImagesToMovieWithDelete(IReadOnlyCollection <ImportableImage> importableImages, IMovieIdentifier embyMovieIdentifier) { var service = _serviceFactory.CreateService <IEmbyImageService>(); var retval = true; foreach (var importableImage in importableImages) { // Get the index of the last image. var maxImageIndex = await service.GetMaxImageIndex(importableImage.ImageType, embyMovieIdentifier); if (maxImageIndex == null) { _logger.Log(Severity.Warn, $"The added {importableImage.ImageType} image might not be diplayed for '{embyMovieIdentifier.Filename}'."); retval = false; continue; } // Delete all existing images of a type from the movie starting from last image. var itemCount = maxImageIndex.Value + 1; foreach (var lastIndex in Enumerable.Range(0, itemCount).OrderByDescending(x => x)) { if (await service.TryDeleteImageFromMovieAsync(importableImage.ImageType, lastIndex, embyMovieIdentifier)) { continue; } _logger.Log(Severity.Warn, $"The added {importableImage.ImageType} image might not be diplayed for '{embyMovieIdentifier.Filename}'."); retval = false; } // Add image. if (await service.TryAddImageToMovieAsync(importableImage.ImageType, importableImage.SourceUri, embyMovieIdentifier) == false) { _logger.Log(Severity.Warn, $"{importableImage.ImageType} image from {importableImage.SourceUri} was not imported."); retval = false; } } return(retval); }
public async Task <bool> RunAsync(IReadOnlyCollection <string> plexMovieCollections, IMovieIdentifier embyMovieIdentifier) { var serverOperatingSystem = await _collectionService.GetServerOperatingSystemAsync(); if (serverOperatingSystem == null) { var msg = "Cannot determine the server's operating system. Movie will not be added to any collection."; _logger.Log(Severity.Warn, msg); return(false); } var isWindowsServer = serverOperatingSystem.Value == OperatingSystem.Windows; // Get required collections already existing in Emby. var existingCollections = await GetExistingCollectionsAsync(plexMovieCollections, isWindowsServer); if (existingCollections == null) { var msg = "Failed to query existing collections. Movie will not be added to any collection."; _logger.Log(Severity.Warn, msg); return(false); } // Create missing collections. var createdCollections = plexMovieCollections.Count == existingCollections.Count ? new ICollectionIdentifier[] {} : await CreateMissingCollectionsAsync(plexMovieCollections, existingCollections, isWindowsServer); if (createdCollections == null) { var msg = "Failed to create missing collections. Movie will not be added to any collection."; _logger.Log(Severity.Warn, msg); return(false); } // Add the movie to all collections. var allCollections = existingCollections.Union(createdCollections).ToArray(); if (await AddMovieToCollectionsAsync(allCollections, embyMovieIdentifier) == false) { _logger.Log(Severity.Warn, "Failed to add movie to one or more collections."); return(false); } return(true); }
/// <remarks> /// FYI: This method is rather just a wrapper, as the only way to update any metadata of an Emby item is to /// send all of the item's metadata properties back to the server. So the heavy work is done in EmbyRepository. /// </remarks> public async Task <bool> UpdateMetadataAsync(IPlexMovieMetadata plexMovieMetadata, IMovieIdentifier movieIdentifier) { await SemSlim.WaitAsync(); try { var embyMovieMetadata = new EmbyMovieMetadata { Name = plexMovieMetadata.Title, ForcedSortName = plexMovieMetadata.TitleSort }; Logger.Log(Severity.Info, "Updating metadata."); await Repository.UpdateMetadataAsync(Client, embyMovieMetadata, movieIdentifier.Id); return(true); } catch (Exception ex) { LogException(ex, "Failed to update metadata:"); return(false); } finally { SemSlim.Release(); } }