Ejemplo n.º 1
0
        private 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.##}"));
            }
        }
Ejemplo n.º 2
0
        public Background(string[] anArgs)
        {
            layer  = GetLayer(anArgs);
            path   = GetPath(anArgs);
            offset = GetOffset(anArgs);

            strippedPath = PathStatic.ParsePath(path, true);
        }
Ejemplo n.º 3
0
        public Sample(string[] args)
        {
            time   = GetTime(args);
            layer  = GetLayer(args);
            path   = GetPath(args);
            volume = GetVolume(args);

            strippedPath = PathStatic.ParsePath(path, true);
        }
Ejemplo n.º 4
0
        public StoryHitSound(string[] anArgs)
        {
            time   = GetTime(anArgs);
            layer  = GetLayer(anArgs);
            path   = GetPath(anArgs);
            volume = GetVolume(anArgs);

            strippedPath = PathStatic.ParsePath(path, true);
        }
Ejemplo n.º 5
0
        public IEnumerable <Issue> GetIssue(BeatmapSet aBeatmapSet, string audioPath, bool isHitSound = false)
        {
            string    audioRelPath = PathStatic.RelativePath(audioPath, aBeatmapSet.songPath);
            AudioFile file         = new AudioFile(audioPath);

            // gets the bitrate in bps, so turn it into kbps
            double bitrate    = file.GetAverageBitrate() / 1000;
            double minBitrate = file.GetLowestBitrate() / 1000;
            double maxBitrate = file.GetHighestBitrate() / 1000;

            if (minBitrate == maxBitrate)
            {
                if (minBitrate < 128 || (maxBitrate > 192 && !isHitSound))
                {
                    if (!isHitSound)
                    {
                        yield return(new Issue(GetTemplate("CBR"), null,
                                               audioRelPath, $"{bitrate:0.##}",
                                               (bitrate < 128 ? "low" : "high")));
                    }
                    else
                    {
                        yield return(new Issue(GetTemplate("CBR Hit Sound"), null,
                                               audioRelPath, $"{bitrate:0.##}"));
                    }
                }
            }
            else
            {
                if (bitrate < 128 || (bitrate > 192 && !isHitSound))
                {
                    if (Math.Round(bitrate) < 128 || (Math.Round(bitrate) > 192 && !isHitSound))
                    {
                        if (!isHitSound)
                        {
                            yield return(new Issue(GetTemplate("VBR"), null,
                                                   audioRelPath,
                                                   $"{bitrate:0.##}", $"{minBitrate:0.##}", $"{maxBitrate:0.##}",
                                                   (bitrate < 128 ? "low" : "high")));
                        }
                        else
                        {
                            yield return(new Issue(GetTemplate("VBR Hit Sound"), null,
                                                   audioRelPath,
                                                   $"{bitrate:0.##}", $"{minBitrate:0.##}", $"{maxBitrate:0.##}"));
                        }
                    }
                    else if (!isHitSound)
                    {
                        yield return(new Issue(GetTemplate("Exact VBR"), null,
                                               audioRelPath,
                                               $"{bitrate:0.##}", $"{minBitrate:0.##}", $"{maxBitrate:0.##}",
                                               (bitrate < 128 ? "low" : "high")));
                    }
                }
            }
        }
Ejemplo n.º 6
0
        public Sprite(string[] anArgs)
        {
            layer  = GetLayer(anArgs);
            origin = GetOrigin(anArgs);
            path   = GetPath(anArgs);
            offset = GetOffset(anArgs);

            strippedPath = PathStatic.ParsePath(path, true);
        }
Ejemplo n.º 7
0
 public override IEnumerable <Issue> GetIssues(BeatmapSet aBeatmapSet)
 {
     foreach (Issue issue in Common.GetInconsistencies(
                  aBeatmapSet,
                  aBeatmap => PathStatic.RelativePath(aBeatmap.GetAudioFilePath(), aBeatmap.songPath),
                  GetTemplate("Multiple")))
     {
         yield return(issue);
     }
 }
