Skip to content

Commit

Permalink
Merge pull request #31307 from bdach/id3-tags
Browse files Browse the repository at this point in the history
Populate metadata from ID3 tags when changing beatmap audio track in editor
  • Loading branch information
peppy authored Dec 27, 2024
2 parents fa0d2f4 + 1b2a223 commit ac348b8
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 26 deletions.
55 changes: 36 additions & 19 deletions osu.Game/Screens/Edit/Setup/MetadataSection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,33 +28,31 @@ public partial class MetadataSection : SetupSection
public override LocalisableString Title => EditorSetupStrings.MetadataHeader;

[BackgroundDependencyLoader]
private void load()
private void load(SetupScreen? setupScreen)
{
var metadata = Beatmap.Metadata;

Children = new[]
{
ArtistTextBox = createTextBox<FormTextBox>(EditorSetupStrings.Artist,
!string.IsNullOrEmpty(metadata.ArtistUnicode) ? metadata.ArtistUnicode : metadata.Artist),
RomanisedArtistTextBox = createTextBox<FormRomanisedTextBox>(EditorSetupStrings.RomanisedArtist,
!string.IsNullOrEmpty(metadata.Artist) ? metadata.Artist : MetadataUtils.StripNonRomanisedCharacters(metadata.ArtistUnicode)),
TitleTextBox = createTextBox<FormTextBox>(EditorSetupStrings.Title,
!string.IsNullOrEmpty(metadata.TitleUnicode) ? metadata.TitleUnicode : metadata.Title),
RomanisedTitleTextBox = createTextBox<FormRomanisedTextBox>(EditorSetupStrings.RomanisedTitle,
!string.IsNullOrEmpty(metadata.Title) ? metadata.Title : MetadataUtils.StripNonRomanisedCharacters(metadata.ArtistUnicode)),
creatorTextBox = createTextBox<FormTextBox>(EditorSetupStrings.Creator, metadata.Author.Username),
difficultyTextBox = createTextBox<FormTextBox>(EditorSetupStrings.DifficultyName, Beatmap.BeatmapInfo.DifficultyName),
sourceTextBox = createTextBox<FormTextBox>(BeatmapsetsStrings.ShowInfoSource, metadata.Source),
tagsTextBox = createTextBox<FormTextBox>(BeatmapsetsStrings.ShowInfoTags, metadata.Tags)
ArtistTextBox = createTextBox<FormTextBox>(EditorSetupStrings.Artist),
RomanisedArtistTextBox = createTextBox<FormRomanisedTextBox>(EditorSetupStrings.RomanisedArtist),
TitleTextBox = createTextBox<FormTextBox>(EditorSetupStrings.Title),
RomanisedTitleTextBox = createTextBox<FormRomanisedTextBox>(EditorSetupStrings.RomanisedTitle),
creatorTextBox = createTextBox<FormTextBox>(EditorSetupStrings.Creator),
difficultyTextBox = createTextBox<FormTextBox>(EditorSetupStrings.DifficultyName),
sourceTextBox = createTextBox<FormTextBox>(BeatmapsetsStrings.ShowInfoSource),
tagsTextBox = createTextBox<FormTextBox>(BeatmapsetsStrings.ShowInfoTags)
};

if (setupScreen != null)
setupScreen.MetadataChanged += reloadMetadata;

reloadMetadata();
}

private TTextBox createTextBox<TTextBox>(LocalisableString label, string initialValue)
private TTextBox createTextBox<TTextBox>(LocalisableString label)
where TTextBox : FormTextBox, new()
=> new TTextBox
{
Caption = label,
Current = { Value = initialValue },
TabbableContentContainer = this
};

Expand Down Expand Up @@ -94,10 +92,29 @@ private void onCommit(TextBox sender, bool newText)

// for now, update on commit rather than making BeatmapMetadata bindables.
// after switching database engines we can reconsider if switching to bindables is a good direction.
updateMetadata();
setMetadata();
}

