Translate foreign artist names.

This commit is contained in:
Lukáš Lalinský
2006-10-15 13:46:31 +02:00
parent a240180d6c
commit 1debfeb822
7 changed files with 222 additions and 13 deletions

View File

@@ -28,6 +28,7 @@ from picard.metadata import Metadata
from picard.dataobj import DataObject
from picard.track import Track
from picard.artist import Artist
from picard.util import translate_artist
class AlbumLoadError(Exception):
pass
@@ -81,6 +82,8 @@ class Album(DataObject):
except WebServiceError, e:
self.hasLoadError = True
raise AlbumLoadError, e
translate = self.config.setting["translate_artist_names"]
self.lock()
@@ -88,8 +91,11 @@ class Album(DataObject):
self.metadata["album"] = release.title
self.metadata["artist"] = release.artist.name
self.metadata["artist_sortname"] = release.artist.sortName
self.metadata["albumartist"] = release.artist.name
self.metadata["albumartist_sortname"] = release.artist.sortName
if translate:
self.metadata["artist"] = translate_artist(
self.metadata["artist"], self.metadata["artist_sortname"])
self.metadata["albumartist"] = self.metadata["artist"]
self.metadata["albumartist_sortname"] = self.metadata["artist_sortname"]
self.metadata["musicbrainz_albumid"] = extractUuid(release.id)
self.metadata["musicbrainz_artistid"] = extractUuid(release.artist.id)
self.metadata["musicbrainz_albumartistid"] = \
@@ -149,27 +155,33 @@ class Album(DataObject):
script = None
self.name = release.title
self.artist = Artist(release.artist.id, release.artist.name)
self.artist = Artist(self.metadata["musicbrainz_artistid"],
self.metadata["artist"])
self.duration = 0
self.tracks = []
tracknum = 1
for track in release.tracks:
if track.artist:
artist = Artist(extractUuid(track.artist.id),
track.artist.name)
artist_id = extractUuid(track.artist.id)
artist_name = track.artist.name
artist_sortname = track.artist.sortName
if translate:
artist_name = translate_artist(artist_name, artist_sortname)
else:
artist = Artist(extractUuid(release.artist.id),
release.artist.name)
tr = Track(extractUuid(track.id), track.title, artist, self)
artist_id = self.metadata["musicbrainz_artistid"]
artist_name = self.metadata["artist"]
artist_sortname = self.metadata["artist_sortname"]
print artist_name
tr = Track(extractUuid(track.id), track.title,
Artist(artist_id, artist_name), self)
tr.duration = track.duration or 0
tr.metadata.copy(self.metadata)
tr.metadata["title"] = track.title
if track.artist:
tr.metadata["artist"] = artist.name
tr.metadata["artist_sortname"] = track.artist.sortName
tr.metadata["musicbrainz_artistid"] = extractUuid(artist.id)
tr.metadata["musicbrainz_trackid"] = extractUuid(track.id)
tr.metadata["artist"] = artist_name
tr.metadata["artist_sortname"] = artist_sortname
tr.metadata["musicbrainz_artistid"] = artist_id
tr.metadata["musicbrainz_trackid"] = tr.id
tr.metadata["tracknumber"] = str(tracknum)
tr.metadata["~#length"] = tr.duration
# Metadata processor plugins

View File

