示例#1
0
        /// <summary>
        /// Determine if the supplied file data points to a music album
        /// </summary>
        /// <param name="path">The path.</param>
        /// <param name="directoryService">The directory service.</param>
        /// <returns><c>true</c> if [is music album] [the specified data]; otherwise, <c>false</c>.</returns>
        public static bool IsMusicAlbum(string path, IDirectoryService directoryService)
        {
            // If list contains at least 2 audio files or at least one and no video files consider it to contain music
            var foundAudio = 0;

            foreach (var file in directoryService.GetFiles(path))
            {
                var fullName = file.FullName;

                if (EntityResolutionHelper.IsAudioFile(fullName))
                {
                    // Don't resolve these into audio files
                    if (string.Equals(Path.GetFileNameWithoutExtension(fullName), BaseItem.ThemeSongFilename) && EntityResolutionHelper.IsAudioFile(fullName))
                    {
                        continue;
                    }

                    foundAudio++;
                }
                if (foundAudio >= 2)
                {
                    return(true);
                }
                if (EntityResolutionHelper.IsVideoFile(fullName))
                {
                    return(false);
                }
            }

            //  or a single audio file and no video files
            return(foundAudio > 0);
        }
示例#2
0
        /// <summary>
        /// Determine if the supplied list contains what we should consider music
        /// </summary>
        /// <param name="list">The list.</param>
        /// <returns><c>true</c> if the specified list contains music; otherwise, <c>false</c>.</returns>
        public static bool ContainsMusic(IEnumerable <WIN32_FIND_DATA> list)
        {
            // If list contains at least 2 audio files or at least one and no video files consider it to contain music
            var foundAudio = 0;
            var foundVideo = 0;

            foreach (var file in list)
            {
                if (AudioResolver.IsAudioFile(file))
                {
                    foundAudio++;
                }
                if (foundAudio >= 2)
                {
                    return(true);
                }
                if (EntityResolutionHelper.IsVideoFile(file.Path))
                {
                    foundVideo++;
                }
            }

            //  or a single audio file and no video files
            if (foundAudio > 0 && foundVideo == 0)
            {
                return(true);
            }
            return(false);
        }
示例#3
0
        /// <summary>
        /// Determine if the supplied list contains what we should consider music
        /// </summary>
        /// <param name="list">The list.</param>
        /// <returns><c>true</c> if the specified list contains music; otherwise, <c>false</c>.</returns>
        public static bool ContainsMusic(IEnumerable <FileSystemInfo> list)
        {
            // If list contains at least 2 audio files or at least one and no video files consider it to contain music
            var foundAudio = 0;

            foreach (var file in list)
            {
                var fullName = file.FullName;

                if (EntityResolutionHelper.IsAudioFile(fullName))
                {
                    foundAudio++;
                }
                if (foundAudio >= 2)
                {
                    return(true);
                }
                if (EntityResolutionHelper.IsVideoFile(fullName))
                {
                    return(false);
                }
                if (EntityResolutionHelper.IsVideoPlaceHolder(fullName))
                {
                    return(false);
                }
            }

            //  or a single audio file and no video files
            return(foundAudio > 0);
        }
