1
0
mirror of https://github.com/ppy/osu.git synced 2025-02-21 20:12:57 +08:00

Merge pull request #31307 from bdach/id3-tags

Populate metadata from ID3 tags when changing beatmap audio track in editor
This commit is contained in:
Dean Herbert 2024-12-28 02:41:49 +09:00 committed by GitHub
commit ac348b8780
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 69 additions and 26 deletions

View File

@ -28,33 +28,31 @@ namespace osu.Game.Screens.Edit.Setup
public override LocalisableString Title => EditorSetupStrings.MetadataHeader; public override LocalisableString Title => EditorSetupStrings.MetadataHeader;
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load(SetupScreen? setupScreen)
{ {
var metadata = Beatmap.Metadata;
Children = new[] Children = new[]
{ {
ArtistTextBox = createTextBox<FormTextBox>(EditorSetupStrings.Artist, ArtistTextBox = createTextBox<FormTextBox>(EditorSetupStrings.Artist),
!string.IsNullOrEmpty(metadata.ArtistUnicode) ? metadata.ArtistUnicode : metadata.Artist), RomanisedArtistTextBox = createTextBox<FormRomanisedTextBox>(EditorSetupStrings.RomanisedArtist),
RomanisedArtistTextBox = createTextBox<FormRomanisedTextBox>(EditorSetupStrings.RomanisedArtist, TitleTextBox = createTextBox<FormTextBox>(EditorSetupStrings.Title),
!string.IsNullOrEmpty(metadata.Artist) ? metadata.Artist : MetadataUtils.StripNonRomanisedCharacters(metadata.ArtistUnicode)), RomanisedTitleTextBox = createTextBox<FormRomanisedTextBox>(EditorSetupStrings.RomanisedTitle),
TitleTextBox = createTextBox<FormTextBox>(EditorSetupStrings.Title, creatorTextBox = createTextBox<FormTextBox>(EditorSetupStrings.Creator),
!string.IsNullOrEmpty(metadata.TitleUnicode) ? metadata.TitleUnicode : metadata.Title), difficultyTextBox = createTextBox<FormTextBox>(EditorSetupStrings.DifficultyName),
RomanisedTitleTextBox = createTextBox<FormRomanisedTextBox>(EditorSetupStrings.RomanisedTitle, sourceTextBox = createTextBox<FormTextBox>(BeatmapsetsStrings.ShowInfoSource),
!string.IsNullOrEmpty(metadata.Title) ? metadata.Title : MetadataUtils.StripNonRomanisedCharacters(metadata.ArtistUnicode)), tagsTextBox = createTextBox<FormTextBox>(BeatmapsetsStrings.ShowInfoTags)
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)
}; };
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() where TTextBox : FormTextBox, new()
=> new TTextBox => new TTextBox
{ {
Caption = label, Caption = label,
Current = { Value = initialValue },
TabbableContentContainer = this TabbableContentContainer = this
}; };
@ -94,10 +92,29 @@ namespace osu.Game.Screens.Edit.Setup
// for now, update on commit rather than making BeatmapMetadata bindables. // 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. // after switching database engines we can reconsider if switching to bindables is a good direction.
updateMetadata(); setMetadata();
} }
private void updateMetadata() 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 setMetadata()
{ {
Beatmap.Metadata.ArtistUnicode = ArtistTextBox.Current.Value; Beatmap.Metadata.ArtistUnicode = ArtistTextBox.Current.Value;
Beatmap.Metadata.Artist = RomanisedArtistTextBox.Current.Value; Beatmap.Metadata.Artist = RomanisedArtistTextBox.Current.Value;

View File

@ -35,6 +35,9 @@ namespace osu.Game.Screens.Edit.Setup
[Resolved] [Resolved]
private Editor? editor { get; set; } private Editor? editor { get; set; }
[Resolved]
private SetupScreen setupScreen { get; set; } = null!;
private SetupScreenHeaderBackground headerBackground = null!; private SetupScreenHeaderBackground headerBackground = null!;
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
@ -93,15 +96,37 @@ namespace osu.Game.Screens.Edit.Setup
if (!source.Exists) if (!source.Exists)
return false; return false;
var tagSource = TagLib.File.Create(source.FullName);
changeResource(source, applyToAllDifficulties, @"audio", changeResource(source, applyToAllDifficulties, @"audio",
metadata => metadata.AudioFile, 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(); music.ReloadCurrentTrack();
setupScreen.MetadataChanged?.Invoke();
return true; 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 set = working.Value.BeatmapSetInfo;
var beatmap = working.Value.BeatmapInfo; var beatmap = working.Value.BeatmapInfo;
@ -148,10 +173,7 @@ namespace osu.Game.Screens.Edit.Setup
{ {
foreach (var b in otherBeatmaps) foreach (var b in otherBeatmaps)
{ {
// This operation is quite expensive, so only perform it if required. writeMetadata(b.Metadata, newFilename);
if (readFilename(b.Metadata) == newFilename) continue;
writeFilename(b.Metadata, newFilename);
// save the difficulty to re-encode the .osu file, updating any reference of the old filename. // save the difficulty to re-encode the .osu file, updating any reference of the old filename.
// //
@ -162,7 +184,7 @@ namespace osu.Game.Screens.Edit.Setup
} }
} }
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. // 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. // for simplicity's sake, trigger a save when changing any resource to ensure the change is correctly saved.

View File

@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using System;
using System.Linq; using System.Linq;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
@ -13,12 +14,15 @@ using osuTK;
namespace osu.Game.Screens.Edit.Setup namespace osu.Game.Screens.Edit.Setup
{ {
[Cached]
public partial class SetupScreen : EditorScreen public partial class SetupScreen : EditorScreen
{ {
public const float COLUMN_WIDTH = 450; public const float COLUMN_WIDTH = 450;
public const float SPACING = 28; public const float SPACING = 28;
public const float MAX_WIDTH = 2 * COLUMN_WIDTH + SPACING; public const float MAX_WIDTH = 2 * COLUMN_WIDTH + SPACING;
public Action? MetadataChanged { get; set; }
public SetupScreen() public SetupScreen()
: base(EditorScreenMode.SongSetup) : base(EditorScreenMode.SongSetup)
{ {