Ejemplo n.º 8
0
        /// <summary> Returns the last file path matching the given search pattern, relative to the song folder.
        /// The search pattern allows two wildcards: * = 0 or more, ? = 0 or 1. </summary>
        private string GetLastMatchingFilePath(string searchPattern)
        {
            var lastMatchingPath = Directory.EnumerateFiles(songPath, searchPattern, SearchOption.AllDirectories).LastOrDefault();

            if (lastMatchingPath == null)
            {
                return(null);
            }

            return(PathStatic.RelativePath(lastMatchingPath, songPath).Replace("\\", "/"));
        }
Ejemplo n.º 9
0
        public override IEnumerable <Issue> GetIssues(BeatmapSet beatmapSet)
        {
            if (beatmapSet.GetAudioFilePath() != null)
            {
                foreach (var issue in GetIssue(beatmapSet, beatmapSet.GetAudioFilePath()))
                {
                    yield return(issue);
                }
            }

            foreach (string hitSoundFile in beatmapSet.hitSoundFiles)
            {
                string hitSoundPath = Path.Combine(beatmapSet.songPath, hitSoundFile);

                ManagedBass.ChannelType hitSoundFormat = 0;
                Issue errorIssue = null;
                try
                {
                    hitSoundFormat = AudioBASS.GetFormat(hitSoundPath);
                }
                catch (Exception exception)
                {
                    errorIssue = new Issue(GetTemplate("Exception"), null,
                                           PathStatic.RelativePath(hitSoundPath, beatmapSet.songPath),
                                           Common.ExceptionTag(exception));
                }

                if (errorIssue != null)
                {
                    yield return(errorIssue);

                    continue;
                }

                if ((hitSoundFormat & ManagedBass.ChannelType.OGG) != 0 &&
                    (hitSoundFormat & ManagedBass.ChannelType.MP3) != 0)
                {
                    continue;
                }

                foreach (var issue in GetIssue(beatmapSet, hitSoundPath, true))
                {
                    yield return(issue);
                }
            }
        }
Ejemplo n.º 10
0
        public override IEnumerable <Issue> GetIssues(BeatmapSet aBeatmapSet)
        {
            foreach (Beatmap beatmap in aBeatmapSet.beatmaps)
            {
                bool hasVideo      = beatmap.videos.Count > 0;
                bool hasStoryboard =
                    beatmap.HasDifficultySpecificStoryboard() ||
                    (aBeatmapSet.osb?.IsUsed() ?? false);

                string audioPath = beatmap.GetAudioFilePath();
                if (audioPath != null)
                {
                    double    duration  = 0;
                    Exception exception = null;
                    try
                    {
                        duration = Audio.GetDuration(audioPath);
                    }
                    catch (Exception ex)
                    {
                        exception = ex;
                    }

                    if (exception == null)
                    {
                        double lastEndTime = beatmap.hitObjects.LastOrDefault()?.GetEndTime() ?? 0;

                        double unusedPercentage = 1 - lastEndTime / duration;
                        if (unusedPercentage >= 0.2)
                        {
                            string roundedPercentage = $"{unusedPercentage * 100:0.##}";
                            string templateKey       = (hasStoryboard || hasVideo ? "With" : "Without") + " Video/Storyboard";

                            yield return(new Issue(GetTemplate(templateKey), beatmap,
                                                   roundedPercentage));
                        }
                    }
                    else
                    {
                        yield return(new Issue(GetTemplate("Unable to check"), null,
                                               PathStatic.RelativePath(audioPath, beatmap.songPath), exception));
                    }
                }
            }
        }
Ejemplo n.º 11
0
        public BeatmapSet(string aBeatmapSetPath)
        {
            Track mapsetTrack = new Track("Parsing mapset \"" + PathStatic.CutPath(aBeatmapSetPath) + "\"...");

            beatmaps = new List <Beatmap>();
            osb      = null;
            songPath = aBeatmapSetPath;

            Initalize(aBeatmapSetPath);

            Track hsTrack = new Track("Finding hit sound files...");

            hitSoundFiles = GetUsedHitSoundFiles().ToList();
            hsTrack.Complete();

            beatmaps = beatmaps.OrderBy(aBeatmap => aBeatmap.GetDifficulty(true)).ThenBy(aBeatmap => aBeatmap.starRating).ToList();

            mapsetTrack.Complete();
        }