示例#4
0
        /// <summary>
        /// Determines whether [is series folder] [the specified path].
        /// </summary>
        /// <param name="path">The path.</param>
        /// <param name="considerSeasonlessEntries">if set to <c>true</c> [consider seasonless entries].</param>
        /// <param name="fileSystemChildren">The file system children.</param>
        /// <param name="directoryService">The directory service.</param>
        /// <param name="fileSystem">The file system.</param>
        /// <returns><c>true</c> if [is series folder] [the specified path]; otherwise, <c>false</c>.</returns>
        public static bool IsSeriesFolder(string path, bool considerSeasonlessEntries, IEnumerable <FileSystemInfo> fileSystemChildren, IDirectoryService directoryService, IFileSystem fileSystem, ILogger logger)
        {
            // A folder with more than 3 non-season folders in will not becounted as a series
            var nonSeriesFolders = 0;

            foreach (var child in fileSystemChildren)
            {
                var attributes = child.Attributes;

                if ((attributes & FileAttributes.Hidden) == FileAttributes.Hidden)
                {
                    //logger.Debug("Igoring series file or folder marked hidden: {0}", child.FullName);
                    continue;
                }

                // Can't enforce this because files saved by Bitcasa are always marked System
                //if ((attributes & FileAttributes.System) == FileAttributes.System)
                //{
                //    logger.Debug("Igoring series subfolder marked system: {0}", child.FullName);
                //    continue;
                //}

                if ((attributes & FileAttributes.Directory) == FileAttributes.Directory)
                {
                    if (IsSeasonFolder(child.FullName, directoryService, fileSystem))
                    {
                        logger.Debug("{0} is a series because of season folder {1}.", path, child.FullName);
                        return(true);
                    }

                    if (IsBadFolder(child.Name))
                    {
                        logger.Debug("Invalid folder under series: {0}", child.FullName);

                        nonSeriesFolders++;
                    }

                    if (nonSeriesFolders >= 3)
                    {
                        logger.Debug("{0} not a series due to 3 or more invalid folders.", path);
                        return(false);
                    }
                }
                else
                {
                    var fullName = child.FullName;

                    if (EntityResolutionHelper.IsVideoFile(fullName) || EntityResolutionHelper.IsVideoPlaceHolder(fullName))
                    {
                        if (GetEpisodeNumberFromFile(fullName, considerSeasonlessEntries).HasValue)
                        {
                            return(true);
                        }
                    }
                }
            }

            logger.Debug("{0} is not a series folder.", path);
            return(false);
        }
        /// <summary>
        /// Determine if the supplied list contains what we should consider music
        /// </summary>
        /// <param name="list">The list.</param>
        /// <param name="isMusicMediaFolder">if set to <c>true</c> [is music media folder].</param>
        /// <param name="allowSubfolders">if set to <c>true</c> [allow subfolders].</param>
        /// <param name="directoryService">The directory service.</param>
        /// <param name="logger">The logger.</param>
        /// <param name="fileSystem">The file system.</param>
        /// <returns><c>true</c> if the specified list contains music; otherwise, <c>false</c>.</returns>
        private static bool ContainsMusic(IEnumerable <FileSystemInfo> list,
                                          bool isMusicMediaFolder,
                                          bool allowSubfolders,
                                          IDirectoryService directoryService,
                                          ILogger logger,
                                          IFileSystem fileSystem)
        {
            // If list contains at least 2 audio files or at least one and no video files consider it to contain music
            var foundAudio = 0;

            var discSubfolderCount = 0;

            foreach (var fileSystemInfo in list)
            {
                if ((fileSystemInfo.Attributes & FileAttributes.Directory) == FileAttributes.Directory)
                {
                    if (isMusicMediaFolder && allowSubfolders && IsAlbumSubfolder(fileSystemInfo, true, directoryService, logger, fileSystem))
                    {
                        discSubfolderCount++;
                    }
                    if (!IsAdditionalSubfolderAllowed(fileSystemInfo))
                    {
                        return(false);
                    }
                }

                var fullName = fileSystemInfo.FullName;

                if (EntityResolutionHelper.IsAudioFile(fullName))
                {
                    // Don't resolve these into audio files
                    if (string.Equals(fileSystem.GetFileNameWithoutExtension(fullName), BaseItem.ThemeSongFilename))
                    {
                        continue;
                    }

                    foundAudio++;
                }
                else if (EntityResolutionHelper.IsVideoFile(fullName))
                {
                    return(false);
                }
                else if (EntityResolutionHelper.IsVideoPlaceHolder(fullName))
                {
                    return(false);
                }

                if (foundAudio >= 2)
                {
                    return(true);
                }
            }

            //  or a single audio file and no video files
            return(foundAudio > 0 || discSubfolderCount > 0);
        }
        /// <summary>
        /// Downloads the trailer for item.
        /// </summary>
        /// <param name="item">The item.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>Task.</returns>
        public async Task DownloadTrailerForItem(BaseItem item, CancellationToken cancellationToken)
        {
            var url = await GetTrailerUrl(item, cancellationToken).ConfigureAwait(false);

            if (string.IsNullOrEmpty(url))
            {
                return;
            }

            var responseInfo = await _httpClient.GetTempFileResponse(new HttpRequestOptions
            {
                Url = url,
                CancellationToken = cancellationToken,
                Progress          = new Progress <double>(),
                UserAgent         = GetUserAgent(url)
            });

            var extension = responseInfo.ContentType.Split('/').Last();

            if (string.Equals("quicktime", extension, StringComparison.OrdinalIgnoreCase))
            {
                extension = "mov";
            }

            var savePath = Directory.Exists(item.Path) ?
                           Path.Combine(item.Path, Path.GetFileNameWithoutExtension(item.Path) + "-trailer." + extension) :
                           Path.Combine(Path.GetDirectoryName(item.Path), Path.GetFileNameWithoutExtension(item.Path) + "-trailer." + extension);

            if (!EntityResolutionHelper.IsVideoFile(savePath))
            {
                _logger.Warn("Unrecognized video extension {0}", savePath);
                return;
            }

            _directoryWatchers.TemporarilyIgnore(savePath);

            _logger.Info("Moving {0} to {1}", responseInfo.TempFilePath, savePath);

            try
            {
                var parentPath = Path.GetDirectoryName(savePath);

                if (!Directory.Exists(parentPath))
                {
                    Directory.CreateDirectory(parentPath);
                }

                File.Move(responseInfo.TempFilePath, savePath);
            }
            finally
            {
                _directoryWatchers.RemoveTempIgnore(savePath);
            }

            await item.RefreshMetadata(cancellationToken).ConfigureAwait(false);
        }
