public override IEnumerable <Issue> GetIssues(BeatmapSet beatmapSet)
        {
            foreach (string hsFile in beatmapSet.hitSoundFiles)
            {
                string hsPath = Path.Combine(beatmapSet.songPath, hsFile);

                double    duration  = 0;
                Exception exception = null;
                try
                { duration = AudioBASS.GetDuration(hsPath); }
                catch (Exception ex)
                { exception = ex; }

                if (exception == null)
                {
                    // Greater than 0 since 44-byte muted hit sounds are fine.
                    if (duration < 25 && duration > 0)
                    {
                        yield return(new Issue(GetTemplate("Length"), null,
                                               hsFile, $"{duration:0.##}"));
                    }
                }
                else
                {
                    yield return(new Issue(GetTemplate("Unable to check"), null,
                                           hsFile, Common.ExceptionTag(exception)));
                }
            }
        }
        public override IEnumerable <Issue> GetIssues(BeatmapSet beatmapSet)
        {
            Dictionary <string, List <AudioUsage> > audioUsage = new Dictionary <string, List <AudioUsage> >();

            foreach (Beatmap beatmap in beatmapSet.beatmaps)
            {
                bool hasVideo      = beatmap.videos.Count > 0;
                bool hasStoryboard =
                    beatmap.HasDifficultySpecificStoryboard() ||
                    (beatmapSet.osb?.IsUsed() ?? false);

                string audioPath = beatmap.GetAudioFilePath();
                if (audioPath == null)
                {
                    continue;
                }

                double    duration  = 0;
                Exception exception = null;
                try
                { duration = AudioBASS.GetDuration(audioPath); }
                catch (Exception ex)
                { exception = ex; }

                if (exception != null)
                {
                    yield return(new Issue(GetTemplate("Unable to check"), null,
                                           PathStatic.RelativePath(audioPath, beatmap.songPath), Common.ExceptionTag(exception)));

                    continue;
                }

                double lastEndTime = beatmap.hitObjects.LastOrDefault()?.GetEndTime() ?? 0;
                double fraction    = lastEndTime / duration;

                if (!audioUsage.ContainsKey(audioPath))
                {
                    audioUsage[audioPath] = new List <AudioUsage>();
                }
                audioUsage[audioPath].Add(new AudioUsage(fraction, hasVideo || hasStoryboard));
            }

            foreach (string audioPath in audioUsage.Keys)
            {
                double maxFraction     = 0;
                bool   anyHasVideoOrSB = false;
                foreach (AudioUsage usage in audioUsage[audioPath])
                {
                    if (usage.fraction > maxFraction)
                    {
                        maxFraction = usage.fraction;
                    }
                    if (usage.hasVideoOrSB)
                    {
                        anyHasVideoOrSB = true;
                    }
                }

                if (maxFraction > 0.8d)
                {
                    continue;
                }

                string templateKey = (anyHasVideoOrSB ? "With" : "Without") + " Video/Storyboard";

                yield return(new Issue(GetTemplate(templateKey), null, $"{(1 - maxFraction) * 100:0.##}"));
            }
        }
