コード例 #1
0
ファイル: TVUtils.cs プロジェクト: zuanbinjai/MediaBrowser
        /// <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);
        }
コード例 #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 <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);
        }
コード例 #3
0
        public void TestMultiPartFiles()
        {
            Assert.IsFalse(EntityResolutionHelper.IsMultiPartFile(@"Braveheart.mkv"));
            Assert.IsFalse(EntityResolutionHelper.IsMultiPartFile(@"Braveheart - 480p.mkv"));
            Assert.IsFalse(EntityResolutionHelper.IsMultiPartFile(@"Braveheart - 720p.mkv"));

            Assert.IsFalse(EntityResolutionHelper.IsMultiPartFile(@"blah blah.mkv"));

            Assert.IsTrue(EntityResolutionHelper.IsMultiPartFile(@"blah blah - cd1.mkv"));
            Assert.IsTrue(EntityResolutionHelper.IsMultiPartFile(@"blah blah - disc1.mkv"));
            Assert.IsTrue(EntityResolutionHelper.IsMultiPartFile(@"blah blah - disk1.mkv"));
            Assert.IsTrue(EntityResolutionHelper.IsMultiPartFile(@"blah blah - pt1.mkv"));
            Assert.IsTrue(EntityResolutionHelper.IsMultiPartFile(@"blah blah - part1.mkv"));
            Assert.IsTrue(EntityResolutionHelper.IsMultiPartFile(@"blah blah - dvd1.mkv"));

            // Add a space
            Assert.IsTrue(EntityResolutionHelper.IsMultiPartFile(@"blah blah - cd 1.mkv"));
            Assert.IsTrue(EntityResolutionHelper.IsMultiPartFile(@"blah blah - disc 1.mkv"));
            Assert.IsTrue(EntityResolutionHelper.IsMultiPartFile(@"blah blah - disk 1.mkv"));
            Assert.IsTrue(EntityResolutionHelper.IsMultiPartFile(@"blah blah - pt 1.mkv"));
            Assert.IsTrue(EntityResolutionHelper.IsMultiPartFile(@"blah blah - part 1.mkv"));
            Assert.IsTrue(EntityResolutionHelper.IsMultiPartFile(@"blah blah - dvd 1.mkv"));

            // Not case sensitive
            Assert.IsTrue(EntityResolutionHelper.IsMultiPartFile(@"blah blah - Disc1.mkv"));
        }
コード例 #4
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);
        }
コード例 #5
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);
        }
コード例 #6
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>
        /// 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);
        }
コード例 #8
0
        /// <summary>
        /// Resolves the specified args.
        /// </summary>
        /// <param name="args">The args.</param>
        /// <returns>Entities.Audio.Audio.</returns>
        protected override Controller.Entities.Audio.Audio Resolve(ItemResolveArgs args)
        {
            // Return audio if the path is a file and has a matching extension

            if (!args.IsDirectory)
            {
                if (EntityResolutionHelper.IsAudioFile(args.Path))
                {
                    return(new Controller.Entities.Audio.Audio());
                }
            }

            return(null);
        }
コード例 #9
0
        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());
        }
コード例 #10
0
ファイル: TVUtils.cs プロジェクト: ilovejs/MediaBrowser
        /// <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);
        }
コード例 #11
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>());
        }
コード例 #12
0
ファイル: BaseItem.cs プロジェクト: rajeshwarn/MediaBrowser
        /// <summary>
        /// Creates ResolveArgs on demand
        /// </summary>
        /// <param name="pathInfo">The path info.</param>
        /// <returns>ItemResolveArgs.</returns>
        /// <exception cref="System.IO.IOException">Unable to retrieve file system info for  + path</exception>
        protected internal virtual ItemResolveArgs CreateResolveArgs(WIN32_FIND_DATA?pathInfo = null)
        {
            var path = Path;

            // non file-system entries will not have a path
            if (this.LocationType != LocationType.FileSystem || string.IsNullOrEmpty(path))
            {
                return(new ItemResolveArgs(ConfigurationManager.ApplicationPaths)
                {
                    FileInfo = new WIN32_FIND_DATA()
                });
            }

            if (UseParentPathToCreateResolveArgs)
            {
                path = System.IO.Path.GetDirectoryName(path);
            }

            pathInfo = pathInfo ?? FileSystem.GetFileData(path);

            if (!pathInfo.HasValue)
            {
                throw new IOException("Unable to retrieve file system info for " + path);
            }

            var args = new ItemResolveArgs(ConfigurationManager.ApplicationPaths)
            {
                FileInfo = pathInfo.Value,
                Path     = path,
                Parent   = Parent
            };

            // Gather child folder and files

            if (args.IsDirectory)
            {
                // When resolving the root, we need it's grandchildren (children of user views)
                var flattenFolderDepth = args.IsPhysicalRoot ? 2 : 0;

                args.FileSystemDictionary = FileData.GetFilteredFileSystemEntries(args.Path, Logger, flattenFolderDepth: flattenFolderDepth, args: args);
            }

            //update our dates
            EntityResolutionHelper.EnsureDates(this, args);

            return(args);
        }