示例#7
0
        /// <summary>
        /// Determines whether [is series folder] [the specified path].
        /// </summary>
        /// <param name="path">The path.</param>
        /// <param name="fileSystemChildren">The file system children.</param>
        /// <returns><c>true</c> if [is series folder] [the specified path]; otherwise, <c>false</c>.</returns>
        public static bool IsSeriesFolder(string path, IEnumerable <FileSystemInfo> fileSystemChildren, IDirectoryService directoryService)
        {
            // A folder with more than 3 non-season folders in will not becounted as a series
            var nonSeriesFolders = 0;

            foreach (var child in fileSystemChildren)
            {
                var attributes = child.Attributes;

                if ((attributes & FileAttributes.Hidden) == FileAttributes.Hidden)
                {
                    continue;
                }

                if ((attributes & FileAttributes.System) == FileAttributes.System)
                {
                    continue;
                }

                if ((attributes & FileAttributes.Directory) == FileAttributes.Directory)
                {
                    if (IsSeasonFolder(child.FullName, directoryService))
                    {
                        return(true);
                    }

                    nonSeriesFolders++;

                    if (nonSeriesFolders >= 3)
                    {
                        return(false);
                    }
                }
                else
                {
                    var fullName = child.FullName;

                    if (EntityResolutionHelper.IsVideoFile(fullName) || EntityResolutionHelper.IsVideoPlaceHolder(fullName))
                    {
                        if (GetEpisodeNumberFromFile(fullName, false).HasValue)
                        {
                            return(true);
                        }
                    }
                }
            }

            return(false);
        }
        private List <string> GetOtherDuplicatePaths(string targetPath, Series series, int seasonNumber, int episodeNumber, int?endingEpisodeNumber)
        {
            var episodePaths = series.RecursiveChildren
                               .OfType <Episode>()
                               .Where(i =>
            {
                var locationType = i.LocationType;

                // Must be file system based and match exactly
                if (locationType != LocationType.Remote &&
                    locationType != LocationType.Virtual &&
                    i.ParentIndexNumber.HasValue &&
                    i.ParentIndexNumber.Value == seasonNumber &&
                    i.IndexNumber.HasValue &&
                    i.IndexNumber.Value == episodeNumber)
                {
                    if (endingEpisodeNumber.HasValue || i.IndexNumberEnd.HasValue)
                    {
                        return(endingEpisodeNumber.HasValue && i.IndexNumberEnd.HasValue &&
                               endingEpisodeNumber.Value == i.IndexNumberEnd.Value);
                    }

                    return(true);
                }

                return(false);
            })
                               .Select(i => i.Path)
                               .ToList();

            var folder = Path.GetDirectoryName(targetPath);
            var targetFileNameWithoutExtension = Path.GetFileNameWithoutExtension(targetPath);

            try
            {
                var filesOfOtherExtensions = Directory.EnumerateFiles(folder, "*", SearchOption.TopDirectoryOnly)
                                             .Where(i => EntityResolutionHelper.IsVideoFile(i) && string.Equals(Path.GetFileNameWithoutExtension(i), targetFileNameWithoutExtension, StringComparison.OrdinalIgnoreCase));

                episodePaths.AddRange(filesOfOtherExtensions);
            }
            catch (DirectoryNotFoundException)
            {
                // No big deal. Maybe the season folder doesn't already exist.
            }

            return(episodePaths.Where(i => !string.Equals(i, targetPath, StringComparison.OrdinalIgnoreCase))
                   .Distinct(StringComparer.OrdinalIgnoreCase)
                   .ToList());
        }