Esempio n. 3
0
        private static string RenderResources(BeatmapSet aBeatmapSet)
        {
            string RenderFloat(List <string> aFiles, Func <string, string> aFunc)
            {
                string content =
                    String.Join("<br>",
                                aFiles.Select(aFile =>
                {
                    string path =
                        aBeatmapSet.hitSoundFiles.FirstOrDefault(anOtherFile =>
                                                                 anOtherFile.StartsWith(aFile + "."));
                    if (path == null)
                    {
                        return(null);
                    }

                    return(aFunc(path));
                }).Where(aValue => aValue != null)
                                );

                if (content.Length == 0)
                {
                    return("");
                }

                return(Div("overview-float", content));
            }

            Dictionary <string, int> hsUsedCount = new Dictionary <string, int>();

            return
                (RenderContainer("Resources",
                                 RenderBeatmapContent(aBeatmapSet, "Used Hit Sound File(s)", aBeatmap =>
            {
                List <string> usedHitSoundFiles =
                    aBeatmap.hitObjects.SelectMany(anObject => anObject.GetUsedHitSoundFileNames()).ToList();

                List <string> distinctSortedFiles =
                    usedHitSoundFiles.Distinct().OrderByDescending(aFile => aFile).ToList();

                return
                RenderFloat(distinctSortedFiles, aPath => Encode(aPath)) +
                RenderFloat(distinctSortedFiles, aPath =>
                {
                    int count = usedHitSoundFiles.Where(anOtherFile => aPath.StartsWith(anOtherFile + ".")).Count();

                    // Used for total hit sound usage overview
                    if (hsUsedCount.ContainsKey(aPath))
                    {
                        hsUsedCount[aPath] += count;
                    }
                    else
                    {
                        hsUsedCount[aPath] = count;
                    }

                    return $"× {count}";
                });
            }, false),
                                 RenderField("Total Used Hit Sound File(s)",
                                             (hsUsedCount.Any() ?
                                              Div("overview-float",
                                                  String.Join("<br>",
                                                              hsUsedCount.Select(aPair => aPair.Key)
                                                              )
                                                  ) +
                                              Div("overview-float",
                                                  String.Join("<br>",
                                                              hsUsedCount.Select(aPair =>
                                                                                 Try(() =>
            {
                string fullPath = Path.Combine(aBeatmapSet.songPath, aPair.Key);

                return Encode(RenderFileSize(fullPath));
            },
                                                                                     noteIfError: "Could not get hit sound file size"
                                                                                     )
                                                                                 )
                                                              )
                                                  ) +
                                              Div("overview-float",
                                                  String.Join("<br>",
                                                              hsUsedCount.Select(aPair =>
                                                                                 Try(() =>
            {
                string fullPath = Path.Combine(aBeatmapSet.songPath, aPair.Key);
                double duration = AudioBASS.GetDuration(fullPath);

                if (duration < 0)
                {
                    return "0 ms";
                }

                return $"{duration:0.##} ms";
            },
                                                                                     noteIfError: "Could not get hit sound duration"
                                                                                     )
                                                                                 )
                                                              )
                                                  ) +
                                              Div("overview-float",
                                                  String.Join("<br>",
                                                              hsUsedCount.Select(aPair =>
                                                                                 Try(() =>
            {
                string fullPath = Path.Combine(aBeatmapSet.songPath, aPair.Key);

                return Encode(AudioBASS.EnumToString(AudioBASS.GetFormat(fullPath)));
            },
                                                                                     noteIfError: "Could not get hit sound file path"
                                                                                     )
                                                                                 )
                                                              )
                                                  ) +
                                              Div("overview-float",
                                                  String.Join("<br>",
                                                              hsUsedCount.Select(aPair => "× " + aPair.Value)
                                                              )
                                                  )
                        : "")
                                             ),
                                 RenderBeatmapContent(aBeatmapSet, "Background File(s)", aBeatmap =>
            {
                if (aBeatmap.backgrounds.Any())
                {
                    string fullPath = Path.Combine(aBeatmap.songPath, aBeatmap.backgrounds.First().path);
                    if (!File.Exists(fullPath))
                    {
                        return "";
                    }

                    string error = null;
                    TagLib.File tagFile = null;
                    try
                    { tagFile = new FileAbstraction(fullPath).GetTagFile(); }
                    catch (Exception exception)
                    {
                        error = exception.Message;
                    }

                    return
                    Div("overview-float",
                        Try(() =>
                            Encode(aBeatmap.backgrounds.First().path),
                            noteIfError: "Could not get background file path"
                            )
                        ) +
                    Div("overview-float",
                        Try(() =>
                            Encode(RenderFileSize(fullPath)),
                            noteIfError: "Could not get background file size"
                            )
                        ) +
                    ((error != null || tagFile == null) ?
                     Div("overview-float",
                         Try(() =>
                             Encode(tagFile.Properties.PhotoWidth + " x " + tagFile.Properties.PhotoHeight),
                             noteIfError: "Could not get background resolution"
                             )
                         ) :
                     Div("overview-float",
                         Encode($"(failed getting proprties; {error})")
                         ));
                }
                else
                {
                    return "";
                }
            }, false),
                                 RenderBeatmapContent(aBeatmapSet, "Video File(s)", aBeatmap =>
            {
                if (aBeatmap.videos.Any() || (aBeatmapSet.osb?.videos.Any() ?? false))
                {
                    string fullPath = Path.Combine(aBeatmap.songPath, aBeatmap.videos.First().path);
                    if (!File.Exists(fullPath))
                    {
                        return "";
                    }

                    string error = null;
                    TagLib.File tagFile = null;
                    try
                    { tagFile = new FileAbstraction(fullPath).GetTagFile(); }
                    catch (Exception exception)
                    { error = exception.Message; }

                    return
                    Div("overview-float",
                        Try(() =>
                            Encode(aBeatmap.videos.First().path),
                            noteIfError: "Could not get video file path"
                            )
                        ) +
                    Div("overview-float",
                        Try(() =>
                            Encode(RenderFileSize(fullPath)),
                            noteIfError: "Could not get video file size"
                            )
                        ) +
                    ((error != null || tagFile == null) ?
                     Div("overview-float",
                         Try(() =>
                             FormatTimestamps(Encode(Timestamp.Get(tagFile.Properties.Duration.TotalMilliseconds))),
                             noteIfError: "Could not get video duration"
                             )
                         ) +
                     Div("overview-float",
                         Try(() =>
                             Encode(tagFile.Properties.VideoWidth + " x " + tagFile.Properties.VideoHeight),
                             noteIfError: "Could not get video resolution"
                             )
                         ) :
                     Div("overview-float",
                         Encode($"(failed getting proprties; {error})")
                         ));
                }
                else
                {
                    return "";
                }
            }, false),
                                 RenderBeatmapContent(aBeatmapSet, "Audio File(s)", aBeatmap =>
            {
                string path = aBeatmap.GetAudioFilePath();
                if (path == null)
                {
                    return "";
                }

                return
                Div("overview-float",
                    Try(() =>
                        Encode(PathStatic.RelativePath(path, aBeatmap.songPath)),
                        noteIfError: "Could not get audio file path"
                        )
                    ) +
                Div("overview-float",
                    Try(() =>
                        Encode(RenderFileSize(path)),
                        noteIfError: "Could not get audio file size"
                        )
                    ) +
                Div("overview-float",
                    Try(() =>
                        FormatTimestamps(Encode(Timestamp.Get(AudioBASS.GetDuration(path)))),
                        noteIfError: "Could not get audio duration"
                        )
                    ) +
                Div("overview-float",
                    Try(() =>
                        Encode(AudioBASS.EnumToString(AudioBASS.GetFormat(path))),
                        noteIfError: "Could not get audio format"
                        )
                    );
            }, false),
                                 RenderBeatmapContent(aBeatmapSet, "Audio Bitrate", aBeatmap =>
            {
                string path = aBeatmap.GetAudioFilePath();
                if (path == null)
                {
                    return "N/A";
                }

                return
                Div("overview-float",
                    $"average {Math.Round(AudioBASS.GetBitrate(path))} kbps"
                    );
            }, false),
                                 RenderField("Has .osb",
                                             Encode((aBeatmapSet.osb?.IsUsed() ?? false).ToString())
                                             ),
                                 RenderBeatmapContent(aBeatmapSet, "Has .osu Specific Storyboard", aBeatmap =>
                                                      aBeatmap.HasDifficultySpecificStoryboard().ToString()),
                                 RenderBeatmapContent(aBeatmapSet, "Song Folder Size", aBeatmap =>
                                                      RenderDirectorySize(aBeatmap.songPath))
                                 ));
        }