コード例 #13
0
ファイル: TVUtils.cs プロジェクト: zuanbinjai/MediaBrowser
        /// <summary>
        /// Determines whether [is season folder] [the specified path].
        /// </summary>
        /// <param name="path">The path.</param>
        /// <param name="directoryService">The directory service.</param>
        /// <param name="fileSystem">The file system.</param>
        /// <returns><c>true</c> if [is season folder] [the specified path]; otherwise, <c>false</c>.</returns>
        private static bool IsSeasonFolder(string path, IDirectoryService directoryService, IFileSystem fileSystem)
        {
            var seasonNumber    = GetSeasonNumberFromPath(path);
            var hasSeasonNumber = seasonNumber != null;

            if (!hasSeasonNumber)
            {
                return(false);
            }

            // It's a season folder if it's named as such and does not contain any audio files, apart from theme.mp3
            foreach (var fileSystemInfo in directoryService.GetFileSystemEntries(path))
            {
                var attributes = fileSystemInfo.Attributes;

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

                // Can't enforce this because files saved by Bitcasa are always marked System
                //if ((attributes & FileAttributes.System) == FileAttributes.System)
                //{
                //    continue;
                //}

                if ((attributes & FileAttributes.Directory) == FileAttributes.Directory)
                {
                    //if (IsBadFolder(fileSystemInfo.Name))
                    //{
                    //    return false;
                    //}
                }
                else
                {
                    if (EntityResolutionHelper.IsAudioFile(fileSystemInfo.FullName) &&
                        !string.Equals(fileSystem.GetFileNameWithoutExtension(fileSystemInfo), BaseItem.ThemeSongFilename))
                    {
                        return(false);
                    }
                }
            }

            return(true);
        }
コード例 #14
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());
        }
コード例 #15
0
        /// <summary>
        /// Gets the multi file movie.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="movies">The movies.</param>
        /// <returns>``0.</returns>
        private T GetMultiFileMovie <T>(IEnumerable <T> movies)
            where T : Video, new()
        {
            var sortedMovies = movies.OrderBy(i => i.Path).ToList();

            var firstMovie = sortedMovies[0];

            // They must all be part of the sequence if we're going to consider it a multi-part movie
            // Only support up to 8 (matches Plex), to help avoid incorrect detection
            if (sortedMovies.All(i => EntityResolutionHelper.IsMultiPartFile(i.Path)) && sortedMovies.Count <= 8)
            {
                firstMovie.IsMultiPart = true;

                return(firstMovie);
            }

            return(null);
        }
コード例 #16
0
        /// <summary>
        /// Gets the multi file movie.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="movies">The movies.</param>
        /// <returns>``0.</returns>
        private T GetMultiFileMovie <T>(List <T> movies)
            where T : Video, new()
        {
            var multiPartMovies = movies.OrderBy(i => i.Path)
                                  .Where(i => EntityResolutionHelper.IsMultiPartFile(i.Path))
                                  .ToList();

            // They must all be part of the sequence
            if (multiPartMovies.Count != movies.Count)
            {
                return(null);
            }

            var firstPart = multiPartMovies[0];

            firstPart.IsMultiPart = true;

            return(firstPart);
        }