示例#9
0
        public IEnumerable <MediaSourceInfo> GetCachedChannelItemMediaSources(IChannelMediaItem item)
        {
            var filenamePrefix = item.Id.ToString("N");
            var parentPath     = Path.Combine(ChannelDownloadPath, item.ChannelId);

            try
            {
                var files = new DirectoryInfo(parentPath).EnumerateFiles("*", SearchOption.TopDirectoryOnly);

                if (string.Equals(item.MediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase))
                {
                    files = files.Where(i => EntityResolutionHelper.IsVideoFile(i.FullName));
                }
                else
                {
                    files = files.Where(i => EntityResolutionHelper.IsAudioFile(i.FullName));
                }

                var file = files
                           .FirstOrDefault(i => i.Name.StartsWith(filenamePrefix, StringComparison.OrdinalIgnoreCase));

                if (file != null)
                {
                    var cachedItem = _libraryManager.ResolvePath(file);

                    if (cachedItem != null)
                    {
                        var hasMediaSources = _libraryManager.GetItemById(cachedItem.Id) as IHasMediaSources;

                        if (hasMediaSources != null)
                        {
                            var source = hasMediaSources.GetMediaSources(true).FirstOrDefault();

                            if (source != null)
                            {
                                source.Type = MediaSourceType.Cache;
                                return(new[] { source });
                            }
                        }
                    }
                }
            }
            catch (DirectoryNotFoundException)
            {
            }

            return(new List <MediaSourceInfo>());
        }
示例#10
0
        /// <summary>
        /// Loads the additional parts.
        /// </summary>
        /// <returns>IEnumerable{Video}.</returns>
        private IEnumerable <Video> LoadAlternateVersionsWithinSameDirectory(IEnumerable <FileSystemInfo> fileSystemChildren, IDirectoryService directoryService)
        {
            IEnumerable <FileSystemInfo> files;

            // Only support this for video files. For folder rips, they'll have to use the linking feature
            if (VideoType == VideoType.VideoFile || VideoType == VideoType.Iso)
            {
                var path = Path;

                var filenamePrefix = System.IO.Path.GetFileName(System.IO.Path.GetDirectoryName(path));

                files = fileSystemChildren.Where(i =>
                {
                    if ((i.Attributes & FileAttributes.Directory) == FileAttributes.Directory)
                    {
                        return(false);
                    }

                    return(!string.Equals(i.FullName, path, StringComparison.OrdinalIgnoreCase) &&
                           EntityResolutionHelper.IsVideoFile(i.FullName) &&
                           i.Name.StartsWith(filenamePrefix + " - ", StringComparison.OrdinalIgnoreCase));
                });
            }
            else
            {
                files = new List <FileSystemInfo>();
            }

            return(LibraryManager.ResolvePaths <Video>(files, directoryService, null).Select(video =>
            {
                // Try to retrieve it from the db. If we don't find it, use the resolved version
                var dbItem = LibraryManager.GetItemById(video.Id) as Video;

                if (dbItem != null)
                {
                    video = dbItem;
                }

                video.PrimaryVersionId = Id;

                return video;

                // Sort them so that the list can be easily compared for changes
            }).OrderBy(i => i.Path).ToList());
        }