private void reloadMetadata()
{
var metadata = Beatmap.Metadata;

RomanisedArtistTextBox.ReadOnly = false;
RomanisedTitleTextBox.ReadOnly = false;

ArtistTextBox.Current.Value = !string.IsNullOrEmpty(metadata.ArtistUnicode) ? metadata.ArtistUnicode : metadata.Artist;
RomanisedArtistTextBox.Current.Value = !string.IsNullOrEmpty(metadata.Artist) ? metadata.Artist : MetadataUtils.StripNonRomanisedCharacters(metadata.ArtistUnicode);
TitleTextBox.Current.Value = !string.IsNullOrEmpty(metadata.TitleUnicode) ? metadata.TitleUnicode : metadata.Title;
RomanisedTitleTextBox.Current.Value = !string.IsNullOrEmpty(metadata.Title) ? metadata.Title : MetadataUtils.StripNonRomanisedCharacters(metadata.ArtistUnicode);
creatorTextBox.Current.Value = metadata.Author.Username;
difficultyTextBox.Current.Value = Beatmap.BeatmapInfo.DifficultyName;
sourceTextBox.Current.Value = metadata.Source;
tagsTextBox.Current.Value = metadata.Tags;

updateReadOnlyState();
}

private void updateMetadata()
private void setMetadata()
{
Beatmap.Metadata.ArtistUnicode = ArtistTextBox.Current.Value;
Beatmap.Metadata.Artist = RomanisedArtistTextBox.Current.Value;
Expand Down
36 changes: 29 additions & 7 deletions osu.Game/Screens/Edit/Setup/ResourcesSection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ public partial class ResourcesSection : SetupSection
[Resolved]
private Editor? editor { get; set; }

[Resolved]
private SetupScreen setupScreen { get; set; } = null!;

private SetupScreenHeaderBackground headerBackground = null!;

[BackgroundDependencyLoader]
Expand Down Expand Up @@ -93,15 +96,37 @@ public bool ChangeAudioTrack(FileInfo source, bool applyToAllDifficulties)
if (!source.Exists)
return false;

var tagSource = TagLib.File.Create(source.FullName);

changeResource(source, applyToAllDifficulties, @"audio",
metadata => metadata.AudioFile,
(metadata, name) => metadata.AudioFile = name);
(metadata, name) =>
{
metadata.AudioFile = name;

string artist = tagSource.Tag.JoinedAlbumArtists;

if (!string.IsNullOrWhiteSpace(artist))
{
metadata.ArtistUnicode = artist;
metadata.Artist = MetadataUtils.StripNonRomanisedCharacters(metadata.ArtistUnicode);
}

string title = tagSource.Tag.Title;

if (!string.IsNullOrEmpty(title))
{
metadata.TitleUnicode = title;
metadata.Title = MetadataUtils.StripNonRomanisedCharacters(metadata.TitleUnicode);
}
});

music.ReloadCurrentTrack();
setupScreen.MetadataChanged?.Invoke();
return true;
}

private void changeResource(FileInfo source, bool applyToAllDifficulties, string baseFilename, Func<BeatmapMetadata, string> readFilename, Action<BeatmapMetadata, string> writeFilename)
private void changeResource(FileInfo source, bool applyToAllDifficulties, string baseFilename, Func<BeatmapMetadata, string> readFilename, Action<BeatmapMetadata, string> writeMetadata)
{
var set = working.Value.BeatmapSetInfo;
var beatmap = working.Value.BeatmapInfo;
Expand Down Expand Up @@ -148,10 +173,7 @@ private void changeResource(FileInfo source, bool applyToAllDifficulties, string
{
foreach (var b in otherBeatmaps)
{
// This operation is quite expensive, so only perform it if required.
if (readFilename(b.Metadata) == newFilename) continue;

writeFilename(b.Metadata, newFilename);
writeMetadata(b.Metadata, newFilename);

// save the difficulty to re-encode the .osu file, updating any reference of the old filename.
//
Expand All @@ -162,7 +184,7 @@ private void changeResource(FileInfo source, bool applyToAllDifficulties, string
}
}

writeFilename(beatmap.Metadata, newFilename);
writeMetadata(beatmap.Metadata, newFilename);

// editor change handler cannot be aware of any file changes or other difficulties having their metadata modified.
// for simplicity's sake, trigger a save when changing any resource to ensure the change is correctly saved.
Expand Down
4 changes: 4 additions & 0 deletions osu.Game/Screens/Edit/Setup/SetupScreen.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd <[email protected]>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.

using System;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
Expand All @@ -13,12 +14,15 @@

namespace osu.Game.Screens.Edit.Setup
{
[Cached]
public partial class SetupScreen : EditorScreen
{
public const float COLUMN_WIDTH = 450;
public const float SPACING = 28;
public const float MAX_WIDTH = 2 * COLUMN_WIDTH + SPACING;

public Action? MetadataChanged { get; set; }

public SetupScreen()
: base(EditorScreenMode.SongSetup)
{
Expand Down

0 comments on commit ac348b8

Please sign in to comment.