コード例 #17
0
        public void TestMultiDiscAlbums()
        {
            Assert.IsFalse(EntityResolutionHelper.IsMultiDiscAlbumFolder(@"blah blah"));
            Assert.IsFalse(EntityResolutionHelper.IsMultiDiscAlbumFolder(@"d:\\music\weezer\\03 Pinkerton"));
            Assert.IsFalse(EntityResolutionHelper.IsMultiDiscAlbumFolder(@"d:\\music\\michael jackson\\Bad (2012 Remaster)"));

            Assert.IsTrue(EntityResolutionHelper.IsMultiDiscAlbumFolder(@"cd1"));
            Assert.IsTrue(EntityResolutionHelper.IsMultiDiscAlbumFolder(@"disc1"));
            Assert.IsTrue(EntityResolutionHelper.IsMultiDiscAlbumFolder(@"disk1"));

            // Add a space
            Assert.IsTrue(EntityResolutionHelper.IsMultiDiscAlbumFolder(@"cd 1"));
            Assert.IsTrue(EntityResolutionHelper.IsMultiDiscAlbumFolder(@"disc 1"));
            Assert.IsTrue(EntityResolutionHelper.IsMultiDiscAlbumFolder(@"disk 1"));

            Assert.IsTrue(EntityResolutionHelper.IsMultiDiscAlbumFolder(@"cd  - 1"));
            Assert.IsTrue(EntityResolutionHelper.IsMultiDiscAlbumFolder(@"disc- 1"));
            Assert.IsTrue(EntityResolutionHelper.IsMultiDiscAlbumFolder(@"disk - 1"));
        }
コード例 #18
0
        /// <summary>
        /// Resolves the specified args.
        /// </summary>
        /// <param name="args">The args.</param>
        /// <returns>Entities.Audio.Audio.</returns>
        protected override Controller.Entities.Audio.Audio Resolve(ItemResolveArgs args)
        {
            // Return audio if the path is a file and has a matching extension

            if (!args.IsDirectory)
            {
                if (EntityResolutionHelper.IsAudioFile(args.Path))
                {
                    var collectionType = args.GetCollectionType();

                    if (string.Equals(collectionType, CollectionType.Music, StringComparison.OrdinalIgnoreCase) ||
                        string.IsNullOrEmpty(collectionType))
                    {
                        return(new Controller.Entities.Audio.Audio());
                    }
                }
            }

            return(null);
        }
コード例 #19
0
        public void TestMultiPartFolders()
        {
            Assert.IsFalse(EntityResolutionHelper.IsMultiPartFile(@"blah blah"));

            Assert.IsTrue(EntityResolutionHelper.IsMultiPartFile(@"blah blah - cd1"));
            Assert.IsTrue(EntityResolutionHelper.IsMultiPartFile(@"blah blah - disc1"));
            Assert.IsTrue(EntityResolutionHelper.IsMultiPartFile(@"blah blah - disk1"));
            Assert.IsTrue(EntityResolutionHelper.IsMultiPartFile(@"blah blah - pt1"));
            Assert.IsTrue(EntityResolutionHelper.IsMultiPartFile(@"blah blah - part1"));
            Assert.IsTrue(EntityResolutionHelper.IsMultiPartFile(@"blah blah - dvd1"));

            // Add a space
            Assert.IsTrue(EntityResolutionHelper.IsMultiPartFile(@"blah blah - cd 1"));
            Assert.IsTrue(EntityResolutionHelper.IsMultiPartFile(@"blah blah - disc 1"));
            Assert.IsTrue(EntityResolutionHelper.IsMultiPartFile(@"blah blah - disk 1"));
            Assert.IsTrue(EntityResolutionHelper.IsMultiPartFile(@"blah blah - pt 1"));
            Assert.IsTrue(EntityResolutionHelper.IsMultiPartFile(@"blah blah - part 1"));
            Assert.IsTrue(EntityResolutionHelper.IsMultiPartFile(@"blah blah - dvd 1"));

            // Not case sensitive
            Assert.IsTrue(EntityResolutionHelper.IsMultiPartFile(@"blah blah - Disc1"));
        }
コード例 #20
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);
        }
コード例 #21
0
        /// <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);
        }
