public IEnumerable <Issue> GetIssue(BeatmapSet beatmapSet, string audioPath, bool isHitSound = false) { // `Audio.GetBitrate` has a < 0.1 kbps error margin, so we should round this. double bitrate = Math.Round(AudioBASS.GetBitrate(audioPath)); // Hit sounds only need to follow the lower limit for quality requirements, as Wave // (which is the most used hit sound format currently) is otherwise uncompressed anyway. if (bitrate >= 128 && (bitrate <= 192 || isHitSound)) { yield break; } string audioRelPath = PathStatic.RelativePath(audioPath, beatmapSet.songPath); if (!isHitSound) { yield return(new Issue(GetTemplate("Bitrate"), null, audioRelPath, $"{bitrate:0.##}", (bitrate < 128 ? "low" : "high"))); } else { yield return(new Issue(GetTemplate("Hit Sound"), null, audioRelPath, $"{bitrate: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)) )); }