Beispiel #1
0
        /// <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();
            }
        }
Beispiel #2
0
        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);
        }
Beispiel #4
0
        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);
        }
Beispiel #6
0
        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));
        }
Beispiel #7
0
        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();
            }
        }
Beispiel #10
0
        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);
        }
Beispiel #11
0
        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();
            }
        }
Beispiel #12
0
        /// <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();
            }
        }
Beispiel #13
0
        /// <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);
        }
Beispiel #14
0
        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);
        }
Beispiel #15
0
        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);
        }
Beispiel #16
0
        /// <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();
            }
        }