コード例 #22
0
        public void TestMultiPartFolders()
        {
            Assert.IsFalse(EntityResolutionHelper.IsMultiPartFolder(@"blah blah"));
            Assert.IsFalse(EntityResolutionHelper.IsMultiPartFolder(@"d:\\music\weezer\\03 Pinkerton"));
            Assert.IsFalse(EntityResolutionHelper.IsMultiPartFolder(@"d:\\music\\michael jackson\\Bad (2012 Remaster)"));

            Assert.IsTrue(EntityResolutionHelper.IsMultiPartFolder(@"blah blah - cd1"));
            Assert.IsTrue(EntityResolutionHelper.IsMultiPartFolder(@"blah blah - disc1"));
            Assert.IsTrue(EntityResolutionHelper.IsMultiPartFolder(@"blah blah - disk1"));
            Assert.IsTrue(EntityResolutionHelper.IsMultiPartFolder(@"blah blah - pt1"));
            Assert.IsTrue(EntityResolutionHelper.IsMultiPartFolder(@"blah blah - part1"));
            Assert.IsTrue(EntityResolutionHelper.IsMultiPartFolder(@"blah blah - dvd1"));

            // Add a space
            Assert.IsTrue(EntityResolutionHelper.IsMultiPartFolder(@"blah blah - cd 1"));
            Assert.IsTrue(EntityResolutionHelper.IsMultiPartFolder(@"blah blah - disc 1"));
            Assert.IsTrue(EntityResolutionHelper.IsMultiPartFolder(@"blah blah - disk 1"));
            Assert.IsTrue(EntityResolutionHelper.IsMultiPartFolder(@"blah blah - pt 1"));
            Assert.IsTrue(EntityResolutionHelper.IsMultiPartFolder(@"blah blah - part 1"));
            Assert.IsTrue(EntityResolutionHelper.IsMultiPartFolder(@"blah blah - dvd 1"));

            // Not case sensitive
            Assert.IsTrue(EntityResolutionHelper.IsMultiPartFolder(@"blah blah - Disc1"));
        }
コード例 #23
0
        /// <summary>
        /// Finds a movie based on a child file system entries
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="path">The path.</param>
        /// <param name="parent">The parent.</param>
        /// <param name="fileSystemEntries">The file system entries.</param>
        /// <returns>Movie.</returns>
        private T FindMovie <T>(string path, Folder parent, IEnumerable <FileSystemInfo> fileSystemEntries, IDirectoryService directoryService)
            where T : Video, new()
        {
            var movies = new List <T>();

            var multiDiscFolders = new List <FileSystemInfo>();

            // Loop through each child file/folder and see if we find a video
            foreach (var child in fileSystemEntries)
            {
                var filename = child.Name;

                if ((child.Attributes & FileAttributes.Directory) == FileAttributes.Directory)
                {
                    if (IsDvdDirectory(filename))
                    {
                        return(new T
                        {
                            Path = path,
                            VideoType = VideoType.Dvd
                        });
                    }
                    if (IsBluRayDirectory(filename))
                    {
                        return(new T
                        {
                            Path = path,
                            VideoType = VideoType.BluRay
                        });
                    }

                    if (EntityResolutionHelper.IsMultiPartFile(filename))
                    {
                        multiDiscFolders.Add(child);
                    }

                    continue;
                }

                // Don't misidentify xbmc trailers as a movie
                if (filename.IndexOf(BaseItem.XbmcTrailerFileSuffix, StringComparison.OrdinalIgnoreCase) != -1)
                {
                    continue;
                }

                var childArgs = new ItemResolveArgs(_applicationPaths, _libraryManager, directoryService)
                {
                    FileInfo = child,
                    Path     = child.FullName,
                    Parent   = parent
                };

                var item = ResolveVideo <T>(childArgs);

                if (item != null)
                {
                    item.IsInMixedFolder = false;
                    movies.Add(item);
                }
            }

            if (movies.Count > 1)
            {
                return(GetMultiFileMovie(movies));
            }

            if (movies.Count == 1)
            {
                return(movies[0]);
            }

            if (multiDiscFolders.Count > 0)
            {
                var folders = fileSystemEntries.Where(child => (child.Attributes & FileAttributes.Directory) == FileAttributes.Directory);

                return(GetMultiDiscMovie <T>(multiDiscFolders, folders));
            }

            return(null);
        }
コード例 #24
0
        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);
        }
コード例 #25
0
 public static bool IsMultiDiscFolder(string path)
 {
     return(EntityResolutionHelper.IsMultiDiscAlbumFolder(path));
 }
