예제 #1
0
        /// <summary>
        /// Process one song.
        /// Song in this context is a song file.
        /// Some songs have multiple song files (an sm and an ssc version).
        /// Will add charts, copy the charts and non-chart files to the output directory,
        /// and write visualizations for the conversion.
        /// </summary>
        /// <param name="songArgs">SongArgs for the song file.</param>
        private static async Task ProcessSong(SongArgs songArgs)
        {
            // Load the song.
            Song song;

            try
            {
                var reader = Reader.CreateReader(songArgs.FileInfo);
                if (reader == null)
                {
                    LogError("Unsupported file format. Cannot parse.", songArgs.FileInfo, songArgs.RelativePath);
                    return;
                }

                song = await reader.Load();
            }
            catch (Exception e)
            {
                LogError($"Failed to load file. {e}", songArgs.FileInfo, songArgs.RelativePath);
                return;
            }

            // Add new charts.
            AddCharts(song, songArgs);

            // Save
            var saveFile = Fumen.Path.GetWin32FileSystemFullPath(Fumen.Path.Combine(songArgs.SaveDir, songArgs.FileInfo.Name));
            var config   = new SMWriterBase.SMWriterBaseConfig
            {
                FilePath = saveFile,
                Song     = song,
                MeasureSpacingBehavior   = SMWriterBase.MeasureSpacingBehavior.UseSubDivisionDenominatorAsMeasureSpacing,
                PropertyEmissionBehavior = SMWriterBase.PropertyEmissionBehavior.MatchSource
            };
            var fileFormat = FileFormat.GetFileFormatByExtension(songArgs.FileInfo.Extension);

            switch (fileFormat.Type)
            {
            case FileFormatType.SM:
                new SMWriter(config).Save();
                break;

            case FileFormatType.SSC:
                new SSCWriter(config).Save();
                break;

            default:
                LogError("Unsupported file format. Cannot save.", songArgs.FileInfo, songArgs.RelativePath);
                break;
            }

            // Copy the non-chart files.
            CopyNonChartFiles(songArgs.CurrentDir, songArgs.SaveDir);
        }
예제 #2
0
파일: Reader.cs 프로젝트: PerryAsleep/Fumen
        /// <summary>
        /// Factory method to create the appropriate Reader based on the given file.
        /// </summary>
        /// <param name="fileInfo">FileInfo for the file to read.</param>
        /// <returns>
        /// New Reader for reading the given or null if no appropriate Reader exists.
        /// </returns>
        public static Reader CreateReader(FileInfo fileInfo)
        {
            var fileFormat = FileFormat.GetFileFormatByExtension(fileInfo.Extension.ToLower());

            if (fileFormat == null)
            {
                return(null);
            }
            var fullName = Fumen.Path.GetWin32FileSystemFullPath(fileInfo.FullName);

            switch (fileFormat.Type)
            {
            case FileFormatType.SM:
                return(new SMReader(fullName));

            case FileFormatType.SSC:
                return(new SSCReader(fullName));
            }
            return(null);
        }
예제 #3
0
        /// <summary>
        /// Copies the non-chart files from the given song directory into the given save directory.
        /// </summary>
        /// <remarks>
        /// Idempotent.
        /// Will not copy if already invoked with the same song directory.
        /// Will not copy if not appropriate based on Config.NonChartFileCopyBehavior.
        /// Expects that saveDir exists and is writable.
        /// Will log errors and warnings on failures.
        /// </remarks>
        /// <param name="songDir">
        /// Directory of the song to copy the non-chart files from.
        /// </param>
        /// <param name="saveDir">
        /// Directory to copy the non-chart files into.
        /// </param>
        private static void CopyNonChartFiles(string songDir, string saveDir)
        {
            if (Config.Instance.NonChartFileCopyBehavior == CopyBehavior.DoNotCopy ||
                Config.Instance.IsOutputDirectorySameAsInputDirectory())
            {
                return;
            }

            // Only copy the non-chart files once per song.
            lock (CopiedDirectories)
            {
                if (CopiedDirectories.Contains(songDir))
                {
                    return;
                }
                CopiedDirectories.Add(songDir);
            }

            // Get the files in the song directory.
            string[] files;
            try
            {
                files = Directory.GetFiles(songDir);
            }
            catch (Exception e)
            {
                LogWarn($"Could not get files in \"{songDir}\". {e}");
                return;
            }

            // Check each file for copying
            foreach (var file in files)
            {
                // Get the FileInfo for this file so we can check its name.
                FileInfo fi;
                try
                {
                    fi = new FileInfo(file);
                }
                catch (Exception e)
                {
                    LogWarn($"Could not get file info for \"{file}\". {e}");
                    continue;
                }

                // Skip this file if it is a chart.
                var fileFormat = FileFormat.GetFileFormatByExtension(fi.Extension);
                if (fileFormat != null && SupportedFileFormats.Contains(fileFormat.Type))
                {
                    continue;
                }

                // Skip this file if it is not newer than the destination file and we
                // should only copy if newer.
                var destFilePath = saveDir + fi.Name;
                if (Config.Instance.NonChartFileCopyBehavior == CopyBehavior.IfNewer)
                {
                    FileInfo dfi;
                    try
                    {
                        dfi = new FileInfo(destFilePath);
                    }
                    catch (Exception e)
                    {
                        LogWarn($"Could not get file info for \"{destFilePath}\". {e}");
                        continue;
                    }

                    if (dfi.Exists && fi.LastWriteTime <= dfi.LastWriteTime)
                    {
                        continue;
                    }
                }

                // Copy the file.
                try
                {
                    File.Copy(Fumen.Path.GetWin32FileSystemFullPath(fi.FullName),
                              Fumen.Path.GetWin32FileSystemFullPath(destFilePath),
                              true);
                }
                catch (Exception e)
                {
                    LogWarn($"Failed to copy \"{fi.FullName}\" to \"{destFilePath}\". {e}");
                }
            }
        }