Ejemplo n.º 12
0
 public override IEnumerable <Issue> GetIssues(BeatmapSet aBeatmapSet)
 {
     if (aBeatmapSet.beatmaps.All(aBeatmap => aBeatmap.GetAudioFilePath() == null))
     {
         foreach (Beatmap beatmap in aBeatmapSet.beatmaps)
         {
             yield return(new Issue(GetTemplate("Missing"), beatmap));
         }
     }
     else
     {
         foreach (Issue issue in Common.GetInconsistencies(
                      aBeatmapSet,
                      aBeatmap =>
                      aBeatmap.GetAudioFilePath() != null ?
                      PathStatic.RelativePath(aBeatmap.GetAudioFilePath(), aBeatmap.songPath) :
                      "None",
                      GetTemplate("Multiple")))
         {
             yield return(issue);
         }
     }
 }
Ejemplo n.º 13
0
        public HitObject(string[] args, Beatmap beatmap)
        {
            this.beatmap = beatmap;
            code         = String.Join(",", args);

            Position = GetPosition(args);

            time     = GetTime(args);
            type     = GetTypeFlags(args);
            hitSound = GetHitSound(args);

            // extras
            Tuple <Beatmap.Sampleset, Beatmap.Sampleset, int?, int?, string> extras = GetExtras(args);

            if (extras != null)
            {
                // custom index and volume are by default 0 if there are edge hitsounds or similar
                sampleset   = extras.Item1;
                addition    = extras.Item2;
                customIndex = extras.Item3 == 0 ? null : extras.Item3;
                volume      = extras.Item4 == 0 ? null : extras.Item4;

                // hitsound filenames only apply to circles and hold notes
                string hitSoundFile = extras.Item5;
                if (hitSoundFile.Trim() != "" && (HasType(Type.Circle) || HasType(Type.ManiaHoldNote)))
                {
                    filename = PathStatic.ParsePath(hitSoundFile, false, true);
                }
            }

            // Sliders and spinners include additional edges which support hit sounding, so we
            // should handle that after those edges are initialized in Slider/Spinner instead.
            if (!(this is Slider) && !(this is Spinner))
            {
                usedHitSamples = GetUsedHitSamples().ToList();
            }
        }