コード例 #26
0
        /// <summary>
        /// Compare our current children (presumably just read from the repo) with the current state of the file system and adjust for any changes
        /// ***Currently does not contain logic to maintain items that are unavailable in the file system***
        /// </summary>
        /// <param name="progress">The progress.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <param name="recursive">if set to <c>true</c> [recursive].</param>
        /// <returns>Task.</returns>
        protected async virtual Task ValidateChildrenInternal(IProgress <double> progress, CancellationToken cancellationToken, bool?recursive = null)
        {
            // Nothing to do here
            if (LocationType != LocationType.FileSystem)
            {
                return;
            }

            cancellationToken.ThrowIfCancellationRequested();

            var changedArgs = new ChildrenChangedEventArgs(this);

            //get the current valid children from filesystem (or wherever)
            var nonCachedChildren = GetNonCachedChildren();

            if (nonCachedChildren == null)
            {
                return;                            //nothing to validate
            }
            progress.Report(5);

            //build a dictionary of the current children we have now by Id so we can compare quickly and easily
            var currentChildren = ActualChildren.ToDictionary(i => i.Id);

            //create a list for our validated children
            var validChildren = new ConcurrentBag <Tuple <BaseItem, bool> >();

            cancellationToken.ThrowIfCancellationRequested();

            Parallel.ForEach(nonCachedChildren, child =>
            {
                BaseItem currentChild;

                if (currentChildren.TryGetValue(child.Id, out currentChild))
                {
                    currentChild.ResolveArgs = child.ResolveArgs;

                    //existing item - check if it has changed
                    if (currentChild.HasChanged(child))
                    {
                        EntityResolutionHelper.EnsureDates(currentChild, child.ResolveArgs);

                        changedArgs.AddUpdatedItem(currentChild);
                        validChildren.Add(new Tuple <BaseItem, bool>(currentChild, true));
                    }
                    else
                    {
                        validChildren.Add(new Tuple <BaseItem, bool>(currentChild, false));
                    }
                }
                else
                {
                    //brand new item - needs to be added
                    changedArgs.AddNewItem(child);

                    validChildren.Add(new Tuple <BaseItem, bool>(child, true));
                }
            });

            // If any items were added or removed....
            if (!changedArgs.ItemsAdded.IsEmpty || currentChildren.Count != validChildren.Count)
            {
                var newChildren = validChildren.Select(c => c.Item1).ToList();

                //that's all the new and changed ones - now see if there are any that are missing
                changedArgs.ItemsRemoved = currentChildren.Values.Except(newChildren).ToList();

                foreach (var item in changedArgs.ItemsRemoved)
                {
                    Logger.Info("** " + item.Name + " Removed from library.");
                }

                var childrenReplaced = false;

                if (changedArgs.ItemsRemoved.Count > 0)
                {
                    ActualChildren   = new ConcurrentBag <BaseItem>(newChildren);
                    childrenReplaced = true;
                }

                var saveTasks = new List <Task>();

                foreach (var item in changedArgs.ItemsAdded)
                {
                    Logger.Info("** " + item.Name + " Added to library.");

                    if (!childrenReplaced)
                    {
                        _children.Add(item);
                    }

                    saveTasks.Add(Kernel.Instance.ItemRepository.SaveItem(item, CancellationToken.None));
                }

                await Task.WhenAll(saveTasks).ConfigureAwait(false);

                //and save children in repo...
                Logger.Info("*** Saving " + newChildren.Count + " children for " + Name);
                await Kernel.Instance.ItemRepository.SaveChildren(Id, newChildren, CancellationToken.None).ConfigureAwait(false);
            }

            if (changedArgs.HasChange)
            {
                //force the indexes to rebuild next time
                IndexCache.Clear();

                //and fire event
                LibraryManager.ReportLibraryChanged(changedArgs);
            }

            progress.Report(10);

            cancellationToken.ThrowIfCancellationRequested();

            await RefreshChildren(validChildren, progress, cancellationToken, recursive).ConfigureAwait(false);

            progress.Report(100);
        }