예제 #4
0
        /// <summary>
        /// Searches for songs matching Config parameters and processes each.
        /// Will add charts, copy the charts and non-chart files to the output directory,
        /// and write visualizations for the conversion.
        /// </summary>
        private static async Task FindAndProcessCharts()
        {
            if (!Directory.Exists(Config.Instance.InputDirectory))
            {
                LogError($"Could not find InputDirectory \"{Config.Instance.InputDirectory}\".");
                return;
            }

            var songTasks = new List <Task>();
            var pathSep   = System.IO.Path.DirectorySeparatorChar.ToString();

            // Search through the configured InputDirectory and all subdirectories.
            var dirs = new Stack <string>();

            dirs.Push(Config.Instance.InputDirectory);
            while (dirs.Count > 0)
            {
                // Get the directory to process.
                var currentDir = dirs.Pop();

                // Get sub directories for the next loop.
                try
                {
                    var subDirs = Directory.GetDirectories(currentDir);
                    // Reverse sort the subdirectories since we use a queue to pop.
                    // Sorting helps the user get a rough idea of progress, and makes it easier to tell if a song pack is complete.
                    Array.Sort(subDirs, (a, b) => String.Compare(b, a, StringComparison.CurrentCultureIgnoreCase));
                    foreach (var str in subDirs)
                    {
                        dirs.Push(str);
                    }
                }
                catch (Exception e)
                {
                    LogWarn($"Could not get directories in \"{currentDir}\". {e}");
                    continue;
                }

                // Get all files in this directory.
                string[] files;
                try
                {
                    files = Directory.GetFiles(currentDir);
                }
                catch (Exception e)
                {
                    LogWarn($"Could not get files in \"{currentDir}\". {e}");
                    continue;
                }

                // Cache some paths needed for processing the charts.
                var relativePath = currentDir.Substring(
                    Config.Instance.InputDirectory.Length,
                    currentDir.Length - Config.Instance.InputDirectory.Length);
                if (relativePath.StartsWith(pathSep))
                {
                    relativePath = relativePath.Substring(1, relativePath.Length - 1);
                }
                if (!relativePath.EndsWith(pathSep))
                {
                    relativePath += pathSep;
                }
                var saveDir = Fumen.Path.Combine(Config.Instance.OutputDirectory, relativePath);

                // Check each file.
                var hasSong = false;
                foreach (var file in files)
                {
                    // Get the FileInfo for this file so we can check its name.
                    FileInfo fi;
                    try
                    {
                        fi = new FileInfo(file);
                    }
                    catch (Exception e)
                    {
                        LogWarn($"Could not get file info for \"{file}\". {e}");
                        continue;
                    }

                    // Check that this is a supported file format.
                    var fileFormat = FileFormat.GetFileFormatByExtension(fi.Extension);
                    if (fileFormat == null || !SupportedFileFormats.Contains(fileFormat.Type))
                    {
                        continue;
                    }

                    // Check if the matches the expression for files to convert.
                    if (!Config.Instance.InputNameMatches(fi.Name))
                    {
                        continue;
                    }

                    // Create the save directory before starting any Tasks which write into it.
                    if (!hasSong)
                    {
                        hasSong = true;
                        Directory.CreateDirectory(saveDir);
                    }

                    // Process the song.
                    songTasks.Add(ProcessSong(new SongArgs
                    {
                        FileInfo     = fi,
                        CurrentDir   = currentDir,
                        RelativePath = relativePath,
                        SaveDir      = saveDir
                    }));
                }

                // TODO: Copy the song's pack assets.
            }

            // Allow the song tasks to complete.
            await Task.WhenAll(songTasks.ToArray());
        }