Ejemplo n.º 14
0
        /// <summary> Returns whether the given full file path is used by the beatmapset. </summary>
        public bool IsFileUsed(string filePath)
        {
            string relativePath = PathStatic.RelativePath(filePath, songPath);
            string fileName     = relativePath.Split(new char[] { '/', '\\' }).Last().ToLower();
            string parsedPath   = PathStatic.ParsePath(relativePath);
            string strippedPath = PathStatic.ParsePath(relativePath, withoutExtension: true);

            if (beatmaps.Any(beatmap => beatmap.generalSettings.audioFileName.ToLower() == parsedPath))
            {
                return(true);
            }

            // When the path is "go", and "go.png" is over "go.jpg" in order, then "go.jpg" will be the one used.
            // So we basically want to find the last path which matches the name.
            string lastMatchingPath = PathStatic.ParsePath(GetLastMatchingPath(parsedPath));

            // These are always used, but you won't be able to update them unless they have the right format.
            if (fileName.EndsWith(".osu"))
            {
                return(true);
            }

            if (beatmaps.Any(beatmap =>
                             beatmap.sprites.Any(element => element.path.ToLower() == parsedPath) ||
                             beatmap.videos.Any(element => element.path.ToLower() == parsedPath) ||
                             beatmap.backgrounds.Any(element => element.path.ToLower() == parsedPath) ||
                             beatmap.animations.Any(element => element.path.ToLower() == parsedPath) ||
                             beatmap.samples.Any(element => element.path.ToLower() == parsedPath)))
            {
                return(true);
            }

            // animations cannot be stripped of their extension
            if (beatmaps.Any(beatmap =>
                             beatmap.sprites.Any(element => element.strippedPath == strippedPath) ||
                             beatmap.videos.Any(element => element.strippedPath == strippedPath) ||
                             beatmap.backgrounds.Any(element => element.strippedPath == strippedPath) ||
                             beatmap.samples.Any(element => element.strippedPath == strippedPath)) &&
                parsedPath == lastMatchingPath)
            {
                return(true);
            }

            if (osb != null && (
                    osb.sprites.Any(element => element.path.ToLower() == parsedPath) ||
                    osb.videos.Any(element => element.path.ToLower() == parsedPath) ||
                    osb.backgrounds.Any(element => element.path.ToLower() == parsedPath) ||
                    osb.animations.Any(element => element.path.ToLower() == parsedPath) ||
                    osb.samples.Any(anElement => anElement.path.ToLower() == parsedPath)))
            {
                return(true);
            }

            if (osb != null && (
                    osb.sprites.Any(element => element.strippedPath == strippedPath) ||
                    osb.videos.Any(element => element.strippedPath == strippedPath) ||
                    osb.backgrounds.Any(element => element.strippedPath == strippedPath) ||
                    osb.samples.Any(element => element.strippedPath == strippedPath)) &&
                parsedPath == lastMatchingPath)
            {
                return(true);
            }

            if (beatmaps.Any(beatmap => beatmap.hitObjects.Any(hitObject =>
                                                               (hitObject.filename != null ? PathStatic.ParsePath(hitObject.filename, true) : null) == strippedPath)))
            {
                return(true);
            }

            if (hitSoundFiles.Any(hsPath => PathStatic.ParsePath(hsPath) == parsedPath))
            {
                return(true);
            }

            if (SkinStatic.IsUsed(fileName, this))
            {
                return(true);
            }

            if (fileName == GetOsbFileName().ToLower() && osb.IsUsed())
            {
                return(true);
            }

            foreach (Beatmap beatmap in beatmaps)
            {
                if (IsAnimationPathUsed(parsedPath, beatmap.animations))
                {
                    return(true);
                }
            }

            if (osb != null && IsAnimationPathUsed(parsedPath, osb.animations))
            {
                return(true);
            }

            return(false);
        }