コード例 #27
0
ファイル: Folder.cs プロジェクト: yardameus/MediaBrowser
        /// <summary>
        /// Compare our current children (presumably just read from the repo) with the current state of the file system and adjust for any changes
        /// ***Currently does not contain logic to maintain items that are unavailable in the file system***
        /// </summary>
        /// <param name="progress">The progress.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <param name="recursive">if set to <c>true</c> [recursive].</param>
        /// <param name="forceRefreshMetadata">if set to <c>true</c> [force refresh metadata].</param>
        /// <returns>Task.</returns>
        protected async virtual Task ValidateChildrenInternal(IProgress <double> progress, CancellationToken cancellationToken, bool?recursive = null, bool forceRefreshMetadata = false)
        {
            var locationType = LocationType;

            // Nothing to do here
            if (locationType == LocationType.Remote || locationType == LocationType.Virtual)
            {
                return;
            }

            cancellationToken.ThrowIfCancellationRequested();

            IEnumerable <BaseItem> nonCachedChildren;

            try
            {
                nonCachedChildren = GetNonCachedChildren();
            }
            catch (IOException ex)
            {
                nonCachedChildren = new BaseItem[] { };

                Logger.ErrorException("Error getting file system entries for {0}", ex, Path);
            }

            if (nonCachedChildren == null)
            {
                return;                            //nothing to validate
            }
            progress.Report(5);

            //build a dictionary of the current children we have now by Id so we can compare quickly and easily
            var currentChildren = ActualChildren;

            //create a list for our validated children
            var validChildren = new ConcurrentBag <Tuple <BaseItem, bool> >();
            var newItems      = new ConcurrentBag <BaseItem>();

            cancellationToken.ThrowIfCancellationRequested();

            var options = new ParallelOptions
            {
                MaxDegreeOfParallelism = 20
            };

            Parallel.ForEach(nonCachedChildren, options, child =>
            {
                BaseItem currentChild;

                if (currentChildren.TryGetValue(child.Id, out currentChild))
                {
                    currentChild.ResolveArgs = child.ResolveArgs;

                    //existing item - check if it has changed
                    if (currentChild.HasChanged(child))
                    {
                        EntityResolutionHelper.EnsureDates(currentChild, child.ResolveArgs, false);

                        validChildren.Add(new Tuple <BaseItem, bool>(currentChild, true));
                    }
                    else
                    {
                        validChildren.Add(new Tuple <BaseItem, bool>(currentChild, false));
                    }

                    currentChild.IsOffline = false;
                }
                else
                {
                    //brand new item - needs to be added
                    newItems.Add(child);

                    validChildren.Add(new Tuple <BaseItem, bool>(child, true));
                }
            });

            // If any items were added or removed....
            if (!newItems.IsEmpty || currentChildren.Count != validChildren.Count)
            {
                var newChildren = validChildren.Select(c => c.Item1).ToList();

                //that's all the new and changed ones - now see if there are any that are missing
                var itemsRemoved = currentChildren.Values.Except(newChildren).ToList();

                foreach (var item in itemsRemoved)
                {
                    if (IsRootPathAvailable(item.Path))
                    {
                        item.IsOffline = false;

                        BaseItem removed;

                        if (!_children.TryRemove(item.Id, out removed))
                        {
                            Logger.Error("Failed to remove {0}", item.Name);
                        }
                        else
                        {
                            LibraryManager.ReportItemRemoved(item);
                        }
                    }
                    else
                    {
                        item.IsOffline = true;

                        validChildren.Add(new Tuple <BaseItem, bool>(item, false));
                    }
                }

                await LibraryManager.CreateItems(newItems, cancellationToken).ConfigureAwait(false);

                foreach (var item in newItems)
                {
                    if (!_children.TryAdd(item.Id, item))
                    {
                        Logger.Error("Failed to add {0}", item.Name);
                    }
                    else
                    {
                        Logger.Debug("** " + item.Name + " Added to library.");
                    }
                }

                await ItemRepository.SaveChildren(Id, _children.Values.ToList().Select(i => i.Id), cancellationToken).ConfigureAwait(false);

                //force the indexes to rebuild next time
                IndexCache.Clear();
            }

            progress.Report(10);

            cancellationToken.ThrowIfCancellationRequested();

            await RefreshChildren(validChildren, progress, cancellationToken, recursive, forceRefreshMetadata).ConfigureAwait(false);

            progress.Report(100);
        }
コード例 #28
0
ファイル: TVUtils.cs プロジェクト: ilovejs/MediaBrowser
 /// <summary>
 /// Determines whether [is season folder] [the specified path].
 /// </summary>
 /// <param name="path">The path.</param>
 /// <param name="directoryService">The directory service.</param>
 /// <returns><c>true</c> if [is season folder] [the specified path]; otherwise, <c>false</c>.</returns>
 private static bool IsSeasonFolder(string path, IDirectoryService directoryService)
 {
     // It's a season folder if it's named as such and does not contain any audio files, apart from theme.mp3
     return(GetSeasonNumberFromPath(path) != null && !directoryService.GetFiles(path).Any(i => EntityResolutionHelper.IsAudioFile(i.FullName) && !string.Equals(Path.GetFileNameWithoutExtension(i.FullName), BaseItem.ThemeSongFilename)));
 }
コード例 #29
0
ファイル: Video.cs プロジェクト: mporcas/MediaBrowser
        /// <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());
        }
コード例 #30
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());
        }