示例#11
0
        /// <summary>
        /// Determines whether [is series folder] [the specified path].
        /// </summary>
        /// <param name="path">The path.</param>
        /// <param name="fileSystemChildren">The file system children.</param>
        /// <returns><c>true</c> if [is series folder] [the specified path]; otherwise, <c>false</c>.</returns>
        public static bool IsSeriesFolder(string path, IEnumerable <WIN32_FIND_DATA> fileSystemChildren)
        {
            // A folder with more than 3 non-season folders in will not becounted as a series
            var nonSeriesFolders = 0;

            foreach (var child in fileSystemChildren)
            {
                if (child.IsHidden || child.IsSystemFile)
                {
                    continue;
                }

                if (child.IsDirectory)
                {
                    if (IsSeasonFolder(child.Path))
                    {
                        return(true);
                    }

                    nonSeriesFolders++;

                    if (nonSeriesFolders >= 3)
                    {
                        return(false);
                    }
                }
                else
                {
                    if (EntityResolutionHelper.IsVideoFile(child.Path) &&
                        !string.IsNullOrEmpty(EpisodeNumberFromFile(child.Path, false)))
                    {
                        return(true);
                    }
                }
            }

            return(false);
        }
        /// <summary>
        /// Determine if the supplied file data points to a music album
        /// </summary>
        /// <param name="path">The path.</param>
        /// <returns><c>true</c> if [is music album] [the specified data]; otherwise, <c>false</c>.</returns>
        public static bool IsMusicAlbum(string path)
        {
            // If list contains at least 2 audio files or at least one and no video files consider it to contain music
            var foundAudio = 0;

            foreach (var fullName in Directory.EnumerateFiles(path))
            {
                if (EntityResolutionHelper.IsAudioFile(fullName))
                {
                    foundAudio++;
                }
                if (foundAudio >= 2)
                {
                    return(true);
                }
                if (EntityResolutionHelper.IsVideoFile(fullName))
                {
                    return(false);
                }
            }

            //  or a single audio file and no video files
            return(foundAudio > 0);
        }
示例#13
0
        /// <summary>
        /// Loads the additional parts.
        /// </summary>
        /// <returns>IEnumerable{Video}.</returns>
        private IEnumerable <Video> LoadAdditionalParts(IEnumerable <FileSystemInfo> fileSystemChildren, IDirectoryService directoryService)
        {
            IEnumerable <FileSystemInfo> files;

            var path = Path;

            if (VideoType == VideoType.BluRay || VideoType == VideoType.Dvd)
            {
                files = fileSystemChildren.Where(i =>
                {
                    if ((i.Attributes & FileAttributes.Directory) == FileAttributes.Directory)
                    {
                        return(!string.Equals(i.FullName, path, StringComparison.OrdinalIgnoreCase) && EntityResolutionHelper.IsMultiPartFolder(i.FullName));
                    }

                    return(false);
                });
            }
            else
            {
                files = fileSystemChildren.Where(i =>
                {
                    if ((i.Attributes & FileAttributes.Directory) == FileAttributes.Directory)
                    {
                        return(false);
                    }

                    return(!string.Equals(i.FullName, path, StringComparison.OrdinalIgnoreCase) && EntityResolutionHelper.IsVideoFile(i.FullName) && EntityResolutionHelper.IsMultiPartFile(i.Name));
                });
            }

            return(LibraryManager.ResolvePaths <Video>(files, directoryService, null).Select(video =>
            {
                // Try to retrieve it from the db. If we don't find it, use the resolved version
                var dbItem = LibraryManager.GetItemById(video.Id) as Video;

                if (dbItem != null)
                {
                    video = dbItem;
                }

                return video;

                // Sort them so that the list can be easily compared for changes
            }).OrderBy(i => i.Path).ToList());
        }