Ejemplo n.º 15
0
        /// <summary> Returns whether the given full file path is used by the beatmapset. </summary>
        public bool IsFileUsed(string aFilePath)
        {
            string relativePath = PathStatic.RelativePath(aFilePath, songPath);
            string fileName     = relativePath.Split(new char[] { '/', '\\' }).Last().ToLower();
            string parsedPath   = PathStatic.ParsePath(relativePath);
            string strippedPath = PathStatic.ParsePath(relativePath, true);

            if (beatmaps.Any(aBeatmap => aBeatmap.generalSettings.audioFileName.ToLower() == parsedPath))
            {
                return(true);
            }

            // When the path is "go", and "go.png" is over "go.jpg" in order, then "go.jpg" will be the one used.
            // So we basically want to find the last path which matches the name.
            string lastStripped = null;

            foreach (string file in Directory.EnumerateFiles(songPath, "*", SearchOption.AllDirectories))
            {
                string relPath = PathStatic.RelativePath(file, songPath).Replace("\\", "/");
                if (relPath.StartsWith(strippedPath + ".", StringComparison.OrdinalIgnoreCase))
                {
                    lastStripped = file.Substring(songPath.Length + 1);
                    break;
                }
            }

            if (lastStripped == null)
            {
                return(false);
            }

            // these are always used, but you won't be able to update them unless they have the right format
            if (fileName.EndsWith(".osu"))
            {
                return(true);
            }

            if (beatmaps.Any(aBeatmap =>
                             aBeatmap.sprites.Any(anElement => anElement.path.ToLower() == parsedPath) ||
                             aBeatmap.videos.Any(anElement => anElement.path.ToLower() == parsedPath) ||
                             aBeatmap.backgrounds.Any(anElement => anElement.path.ToLower() == parsedPath) ||
                             aBeatmap.animations.Any(anElement => anElement.path.ToLower() == parsedPath) ||
                             aBeatmap.storyHitSounds.Any(anElement => anElement.path.ToLower() == parsedPath)))
            {
                return(true);
            }

            // animations cannot be stripped of their extension
            if (beatmaps.Any(aBeatmap =>
                             aBeatmap.sprites.Any(anElement => anElement.strippedPath == strippedPath && lastStripped.StartsWith(anElement.path)) ||
                             aBeatmap.videos.Any(anElement => anElement.strippedPath == strippedPath && lastStripped.StartsWith(anElement.path)) ||
                             aBeatmap.backgrounds.Any(anElement => anElement.strippedPath == strippedPath && lastStripped.StartsWith(anElement.path)) ||
                             aBeatmap.storyHitSounds.Any(anElement => anElement.strippedPath == strippedPath && lastStripped.StartsWith(anElement.path))) &&
                parsedPath == lastStripped)
            {
                return(true);
            }

            if (osb != null && (
                    osb.sprites.Any(anElement => anElement.path.ToLower() == parsedPath) ||
                    osb.videos.Any(anElement => anElement.path.ToLower() == parsedPath) ||
                    osb.backgrounds.Any(anElement => anElement.path.ToLower() == parsedPath) ||
                    osb.animations.Any(anElement => anElement.path.ToLower() == parsedPath) ||
                    osb.storyHitSounds.Any(anElement => anElement.path.ToLower() == parsedPath)))
            {
                return(true);
            }

            if (osb != null && (
                    osb.sprites.Any(anElement => anElement.strippedPath == strippedPath && lastStripped.StartsWith(anElement.path)) ||
                    osb.videos.Any(anElement => anElement.strippedPath == strippedPath && lastStripped.StartsWith(anElement.path)) ||
                    osb.backgrounds.Any(anElement => anElement.strippedPath == strippedPath && lastStripped.StartsWith(anElement.path)) ||
                    osb.storyHitSounds.Any(anElement => anElement.strippedPath == strippedPath && lastStripped.StartsWith(anElement.path))) &&
                parsedPath == lastStripped)
            {
                return(true);
            }

            if (beatmaps.Any(aBeatmap => aBeatmap.hitObjects.Any(anObject =>
                                                                 (anObject.filename != null ? PathStatic.ParsePath(anObject.filename, true) : null) == strippedPath)))
            {
                return(true);
            }

            if (hitSoundFiles.Any(aHitSoundPath => PathStatic.ParsePath(aHitSoundPath) == parsedPath))
            {
                return(true);
            }

            if (SkinStatic.IsUsed(fileName, this))
            {
                return(true);
            }

            if (fileName == GetOsbFileName().ToLower() && osb.IsUsed())
            {
                return(true);
            }

            foreach (Beatmap beatmap in beatmaps)
            {
                if (IsAnimationUsed(parsedPath, beatmap.animations))
                {
                    return(true);
                }
            }

            if (osb != null && IsAnimationUsed(parsedPath, osb.animations))
            {
                return(true);
            }

            return(false);
        }
Ejemplo n.º 16
0
 // path
 private string GetPath(string[] anArgs)
 {
     return(PathStatic.ParsePath(anArgs[3], false, true));
 }
Ejemplo n.º 17
0
 /// <summary> Returns the file path which this background uses. Retains case and extension. </summary>
 private string GetPath(string[] args) =>
 PathStatic.ParsePath(args[2], retainCase: true);
Ejemplo n.º 18
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))
                                 ));
        }
        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.##}"));
            }
        }
Ejemplo n.º 20
0
 // filename
 private string GetPath(string[] anArgs)
 {
     // remove quotes for consistency, no way to add quotes manually anyway
     return(PathStatic.ParsePath(anArgs[3], false, true));
 }