@@ -26,6 +26,7 @@ from picard.ui.options import (
advanced,
cdlookup,
general,
metadata,
naming,
proxy,
scripting,

View File

@@ -0,0 +1,47 @@
# -*- coding: utf-8 -*-
#
# Picard, the next-generation MusicBrainz tagger
# Copyright (C) 2006 Lukáš Lalinský
#
# 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
# of the License, 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 PyQt4 import QtCore, QtGui
from picard.api import IOptionsPage
from picard.component import Component, implements
from picard.config import BoolOption, TextOption
class MetadataOptionsPage(Component):
implements(IOptionsPage)
options = [
BoolOption("setting", "translate_artist_names", False),
]
def get_page_info(self):
return _("Metadata"), "metadata", None, 20
def get_page_widget(self, parent=None):
self.widget = QtGui.QWidget(parent)
from picard.ui.ui_options_metadata import Ui_Form
self.ui = Ui_Form()
self.ui.setupUi(self.widget)
self.ui.translate_artist_names.setChecked(
self.config.setting["translate_artist_names"])
return self.widget
def save_options(self):
self.config.setting["translate_artist_names"] = \
self.ui.translate_artist_names.isChecked()

View File

@@ -0,0 +1,45 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'ui\options_metadata.ui'
#
# Created: Sun Oct 15 13:45:25 2006
# by: PyQt4 UI code generator 4.0
# E:\projects\picard-qt\setup.py build_ui
#
# WARNING! All changes made in this file will be lost!
import sys
from PyQt4 import QtCore, QtGui
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName("Form")
Form.resize(QtCore.QSize(QtCore.QRect(0,0,350,300).size()).expandedTo(Form.minimumSizeHint()))
self.vboxlayout = QtGui.QVBoxLayout(Form)
self.vboxlayout.setMargin(9)
self.vboxlayout.setSpacing(2)
self.vboxlayout.setObjectName("vboxlayout")
self.rename_files = QtGui.QGroupBox(Form)
self.rename_files.setObjectName("rename_files")
self.gridlayout = QtGui.QGridLayout(self.rename_files)
self.gridlayout.setMargin(9)
self.gridlayout.setSpacing(2)
self.gridlayout.setObjectName("gridlayout")
self.translate_artist_names = QtGui.QCheckBox(self.rename_files)
self.translate_artist_names.setObjectName("translate_artist_names")
self.gridlayout.addWidget(self.translate_artist_names,0,0,1,1)
self.vboxlayout.addWidget(self.rename_files)
spacerItem = QtGui.QSpacerItem(61,201,QtGui.QSizePolicy.Minimum,QtGui.QSizePolicy.Expanding)
self.vboxlayout.addItem(spacerItem)
self.retranslateUi(Form)
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
self.rename_files.setTitle(_("Metadata"))
self.translate_artist_names.setText(_("Translate foreign artist names to English where possible"))

View File

@@ -175,3 +175,21 @@ def make_short_filename(prefix, filename, length=250, max_length=250,
parts.reverse()
return os.path.join(*parts)
def reverse_sortname(sortname):
chunks = map(unicode.strip, sortname.split(u","))
if len(chunks) == 2:
return u"%s %s" % (chunks[1], chunks[0])
elif len(chunks) == 3:
return u"%s %s %s" % (chunks[2], chunks[1], chunks[0])
elif len(chunks) == 4:
return u"%s %s, %s %s" % (chunks[1], chunks[0], chunks[3], chunks[2])
else:
return sortname.strip()
def translate_artist(name, sortname):
for c in name:
ctg = unicodedata.category(c)
if (ctg[0] not in ("P", "Z") and ctg != "Nd" and
unicodedata.name(c).find("LATIN") == -1):
return " & ".join(map(reverse_sortname, sortname.split("&")))
return name

View File

@@ -73,3 +73,24 @@ class ShortFilenameTest(unittest.TestCase):
def test_too_long(self):
self.failUnlessRaises(IOError, util.make_short_filename, "/home/me/", os.path.join("a1234567890", "b1234567890"), 10)
class TranslateArtistTest(unittest.TestCase):
def test_latin(self):
self.failUnlessEqual(u"Jean Michel Jarre", util.translate_artist(u"Jean Michel Jarre", u"Jarre, Jean Michel"))
self.failIfEqual(u"Jarre, Jean Michel", util.translate_artist(u"Jean Michel Jarre", u"Jarre, Jean Michel"))
def test_kanji(self):
self.failUnlessEqual(u"Tetsuya Komuro", util.translate_artist(u"小室哲哉", u"Komuro, Tetsuya"))
self.failIfEqual(u"Komuro, Tetsuya", util.translate_artist(u"小室哲哉", u"Komuro, Tetsuya"))
self.failIfEqual(u"小室哲哉", util.translate_artist(u"小室哲哉", u"Komuro, Tetsuya"))
def test_kanji2(self):
self.failUnlessEqual(u"Ayumi Hamasaki & Keiko", util.translate_artist(u"浜崎あゆみ & KEIKO", u"Hamasaki, Ayumi & Keiko"))
self.failIfEqual(u"浜崎あゆみ & KEIKO", util.translate_artist(u"浜崎あゆみ & KEIKO", u"Hamasaki, Ayumi & Keiko"))
self.failIfEqual(u"Hamasaki, Ayumi & Keiko", util.translate_artist(u"浜崎あゆみ & KEIKO", u"Hamasaki, Ayumi & Keiko"))
def test_cyrillic(self):
self.failUnlessEqual(u"Pyotr Ilyich Tchaikovsky", util.translate_artist(u"Пётр Ильич Чайковский", u"Tchaikovsky, Pyotr Ilyich"))
self.failIfEqual(u"Tchaikovsky, Pyotr Ilyich", util.translate_artist(u"Пётр Ильич Чайковский", u"Tchaikovsky, Pyotr Ilyich"))
self.failIfEqual(u"Пётр Ильич Чайковский", util.translate_artist(u"Пётр Ильич Чайковский", u"Tchaikovsky, Pyotr Ilyich"))

65
ui/options_metadata.ui Normal file
View File

@@ -0,0 +1,65 @@
<ui version="4.0" >
<author></author>
<comment></comment>
<exportmacro></exportmacro>
<class>Form</class>
<widget class="QWidget" name="Form" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>350</width>
<height>300</height>
</rect>
</property>
<layout class="QVBoxLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<number>2</number>
</property>
<item>
<widget class="QGroupBox" name="rename_files" >
<property name="title" >
<string>Metadata</string>
</property>
<layout class="QGridLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<number>2</number>
</property>
<item row="0" column="0" >
<widget class="QCheckBox" name="translate_artist_names" >
<property name="text" >
<string>Translate foreign artist names to English where possible</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" >
<size>
<width>61</width>
<height>201</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<pixmapfunction></pixmapfunction>
<tabstops>
<tabstop>translate_artist_names</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>