示例#14
0
        /// <summary>
        /// Loads the additional parts.
        /// </summary>
        /// <returns>IEnumerable{Video}.</returns>
        private IEnumerable <Video> LoadAdditionalParts()
        {
            IEnumerable <FileSystemInfo> files;

            if (VideoType == VideoType.BluRay || VideoType == VideoType.Dvd)
            {
                files = new DirectoryInfo(System.IO.Path.GetDirectoryName(Path))
                        .EnumerateDirectories()
                        .Where(i => !string.Equals(i.FullName, Path, StringComparison.OrdinalIgnoreCase) && EntityResolutionHelper.IsMultiPartFile(i.Name));
            }
            else
            {
                files = ResolveArgs.FileSystemChildren.Where(i =>
                {
                    if ((i.Attributes & FileAttributes.Directory) == FileAttributes.Directory)
                    {
                        return(false);
                    }

                    return(!string.Equals(i.FullName, Path, StringComparison.OrdinalIgnoreCase) && EntityResolutionHelper.IsVideoFile(i.FullName) && EntityResolutionHelper.IsMultiPartFile(i.Name));
                });
            }

            return(LibraryManager.ResolvePaths <Video>(files, null).Select(video =>
            {
                // Try to retrieve it from the db. If we don't find it, use the resolved version
                var dbItem = LibraryManager.RetrieveItem(video.Id) as Video;

                if (dbItem != null)
                {
                    dbItem.ResolveArgs = video.ResolveArgs;
                    video = dbItem;
                }

                return video;
            }).ToList());
        }
        public async Task Organize(TvFileOrganizationOptions options, CancellationToken cancellationToken, IProgress <double> progress)
        {
            var minFileBytes = options.MinFileSizeMb * 1024 * 1024;

            var watchLocations = options.WatchLocations.ToList();

            var eligibleFiles = watchLocations.SelectMany(GetFilesToOrganize)
                                .OrderBy(_fileSystem.GetCreationTimeUtc)
                                .Where(i => EntityResolutionHelper.IsVideoFile(i.FullName) && i.Length >= minFileBytes)
                                .ToList();

            progress.Report(10);

            var scanLibrary = false;

            if (eligibleFiles.Count > 0)
            {
                var numComplete = 0;

                foreach (var file in eligibleFiles)
                {
                    var organizer = new EpisodeFileOrganizer(_organizationService, _config, _fileSystem, _logger, _libraryManager,
                                                             _libraryMonitor, _providerManager);

                    var result = await organizer.OrganizeEpisodeFile(file.FullName, options, options.OverwriteExistingEpisodes, cancellationToken).ConfigureAwait(false);

                    if (result.Status == FileSortingStatus.Success)
                    {
                        scanLibrary = true;
                    }

                    numComplete++;
                    double percent = numComplete;
                    percent /= eligibleFiles.Count;

                    progress.Report(10 + (89 * percent));
                }
            }

            cancellationToken.ThrowIfCancellationRequested();
            progress.Report(99);

            foreach (var path in watchLocations)
            {
                var deleteExtensions = options.LeftOverFileExtensionsToDelete
                                       .Select(i => i.Trim().TrimStart('.'))
                                       .Where(i => !string.IsNullOrEmpty(i))
                                       .Select(i => "." + i)
                                       .ToList();

                if (deleteExtensions.Count > 0)
                {
                    DeleteLeftOverFiles(path, deleteExtensions);
                }

                if (options.DeleteEmptyFolders)
                {
                    foreach (var subfolder in GetDirectories(path).ToList())
                    {
                        DeleteEmptyFolders(subfolder);
                    }
                }
            }

            if (scanLibrary)
            {
                await _libraryManager.ValidateMediaLibrary(new Progress <double>(), CancellationToken.None)
                .ConfigureAwait(false);
            }

            progress.Report(100);
        }