Skip to content

Commit

Permalink
Migrate metadata mapping (#871)
Browse files Browse the repository at this point in the history
* Update FLAC/OGG metadata for bpm and comment to musicbrainz mapping
  • Loading branch information
luzip665 committed May 17, 2023
1 parent 84c773f commit 7f37b1e
Show file tree
Hide file tree
Showing 6 changed files with 217 additions and 5 deletions.
55 changes: 55 additions & 0 deletions data/ui/preferences/collection.ui
Original file line number Diff line number Diff line change
Expand Up @@ -150,5 +150,60 @@ This feature should work for MP3, MP4, FLAC and OGG. </property>
<property name="width">2</property>
</packing>
</child>
<child>
<object class="GtkCheckButton" id="collection/use_legacy_metadata_mapping">
<property name="label" translatable="yes">Use legacy tag mapping</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="draw_indicator">True</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">9</property>
<property name="width">2</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="collection/use_legacy_metadata_mapping_hint">
<property name="can_focus">False</property>
<property name="label" translatable="yes">Use legacy tag mapping for Ogg Vorbis and FLAC files for comment and bpm tags. From Exaile 4.1.3 the mapping is equivalent to MusicBrainz.
Your can start migration here. After migration this feature will be disabled.</property>
<property name="justify">fill</property>
<property name="wrap">True</property>
<accessibility>
<relation type="label-for" target="collection/use_legacy_metadata_mapping"/>
</accessibility>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">10</property>
<property name="width">2</property>
</packing>
</child>
<child>
<object class="GtkButton" id="collection/use_legacy_metadata_mapping_sync_now">
<property name="width_request">150</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">Migrate existing tempo and comment tags now</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">11</property>
<property name="width">2</property>
</packing>
</child>
<child>
<object class="GtkBox" id="collection/use_legacy_metadata_mapping_progress">
<property name="visible">True</property>
<property name="can_focus">True</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">12</property>
<property name="width">2</property>
</packing>
</child>
</object>
</interface>
5 changes: 5 additions & 0 deletions xl/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -644,6 +644,11 @@ def __init(self):

engine.migrate()

# Activate new flac/ogg metadata handling for new installations
from xl.migrations.settings import flac_tempo

flac_tempo.migrate()

# TODO: enable audio plugins separately from normal
# plugins? What about plugins that use the player?

Expand Down
27 changes: 25 additions & 2 deletions xl/metadata/flac.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,15 @@

import xl.unicode
from xl.metadata._base import CaseInsensitiveBaseFormat, CoverImage
from xl import settings
from mutagen import flac
from mutagen.flac import Picture


class FlacFormat(CaseInsensitiveBaseFormat):
MutagenType = flac.FLAC
tag_mapping = {
'bpm': 'tempo',
'cover': '__cover',
'comment': 'description',
'language': "Language",
'__rating': 'rating',
}
Expand Down Expand Up @@ -65,6 +64,20 @@ def _get_tag(self, raw, tag):
data = int(raw['rating'][0])
return [str(self._rating_to_stars(data))]

elif tag == 'bpm':
if (
settings.get_option('collection/use_legacy_metadata_mapping', False)
and 'tempo' in raw
):
tag = 'tempo'

elif tag == 'comment':
if (
settings.get_option('collection/use_legacy_metadata_mapping', False)
and 'description' in raw
):
tag = 'description'

return CaseInsensitiveBaseFormat._get_tag(self, raw, tag)

def _set_tag(self, raw, tag, value):
Expand All @@ -83,6 +96,16 @@ def _set_tag(self, raw, tag, value):
# Rating Stars
value = [str(self._stars_to_rating(int(value[0])))]

elif tag == 'bpm':
if settings.get_option('collection/use_legacy_metadata_mapping', False):
tag = 'tempo'
value = [xl.unicode.to_unicode(v) for v in value]

elif tag == 'comment':
if settings.get_option('collection/use_legacy_metadata_mapping', False):
tag = 'description'
value = [xl.unicode.to_unicode(v) for v in value]

else:
# flac has text based attributes, so convert everything to unicode
value = [xl.unicode.to_unicode(v) for v in value]
Expand Down
25 changes: 23 additions & 2 deletions xl/metadata/ogg.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

import xl.unicode
from xl.metadata._base import CaseInsensitiveBaseFormat, CoverImage
from xl import settings
from mutagen import oggvorbis, oggopus
from mutagen.flac import Picture
import base64
Expand All @@ -34,8 +35,6 @@
class OggFormat(CaseInsensitiveBaseFormat):
MutagenType = oggvorbis.OggVorbis
tag_mapping = {
'bpm': 'tempo',
'comment': 'description',
'cover': 'metadata_block_picture',
'__rating': 'rating',
}
Expand All @@ -59,6 +58,20 @@ def _get_tag(self, raw, tag):
if value and tag == 'rating':
value = [str(self._rating_to_stars(int(value[0])))]

elif tag == 'bpm':
if (
settings.get_option('collection/use_legacy_metadata_mapping', False)
and 'tempo' in raw
):
value = CaseInsensitiveBaseFormat._get_tag(self, raw, 'tempo')

elif tag == 'comment':
if (
settings.get_option('collection/use_legacy_metadata_mapping', False)
and 'description' in raw
):
value = CaseInsensitiveBaseFormat._get_tag(self, raw, 'description')

return value

def _set_tag(self, raw, tag, value):
Expand All @@ -77,6 +90,14 @@ def _set_tag(self, raw, tag, value):
elif tag == 'rating':
rating = self._stars_to_rating(value[0])
value = [str(rating)]
elif tag == 'bpm':
if settings.get_option('collection/use_legacy_metadata_mapping', False):
tag = 'tempo'
value = [xl.unicode.to_unicode(v) for v in value]
elif tag == 'comment':
if settings.get_option('collection/use_legacy_metadata_mapping', False):
tag = 'description'
value = [xl.unicode.to_unicode(v) for v in value]
else:
# vorbis has text based attributes, so convert everything to unicode
value = [xl.unicode.to_unicode(v) for v in value]
Expand Down
31 changes: 31 additions & 0 deletions xl/migrations/settings/flac_tempo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Copyright (C) 2023 luzip665
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

from xl import settings


def migrate():
"""
Migration for flac bpm and tempo tag setting.
In case it's a new instance disable the old behaviour.
Otherwise leave it disabled
"""
firstrun = settings.get_option("general/first_run", True)
migrated = settings.get_option('collection/use_legacy_metadata_mapping', None)
if not firstrun and migrated == None:
settings.set_option('collection/use_legacy_metadata_mapping', True)
elif firstrun:
settings.set_option('collection/use_legacy_metadata_mapping', False)
79 changes: 78 additions & 1 deletion xlgui/preferences/collection.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

from xl import xdg, main, metadata
from xl import xdg, main, metadata, settings
from xl.nls import gettext as _
from xlgui.preferences import widgets
from xlgui import progress
Expand Down Expand Up @@ -156,4 +156,81 @@ def on_done(self, a):
self.progress = None


class UseLegacyMetadataMappingPreference(widgets.CheckPreference):
default = False
name = 'collection/use_legacy_metadata_mapping'


class UseLegacyMetadataMappingSyncNow(widgets.Button, widgets.Conditional):
default = ""
name = "collection/use_legacy_metadata_mapping_sync_now"
condition_preference_name = 'collection/use_legacy_metadata_mapping'

def __init__(self, preferences, widget):
widgets.Button.__init__(self, preferences, widget)
widgets.Conditional.__init__(self)
self.progress = None
self.scan_thread = None
self.monitor = None

def on_check_condition(self):
return self.condition_widget.get_active() is True

def on_clicked(self, button):
if self.progress:
return

curr_page = self.preferences.last_page
box = self.preferences.builders[curr_page].get_object(
'collection/use_legacy_metadata_mapping_progress'
)
self.progress = progress.ProgressManager(box)

self.scan_thread = SimpleProgressThread(
self.track_scan,
)
self.scan_thread.connect('done', self.on_done)
self.monitor = self.progress.add_monitor(
self.scan_thread,
_("Migrating metadata"),
'document-open',
)

box.show()

def track_scan(self):
from xl.metadata import flac, ogg

exaile = main.exaile()
collection = exaile.collection
total = len(collection.tracks)
i = 0

for track in collection.tracks:
trax = collection.tracks[track]
format_data = metadata.get_format(track)

if not isinstance(format_data, flac.FlacFormat) and not isinstance(
format_data, ogg.OggFormat
):
continue

settings.set_option('collection/use_legacy_metadata_mapping', True)
bpm = trax.get_tag_disk('tempo')
comment = trax.get_tag_disk('description')

settings.set_option('collection/use_legacy_metadata_mapping', False)
trax.set_tag_disk('bpm', bpm)
trax.set_tag_disk('comment', comment)

i += 1
yield i, total

def on_done(self, a):
self.progress.remove_monitor(self.monitor)
self.progress = None
settings.set_option('collection/use_legacy_metadata_mapping', False)
self.condition_widget.set_active(False)


# vim:ts=4 et sw=4

0 comments on commit 7f37b1e

Please sign in to comment.