Make config and log importable

Conflicts:

	picard/ui/mainwindow.py
This commit is contained in:
Michael Wiencek
2013-06-09 00:49:01 -05:00
parent 63b241e053
commit 7c4fdf765c
53 changed files with 750 additions and 721 deletions

View File

@@ -19,6 +19,7 @@
from collections import deque
from PyQt4 import QtCore
from picard import config, log
from picard.const import ACOUSTID_KEY, FPCALC_NAMES
from picard.util import partial, call_next, find_executable
from picard.webservice import XmlNode
@@ -32,10 +33,10 @@ class AcoustIDClient(QtCore.QObject):
self._running = 0
self._max_processes = 2
if not self.config.setting["acoustid_fpcalc"]:
if not config.setting["acoustid_fpcalc"]:
fpcalc_path = find_executable(*FPCALC_NAMES)
if fpcalc_path:
self.config.setting["acoustid_fpcalc"] = fpcalc_path
config.setting["acoustid_fpcalc"] = fpcalc_path
def init(self):
pass
@@ -106,7 +107,7 @@ class AcoustIDClient(QtCore.QObject):
parse_recording(recording)
else:
error_message = document.response[0].error[0].message[0].text
self.log.error("Fingerprint lookup failed: %r", error_message)
log.error("Fingerprint lookup failed: %r", error_message)
next(doc, http, error)
@@ -161,7 +162,7 @@ class AcoustIDClient(QtCore.QObject):
if fingerprint and duration:
result = 'fingerprint', fingerprint, duration
else:
self.log.error("Fingerprint calculator failed exit code = %r, exit status = %r, error = %s", exit_code, exit_status, unicode(process.errorString()))
log.error("Fingerprint calculator failed exit code = %r, exit status = %r, error = %s", exit_code, exit_status, unicode(process.errorString()))
finally:
next(result)
@@ -174,7 +175,7 @@ class AcoustIDClient(QtCore.QObject):
try:
self._running -= 1
self._run_next_task()
self.log.error("Fingerprint calculator failed error = %s (%r)", unicode(process.errorString()), error)
log.error("Fingerprint calculator failed error = %s (%r)", unicode(process.errorString()), error)
finally:
next(None)
@@ -183,14 +184,14 @@ class AcoustIDClient(QtCore.QObject):
file, next = self._queue.popleft()
except IndexError:
return
fpcalc = self.config.setting["acoustid_fpcalc"] or "fpcalc"
fpcalc = config.setting["acoustid_fpcalc"] or "fpcalc"
self._running += 1
process = QtCore.QProcess(self)
process.setProperty('picard_finished', QtCore.QVariant(False))
process.finished.connect(partial(self._on_fpcalc_finished, next, file))
process.error.connect(partial(self._on_fpcalc_error, next, file))
process.start(fpcalc, ["-length", "120", file.filename])
self.log.debug("Starting fingerprint calculator %r %r", fpcalc, file.filename)
log.debug("Starting fingerprint calculator %r %r", fpcalc, file.filename)
def analyze(self, file, next):
fpcalc_next = partial(self._lookup_fingerprint, next, file.filename)

View File

@@ -20,6 +20,7 @@
import traceback
from PyQt4 import QtCore, QtNetwork
from picard import config, log
from picard.coverart import coverart
from picard.metadata import (Metadata,
register_album_metadata_processor,
@@ -74,7 +75,7 @@ class Album(DataObject, Item):
yield file
def _parse_release(self, document):
self.log.debug("Loading release %r", self.id)
log.debug("Loading release %r", self.id)
self._tracks_loaded = False
release_node = document.metadata[0].release[0]
@@ -82,7 +83,7 @@ class Album(DataObject, Item):
self.tagger.mbid_redirects[self.id] = release_node.id
album = self.tagger.albums.get(release_node.id)
if album:
self.log.debug("Release %r already loaded", release_node.id)
log.debug("Release %r already loaded", release_node.id)
album.match_files(self.unmatched_files.files)
album.update()
self.tagger.remove_album(self)
@@ -101,19 +102,19 @@ class Album(DataObject, Item):
rg.loaded_albums.add(self.id)
rg.refcount += 1
release_group_to_metadata(rg_node, rg.metadata, self.config, rg)
release_group_to_metadata(rg_node, rg.metadata, rg)
m.copy(rg.metadata)
release_to_metadata(release_node, m, config=self.config, album=self)
release_to_metadata(release_node, m, album=self)
if self._discid:
m['musicbrainz_discid'] = self._discid
# Custom VA name
if m['musicbrainz_albumartistid'] == VARIOUS_ARTISTS_ID:
m['albumartistsort'] = m['albumartist'] = self.config.setting['va_name']
m['albumartistsort'] = m['albumartist'] = config.setting['va_name']
# Convert Unicode punctuation
if self.config.setting['convert_punctuation']:
if config.setting['convert_punctuation']:
m.apply_func(asciipunct)
m['totaldiscs'] = release_node.medium_list[0].count
@@ -121,7 +122,7 @@ class Album(DataObject, Item):
# Add album to collections
if "collection_list" in release_node.children:
for node in release_node.collection_list[0].collection:
if node.editor[0].text.lower() == self.config.setting["username"].lower():
if node.editor[0].text.lower() == config.setting["username"].lower():
if node.id not in user_collections:
user_collections[node.id] = \
Collection(node.id, node.name[0].text, node.release_list[0].count)
@@ -131,7 +132,7 @@ class Album(DataObject, Item):
try:
run_album_metadata_processors(self, m, release_node)
except:
self.log.error(traceback.format_exc())
log.error(traceback.format_exc())
self._release_node = release_node
return True
@@ -143,11 +144,11 @@ class Album(DataObject, Item):
parsed = False
try:
if error:
self.log.error("%r", unicode(http.errorString()))
log.error("%r", unicode(http.errorString()))
# Fix for broken NAT releases
if error == QtNetwork.QNetworkReply.ContentNotFoundError:
nats = False
nat_name = self.config.setting["nat_name"]
nat_name = config.setting["nat_name"]
files = list(self.unmatched_files.files)
for file in files:
trackid = file.metadata["musicbrainz_trackid"]
@@ -163,7 +164,7 @@ class Album(DataObject, Item):
parsed = self._parse_release(document)
except:
error = True
self.log.error(traceback.format_exc())
log.error(traceback.format_exc())
finally:
self._requests -= 1
if parsed or error:
@@ -205,7 +206,7 @@ class Album(DataObject, Item):
# Get track metadata
tm = track.metadata
tm.copy(mm)
track_to_metadata(track_node, track, self.config)
track_to_metadata(track_node, track)
track._customize_metadata()
self._new_metadata.length += tm.length
@@ -215,7 +216,7 @@ class Album(DataObject, Item):
try:
run_track_metadata_processors(self, tm, self._release_node, track_node)
except:
self.log.error(traceback.format_exc())
log.error(traceback.format_exc())
totalalbumtracks = str(totalalbumtracks)
@@ -229,8 +230,8 @@ class Album(DataObject, Item):
if not self._requests:
# Prepare parser for user's script
if self.config.setting["enable_tagger_script"]:
script = self.config.setting["tagger_script"]
if config.setting["enable_tagger_script"]:
script = config.setting["tagger_script"]
if script:
parser = ScriptParser()
for track in self._new_tracks:
@@ -238,14 +239,14 @@ class Album(DataObject, Item):
try:
parser.eval(script, track.metadata)
except:
self.log.error(traceback.format_exc())
log.error(traceback.format_exc())
# Strip leading/trailing whitespace
track.metadata.strip_whitespace()
# Run tagger script for the album itself
try:
parser.eval(script, self._new_metadata)
except:
self.log.error(traceback.format_exc())
log.error(traceback.format_exc())
self._new_metadata.strip_whitespace()
for track in self.tracks:
@@ -265,7 +266,7 @@ class Album(DataObject, Item):
def load(self):
if self._requests:
self.log.info("Not reloading, some requests are still active.")
log.info("Not reloading, some requests are still active.")
return
self.tagger.window.set_statusbar_message('Loading album %s...', self.id)
self.loaded = False
@@ -282,17 +283,17 @@ class Album(DataObject, Item):
require_authentication = False
inc = ['release-groups', 'media', 'recordings', 'artist-credits',
'artists', 'aliases', 'labels', 'isrcs', 'collections']
if self.config.setting['release_ars'] or self.config.setting['track_ars']:
if config.setting['release_ars'] or config.setting['track_ars']:
inc += ['artist-rels', 'release-rels', 'url-rels', 'recording-rels', 'work-rels']
if self.config.setting['track_ars']:
if config.setting['track_ars']:
inc += ['recording-level-rels', 'work-level-rels']
if self.config.setting['folksonomy_tags']:
if self.config.setting['only_my_tags']:
if config.setting['folksonomy_tags']:
if config.setting['only_my_tags']:
require_authentication = True
inc += ['user-tags']
else:
inc += ['tags']
if self.config.setting['enable_ratings']:
if config.setting['enable_ratings']:
require_authentication = True
inc += ['user-ratings']
self.load_task = self.tagger.xmlws.get_release_by_id(
@@ -334,7 +335,7 @@ class Album(DataObject, Item):
if not matches:
for track in self.tracks:
sim = track.metadata.compare(file.orig_metadata)
if sim >= self.config.setting['track_matching_threshold']:
if sim >= config.setting['track_matching_threshold']:
matches.append((sim, track))
if matches:
matches.sort(reverse=True)
@@ -478,7 +479,7 @@ class NatAlbum(Album):
self.update()
def update(self, update_tracks=True):
self.metadata["album"] = self.config.setting["nat_name"]
self.metadata["album"] = config.setting["nat_name"]
for track in self.tracks:
track.metadata["album"] = self.metadata["album"]
for file in track.linked_files:

View File

@@ -18,6 +18,7 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
from PyQt4 import QtCore, QtNetwork
from picard import log
class BrowserIntegration(QtNetwork.QTcpServer):
@@ -30,14 +31,14 @@ class BrowserIntegration(QtNetwork.QTcpServer):
def start(self):
self.port = 8000
while self.port < 65535:
self.log.debug("Starting the browser integration (port %d)", self.port)
log.debug("Starting the browser integration (port %d)", self.port)
if self.listen(QtNetwork.QHostAddress(QtNetwork.QHostAddress.Any), self.port):
self.tagger.listen_port_changed.emit(self.port)
break
self.port += 1
def stop(self):
self.log.debug("Stopping the browser integration")
log.debug("Stopping the browser integration")
self.close()
def process_request(self):
@@ -46,7 +47,7 @@ class BrowserIntegration(QtNetwork.QTcpServer):
conn.write("HTTP/1.1 200 OK\r\nCache-Control: max-age=0\r\n\r\nNothing to see here.")
conn.disconnectFromHost()
line = line.split()
self.log.debug("Browser integration request: %r", line)
log.debug("Browser integration request: %r", line)
if line[0] == "GET" and "?" in line[1]:
action, args = line[1].split("?")
args = [a.split("=", 1) for a in args.split("&")]
@@ -56,7 +57,7 @@ class BrowserIntegration(QtNetwork.QTcpServer):
elif action == "/opennat":
self.tagger.load_nat(args["id"])
else:
self.log.error("Unknown browser integration request: %r", action)
log.error("Unknown browser integration request: %r", action)
def accept_connection(self):
conn = self.nextPendingConnection()

View File

@@ -22,6 +22,7 @@ import re
from operator import itemgetter
from heapq import heappush, heappop
from PyQt4 import QtCore
from picard import config
from picard.metadata import Metadata
from picard.similarity import similarity2, similarity
from picard.ui.item import Item
@@ -155,7 +156,7 @@ class Cluster(QtCore.QObject, Item):
release, Cluster.comparison_weights) for release in releases),
reverse=True, key=itemgetter(0))[0]
if match[0] < self.config.setting['cluster_lookup_threshold']:
if match[0] < config.setting['cluster_lookup_threshold']:
self.tagger.window.set_statusbar_message(N_("No matching releases for cluster %s"), self.metadata['album'], timeout=3000)
return
self.tagger.window.set_statusbar_message(N_("Cluster %s identified!"), self.metadata['album'], timeout=3000)

View File

@@ -18,6 +18,7 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
from PyQt4 import QtCore
from picard import config
from picard.util import partial
@@ -98,6 +99,5 @@ def load_user_collections(callback=None):
if callback:
callback()
setting = QtCore.QObject.config.setting
if setting["username"] and setting["password"]:
if config.setting["username"] and config.setting["password"]:
tagger.xmlws.get_collection_list(partial(request_finished))

View File

@@ -21,10 +21,6 @@ from PyQt4 import QtCore
from picard.util import LockableObject, rot13
class ConfigError(Exception):
pass
class ConfigSection(LockableObject):
"""Configuration section."""
@@ -64,6 +60,7 @@ class ConfigSection(LockableObject):
if self.__config.contains(key):
self.__config.remove(key)
class Config(QtCore.QSettings):
"""Configuration."""
@@ -81,7 +78,7 @@ class Config(QtCore.QSettings):
if self.contains(key):
self.profile.name = key
else:
raise ConfigError, "Unknown profile '%s'" % (profilename,)
raise KeyError, "Unknown profile '%s'" % (profilename,)
class Option(QtCore.QObject):
@@ -147,3 +144,9 @@ class PasswordOption(Option):
def convert(value):
return rot13(unicode(value.toString()))
Option.__init__(self, section, name, default, convert)
_config = Config()
setting = _config.setting
persist = _config.persist

View File

@@ -17,10 +17,24 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
import os, sys
# Install gettext "noop" function in case const.py gets imported directly.
import __builtin__
__builtin__.__dict__['N_'] = lambda a: a
# Config directory
if sys.platform == "win32":
USER_DIR = os.environ.get("APPDATA", "~\\Application Data")
else:
USER_DIR = os.environ.get("XDG_CONFIG_HOME", "~/.config")
USER_DIR = os.path.join(
os.path.expanduser(USER_DIR), "MusicBrainz", "Picard"
)
USER_PLUGIN_DIR = os.path.join(USER_DIR, "plugins")
# AcoustID client API key
ACOUSTID_KEY = '0zClDiGo'
ACOUSTID_HOST = 'api.acoustid.org'

View File

@@ -25,6 +25,7 @@ import re
import traceback
import picard.webservice
from picard import config, log
from picard.util import partial, mimetype
from PyQt4.QtCore import QUrl, QObject
@@ -88,13 +89,13 @@ def _coverart_downloaded(album, metadata, release, try_list, imagedata, data, ht
if error or len(data) < 1000:
if error:
album.log.error(str(http.errorString()))
log.error(str(http.errorString()))
else:
QObject.tagger.window.set_statusbar_message(N_("Coverart %s downloaded"),
http.url().toString())
mime = mimetype.get_from_data(data, default="image/jpeg")
filename = None
if imagetype != 'front' and QObject.config.setting["caa_image_type_as_filename"]:
if imagetype != 'front' and config.setting["caa_image_type_as_filename"]:
filename = imagetype
metadata.add_image(mime, data, filename, imagedata["description"],
imagetype)
@@ -116,17 +117,17 @@ def _caa_json_downloaded(album, metadata, release, try_list, data, http, error):
album._requests -= 1
caa_front_found = False
if error:
album.log.error(str(http.errorString()))
log.error(str(http.errorString()))
else:
try:
caa_data = json.loads(data)
except ValueError:
QObject.log.debug("Invalid JSON: %s", http.url().toString())
log.debug("Invalid JSON: %s", http.url().toString())
else:
caa_types = QObject.config.setting["caa_image_types"].split()
caa_types = config.setting["caa_image_types"].split()
caa_types = map(unicode.lower, caa_types)
for image in caa_data["images"]:
if QObject.config.setting["caa_approved_only"] and not image["approved"]:
if config.setting["caa_approved_only"] and not image["approved"]:
continue
if not image["types"] and 'unknown' in caa_types:
_caa_append_image_to_trylist(try_list, image)
@@ -150,7 +151,7 @@ _CAA_THUMBNAIL_SIZE_MAP = {
def _caa_append_image_to_trylist(try_list, imagedata):
"""Adds URLs to `try_list` depending on the users CAA image size settings."""
imagesize = QObject.config.setting["caa_image_size"]
imagesize = config.setting["caa_image_size"]
thumbsize = _CAA_THUMBNAIL_SIZE_MAP.get(imagesize, None)
if thumbsize is None:
url = QUrl(imagedata["image"])
@@ -171,7 +172,7 @@ def coverart(album, metadata, release, try_list=None):
# http://tickets.musicbrainz.org/browse/MBS-4536
has_caa_artwork = False
caa_types = map(unicode.lower,
QObject.config.setting["caa_image_types"].split())
config.setting["caa_image_types"].split())
if 'cover_art_archive' in release.children:
caa_node = release.children['cover_art_archive'][0]
@@ -196,9 +197,9 @@ def coverart(album, metadata, release, try_list=None):
back_in_caa = caa_node.back[0].text == 'true' and 'back' in caa_types
has_caa_artwork = has_caa_artwork and (front_in_caa or back_in_caa)
if QObject.config.setting['ca_provider_use_caa'] and has_caa_artwork\
if config.setting['ca_provider_use_caa'] and has_caa_artwork\
and len(caa_types) > 0:
QObject.log.debug("There are suitable images in the cover art archive for %s"
log.debug("There are suitable images in the cover art archive for %s"
% release.id)
album._requests += 1
album.tagger.xmlws.download(
@@ -207,7 +208,7 @@ def coverart(album, metadata, release, try_list=None):
partial(_caa_json_downloaded, album, metadata, release, try_list),
priority=True, important=True)
else:
QObject.log.debug("There are no suitable images in the cover art archive for %s"
log.debug("There are no suitable images in the cover art archive for %s"
% release.id)
_fill_try_list(album, release, try_list)
_walk_try_list(album, metadata, release, try_list)
@@ -223,16 +224,16 @@ def _fill_try_list(album, release, try_list):
_process_url_relation(try_list, relation)
# Use the URL of a cover art link directly
if QObject.config.setting['ca_provider_use_whitelist']\
if config.setting['ca_provider_use_whitelist']\
and (relation.type == 'cover art link' or
relation.type == 'has_cover_art_at'):
_try_list_append_image_url(try_list, QUrl(relation.target[0].text))
elif QObject.config.setting['ca_provider_use_amazon']\
elif config.setting['ca_provider_use_amazon']\
and (relation.type == 'amazon asin' or
relation.type == 'has_Amazon_ASIN'):
_process_asin_relation(try_list, relation)
except AttributeError, e:
album.log.error(traceback.format_exc())
log.error(traceback.format_exc())
def _walk_try_list(album, metadata, release, try_list):
@@ -262,7 +263,7 @@ def _process_url_relation(try_list, relation):
# musicbrainz server.
# See mb_server/cgi-bin/MusicBrainz/Server/CoverArt.pm
# hartzell --- Tue Apr 15 15:25:58 PDT 2008
if not QObject.config.setting['ca_provider_use_%s' % site['name']]:
if not config.setting['ca_provider_use_%s' % site['name']]:
continue
match = re.match(site['regexp'], relation.target[0].text)
if match is not None:
@@ -290,7 +291,7 @@ def _process_asin_relation(try_list, relation):
def _try_list_append_image_url(try_list, parsedUrl, imagetype="front", description=""):
QObject.log.debug("Adding %s image %s", imagetype, parsedUrl)
log.debug("Adding %s image %s", imagetype, parsedUrl)
path = str(parsedUrl.encodedPath())
if parsedUrl.hasQuery():
path += '?' + parsedUrl.encodedQuery()

View File

@@ -22,6 +22,7 @@ import ctypes
import sys
import traceback
from PyQt4 import QtCore
from picard import log
from picard.ui.cdlookup import CDLookupDialog
@@ -62,12 +63,12 @@ class Disc(QtCore.QObject):
self.tagger.restore_cursor()
releases = []
if error:
self.log.error("%r", unicode(http.errorString()))
log.error("%r", unicode(http.errorString()))
else:
try:
releases = document.metadata[0].disc[0].release_list[0].release
except (AttributeError, IndexError):
self.log.error(traceback.format_exc())
log.error(traceback.format_exc())
dialog = CDLookupDialog(releases, self, parent=self.tagger.window)
dialog.exec_()

View File

@@ -27,6 +27,7 @@ import unicodedata
from operator import itemgetter
from collections import defaultdict
from PyQt4 import QtCore
from picard import config, log
from picard.track import Track
from picard.metadata import Metadata
from picard.ui.item import Item
@@ -132,7 +133,7 @@ class File(QtCore.QObject, Item):
def copy_metadata(self, metadata):
acoustid = self.metadata["acoustid_id"]
preserve = self.config.setting["preserved_tags"].strip()
preserve = config.setting["preserved_tags"].strip()
saved_metadata = {}
for tag in re.split(r"\s+", preserve) + File._default_preserved_tags:
@@ -152,35 +153,35 @@ class File(QtCore.QObject, Item):
"""Load metadata from the file."""
raise NotImplementedError
def save(self, next, settings):
def save(self, next):
self.set_pending()
metadata = Metadata()
metadata.copy(self.metadata)
self.tagger.save_queue.put((
partial(self._save_and_rename, self.filename, metadata, settings),
partial(self._save_and_rename, self.filename, metadata),
partial(self._saving_finished, next),
QtCore.Qt.LowEventPriority + 2))
def _save_and_rename(self, old_filename, metadata, settings):
def _save_and_rename(self, old_filename, metadata):
"""Save the metadata."""
new_filename = old_filename
if not settings["dont_write_tags"]:
if not config.setting["dont_write_tags"]:
encoded_old_filename = encode_filename(old_filename)
info = os.stat(encoded_old_filename)
self._save(old_filename, metadata, settings)
if settings["preserve_timestamps"]:
self._save(old_filename, metadata)
if config.setting["preserve_timestamps"]:
try:
os.utime(encoded_old_filename, (info.st_atime, info.st_mtime))
except OSError:
self.log.warning("Couldn't preserve timestamp for %r", old_filename)
log.warning("Couldn't preserve timestamp for %r", old_filename)
# Rename files
if settings["rename_files"] or settings["move_files"]:
new_filename = self._rename(old_filename, metadata, settings)
if config.setting["rename_files"] or config.setting["move_files"]:
new_filename = self._rename(old_filename, metadata)
# Move extra files (images, playlists, etc.)
if settings["move_files"] and settings["move_additional_files"]:
self._move_additional_files(old_filename, new_filename, settings)
if config.setting["move_files"] and config.setting["move_additional_files"]:
self._move_additional_files(old_filename, new_filename)
# Delete empty directories
if settings["delete_empty_dirs"]:
if config.setting["delete_empty_dirs"]:
dirname = encode_filename(os.path.dirname(old_filename))
try:
self._rmdir(dirname)
@@ -196,8 +197,8 @@ class File(QtCore.QObject, Item):
except EnvironmentError:
pass
# Save cover art images
if settings["save_images_to_files"]:
self._save_images(os.path.dirname(new_filename), metadata, settings)
if config.setting["save_images_to_files"]:
self._save_images(os.path.dirname(new_filename), metadata)
return new_filename
@staticmethod
@@ -222,7 +223,7 @@ class File(QtCore.QObject, Item):
for info in ('~bitrate', '~sample_rate', '~channels',
'~bits_per_sample', '~format'):
temp_info[info] = self.orig_metadata[info]
if self.config.setting["clear_existing_tags"]:
if config.setting["clear_existing_tags"]:
self.orig_metadata.copy(self.metadata)
else:
self.orig_metadata.update(self.metadata)
@@ -235,13 +236,13 @@ class File(QtCore.QObject, Item):
self._add_path_to_metadata(self.orig_metadata)
return self, old_filename, new_filename
def _save(self, filename, metadata, settings):
def _save(self, filename, metadata):
"""Save the metadata."""
raise NotImplementedError
def _script_to_filename(self, format, file_metadata, settings):
def _script_to_filename(self, format, file_metadata):
metadata = Metadata()
if self.config.setting["clear_existing_tags"]:
if config.setting["clear_existing_tags"]:
metadata.copy(file_metadata)
else:
metadata.copy(self.orig_metadata)
@@ -252,37 +253,37 @@ class File(QtCore.QObject, Item):
metadata[name] = sanitize_filename(metadata[name])
format = format.replace("\t", "").replace("\n", "")
filename = ScriptParser().eval(format, metadata, self)
if settings["ascii_filenames"]:
if config.setting["ascii_filenames"]:
if isinstance(filename, unicode):
filename = unaccent(filename)
filename = replace_non_ascii(filename)
# replace incompatible characters
if settings["windows_compatible_filenames"] or sys.platform == "win32":
if config.setting["windows_compatible_filenames"] or sys.platform == "win32":
filename = replace_win32_incompat(filename)
# remove null characters
filename = filename.replace("\x00", "")
return filename
def _make_filename(self, filename, metadata, settings):
def _make_filename(self, filename, metadata):
"""Constructs file name based on metadata and file naming formats."""
if settings["move_files"]:
new_dirname = settings["move_files_to"]
if config.setting["move_files"]:
new_dirname = config.setting["move_files_to"]
if not os.path.isabs(new_dirname):
new_dirname = os.path.normpath(os.path.join(os.path.dirname(filename), new_dirname))
else:
new_dirname = os.path.dirname(filename)
new_filename, ext = os.path.splitext(os.path.basename(filename))
if settings["rename_files"]:
if config.setting["rename_files"]:
# expand the naming format
format = settings['file_naming_format']
format = config.setting['file_naming_format']
if len(format) > 0:
new_filename = self._script_to_filename(format, metadata, settings)
if not settings['move_files']:
new_filename = self._script_to_filename(format, metadata)
if not config.setting['move_files']:
new_filename = os.path.basename(new_filename)
new_filename = make_short_filename(new_dirname, new_filename)
# win32 compatibility fixes
if settings['windows_compatible_filenames'] or sys.platform == 'win32':
if config.setting['windows_compatible_filenames'] or sys.platform == 'win32':
new_filename = new_filename.replace('./', '_/').replace('.\\', '_\\')
# replace . at the beginning of file and directory names
new_filename = new_filename.replace('/.', '/_').replace('\\.', '\\_')
@@ -293,9 +294,9 @@ class File(QtCore.QObject, Item):
new_filename = unicodedata.normalize("NFD", unicode(new_filename))
return os.path.realpath(os.path.join(new_dirname, new_filename + ext.lower()))
def _rename(self, old_filename, metadata, settings):
def _rename(self, old_filename, metadata):
new_filename, ext = os.path.splitext(
self._make_filename(old_filename, metadata, settings))
self._make_filename(old_filename, metadata))
if old_filename != new_filename + ext:
new_dirname = os.path.dirname(new_filename)
if not os.path.isdir(encode_filename(new_dirname)):
@@ -307,31 +308,31 @@ class File(QtCore.QObject, Item):
new_filename = "%s (%d)" % (tmp_filename, i)
i += 1
new_filename = new_filename + ext
self.log.debug("Moving file %r => %r", old_filename, new_filename)
log.debug("Moving file %r => %r", old_filename, new_filename)
shutil.move(encode_filename(old_filename), encode_filename(new_filename))
return new_filename
else:
return old_filename
def _make_image_filename(self, image_filename, dirname, metadata, settings):
image_filename = self._script_to_filename(image_filename, metadata, settings)
def _make_image_filename(self, image_filename, dirname, metadata):
image_filename = self._script_to_filename(image_filename, metadata)
if not image_filename:
image_filename = "cover"
if os.path.isabs(image_filename):
filename = image_filename
else:
filename = os.path.join(dirname, image_filename)
if settings['windows_compatible_filenames'] or sys.platform == 'win32':
if config.setting['windows_compatible_filenames'] or sys.platform == 'win32':
filename = filename.replace('./', '_/').replace('.\\', '_\\')
return encode_filename(filename)
def _save_images(self, dirname, metadata, settings):
def _save_images(self, dirname, metadata):
"""Save the cover images to disk."""
if not metadata.images:
return
default_filename = self._make_image_filename(
settings["cover_image_filename"], dirname, metadata, settings)
overwrite = settings["save_images_overwrite"]
config.setting["cover_image_filename"], dirname, metadata)
overwrite = config.setting["save_images_overwrite"]
counters = defaultdict(lambda: 0)
for image in metadata.images:
filename = image["filename"]
@@ -340,7 +341,7 @@ class File(QtCore.QObject, Item):
if filename is None:
filename = default_filename
else:
filename = self._make_image_filename(filename, dirname, metadata, settings)
filename = self._make_image_filename(filename, dirname, metadata)
image_filename = filename
ext = mimetype.get_extension(mime, ".jpg")
if counters[filename] > 0:
@@ -348,7 +349,7 @@ class File(QtCore.QObject, Item):
counters[filename] = counters[filename] + 1
while os.path.exists(image_filename + ext) and not overwrite:
if os.path.getsize(image_filename + ext) == len(data):
self.log.debug("Identical file size, not saving %r", image_filename)
log.debug("Identical file size, not saving %r", image_filename)
break
image_filename = "%s (%d)" % (filename, counters[filename])
counters[filename] = counters[filename] + 1
@@ -358,9 +359,9 @@ class File(QtCore.QObject, Item):
# image multiple times
if (os.path.exists(new_filename) and
os.path.getsize(new_filename) == len(data)):
self.log.debug("Identical file size, not saving %r", image_filename)
log.debug("Identical file size, not saving %r", image_filename)
return
self.log.debug("Saving cover images to %r", image_filename)
log.debug("Saving cover images to %r", image_filename)
new_dirname = os.path.dirname(image_filename)
if not os.path.isdir(new_dirname):
os.makedirs(new_dirname)
@@ -368,11 +369,11 @@ class File(QtCore.QObject, Item):
f.write(data)
f.close()
def _move_additional_files(self, old_filename, new_filename, settings):
def _move_additional_files(self, old_filename, new_filename):
"""Move extra files, like playlists..."""
old_path = encode_filename(os.path.dirname(old_filename))
new_path = encode_filename(os.path.dirname(new_filename))
patterns = encode_filename(settings["move_additional_files_pattern"])
patterns = encode_filename(config.setting["move_additional_files_pattern"])
patterns = filter(bool, [p.strip() for p in patterns.split()])
for pattern in patterns:
# FIXME glob1 is not documented, maybe we need our own implemention?
@@ -381,21 +382,21 @@ class File(QtCore.QObject, Item):
old_file = os.path.join(old_path, old_file)
# FIXME we shouldn't do this from a thread!
if self.tagger.files.get(decode_filename(old_file)):
self.log.debug("File loaded in the tagger, not moving %r", old_file)
log.debug("File loaded in the tagger, not moving %r", old_file)
continue
self.log.debug("Moving %r to %r", old_file, new_file)
log.debug("Moving %r to %r", old_file, new_file)
shutil.move(old_file, new_file)
def remove(self, from_parent=True):
if from_parent and self.parent:
self.log.debug("Removing %r from %r", self, self.parent)
log.debug("Removing %r from %r", self, self.parent)
self.parent.remove_file(self)
self.tagger.acoustidmanager.remove(self)
self.state = File.REMOVED
def move(self, parent):
if parent != self.parent:
self.log.debug("Moving %r from %r to %r", self, self.parent, parent)
log.debug("Moving %r from %r to %r", self, self.parent, parent)
self.clear_lookup_task()
self.tagger._acoustid.stop_analyze(file)
if self.parent:
@@ -407,7 +408,7 @@ class File(QtCore.QObject, Item):
def _move(self, parent):
if parent != self.parent:
self.log.debug("Moving %r from %r to %r", self, self.parent, parent)
log.debug("Moving %r from %r to %r", self, self.parent, parent)
if self.parent:
self.parent.remove_file(self)
self.parent = parent
@@ -423,7 +424,7 @@ class File(QtCore.QObject, Item):
def update(self, signal=True):
names = set(self.metadata.keys())
names.update(self.orig_metadata.keys())
clear_existing_tags = self.config.setting["clear_existing_tags"]
clear_existing_tags = config.setting["clear_existing_tags"]
for name in names:
if not name.startswith('~') and self.supports_tag(name):
new_values = self.metadata.getall(name)
@@ -440,7 +441,7 @@ class File(QtCore.QObject, Item):
if self.state in (File.CHANGED, File.NORMAL):
self.state = File.NORMAL
if signal:
self.log.debug("Updating file %r", self)
log.debug("Updating file %r", self)
if self.item:
self.item.update()
@@ -542,7 +543,7 @@ class File(QtCore.QObject, Item):
reverse=True, key=itemgetter(0))[0]
if lookuptype != 'acoustid':
threshold = self.config.setting['file_lookup_threshold']
threshold = config.setting['file_lookup_threshold']
if match[0] < threshold:
self.tagger.window.set_statusbar_message(N_("No matching tracks above the threshold for file %s"), self.filename, timeout=3000)
self.clear_pending()

View File

@@ -23,11 +23,13 @@ import mutagen.musepack
import mutagen.wavpack
import mutagen.optimfrog
import mutagenext.tak
from picard import log
from picard.file import File
from picard.metadata import Metadata
from picard.util import encode_filename, sanitize_date, mimetype
from os.path import isfile
class APEv2File(File):
"""Generic APEv2-based file."""
_File = None
@@ -49,7 +51,7 @@ class APEv2File(File):
__rtranslate = dict([(v, k) for k, v in __translate.iteritems()])
def _load(self, filename):
self.log.debug("Loading file %r", filename)
log.debug("Loading file %r", filename)
file = self._File(encode_filename(filename))
metadata = Metadata()
if file.tags:
@@ -96,7 +98,7 @@ class APEv2File(File):
def _save(self, filename, metadata, settings):
"""Save metadata to the file."""
self.log.debug("Saving file %r", filename)
log.debug("Saving file %r", filename)
try:
tags = mutagen.apev2.APEv2(encode_filename(filename))
except mutagen.apev2.APENoHeaderError:

View File

@@ -17,6 +17,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 picard import config, log
from picard.file import File
from picard.formats.id3 import ID3_IMAGE_TYPE_MAP, ID3_REVERSE_IMAGE_TYPE_MAP
from picard.util import encode_filename
@@ -123,7 +124,7 @@ class ASFFile(File):
__RTRANS = dict([(b, a) for a, b in __TRANS.items()])
def _load(self, filename):
self.log.debug("Loading file %r", filename)
log.debug("Loading file %r", filename)
file = ASF(encode_filename(filename))
metadata = Metadata()
for name, values in file.tags.items():
@@ -138,7 +139,7 @@ class ASFFile(File):
continue
elif name == 'WM/SharedUserRating':
# Rating in WMA ranges from 0 to 99, normalize this to the range 0 to 5
values[0] = int(round(int(unicode(values[0])) / 99.0 * (self.config.setting['rating_steps'] - 1)))
values[0] = int(round(int(unicode(values[0])) / 99.0 * (config.setting['rating_steps'] - 1)))
name = self.__RTRANS[name]
values = filter(bool, map(unicode, values))
if values:
@@ -147,7 +148,7 @@ class ASFFile(File):
return metadata
def _save(self, filename, metadata, settings):
self.log.debug("Saving file %r", filename)
log.debug("Saving file %r", filename)
file = ASF(encode_filename(filename))
if settings['clear_existing_tags']:
@@ -155,7 +156,7 @@ class ASFFile(File):
if settings['save_images_to_tags']:
cover = []
for image in metadata.images:
if self.config.setting["save_only_front_images_to_tags"] and image["type"] != "front":
if config.setting["save_only_front_images_to_tags"] and image["type"] != "front":
continue
imagetype = ID3_IMAGE_TYPE_MAP.get(image["type"], 0)
tag_data = pack_image(image["mime"], image["data"], imagetype,

View File

@@ -22,6 +22,7 @@ import mutagen.mp3
import mutagen.trueaudio
from collections import defaultdict
from mutagen import id3
from picard import config, log
from picard.metadata import Metadata
from picard.file import File
from picard.formats.mutagenext import compatid3
@@ -156,7 +157,7 @@ class ID3File(File):
"totaldiscs", "totaltracks")
def _load(self, filename):
self.log.debug("Loading file %r", filename)
log.debug("Loading file %r", filename)
file = self._File(encode_filename(filename), ID3=compatid3.CompatID3)
tags = file.tags or {}
# upgrade custom 2.3 frames to 2.4
@@ -228,8 +229,8 @@ class ID3File(File):
description=frame.desc, type_=imagetype)
elif frameid == 'POPM':
# Rating in ID3 ranges from 0 to 255, normalize this to the range 0 to 5
if frame.email == self.config.setting['rating_user_email']:
rating = unicode(int(round(frame.rating / 255.0 * (self.config.setting['rating_steps'] - 1))))
if frame.email == config.setting['rating_user_email']:
rating = unicode(int(round(frame.rating / 255.0 * (config.setting['rating_steps'] - 1))))
metadata.add('~rating', rating)
if 'date' in metadata:
@@ -242,7 +243,7 @@ class ID3File(File):
def _save(self, filename, metadata, settings):
"""Save metadata to the file."""
self.log.debug("Saving file %r", filename)
log.debug("Saving file %r", filename)
try:
tags = compatid3.CompatID3(encode_filename(filename))
except mutagen.id3.ID3NoHeaderError:
@@ -281,7 +282,7 @@ class ID3File(File):
counters = defaultdict(lambda: 0)
for image in metadata.images:
desc = image["description"]
if self.config.setting["save_only_front_images_to_tags"] and image["type"] != "front":
if config.setting["save_only_front_images_to_tags"] and image["type"] != "front":
continue
type_ = ID3_IMAGE_TYPE_MAP.get(image["type"], 0)
if counters[desc] > 0:

View File

@@ -18,6 +18,7 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
from mutagen.mp4 import MP4, MP4Cover
from picard import config, log
from picard.file import File
from picard.metadata import Metadata
from picard.util import encode_filename
@@ -103,7 +104,7 @@ class MP4File(File):
"totaldiscs", "totaltracks")
def _load(self, filename):
self.log.debug("Loading file %r", filename)
log.debug("Loading file %r", filename)
file = MP4(encode_filename(filename))
if file.tags is None:
file.add_tags()
@@ -144,7 +145,7 @@ class MP4File(File):
return metadata
def _save(self, filename, metadata, settings):
self.log.debug("Saving file %r", filename)
log.debug("Saving file %r", filename)
file = MP4(encode_filename(self.filename))
if file.tags is None:
file.add_tags()
@@ -187,7 +188,7 @@ class MP4File(File):
if settings['save_images_to_tags']:
covr = []
for image in metadata.images:
if self.config.setting["save_only_front_images_to_tags"] and image["type"] != "front":
if config.setting["save_only_front_images_to_tags"] and image["type"] != "front":
continue
mime = image["mime"]
if mime == "image/jpeg":

View File

@@ -30,6 +30,7 @@ try:
except ImportError:
OggOpus = None
with_opus = False
from picard import config, log
from picard.file import File
from picard.formats.id3 import ID3_IMAGE_TYPE_MAP, ID3_REVERSE_IMAGE_TYPE_MAP
from picard.metadata import Metadata
@@ -40,7 +41,7 @@ class VCommentFile(File):
_File = None
def _load(self, filename):
self.log.debug("Loading file %r", filename)
log.debug("Loading file %r", filename)
file = self._File(encode_filename(filename))
file.tags = file.tags or {}
metadata = Metadata()
@@ -68,10 +69,10 @@ class VCommentFile(File):
elif name.startswith('rating'):
try: name, email = name.split(':', 1)
except ValueError: email = ''
if email != self.config.setting['rating_user_email']:
if email != config.setting['rating_user_email']:
continue
name = '~rating'
value = unicode(int(round((float(value) * (self.config.setting['rating_steps'] - 1)))))
value = unicode(int(round((float(value) * (config.setting['rating_steps'] - 1)))))
elif name == "fingerprint" and value.startswith("MusicMagic Fingerprint"):
name = "musicip_fingerprint"
value = value[22:]
@@ -108,7 +109,7 @@ class VCommentFile(File):
def _save(self, filename, metadata, settings):
"""Save metadata to the file."""
self.log.debug("Saving file %r", filename)
log.debug("Saving file %r", filename)
file = self._File(encode_filename(filename))
if file.tags is None:
file.add_tags()
@@ -152,7 +153,7 @@ class VCommentFile(File):
if settings['save_images_to_tags']:
for image in metadata.images:
if self.config.setting["save_only_front_images_to_tags"] and image["type"] != "front":
if config.setting["save_only_front_images_to_tags"] and image["type"] != "front":
continue
picture = mutagen.flac.Picture()
picture.data = image["data"]

View File

@@ -18,16 +18,18 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
import wave
from picard import log
from picard.file import File
from picard.metadata import Metadata
from picard.util import encode_filename
class WAVFile(File):
EXTENSIONS = [".wav"]
NAME = "Microsoft WAVE"
def _load(self, filename):
self.log.debug("Loading file %r", filename)
log.debug("Loading file %r", filename)
f = wave.open(encode_filename(filename), "rb")
metadata = Metadata()
metadata['~channels'] = f.getnchannels()
@@ -39,5 +41,5 @@ class WAVFile(File):
return metadata
def _save(self, filename, metadata, settings):
self.log.debug("Saving file %r", filename)
log.debug("Saving file %r", filename)
pass

View File

@@ -20,7 +20,6 @@
import sys
import os
from PyQt4 import QtCore
import picard
from picard.util import thread
@@ -28,54 +27,49 @@ def _stderr_receiver(prefix, time, msg):
sys.stderr.write("%s %s %s %s%s" % (prefix, str(QtCore.QThread.currentThreadId()), time, msg, os.linesep))
class Log(object):
def __init__(self):
self.entries = []
self.receivers = [_stderr_receiver]
picard.log.log = self
picard.log.debug = self.debug
picard.log.info = self.info
picard.log.warning = self.warning
picard.log.error = self.error
def _message(self, prefix, message, args, kwargs):
if not (isinstance(message, str) or isinstance(message, unicode)):
message = repr(message)
if args:
message = message % args
prefix = "%s" % (prefix,)
time = str(QtCore.QTime.currentTime().toString())
message = "%s" % (message,)
if isinstance(prefix, unicode):
prefix = prefix.encode("utf-8", "replace")
if isinstance(message, unicode):
message = message.encode("utf-8", "replace")
self.entries.append((prefix, time, message))
for func in self.receivers:
try:
func(prefix, time, message)
except Exception, e:
import traceback
traceback.print_exc()
def add_receiver(self, receiver):
self.receivers.append(receiver)
def debug(self, message, *args, **kwargs):
pass
def info(self, message, *args, **kwargs):
thread.proxy_to_main(self._message, "I:", message, args, kwargs)
def warning(self, message, *args, **kwargs):
thread.proxy_to_main(self._message, "W:", message, args, kwargs)
def error(self, message, *args, **kwargs):
thread.proxy_to_main(self._message, "E:", message, args, kwargs)
_entries = []
_receivers = [_stderr_receiver]
class DebugLog(Log):
def _message(prefix, message, args, kwargs):
if not (isinstance(message, str) or isinstance(message, unicode)):
message = repr(message)
if args:
message = message % args
prefix = "%s" % (prefix,)
time = str(QtCore.QTime.currentTime().toString())
message = "%s" % (message,)
if isinstance(prefix, unicode):
prefix = prefix.encode("utf-8", "replace")
if isinstance(message, unicode):
message = message.encode("utf-8", "replace")
_entries.append((prefix, time, message))
for func in _receivers:
try:
func(prefix, time, message)
except Exception, e:
import traceback
traceback.print_exc()
def debug(self, message, *args, **kwargs):
thread.proxy_to_main(self._message, "D:", message, args, kwargs)
def add_receiver(receiver):
_receivers.append(receiver)
_log_debug_messages = False
def debug(message, *args, **kwargs):
if _log_debug_messages:
thread.proxy_to_main(_message, "D:", message, args, kwargs)
def info(message, *args, **kwargs):
thread.proxy_to_main(_message, "I:", message, args, kwargs)
def warning(message, *args, **kwargs):
thread.proxy_to_main(_message, "W:", message, args, kwargs)
def error(message, *args, **kwargs):
thread.proxy_to_main(_message, "E:", message, args, kwargs)

View File

@@ -18,6 +18,7 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
import re
from picard import config
from picard.util import format_time, translate_from_sortname
from picard.const import RELEASE_FORMATS
@@ -67,12 +68,12 @@ def _parse_attributes(attrs):
return ' '.join([prefix, attrs]).strip().lower()
def _relations_to_metadata(relation_lists, m, config):
def _relations_to_metadata(relation_lists, m):
for relation_list in relation_lists:
if relation_list.target_type == 'artist':
for relation in relation_list.relation:
artist = relation.artist[0]
value = _translate_artist_node(artist, config)[0] or artist.name[0].text
value = _translate_artist_node(artist)[0] or artist.name[0].text
reltype = relation.type
attribs = []
if 'attribute_list' in relation.children:
@@ -95,7 +96,7 @@ def _relations_to_metadata(relation_lists, m, config):
elif relation_list.target_type == 'work':
for relation in relation_list.relation:
if relation.type == 'performance':
work_to_metadata(relation.work[0], m, config)
work_to_metadata(relation.work[0], m)
elif relation_list.target_type == 'url':
for relation in relation_list.relation:
if relation.type == 'amazon asin':
@@ -108,9 +109,9 @@ def _relations_to_metadata(relation_lists, m, config):
m.add('license', url)
def _translate_artist_node(node, config=None):
def _translate_artist_node(node):
transl, translsort = None, None
if config and config.setting['translate_artist_names']:
if config.setting['translate_artist_names']:
locale = config.setting["artist_locale"]
lang = locale.split("_")[0]
if "alias_list" in node.children:
@@ -131,16 +132,16 @@ def _translate_artist_node(node, config=None):
return (transl, translsort)
def artist_credit_from_node(node, config=None):
def artist_credit_from_node(node):
artist = ""
artistsort = ""
for credit in node.name_credit:
a = credit.artist[0]
transl, translsort = _translate_artist_node(a, config)
transl, translsort = _translate_artist_node(a)
if transl:
artist += transl
else:
if 'name' in credit.children and not (config and config.setting["standardize_artists"]):
if 'name' in credit.children and not config.setting["standardize_artists"]:
artist += credit.name[0].text
else:
artist += a.name[0].text
@@ -151,9 +152,9 @@ def artist_credit_from_node(node, config=None):
return (artist, artistsort)
def artist_credit_to_metadata(node, m, config, release=False):
def artist_credit_to_metadata(node, m, release=False):
ids = [n.artist[0].id for n in node.name_credit]
artist, artistsort = artist_credit_from_node(node, config)
artist, artistsort = artist_credit_from_node(node)
if release:
m["musicbrainz_albumartistid"] = ids
m["albumartist"] = artist
@@ -199,9 +200,9 @@ def media_formats_from_node(node):
return " + ".join(formats)
def track_to_metadata(node, track, config):
def track_to_metadata(node, track):
m = track.metadata
recording_to_metadata(node.recording[0], track, config)
recording_to_metadata(node.recording[0], track)
# overwrite with data we have on the track
for name, nodes in node.children.iteritems():
if not nodes:
@@ -213,11 +214,11 @@ def track_to_metadata(node, track, config):
elif name == 'length' and nodes[0].text:
m.length = int(nodes[0].text)
elif name == 'artist_credit':
artist_credit_to_metadata(nodes[0], m, config)
artist_credit_to_metadata(nodes[0], m)
m['~length'] = format_time(m.length)
def recording_to_metadata(node, track, config):
def recording_to_metadata(node, track):
m = track.metadata
m.length = 0
m['musicbrainz_trackid'] = node.attribs['id']
@@ -231,9 +232,9 @@ def recording_to_metadata(node, track, config):
elif name == 'disambiguation':
m['~recordingcomment'] = nodes[0].text
elif name == 'artist_credit':
artist_credit_to_metadata(nodes[0], m, config)
artist_credit_to_metadata(nodes[0], m)
elif name == 'relation_list':
_relations_to_metadata(nodes, m, config)
_relations_to_metadata(nodes, m)
elif name == 'tag_list':
add_folksonomy_tags(nodes[0], track)
elif name == 'user_tag_list':
@@ -244,12 +245,12 @@ def recording_to_metadata(node, track, config):
m['~rating'] = nodes[0].text
m['~length'] = format_time(m.length)
def work_to_metadata(work, m, config):
def work_to_metadata(work, m):
m.add("musicbrainz_workid", work.attribs['id'])
if 'language' in work.children:
m.add_unique("language", work.language[0].text)
if 'relation_list' in work.children:
_relations_to_metadata(work.relation_list, m, config)
_relations_to_metadata(work.relation_list, m)
def medium_to_metadata(node, m):
for name, nodes in node.children.iteritems():
@@ -265,7 +266,7 @@ def medium_to_metadata(node, m):
m['media'] = nodes[0].text
def release_to_metadata(node, m, config, album=None):
def release_to_metadata(node, m, album=None):
"""Make metadata dict from a XML 'release' node."""
m['musicbrainz_albumid'] = node.attribs['id']
for name, nodes in node.children.iteritems():
@@ -280,7 +281,7 @@ def release_to_metadata(node, m, config, album=None):
elif name == 'asin':
m['asin'] = nodes[0].text
elif name == 'artist_credit':
artist_credit_to_metadata(nodes[0], m, config, release=True)
artist_credit_to_metadata(nodes[0], m, release=True)
elif name == 'date':
m['date'] = nodes[0].text
elif name == 'country':
@@ -288,7 +289,7 @@ def release_to_metadata(node, m, config, album=None):
elif name == 'barcode':
m['barcode'] = nodes[0].text
elif name == 'relation_list':
_relations_to_metadata(nodes, m, config)
_relations_to_metadata(nodes, m)
elif name == 'label_info_list' and nodes[0].count != '0':
m['label'], m['catalognumber'] = label_info_from_node(nodes[0])
elif name == 'text_representation':
@@ -302,7 +303,7 @@ def release_to_metadata(node, m, config, album=None):
add_user_folksonomy_tags(nodes[0], album)
def release_group_to_metadata(node, m, config, release_group=None):
def release_group_to_metadata(node, m, release_group=None):
"""Make metadata dict from a XML 'release-group' node taken from inside a 'release' node."""
m['musicbrainz_releasegroupid'] = node.attribs['id']
for name, nodes in node.children.iteritems():

View File

@@ -18,6 +18,7 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
from PyQt4.QtCore import QObject
from picard import config
from picard.plugin import ExtensionPoint
from picard.similarity import similarity2
from picard.util import load_release_type_scores
@@ -95,7 +96,6 @@ class Metadata(dict):
Compare metadata to a MusicBrainz release. Produces a probability as a
linear combination of weights that the metadata matches a certain album.
"""
config = QObject.config
total = 0.0
parts = []
@@ -106,7 +106,7 @@ class Metadata(dict):
if "albumartist" in self and "albumartist" in weights:
a = self["albumartist"]
b = artist_credit_from_node(release.artist_credit[0], config)[0]
b = artist_credit_from_node(release.artist_credit[0])[0]
parts.append((similarity2(a, b), weights["albumartist"]))
total += weights["albumartist"]
@@ -168,7 +168,6 @@ class Metadata(dict):
(reduce(lambda x, y: x + y[0] * y[1] / total, parts, 0.0), release)
def compare_to_track(self, track, weights):
config = QObject.config
total = 0.0
parts = []
@@ -180,7 +179,7 @@ class Metadata(dict):
if 'artist' in self:
a = self['artist']
b = artist_credit_from_node(track.artist_credit[0], config)[0]
b = artist_credit_from_node(track.artist_credit[0])[0]
parts.append((similarity2(a, b), weights["artist"]))
total += weights["artist"]

View File

@@ -23,6 +23,9 @@ import os.path
import shutil
import picard.plugins
import traceback
from picard import config, log
from picard.const import USER_PLUGIN_DIR
_suffixes = [s[0] for s in imp.get_suffixes()]
_package_entries = ["__init__.py", "__init__.pyc", "__init__.pyo"]
@@ -50,10 +53,9 @@ def _unregister_module_extensions(module):
ep.unregister_module(module)
class ExtensionPoint(QtCore.QObject):
class ExtensionPoint(object):
def __init__(self):
QtCore.QObject.__init__(self)
self.__items = []
_extension_points.append(self)
@@ -68,7 +70,7 @@ class ExtensionPoint(QtCore.QObject):
self.__items = filter(lambda i: i[0] != name, self.__items)
def __iter__(self):
enabled_plugins = self.config.setting["enabled_plugins"].split()
enabled_plugins = config.setting["enabled_plugins"].split()
for module, item in self.__items:
if module is None or module in enabled_plugins:
yield item
@@ -138,7 +140,7 @@ class PluginManager(QtCore.QObject):
def load_plugindir(self, plugindir):
if not os.path.isdir(plugindir):
self.log.debug("Plugin directory %r doesn't exist", plugindir)
log.debug("Plugin directory %r doesn't exist", plugindir)
return
names = set()
for path in [os.path.join(plugindir, file) for file in os.listdir(plugindir)]:
@@ -149,7 +151,7 @@ class PluginManager(QtCore.QObject):
self.load_plugin(name, plugindir)
def load_plugin(self, name, plugindir):
self.log.debug("Loading plugin %r", name)
log.debug("Loading plugin %r", name)
info = imp.find_module(name, [plugindir])
plugin = None
try:
@@ -175,17 +177,16 @@ class PluginManager(QtCore.QObject):
continue
break
else:
self.log.info("Plugin '%s' from '%s' is not compatible"
log.info("Plugin '%s' from '%s' is not compatible"
" with this version of Picard." % (plugin.name, plugin.file))
except:
self.log.error(traceback.format_exc())
log.error(traceback.format_exc())
if info[0] is not None:
info[0].close()
return plugin
def install_plugin(self, path, dest):
plugin_name = _plugin_name_from_path(path)
plugin_dir = self.tagger.user_plugin_dir
if plugin_name:
try:
dest_exists = os.path.exists(dest)
@@ -196,11 +197,11 @@ class PluginManager(QtCore.QObject):
if dest_exists:
shutil.rmtree(dest)
shutil.copytree(path, dest)
plugin = self.load_plugin(plugin_name, plugin_dir)
plugin = self.load_plugin(plugin_name, USER_PLUGIN_DIR)
if plugin is not None:
self.plugin_installed.emit(plugin, False)
except OSError, IOError:
self.tagger.log.debug("Unable to copy %s to plugin folder %s" % (path, plugin_dir))
log.debug("Unable to copy %s to plugin folder %s" % (path, USER_PLUGIN_DIR))
def enabled(self, name):
return True

View File

@@ -19,6 +19,7 @@
import traceback
from PyQt4 import QtCore
from picard import config, log
from picard.metadata import Metadata
from picard.dataobj import DataObject
from picard.mbxml import media_formats_from_node, label_info_from_node
@@ -67,13 +68,13 @@ class ReleaseGroup(DataObject):
def _request_finished(self, callback, document, http, error):
try:
if error:
self.log.error("%r", unicode(http.errorString()))
log.error("%r", unicode(http.errorString()))
else:
try:
self._parse_versions(document)
except:
error = True
self.log.error(traceback.format_exc())
log.error(traceback.format_exc())
finally:
self.loaded = True
callback()

View File

@@ -52,12 +52,12 @@ shutil.copystat = _patched_shutil_copystat
import picard.resources
import picard.plugins
from picard import version_string, log, acoustid
from picard import version_string, log, acoustid, config
from picard.album import Album, NatAlbum
from picard.browser.browser import BrowserIntegration
from picard.browser.filelookup import FileLookup
from picard.cluster import Cluster, ClusterList, UnmatchedFiles
from picard.config import Config
from picard.const import USER_DIR, USER_PLUGIN_DIR
from picard.disc import Disc
from picard.file import File
from picard.formats import open as open_file
@@ -96,13 +96,6 @@ class Tagger(QtGui.QApplication):
self._args = args
self._autoupdate = autoupdate
self.config = Config()
if sys.platform == "win32":
userdir = os.environ.get("APPDATA", "~\\Application Data")
else:
userdir = os.environ.get("XDG_CONFIG_HOME", "~/.config")
self.userdir = os.path.join(os.path.expanduser(userdir), "MusicBrainz", "Picard")
# Initialize threading and allocate threads
self.thread_pool = thread.ThreadPool(self)
@@ -124,11 +117,8 @@ class Tagger(QtGui.QApplication):
self.stopping = False
# Setup logging
if debug or "PICARD_DEBUG" in os.environ:
self.log = log.DebugLog()
else:
self.log = log.Log()
self.log.debug("Starting Picard %s from %r", picard.__version__, os.path.abspath(__file__))
log._log_debug_messages = debug or "PICARD_DEBUG" in os.environ
log.debug("Starting Picard %s from %r", picard.__version__, os.path.abspath(__file__))
# TODO remove this before the final release
if sys.platform == "win32":
@@ -137,15 +127,16 @@ class Tagger(QtGui.QApplication):
olduserdir = "~/.picard"
olduserdir = os.path.expanduser(olduserdir)
if os.path.isdir(olduserdir):
self.log.info("Moving %s to %s", olduserdir, self.userdir)
log.info("Moving %s to %s", olduserdir, USER_DIR)
try:
shutil.move(olduserdir, self.userdir)
shutil.move(olduserdir, USER_DIR)
except:
pass
# for compatibility with pre-1.3 plugins
QtCore.QObject.tagger = self
QtCore.QObject.config = self.config
QtCore.QObject.log = self.log
QtCore.QObject.config = config
QtCore.QObject.log = log
check_io_encoding()
@@ -165,10 +156,10 @@ class Tagger(QtGui.QApplication):
self.pluginmanager.load_plugindir(os.path.join(os.path.dirname(sys.argv[0]), "plugins"))
else:
self.pluginmanager.load_plugindir(os.path.join(os.path.dirname(__file__), "plugins"))
self.user_plugin_dir = os.path.join(self.userdir, "plugins")
if not os.path.exists(self.user_plugin_dir):
os.makedirs(self.user_plugin_dir)
self.pluginmanager.load_plugindir(self.user_plugin_dir)
if not os.path.exists(USER_PLUGIN_DIR):
os.makedirs(USER_PLUGIN_DIR)
self.pluginmanager.load_plugindir(USER_PLUGIN_DIR)
self.acoustidmanager = AcoustIDManager()
self.browser_integration = BrowserIntegration()
@@ -184,20 +175,20 @@ class Tagger(QtGui.QApplication):
def remove_va_file_naming_format(merge=True):
if merge:
self.config.setting["file_naming_format"] = \
config.setting["file_naming_format"] = \
"$if($eq(%compilation%,1),\n$noop(Various Artist albums)\n"+\
"%s,\n$noop(Single Artist Albums)\n%s)" %\
(self.config.setting["va_file_naming_format"].toString(),
self.config.setting["file_naming_format"])
self.config.setting.remove("va_file_naming_format")
self.config.setting.remove("use_va_format")
(config.setting["va_file_naming_format"].toString(),
config.setting["file_naming_format"])
config.setting.remove("va_file_naming_format")
config.setting.remove("use_va_format")
if "va_file_naming_format" in self.config.setting\
and "use_va_format" in self.config.setting:
if self.config.setting["use_va_format"].toBool():
if "va_file_naming_format" in config.setting\
and "use_va_format" in config.setting:
if config.setting["use_va_format"].toBool():
remove_va_file_naming_format()
self.window.show_va_removal_notice()
elif self.config.setting["va_file_naming_format"].toString() !=\
elif config.setting["va_file_naming_format"].toString() !=\
r"$if2(%albumartist%,%artist%)/%album%/$if($gt(%totaldiscs%,1),%discnumber%-,)$num(%tracknumber%,2) %artist% - %title%":
if self.window.confirm_va_removal():
remove_va_file_naming_format(merge=False)
@@ -209,7 +200,7 @@ class Tagger(QtGui.QApplication):
def setup_gettext(self, localedir):
"""Setup locales, load translations, install gettext functions."""
ui_language = self.config.setting["ui_language"]
ui_language = config.setting["ui_language"]
if ui_language:
os.environ['LANGUAGE'] = ''
os.environ['LANG'] = ui_language
@@ -237,7 +228,7 @@ class Tagger(QtGui.QApplication):
except:
pass
try:
self.log.debug("Loading gettext translation, localedir=%r", localedir)
log.debug("Loading gettext translation, localedir=%r", localedir)
self.translation = gettext.translation("picard", localedir)
self.translation.install(True)
ungettext = self.translation.ungettext
@@ -326,7 +317,7 @@ class Tagger(QtGui.QApplication):
trackid = file.metadata['musicbrainz_trackid']
if target is not None:
self.move_files([file], target)
elif not self.config.setting["ignore_file_mbids"]:
elif not config.setting["ignore_file_mbids"]:
albumid = file.metadata['musicbrainz_albumid']
if mbid_validate(albumid):
if mbid_validate(trackid):
@@ -335,9 +326,9 @@ class Tagger(QtGui.QApplication):
self.move_file_to_album(file, albumid)
elif mbid_validate(trackid):
self.move_file_to_nat(file, trackid)
elif self.config.setting['analyze_new_files'] and file.can_analyze():
elif config.setting['analyze_new_files'] and file.can_analyze():
self.analyze([file])
elif self.config.setting['analyze_new_files'] and file.can_analyze():
elif config.setting['analyze_new_files'] and file.can_analyze():
self.analyze([file])
def move_files(self, files, target):
@@ -354,7 +345,7 @@ class Tagger(QtGui.QApplication):
def add_files(self, filenames, target=None):
"""Add files to the tagger."""
self.log.debug("Adding files %r", filenames)
log.debug("Adding files %r", filenames)
new_files = []
for filename in filenames:
filename = os.path.normpath(os.path.realpath(filename))
@@ -392,8 +383,8 @@ class Tagger(QtGui.QApplication):
def get_file_lookup(self):
"""Return a FileLookup object."""
return FileLookup(self, self.config.setting["server_host"],
self.config.setting["server_port"],
return FileLookup(self, config.setting["server_host"],
config.setting["server_port"],
self.browser_integration.port)
def search(self, text, type, adv=False):
@@ -438,7 +429,7 @@ class Tagger(QtGui.QApplication):
"""Save the specified objects."""
files = self.get_files_from_objects(objects, save=True)
for file in files:
file.save(self._file_saved, self.tagger.config.setting)
file.save(self._file_saved)
def load_album(self, id, discid=None):
id = self.mbid_redirects.get(id, id)
@@ -485,7 +476,7 @@ class Tagger(QtGui.QApplication):
def remove_album(self, album):
"""Remove the specified album."""
self.log.debug("Removing %r", album)
log.debug("Removing %r", album)
album.stop_loading()
self.remove_files(self.get_files_from_objects([album]))
del self.albums[album.id]
@@ -498,7 +489,7 @@ class Tagger(QtGui.QApplication):
def remove_cluster(self, cluster):
"""Remove the specified cluster."""
if not cluster.special:
self.log.debug("Removing %r", cluster)
log.debug("Removing %r", cluster)
files = list(cluster.files)
cluster.files = []
cluster.clear_lookup_task()
@@ -534,7 +525,7 @@ class Tagger(QtGui.QApplication):
if isinstance(action, QtGui.QAction):
device = unicode(action.text())
else:
device = self.config.setting["cd_lookup_device"].split(",", 1)[0]
device = config.setting["cd_lookup_device"].split(",", 1)[0]
disc = Disc()
self.set_wait_cursor()
@@ -545,7 +536,7 @@ class Tagger(QtGui.QApplication):
@property
def use_acoustid(self):
return self.config.setting["fingerprinting_system"] == "acoustid"
return config.setting["fingerprinting_system"] == "acoustid"
def analyze(self, objs):
"""Analyze the file(s)."""
@@ -570,7 +561,7 @@ class Tagger(QtGui.QApplication):
def cluster(self, objs):
"""Group files with similar metadata to 'clusters'."""
self.log.debug("Clustering %r", objs)
log.debug("Clustering %r", objs)
if len(objs) <= 1 or self.unmatched_files in objs:
files = list(self.unmatched_files.files)
else:

View File

@@ -18,6 +18,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 picard import config, log
from picard.metadata import Metadata, run_track_metadata_processors
from picard.dataobj import DataObject
from picard.util import asciipunct, partial
@@ -116,13 +117,13 @@ class Track(DataObject, Item):
# Custom VA name
if tm['musicbrainz_artistid'] == VARIOUS_ARTISTS_ID:
tm['artistsort'] = tm['artist'] = self.config.setting['va_name']
tm['artistsort'] = tm['artist'] = config.setting['va_name']
if self.config.setting['folksonomy_tags']:
if config.setting['folksonomy_tags']:
self._convert_folksonomy_tags_to_genre()
# Convert Unicode punctuation
if self.config.setting['convert_punctuation']:
if config.setting['convert_punctuation']:
tm.apply_func(asciipunct)
def _convert_folksonomy_tags_to_genre(self):
@@ -140,9 +141,9 @@ class Track(DataObject, Item):
taglist.append((100 * count / maxcount, name))
taglist.sort(reverse=True)
# And generate the genre metadata tag
maxtags = self.config.setting['max_tags']
minusage = self.config.setting['min_tag_usage']
ignore_tags = self.config.setting['ignore_tags']
maxtags = config.setting['max_tags']
minusage = config.setting['min_tag_usage']
ignore_tags = config.setting['ignore_tags']
genre = []
for usage, name in taglist[:maxtags]:
if name in ignore_tags:
@@ -151,7 +152,7 @@ class Track(DataObject, Item):
break
name = _TRANSLATE_TAGS.get(name, name.title())
genre.append(name)
join_tags = self.config.setting['join_tags']
join_tags = config.setting['join_tags']
if join_tags:
genre = [join_tags.join(genre)]
self.metadata['genre'] = genre
@@ -179,16 +180,16 @@ class NonAlbumTrack(Track):
self.tagger.nats.update(True)
mblogin = False
inc = ["artist-credits", "artists", "aliases"]
if self.config.setting["track_ars"]:
if config.setting["track_ars"]:
inc += ["artist-rels", "url-rels", "recording-rels",
"work-rels", "work-level-rels"]
if self.config.setting["folksonomy_tags"]:
if self.config.setting["only_my_tags"]:
if config.setting["folksonomy_tags"]:
if config.setting["only_my_tags"]:
mblogin = True
inc += ["user-tags"]
else:
inc += ["tags"]
if self.config.setting["enable_ratings"]:
if config.setting["enable_ratings"]:
mblogin = True
inc += ["user-ratings"]
self.tagger.xmlws.get_track_by_id(self.id,
@@ -196,7 +197,7 @@ class NonAlbumTrack(Track):
def _recording_request_finished(self, document, http, error):
if error:
self.log.error("%r", unicode(http.errorString()))
log.error("%r", unicode(http.errorString()))
return
try:
recording = document.metadata[0].recording[0]
@@ -204,21 +205,21 @@ class NonAlbumTrack(Track):
for file in self.linked_files:
self.update_file_metadata(file)
except:
self.log.error(traceback.format_exc())
log.error(traceback.format_exc())
def _parse_recording(self, recording):
recording_to_metadata(recording, self, self.config)
recording_to_metadata(recording, self)
self._customize_metadata()
m = self.metadata
run_track_metadata_processors(self.album, m, None, recording)
if self.config.setting["enable_tagger_script"]:
script = self.config.setting["tagger_script"]
if config.setting["enable_tagger_script"]:
script = config.setting["tagger_script"]
if script:
parser = ScriptParser()
try:
parser.eval(script, m)
except:
self.log.error(traceback.format_exc())
log.error(traceback.format_exc())
m.strip_whitespace()
self.loaded = True
if self.callback:

View File

@@ -40,7 +40,7 @@ class CDLookupDialog(QtGui.QDialog):
barcode = release.barcode[0].text if "barcode" in release.children else ""
item = QtGui.QTreeWidgetItem(self.ui.release_list)
item.setText(0, release.title[0].text)
item.setText(1, artist_credit_from_node(release.artist_credit[0], self.config)[0])
item.setText(1, artist_credit_from_node(release.artist_credit[0])[0])
item.setText(2, date)
item.setText(3, country)
item.setText(4, ", ".join(labels))

View File

@@ -19,6 +19,7 @@
import os
from PyQt4 import QtCore, QtGui, QtNetwork
from picard import config, log
from picard.album import Album
from picard.track import Track
from picard.file import File
@@ -137,8 +138,8 @@ class CoverArtBox(QtGui.QGroupBox):
self.release = release
def open_release_page(self):
host = self.config.setting["server_host"]
port = self.config.setting["server_port"]
host = config.setting["server_host"]
port = config.setting["server_port"]
url = "http://%s:%s/release/%s" % (host, port, self.release)
webbrowser2.open(url)
@@ -164,14 +165,14 @@ class CoverArtBox(QtGui.QGroupBox):
def on_remote_image_fetched(self, data, reply, error):
mime = str(reply.header(QtNetwork.QNetworkRequest.ContentTypeHeader).toString())
if mime not in ('image/jpeg', 'image/png'):
self.log.warning("Can't load image with MIME-Type %s", mime)
log.warning("Can't load image with MIME-Type %s", mime)
return
return self.load_remote_image(mime, data)
def load_remote_image(self, mime, data):
pixmap = QtGui.QPixmap()
if not pixmap.loadFromData(data):
self.log.warning("Can't load image")
log.warning("Can't load image")
return
self.__set_data([mime, data], pixmap=pixmap)
if isinstance(self.item, Album):

View File

@@ -20,15 +20,16 @@
import os, sys
from PyQt4 import QtCore, QtGui
from picard import config
from picard.formats import supported_formats
from picard.config import TextOption, BoolOption
from picard.util import find_existing_path
class FileBrowser(QtGui.QTreeView):
options = [
TextOption("persist", "current_browser_path", ""),
BoolOption("persist", "show_hidden_files", False),
config.TextOption("persist", "current_browser_path", ""),
config.BoolOption("persist", "show_hidden_files", False),
]
def __init__(self, parent):
@@ -40,7 +41,7 @@ class FileBrowser(QtGui.QTreeView):
self.addAction(self.move_files_here_action)
self.toggle_hidden_action = QtGui.QAction(_("Show &Hidden Files"), self)
self.toggle_hidden_action.setCheckable(True)
self.toggle_hidden_action.setChecked(self.config.persist["show_hidden_files"])
self.toggle_hidden_action.setChecked(config.persist["show_hidden_files"])
self.toggle_hidden_action.toggled.connect(self.show_hidden)
self.addAction(self.toggle_hidden_action)
self.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu)
@@ -71,7 +72,7 @@ class FileBrowser(QtGui.QTreeView):
def _set_model_filter(self):
filter = QtCore.QDir.AllDirs | QtCore.QDir.Files | QtCore.QDir.Drives | QtCore.QDir.NoDotAndDotDot
if self.config.persist["show_hidden_files"]:
if config.persist["show_hidden_files"]:
filter |= QtCore.QDir.Hidden
self.model.setFilter(filter)
@@ -98,20 +99,20 @@ class FileBrowser(QtGui.QTreeView):
QtGui.QTreeView.focusInEvent(self, event)
def show_hidden(self, state):
self.config.persist["show_hidden_files"] = state
config.persist["show_hidden_files"] = state
self._set_model_filter()
def save_state(self):
indexes = self.selectedIndexes()
if indexes:
path = self.model.filePath(indexes[0])
self.config.persist["current_browser_path"] = path
config.persist["current_browser_path"] = path
def restore_state(self):
pass
def _restore_state(self):
path = self.config.persist["current_browser_path"]
path = config.persist["current_browser_path"]
if path:
index = self.model.index(find_existing_path(unicode(path)))
self.setCurrentIndex(index)
@@ -122,4 +123,4 @@ class FileBrowser(QtGui.QTreeView):
if not indexes:
return
path = self.model.filePath(indexes[0])
self.config.setting["move_files_to"] = os.path.normpath(unicode(path))
config.setting["move_files_to"] = os.path.normpath(unicode(path))

View File

@@ -20,12 +20,12 @@
import os
import re
from PyQt4 import QtCore, QtGui
from picard import config, log
from picard.album import Album, NatAlbum
from picard.cluster import Cluster, ClusterList, UnmatchedFiles
from picard.file import File
from picard.track import Track, NonAlbumTrack
from picard.util import encode_filename, icontheme, partial
from picard.config import Option, TextOption
from picard.plugin import ExtensionPoint
from picard.ui.ratingwidget import RatingWidget
from picard.ui.collectionmenu import CollectionMenu
@@ -80,7 +80,7 @@ def get_match_color(similarity, basecolor):
class MainPanel(QtGui.QSplitter):
options = [
Option("persist", "splitter_state", QtCore.QByteArray(), QtCore.QVariant.toByteArray),
config.Option("persist", "splitter_state", QtCore.QByteArray(), QtCore.QVariant.toByteArray),
]
columns = [
@@ -103,25 +103,25 @@ class MainPanel(QtGui.QSplitter):
TreeItem.base_color = self.palette().base().color()
TreeItem.text_color = self.palette().text().color()
TrackItem.track_colors = {
File.NORMAL: self.config.setting["color_saved"],
File.NORMAL: config.setting["color_saved"],
File.CHANGED: TreeItem.text_color,
File.PENDING: self.config.setting["color_pending"],
File.ERROR: self.config.setting["color_error"],
File.PENDING: config.setting["color_pending"],
File.ERROR: config.setting["color_error"],
}
FileItem.file_colors = {
File.NORMAL: TreeItem.text_color,
File.CHANGED: self.config.setting["color_modified"],
File.PENDING: self.config.setting["color_pending"],
File.ERROR: self.config.setting["color_error"],
File.CHANGED: config.setting["color_modified"],
File.PENDING: config.setting["color_pending"],
File.ERROR: config.setting["color_error"],
}
def save_state(self):
self.config.persist["splitter_state"] = self.saveState()
config.persist["splitter_state"] = self.saveState()
for view in self.views:
view.save_state()
def restore_state(self):
self.restoreState(self.config.persist["splitter_state"])
self.restoreState(config.persist["splitter_state"])
def create_icons(self):
if hasattr(QtGui.QStyle, 'SP_DirIcon'):
@@ -191,10 +191,10 @@ class MainPanel(QtGui.QSplitter):
class BaseTreeView(QtGui.QTreeWidget):
options = [
Option("setting", "color_modified", QtGui.QColor(QtGui.QPalette.WindowText), QtGui.QColor),
Option("setting", "color_saved", QtGui.QColor(0, 128, 0), QtGui.QColor),
Option("setting", "color_error", QtGui.QColor(200, 0, 0), QtGui.QColor),
Option("setting", "color_pending", QtGui.QColor(128, 128, 128), QtGui.QColor),
config.Option("setting", "color_modified", QtGui.QColor(QtGui.QPalette.WindowText), QtGui.QColor),
config.Option("setting", "color_saved", QtGui.QColor(0, 128, 0), QtGui.QColor),
config.Option("setting", "color_error", QtGui.QColor(200, 0, 0), QtGui.QColor),
config.Option("setting", "color_pending", QtGui.QColor(128, 128, 128), QtGui.QColor),
]
def __init__(self, window, parent=None):
@@ -303,7 +303,7 @@ class BaseTreeView(QtGui.QTreeWidget):
else:
releases_menu.setEnabled(False)
if self.config.setting["enable_ratings"] and \
if config.setting["enable_ratings"] and \
len(self.window.selected_objects) == 1 and isinstance(obj, Track):
menu.addSeparator()
action = QtGui.QWidgetAction(menu)
@@ -343,7 +343,7 @@ class BaseTreeView(QtGui.QTreeWidget):
event.accept()
def restore_state(self):
sizes = self.config.persist[self.view_sizes.name]
sizes = config.persist[self.view_sizes.name]
header = self.header()
sizes = sizes.split(" ")
try:
@@ -355,7 +355,7 @@ class BaseTreeView(QtGui.QTreeWidget):
def save_state(self):
cols = range(self.numHeaderSections - 1)
sizes = " ".join(str(self.header().sectionSize(i)) for i in cols)
self.config.persist[self.view_sizes.name] = sizes
config.persist[self.view_sizes.name] = sizes
def supportedDropActions(self):
return QtCore.Qt.CopyAction | QtCore.Qt.MoveAction
@@ -444,7 +444,7 @@ class BaseTreeView(QtGui.QTreeWidget):
item = parent.child(index)
if item is not None:
target = item.obj
self.log.debug("Drop target = %r", target)
log.debug("Drop target = %r", target)
handled = False
# text/uri-list
urls = data.urls()
@@ -490,7 +490,7 @@ class BaseTreeView(QtGui.QTreeWidget):
class FileTreeView(BaseTreeView):
view_sizes = TextOption("persist", "file_view_sizes", "250 40 100")
view_sizes = config.TextOption("persist", "file_view_sizes", "250 40 100")
def __init__(self, window, parent=None):
BaseTreeView.__init__(self, window, parent)
@@ -512,7 +512,7 @@ class FileTreeView(BaseTreeView):
class AlbumTreeView(BaseTreeView):
view_sizes = TextOption("persist", "album_view_sizes", "250 40 100")
view_sizes = config.TextOption("persist", "album_view_sizes", "250 40 100")
def __init__(self, window, parent=None):
BaseTreeView.__init__(self, window, parent)

View File

@@ -19,7 +19,7 @@
from PyQt4 import QtCore, QtGui
from picard.log import log
from picard import log
class LogView(QtGui.QDialog):
@@ -38,7 +38,7 @@ class LogView(QtGui.QDialog):
self.browser.setDocument(self.doc)
vbox = QtGui.QHBoxLayout(self)
vbox.addWidget(self.browser)
for prefix, time, msg in log.entries:
for prefix, time, msg in log._entries:
self.add_entry(prefix, time, msg)
log.add_receiver(self.add_entry)

View File

@@ -22,10 +22,10 @@ from PyQt4 import QtCore, QtGui
import sys
import os.path
from picard import config, log
from picard.file import File
from picard.track import Track
from picard.album import Album
from picard.config import Option, BoolOption, TextOption
from picard.formats import supported_formats
from picard.ui.coverartbox import CoverArtBox
from picard.ui.itemviews import MainPanel
@@ -46,18 +46,18 @@ def register_ui_init (function):
class MainWindow(QtGui.QMainWindow):
options = [
Option("persist", "window_state", QtCore.QByteArray(),
config.Option("persist", "window_state", QtCore.QByteArray(),
QtCore.QVariant.toByteArray),
Option("persist", "window_position", QtCore.QPoint(),
config.Option("persist", "window_position", QtCore.QPoint(),
QtCore.QVariant.toPoint),
Option("persist", "window_size", QtCore.QSize(780, 560),
config.Option("persist", "window_size", QtCore.QSize(780, 560),
QtCore.QVariant.toSize),
Option("persist", "bottom_splitter_state", QtCore.QByteArray(),
config.Option("persist", "bottom_splitter_state", QtCore.QByteArray(),
QtCore.QVariant.toByteArray),
BoolOption("persist", "window_maximized", False),
BoolOption("persist", "view_cover_art", False),
BoolOption("persist", "view_file_browser", False),
TextOption("persist", "current_directory", ""),
config.BoolOption("persist", "window_maximized", False),
config.BoolOption("persist", "view_cover_art", False),
config.BoolOption("persist", "view_file_browser", False),
config.TextOption("persist", "current_directory", ""),
]
def __init__(self, parent=None):
@@ -134,7 +134,7 @@ class MainWindow(QtGui.QMainWindow):
self.metadata_box.restore_state()
def closeEvent(self, event):
if self.config.setting["quit_confirmation"] and not self.show_quit_confirmation():
if config.setting["quit_confirmation"] and not self.show_quit_confirmation():
event.ignore()
return
self.saveWindowState()
@@ -166,39 +166,39 @@ class MainWindow(QtGui.QMainWindow):
return True
def saveWindowState(self):
self.config.persist["window_state"] = self.saveState()
config.persist["window_state"] = self.saveState()
isMaximized = int(self.windowState()) & QtCore.Qt.WindowMaximized != 0
if isMaximized:
# FIXME: this doesn't include the window frame
geom = self.normalGeometry()
self.config.persist["window_position"] = geom.topLeft()
self.config.persist["window_size"] = geom.size()
config.persist["window_position"] = geom.topLeft()
config.persist["window_size"] = geom.size()
else:
pos = self.pos()
if not pos.isNull():
self.config.persist["window_position"] = pos
self.config.persist["window_size"] = self.size()
self.config.persist["window_maximized"] = isMaximized
self.config.persist["view_cover_art"] = self.show_cover_art_action.isChecked()
self.config.persist["view_file_browser"] = self.show_file_browser_action.isChecked()
self.config.persist["bottom_splitter_state"] = self.centralWidget().saveState()
config.persist["window_position"] = pos
config.persist["window_size"] = self.size()
config.persist["window_maximized"] = isMaximized
config.persist["view_cover_art"] = self.show_cover_art_action.isChecked()
config.persist["view_file_browser"] = self.show_file_browser_action.isChecked()
config.persist["bottom_splitter_state"] = self.centralWidget().saveState()
self.file_browser.save_state()
self.panel.save_state()
self.metadata_box.save_state()
def restoreWindowState(self):
self.restoreState(self.config.persist["window_state"])
pos = self.config.persist["window_position"]
size = self.config.persist["window_size"]
self.restoreState(config.persist["window_state"])
pos = config.persist["window_position"]
size = config.persist["window_size"]
self._desktopgeo = self.tagger.desktop().screenGeometry()
if pos.x() > 0 and pos.y() > 0 and pos.x()+size.width() < self._desktopgeo.width() and pos.y()+size.height() < self._desktopgeo.height():
self.move(pos)
if size.width() <= 0 or size.height() <= 0:
size = QtCore.QSize(780, 560)
self.resize(size)
if self.config.persist["window_maximized"]:
if config.persist["window_maximized"]:
self.setWindowState(QtCore.Qt.WindowMaximized)
bottom_splitter_state = self.config.persist["bottom_splitter_state"]
bottom_splitter_state = config.persist["bottom_splitter_state"]
if bottom_splitter_state.isEmpty():
self.centralWidget().setSizes([366, 194])
else:
@@ -232,7 +232,7 @@ class MainWindow(QtGui.QMainWindow):
"""Set the status bar message."""
try:
if message:
self.log.debug(repr(message.replace('%%s', '%%r')), *args)
log.debug(repr(message.replace('%%s', '%%r')), *args)
except:
pass
self.tagger.thread_pool.call_from_thread(
@@ -248,7 +248,7 @@ class MainWindow(QtGui.QMainWindow):
def _on_submit(self):
if self.tagger.use_acoustid:
if not self.config.setting["acoustid_apikey"]:
if not config.setting["acoustid_apikey"]:
QtGui.QMessageBox.warning(self,
_(u"Submission Error"),
_(u"You need to configure your AcoustID API key before you can submit fingerprints."))
@@ -330,14 +330,14 @@ class MainWindow(QtGui.QMainWindow):
self.show_file_browser_action = QtGui.QAction(_(u"File &Browser"), self)
self.show_file_browser_action.setCheckable(True)
if self.config.persist["view_file_browser"]:
if config.persist["view_file_browser"]:
self.show_file_browser_action.setChecked(True)
self.show_file_browser_action.setShortcut(QtGui.QKeySequence(_(u"Ctrl+B")))
self.show_file_browser_action.triggered.connect(self.show_file_browser)
self.show_cover_art_action = QtGui.QAction(_(u"&Cover Art"), self)
self.show_cover_art_action.setCheckable(True)
if self.config.persist["view_cover_art"]:
if config.persist["view_cover_art"]:
self.show_cover_art_action.setChecked(True)
self.show_cover_art_action.triggered.connect(self.show_cover_art)
@@ -383,17 +383,17 @@ class MainWindow(QtGui.QMainWindow):
self.enable_renaming_action = QtGui.QAction(_(u"&Rename Files"), self)
self.enable_renaming_action.setCheckable(True)
self.enable_renaming_action.setChecked(self.config.setting["rename_files"])
self.enable_renaming_action.setChecked(config.setting["rename_files"])
self.enable_renaming_action.triggered.connect(self.toggle_rename_files)
self.enable_moving_action = QtGui.QAction(_(u"&Move Files"), self)
self.enable_moving_action.setCheckable(True)
self.enable_moving_action.setChecked(self.config.setting["move_files"])
self.enable_moving_action.setChecked(config.setting["move_files"])
self.enable_moving_action.triggered.connect(self.toggle_move_files)
self.enable_tag_saving_action = QtGui.QAction(_(u"Save &Tags"), self)
self.enable_tag_saving_action.setCheckable(True)
self.enable_tag_saving_action.setChecked(not self.config.setting["dont_write_tags"])
self.enable_tag_saving_action.setChecked(not config.setting["dont_write_tags"])
self.enable_tag_saving_action.triggered.connect(self.toggle_tag_saving)
self.tags_from_filenames_action = QtGui.QAction(_(u"Tags From &File Names..."), self)
@@ -415,13 +415,13 @@ class MainWindow(QtGui.QMainWindow):
self.open_folder_action.triggered.connect(self.open_folder)
def toggle_rename_files(self, checked):
self.config.setting["rename_files"] = checked
config.setting["rename_files"] = checked
def toggle_move_files(self, checked):
self.config.setting["move_files"] = checked
config.setting["move_files"] = checked
def toggle_tag_saving(self, checked):
self.config.setting["dont_write_tags"] = not checked
config.setting["dont_write_tags"] = not checked
def open_tags_from_filenames(self):
files = self.tagger.get_files_from_objects(self.selected_objects)
@@ -480,7 +480,7 @@ class MainWindow(QtGui.QMainWindow):
menu.addAction(self.about_action)
def update_toolbar_style(self):
if self.config.setting["toolbar_show_labels"]:
if config.setting["toolbar_show_labels"]:
self.toolbar.setToolButtonStyle(QtCore.Qt.ToolButtonTextUnderIcon)
else:
self.toolbar.setToolButtonStyle(QtCore.Qt.ToolButtonIconOnly)
@@ -578,11 +578,11 @@ class MainWindow(QtGui.QMainWindow):
text = unicode(self.search_edit.text())
type = unicode(self.search_combo.itemData(
self.search_combo.currentIndex()).toString())
self.tagger.search(text, type, self.config.setting["use_adv_search_syntax"])
self.tagger.search(text, type, config.setting["use_adv_search_syntax"])
def add_files(self):
"""Add files to the tagger."""
current_directory = self.config.persist["current_directory"] or QtCore.QDir.homePath()
current_directory = config.persist["current_directory"] or QtCore.QDir.homePath()
current_directory = find_existing_path(unicode(current_directory))
formats = []
extensions = []
@@ -596,16 +596,16 @@ class MainWindow(QtGui.QMainWindow):
files = QtGui.QFileDialog.getOpenFileNames(self, "", current_directory, u";;".join(formats))
if files:
files = map(unicode, files)
self.config.persist["current_directory"] = os.path.dirname(files[0])
config.persist["current_directory"] = os.path.dirname(files[0])
self.tagger.add_files(files)
def add_directory(self):
"""Add directory to the tagger."""
current_directory = self.config.persist["current_directory"] or QtCore.QDir.homePath()
current_directory = config.persist["current_directory"] or QtCore.QDir.homePath()
current_directory = find_existing_path(unicode(current_directory))
dir_list = []
if not self.config.setting["toolbar_multiselect"]:
if not config.setting["toolbar_multiselect"]:
directory = QtGui.QFileDialog.getExistingDirectory(self, "", current_directory)
if directory:
dir_list.append(directory)
@@ -624,10 +624,10 @@ class MainWindow(QtGui.QMainWindow):
dir_list = file_dialog.selectedFiles()
if len(dir_list) == 1:
self.config.persist["current_directory"] = dir_list[0]
config.persist["current_directory"] = dir_list[0]
elif len(dir_list) > 1:
(parent, dir) = os.path.split(str(dir_list[0]))
self.config.persist["current_directory"] = parent
config.persist["current_directory"] = parent
for directory in dir_list:
directory = unicode(directory)
@@ -684,10 +684,10 @@ been merged with that of single artist albums."""),
self.panel.remove(self.selected_objects)
def analyze(self):
if not self.config.setting['fingerprinting_system']:
if not config.setting['fingerprinting_system']:
if self.show_analyze_settings_info():
self.show_options("fingerprinting")
if not self.config.setting['fingerprinting_system']:
if not config.setting['fingerprinting_system']:
return
return self.tagger.analyze(self.selected_objects)

View File

@@ -20,11 +20,11 @@
from PyQt4 import QtCore, QtGui
from collections import defaultdict
from picard import config
from picard.album import Album
from picard.cluster import Cluster
from picard.track import Track
from picard.file import File
from picard.config import TextOption, BoolOption
from picard.util import partial, format_time
from picard.util.tags import display_tag_name
from picard.ui.edittagdialog import EditTagDialog
@@ -141,8 +141,8 @@ class TagDiff:
class MetadataBox(QtGui.QTableWidget):
options = (
TextOption("persist", "metadata_box_sizes", "150 300 300"),
BoolOption("persist", "show_changes_first", False)
config.TextOption("persist", "metadata_box_sizes", "150 300 300"),
config.BoolOption("persist", "show_changes_first", False)
)
def __init__(self, parent):
@@ -181,7 +181,7 @@ class MetadataBox(QtGui.QTableWidget):
self.add_tag_action.triggered.connect(partial(self.edit_tag, ""))
self.changes_first_action = QtGui.QAction(_(u"Show Changes First"), parent)
self.changes_first_action.setCheckable(True)
self.changes_first_action.setChecked(self.config.persist["show_changes_first"])
self.changes_first_action.setChecked(config.persist["show_changes_first"])
self.changes_first_action.toggled.connect(self.toggle_changes_first)
def edit(self, index, trigger, event):
@@ -267,7 +267,7 @@ class MetadataBox(QtGui.QTableWidget):
EditTagDialog(self.parent, tag).exec_()
def toggle_changes_first(self, checked):
self.config.persist["show_changes_first"] = checked
config.persist["show_changes_first"] = checked
self.update()
def set_tag_values(self, tag, values, objects=None):
@@ -358,7 +358,7 @@ class MetadataBox(QtGui.QTableWidget):
existing_tags = set()
tag_diff.objects = len(self.files)
clear_existing_tags = self.config.setting["clear_existing_tags"]
clear_existing_tags = config.setting["clear_existing_tags"]
for file in self.files:
new_metadata = file.metadata
@@ -393,7 +393,7 @@ class MetadataBox(QtGui.QTableWidget):
all_tags = set(orig_tags.keys() + new_tags.keys())
tag_names = COMMON_TAGS + sorted(all_tags.difference(COMMON_TAGS))
if self.config.persist["show_changes_first"]:
if config.persist["show_changes_first"]:
self.tag_names = []
tags_by_status = {}
@@ -467,7 +467,7 @@ class MetadataBox(QtGui.QTableWidget):
self.set_tag_values(self.tag_names[item.row()], [unicode(item.text())])
def restore_state(self):
sizes = self.config.persist["metadata_box_sizes"].split(" ")
sizes = config.persist["metadata_box_sizes"].split(" ")
header = self.horizontalHeader()
try:
for i in range(header.count()):
@@ -482,7 +482,7 @@ class MetadataBox(QtGui.QTableWidget):
header = self.horizontalHeader()
for i in range(header.count()):
sizes.append(str(header.sectionSize(i)))
self.config.persist["metadata_box_sizes"] = " ".join(sizes)
config.persist["metadata_box_sizes"] = " ".join(sizes)
def shrink_columns(self):
header = self.horizontalHeader()

View File

@@ -18,7 +18,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 picard.config import TextOption
from picard import config
from picard.ui.options import OptionsPage, register_options_page
from picard.util.cdrom import get_cdrom_drives, AUTO_DETECT_DRIVES
@@ -37,7 +37,7 @@ class CDLookupOptionsPage(OptionsPage):
ACTIVE = True
options = [
TextOption("setting", "cd_lookup_device", ""),
config.TextOption("setting", "cd_lookup_device", ""),
]
def __init__(self, parent=None):
@@ -51,17 +51,17 @@ class CDLookupOptionsPage(OptionsPage):
def load(self):
if AUTO_DETECT_DRIVES:
try:
self.ui.cd_lookup_device.setCurrentIndex(self.drives.index(self.config.setting["cd_lookup_device"]))
self.ui.cd_lookup_device.setCurrentIndex(self.drives.index(config.setting["cd_lookup_device"]))
except ValueError:
pass
else:
self.ui.cd_lookup_device.setText(self.config.setting["cd_lookup_device"])
self.ui.cd_lookup_device.setText(config.setting["cd_lookup_device"])
def save(self):
if AUTO_DETECT_DRIVES:
self.config.setting["cd_lookup_device"] = unicode(self.ui.cd_lookup_device.currentText())
config.setting["cd_lookup_device"] = unicode(self.ui.cd_lookup_device.currentText())
else:
self.config.setting["cd_lookup_device"] = unicode(self.ui.cd_lookup_device.text())
config.setting["cd_lookup_device"] = unicode(self.ui.cd_lookup_device.text())
register_options_page(CDLookupOptionsPage)

View File

@@ -18,7 +18,7 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
from PyQt4 import QtCore, QtGui
from picard.config import BoolOption, IntOption, TextOption
from picard import config
from picard.ui.options import OptionsPage, register_options_page
from picard.ui.ui_options_cover import Ui_CoverOptionsPage
from picard.coverartarchive import CAA_TYPES, CAA_TYPES_SEPARATOR
@@ -71,19 +71,19 @@ class CoverOptionsPage(OptionsPage):
ACTIVE = True
options = [
BoolOption("setting", "save_images_to_tags", True),
BoolOption("setting", "save_only_front_images_to_tags", False),
BoolOption("setting", "save_images_to_files", False),
TextOption("setting", "cover_image_filename", "cover"),
BoolOption("setting", "save_images_overwrite", False),
BoolOption("setting", "ca_provider_use_amazon", False),
BoolOption("setting", "ca_provider_use_cdbaby", False),
BoolOption("setting", "ca_provider_use_caa", False),
BoolOption("setting", "ca_provider_use_whitelist", False),
BoolOption("setting", "caa_approved_only", False),
BoolOption("setting", "caa_image_type_as_filename", False),
IntOption("setting", "caa_image_size", 2),
TextOption("setting", "caa_image_types", "front"),
config.BoolOption("setting", "save_images_to_tags", True),
config.BoolOption("setting", "save_only_front_images_to_tags", False),
config.BoolOption("setting", "save_images_to_files", False),
config.TextOption("setting", "cover_image_filename", "cover"),
config.BoolOption("setting", "save_images_overwrite", False),
config.BoolOption("setting", "ca_provider_use_amazon", False),
config.BoolOption("setting", "ca_provider_use_cdbaby", False),
config.BoolOption("setting", "ca_provider_use_caa", False),
config.BoolOption("setting", "ca_provider_use_whitelist", False),
config.BoolOption("setting", "caa_approved_only", False),
config.BoolOption("setting", "caa_image_type_as_filename", False),
config.IntOption("setting", "caa_image_size", 2),
config.TextOption("setting", "caa_image_types", "front"),
]
def __init__(self, parent=None):
@@ -93,51 +93,51 @@ class CoverOptionsPage(OptionsPage):
self.ui.save_images_to_files.clicked.connect(self.update_filename)
def load(self):
self.ui.save_images_to_tags.setChecked(self.config.setting["save_images_to_tags"])
self.ui.cb_embed_front_only.setChecked(self.config.setting["save_only_front_images_to_tags"])
self.ui.save_images_to_files.setChecked(self.config.setting["save_images_to_files"])
self.ui.cover_image_filename.setText(self.config.setting["cover_image_filename"])
self.ui.save_images_overwrite.setChecked(self.config.setting["save_images_overwrite"])
self.ui.save_images_to_tags.setChecked(config.setting["save_images_to_tags"])
self.ui.cb_embed_front_only.setChecked(config.setting["save_only_front_images_to_tags"])
self.ui.save_images_to_files.setChecked(config.setting["save_images_to_files"])
self.ui.cover_image_filename.setText(config.setting["cover_image_filename"])
self.ui.save_images_overwrite.setChecked(config.setting["save_images_overwrite"])
self.update_filename()
self.ui.caprovider_amazon.setChecked(self.config.setting["ca_provider_use_amazon"])
self.ui.caprovider_cdbaby.setChecked(self.config.setting["ca_provider_use_cdbaby"])
self.ui.caprovider_caa.setChecked(self.config.setting["ca_provider_use_caa"])
self.ui.caprovider_whitelist.setChecked(self.config.setting["ca_provider_use_whitelist"])
self.ui.gb_caa.setEnabled(self.config.setting["ca_provider_use_caa"])
self.ui.caprovider_amazon.setChecked(config.setting["ca_provider_use_amazon"])
self.ui.caprovider_cdbaby.setChecked(config.setting["ca_provider_use_cdbaby"])
self.ui.caprovider_caa.setChecked(config.setting["ca_provider_use_caa"])
self.ui.caprovider_whitelist.setChecked(config.setting["ca_provider_use_whitelist"])
self.ui.gb_caa.setEnabled(config.setting["ca_provider_use_caa"])
self.ui.cb_image_size.setCurrentIndex(self.config.setting["caa_image_size"])
self.ui.cb_image_size.setCurrentIndex(config.setting["caa_image_size"])
widget = self.ui.caa_types_selector_1
self._selector = CAATypesSelector(widget, self.config.setting["caa_image_types"])
self.config.setting["caa_image_types"] = \
self._selector = CAATypesSelector(widget, config.setting["caa_image_types"])
config.setting["caa_image_types"] = \
self._selector.get_selected_types_as_string()
self.ui.cb_approved_only.setChecked(self.config.setting["caa_approved_only"])
self.ui.cb_type_as_filename.setChecked(self.config.setting["caa_image_type_as_filename"])
self.ui.cb_approved_only.setChecked(config.setting["caa_approved_only"])
self.ui.cb_type_as_filename.setChecked(config.setting["caa_image_type_as_filename"])
self.connect(self.ui.caprovider_caa, QtCore.SIGNAL("toggled(bool)"),
self.ui.gb_caa.setEnabled)
def save(self):
self.config.setting["save_images_to_tags"] = self.ui.save_images_to_tags.isChecked()
self.config.setting["save_only_front_images_to_tags"] = self.ui.cb_embed_front_only.isChecked()
self.config.setting["save_images_to_files"] = self.ui.save_images_to_files.isChecked()
self.config.setting["cover_image_filename"] = unicode(self.ui.cover_image_filename.text())
self.config.setting["ca_provider_use_amazon"] =\
config.setting["save_images_to_tags"] = self.ui.save_images_to_tags.isChecked()
config.setting["save_only_front_images_to_tags"] = self.ui.cb_embed_front_only.isChecked()
config.setting["save_images_to_files"] = self.ui.save_images_to_files.isChecked()
config.setting["cover_image_filename"] = unicode(self.ui.cover_image_filename.text())
config.setting["ca_provider_use_amazon"] =\
self.ui.caprovider_amazon.isChecked()
self.config.setting["ca_provider_use_cdbaby"] =\
config.setting["ca_provider_use_cdbaby"] =\
self.ui.caprovider_cdbaby.isChecked()
self.config.setting["ca_provider_use_caa"] =\
config.setting["ca_provider_use_caa"] =\
self.ui.caprovider_caa.isChecked()
self.config.setting["ca_provider_use_whitelist"] =\
config.setting["ca_provider_use_whitelist"] =\
self.ui.caprovider_whitelist.isChecked()
self.config.setting["caa_image_size"] =\
config.setting["caa_image_size"] =\
self.ui.cb_image_size.currentIndex()
self.config.setting["caa_image_types"] = \
config.setting["caa_image_types"] = \
self._selector.get_selected_types_as_string()
self.config.setting["caa_approved_only"] =\
config.setting["caa_approved_only"] =\
self.ui.cb_approved_only.isChecked()
self.config.setting["caa_image_type_as_filename"] = \
config.setting["caa_image_type_as_filename"] = \
self.ui.cb_type_as_filename.isChecked()
self.config.setting["save_images_overwrite"] = self.ui.save_images_overwrite.isChecked()
config.setting["save_images_overwrite"] = self.ui.save_images_overwrite.isChecked()
def update_filename(self):
enabled = self.ui.save_images_to_files.isChecked()

View File

@@ -18,7 +18,7 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
from PyQt4 import QtCore, QtGui
from picard.config import Option
from picard import config
from picard.plugin import ExtensionPoint
from picard.util import webbrowser2
from picard.ui.util import StandardButton
@@ -48,9 +48,9 @@ from picard.ui.options import (
class OptionsDialog(QtGui.QDialog):
options = [
Option("persist", "options_position", QtCore.QPoint(), QtCore.QVariant.toPoint),
Option("persist", "options_size", QtCore.QSize(560, 400), QtCore.QVariant.toSize),
Option("persist", "options_splitter", QtCore.QByteArray(), QtCore.QVariant.toByteArray),
config.Option("persist", "options_position", QtCore.QPoint(), QtCore.QVariant.toPoint),
config.Option("persist", "options_size", QtCore.QSize(560, 400), QtCore.QVariant.toSize),
config.Option("persist", "options_splitter", QtCore.QByteArray(), QtCore.QVariant.toByteArray),
]
def add_pages(self, parent, default_page, parent_item):
@@ -134,13 +134,13 @@ class OptionsDialog(QtGui.QDialog):
def saveWindowState(self):
pos = self.pos()
if not pos.isNull():
self.config.persist["options_position"] = pos
self.config.persist["options_size"] = self.size()
self.config.persist["options_splitter"] = self.ui.splitter.saveState()
config.persist["options_position"] = pos
config.persist["options_size"] = self.size()
config.persist["options_splitter"] = self.ui.splitter.saveState()
def restoreWindowState(self):
pos = self.config.persist["options_position"]
pos = config.persist["options_position"]
if pos.x() > 0 and pos.y() > 0:
self.move(pos)
self.resize(self.config.persist["options_size"])
self.ui.splitter.restoreState(self.config.persist["options_splitter"])
self.resize(config.persist["options_size"])
self.ui.splitter.restoreState(config.persist["options_splitter"])

View File

@@ -19,9 +19,9 @@
import os
from PyQt4 import QtCore, QtGui
from picard import config
from picard.util import webbrowser2, find_executable
from picard.const import FPCALC_NAMES
from picard.config import BoolOption, TextOption
from picard.ui.options import OptionsPage, register_options_page
from picard.ui.ui_options_fingerprinting import Ui_FingerprintingOptionsPage
@@ -35,9 +35,9 @@ class FingerprintingOptionsPage(OptionsPage):
ACTIVE = True
options = [
TextOption("setting", "fingerprinting_system", "acoustid"),
TextOption("setting", "acoustid_fpcalc", ""),
TextOption("setting", "acoustid_apikey", ""),
config.TextOption("setting", "fingerprinting_system", "acoustid"),
config.TextOption("setting", "acoustid_fpcalc", ""),
config.TextOption("setting", "acoustid_apikey", ""),
]
def __init__(self, parent=None):
@@ -51,21 +51,21 @@ class FingerprintingOptionsPage(OptionsPage):
self.ui.acoustid_apikey_get.clicked.connect(self.acoustid_apikey_get)
def load(self):
if self.config.setting["fingerprinting_system"] == "acoustid":
if config.setting["fingerprinting_system"] == "acoustid":
self.ui.use_acoustid.setChecked(True)
else:
self.ui.disable_fingerprinting.setChecked(True)
self.ui.acoustid_fpcalc.setText(self.config.setting["acoustid_fpcalc"])
self.ui.acoustid_apikey.setText(self.config.setting["acoustid_apikey"])
self.ui.acoustid_fpcalc.setText(config.setting["acoustid_fpcalc"])
self.ui.acoustid_apikey.setText(config.setting["acoustid_apikey"])
self.update_groupboxes()
def save(self):
if self.ui.use_acoustid.isChecked():
self.config.setting["fingerprinting_system"] = "acoustid"
config.setting["fingerprinting_system"] = "acoustid"
else:
self.config.setting["fingerprinting_system"] = ""
self.config.setting["acoustid_fpcalc"] = unicode(self.ui.acoustid_fpcalc.text())
self.config.setting["acoustid_apikey"] = unicode(self.ui.acoustid_apikey.text())
config.setting["fingerprinting_system"] = ""
config.setting["acoustid_fpcalc"] = unicode(self.ui.acoustid_fpcalc.text())
config.setting["acoustid_apikey"] = unicode(self.ui.acoustid_apikey.text())
def update_groupboxes(self):
if self.ui.use_acoustid.isChecked():

View File

@@ -17,7 +17,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 picard.config import BoolOption, TextOption, IntOption
from picard import config
from picard.ui.options import OptionsPage, register_options_page
from picard.ui.ui_options_folksonomy import Ui_FolksonomyOptionsPage
@@ -31,11 +31,11 @@ class FolksonomyOptionsPage(OptionsPage):
ACTIVE = True
options = [
IntOption("setting", "max_tags", 5),
IntOption("setting", "min_tag_usage", 90),
TextOption("setting", "ignore_tags", "seen live,favorites,fixme,owned"),
TextOption("setting", "join_tags", ""),
BoolOption("setting", "only_my_tags", False),
config.IntOption("setting", "max_tags", 5),
config.IntOption("setting", "min_tag_usage", 90),
config.TextOption("setting", "ignore_tags", "seen live,favorites,fixme,owned"),
config.TextOption("setting", "join_tags", ""),
config.BoolOption("setting", "only_my_tags", False),
]
def __init__(self, parent=None):
@@ -44,18 +44,18 @@ class FolksonomyOptionsPage(OptionsPage):
self.ui.setupUi(self)
def load(self):
self.ui.max_tags.setValue(self.config.setting["max_tags"])
self.ui.min_tag_usage.setValue(self.config.setting["min_tag_usage"])
self.ui.join_tags.setEditText(self.config.setting["join_tags"])
self.ui.ignore_tags.setText(self.config.setting["ignore_tags"])
self.ui.only_my_tags.setChecked(self.config.setting["only_my_tags"])
self.ui.max_tags.setValue(config.setting["max_tags"])
self.ui.min_tag_usage.setValue(config.setting["min_tag_usage"])
self.ui.join_tags.setEditText(config.setting["join_tags"])
self.ui.ignore_tags.setText(config.setting["ignore_tags"])
self.ui.only_my_tags.setChecked(config.setting["only_my_tags"])
def save(self):
self.config.setting["max_tags"] = self.ui.max_tags.value()
self.config.setting["min_tag_usage"] = self.ui.min_tag_usage.value()
self.config.setting["join_tags"] = self.ui.join_tags.currentText()
self.config.setting["ignore_tags"] = self.ui.ignore_tags.text()
self.config.setting["only_my_tags"] = self.ui.only_my_tags.isChecked()
config.setting["max_tags"] = self.ui.max_tags.value()
config.setting["min_tag_usage"] = self.ui.min_tag_usage.value()
config.setting["join_tags"] = self.ui.join_tags.currentText()
config.setting["ignore_tags"] = self.ui.ignore_tags.text()
config.setting["only_my_tags"] = self.ui.only_my_tags.isChecked()
register_options_page(FolksonomyOptionsPage)

View File

@@ -17,7 +17,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 picard.config import IntOption, TextOption, BoolOption, PasswordOption
from picard import config
from picard.ui.options import OptionsPage, register_options_page
from picard.ui.ui_options_general import Ui_GeneralOptionsPage
from picard.util import rot13
@@ -32,12 +32,12 @@ class GeneralOptionsPage(OptionsPage):
ACTIVE = True
options = [
TextOption("setting", "server_host", "musicbrainz.org"),
IntOption("setting", "server_port", 80),
TextOption("setting", "username", ""),
PasswordOption("setting", "password", ""),
BoolOption("setting", "analyze_new_files", False),
BoolOption("setting", "ignore_file_mbids", False),
config.TextOption("setting", "server_host", "musicbrainz.org"),
config.IntOption("setting", "server_port", 80),
config.TextOption("setting", "username", ""),
config.PasswordOption("setting", "password", ""),
config.BoolOption("setting", "analyze_new_files", False),
config.BoolOption("setting", "ignore_file_mbids", False),
]
def __init__(self, parent=None):
@@ -50,21 +50,21 @@ class GeneralOptionsPage(OptionsPage):
self.ui.server_host.addItems(sorted(mirror_servers))
def load(self):
self.ui.server_host.setEditText(self.config.setting["server_host"])
self.ui.server_port.setValue(self.config.setting["server_port"])
self.ui.username.setText(self.config.setting["username"])
self.ui.password.setText(self.config.setting["password"])
self.ui.analyze_new_files.setChecked(self.config.setting["analyze_new_files"])
self.ui.ignore_file_mbids.setChecked(self.config.setting["ignore_file_mbids"])
self.ui.server_host.setEditText(config.setting["server_host"])
self.ui.server_port.setValue(config.setting["server_port"])
self.ui.username.setText(config.setting["username"])
self.ui.password.setText(config.setting["password"])
self.ui.analyze_new_files.setChecked(config.setting["analyze_new_files"])
self.ui.ignore_file_mbids.setChecked(config.setting["ignore_file_mbids"])
def save(self):
self.config.setting["server_host"] = unicode(self.ui.server_host.currentText()).strip()
self.config.setting["server_port"] = self.ui.server_port.value()
self.config.setting["username"] = unicode(self.ui.username.text())
config.setting["server_host"] = unicode(self.ui.server_host.currentText()).strip()
config.setting["server_port"] = self.ui.server_port.value()
config.setting["username"] = unicode(self.ui.username.text())
# trivially encode the password, just to not make it so apparent
self.config.setting["password"] = rot13(unicode(self.ui.password.text()))
self.config.setting["analyze_new_files"] = self.ui.analyze_new_files.isChecked()
self.config.setting["ignore_file_mbids"] = self.ui.ignore_file_mbids.isChecked()
config.setting["password"] = rot13(unicode(self.ui.password.text()))
config.setting["analyze_new_files"] = self.ui.analyze_new_files.isChecked()
config.setting["ignore_file_mbids"] = self.ui.ignore_file_mbids.isChecked()
register_options_page(GeneralOptionsPage)

View File

@@ -18,7 +18,7 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
from PyQt4 import QtCore, QtGui
from picard.config import BoolOption, TextOption
from picard import config
from picard.ui.options import OptionsPage, register_options_page
from picard.ui.ui_options_interface import Ui_InterfaceOptionsPage
from picard.const import UI_LANGUAGES
@@ -35,11 +35,11 @@ class InterfaceOptionsPage(OptionsPage):
ACTIVE = True
options = [
BoolOption("setting", "toolbar_show_labels", True),
BoolOption("setting", "toolbar_multiselect", False),
BoolOption("setting", "use_adv_search_syntax", False),
BoolOption("setting", "quit_confirmation", True),
TextOption("setting", "ui_language", u""),
config.BoolOption("setting", "toolbar_show_labels", True),
config.BoolOption("setting", "toolbar_multiselect", False),
config.BoolOption("setting", "use_adv_search_syntax", False),
config.BoolOption("setting", "quit_confirmation", True),
config.TextOption("setting", "ui_language", u""),
]
def __init__(self, parent=None):
@@ -57,22 +57,22 @@ class InterfaceOptionsPage(OptionsPage):
self.ui.ui_language.addItem(name, QtCore.QVariant(lang_code))
def load(self):
self.ui.toolbar_show_labels.setChecked(self.config.setting["toolbar_show_labels"])
self.ui.toolbar_multiselect.setChecked(self.config.setting["toolbar_multiselect"])
self.ui.use_adv_search_syntax.setChecked(self.config.setting["use_adv_search_syntax"])
self.ui.quit_confirmation.setChecked(self.config.setting["quit_confirmation"])
current_ui_language = QtCore.QVariant(self.config.setting["ui_language"])
self.ui.toolbar_show_labels.setChecked(config.setting["toolbar_show_labels"])
self.ui.toolbar_multiselect.setChecked(config.setting["toolbar_multiselect"])
self.ui.use_adv_search_syntax.setChecked(config.setting["use_adv_search_syntax"])
self.ui.quit_confirmation.setChecked(config.setting["quit_confirmation"])
current_ui_language = QtCore.QVariant(config.setting["ui_language"])
self.ui.ui_language.setCurrentIndex(self.ui.ui_language.findData(current_ui_language))
def save(self):
self.config.setting["toolbar_show_labels"] = self.ui.toolbar_show_labels.isChecked()
self.config.setting["toolbar_multiselect"] = self.ui.toolbar_multiselect.isChecked()
self.config.setting["use_adv_search_syntax"] = self.ui.use_adv_search_syntax.isChecked()
self.config.setting["quit_confirmation"] = self.ui.quit_confirmation.isChecked()
config.setting["toolbar_show_labels"] = self.ui.toolbar_show_labels.isChecked()
config.setting["toolbar_multiselect"] = self.ui.toolbar_multiselect.isChecked()
config.setting["use_adv_search_syntax"] = self.ui.use_adv_search_syntax.isChecked()
config.setting["quit_confirmation"] = self.ui.quit_confirmation.isChecked()
self.tagger.window.update_toolbar_style()
new_language = self.ui.ui_language.itemData(self.ui.ui_language.currentIndex()).toString()
if new_language != self.config.setting["ui_language"]:
self.config.setting["ui_language"] = self.ui.ui_language.itemData(self.ui.ui_language.currentIndex()).toString()
if new_language != config.setting["ui_language"]:
config.setting["ui_language"] = self.ui.ui_language.itemData(self.ui.ui_language.currentIndex()).toString()
dialog = QtGui.QMessageBox(QtGui.QMessageBox.Information, _('Language changed'), _('You have changed the interface language. You have to restart Picard in order for the change to take effect.'), QtGui.QMessageBox.Ok, self)
dialog.exec_()

View File

@@ -17,7 +17,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 picard.config import FloatOption
from picard import config
from picard.ui.options import OptionsPage, register_options_page
from picard.ui.ui_options_matching import Ui_MatchingOptionsPage
@@ -31,9 +31,9 @@ class MatchingOptionsPage(OptionsPage):
ACTIVE = True
options = [
FloatOption("setting", "file_lookup_threshold", 0.7),
FloatOption("setting", "cluster_lookup_threshold", 0.8),
FloatOption("setting", "track_matching_threshold", 0.4),
config.FloatOption("setting", "file_lookup_threshold", 0.7),
config.FloatOption("setting", "cluster_lookup_threshold", 0.8),
config.FloatOption("setting", "track_matching_threshold", 0.4),
]
_release_type_sliders = {}
@@ -44,14 +44,14 @@ class MatchingOptionsPage(OptionsPage):
self.ui.setupUi(self)
def load(self):
self.ui.file_lookup_threshold.setValue(int(self.config.setting["file_lookup_threshold"] * 100))
self.ui.cluster_lookup_threshold.setValue(int(self.config.setting["cluster_lookup_threshold"] * 100))
self.ui.track_matching_threshold.setValue(int(self.config.setting["track_matching_threshold"] * 100))
self.ui.file_lookup_threshold.setValue(int(config.setting["file_lookup_threshold"] * 100))
self.ui.cluster_lookup_threshold.setValue(int(config.setting["cluster_lookup_threshold"] * 100))
self.ui.track_matching_threshold.setValue(int(config.setting["track_matching_threshold"] * 100))
def save(self):
self.config.setting["file_lookup_threshold"] = float(self.ui.file_lookup_threshold.value()) / 100.0
self.config.setting["cluster_lookup_threshold"] = float(self.ui.cluster_lookup_threshold.value()) / 100.0
self.config.setting["track_matching_threshold"] = float(self.ui.track_matching_threshold.value()) / 100.0
config.setting["file_lookup_threshold"] = float(self.ui.file_lookup_threshold.value()) / 100.0
config.setting["cluster_lookup_threshold"] = float(self.ui.cluster_lookup_threshold.value()) / 100.0
config.setting["track_matching_threshold"] = float(self.ui.track_matching_threshold.value()) / 100.0
register_options_page(MatchingOptionsPage)

View File

@@ -18,7 +18,7 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
from PyQt4 import QtCore
from picard.config import BoolOption, TextOption
from picard import config
from picard.ui.options import OptionsPage, register_options_page
from picard.ui.ui_options_metadata import Ui_MetadataOptionsPage
from picard.const import ALIAS_LOCALES
@@ -33,15 +33,15 @@ class MetadataOptionsPage(OptionsPage):
ACTIVE = True
options = [
TextOption("setting", "va_name", u"Various Artists"),
TextOption("setting", "nat_name", u"[non-album tracks]"),
TextOption("setting", "artist_locale", u"en"),
BoolOption("setting", "translate_artist_names", False),
BoolOption("setting", "release_ars", True),
BoolOption("setting", "track_ars", False),
BoolOption("setting", "folksonomy_tags", False),
BoolOption("setting", "convert_punctuation", True),
BoolOption("setting", "standardize_artists", False),
config.TextOption("setting", "va_name", u"Various Artists"),
config.TextOption("setting", "nat_name", u"[non-album tracks]"),
config.TextOption("setting", "artist_locale", u"en"),
config.BoolOption("setting", "translate_artist_names", False),
config.BoolOption("setting", "release_ars", True),
config.BoolOption("setting", "track_ars", False),
config.BoolOption("setting", "folksonomy_tags", False),
config.BoolOption("setting", "convert_punctuation", True),
config.BoolOption("setting", "standardize_artists", False),
]
def __init__(self, parent=None):
@@ -52,7 +52,7 @@ class MetadataOptionsPage(OptionsPage):
self.ui.nat_name_default.clicked.connect(self.set_nat_name_default)
def load(self):
self.ui.translate_artist_names.setChecked(self.config.setting["translate_artist_names"])
self.ui.translate_artist_names.setChecked(config.setting["translate_artist_names"])
combo_box = self.ui.artist_locale
locales = ALIAS_LOCALES.keys()
@@ -62,30 +62,30 @@ class MetadataOptionsPage(OptionsPage):
if "_" in loc:
name = " " + name
combo_box.addItem(name, loc)
if loc == self.config.setting["artist_locale"]:
if loc == config.setting["artist_locale"]:
combo_box.setCurrentIndex(i)
self.ui.convert_punctuation.setChecked(self.config.setting["convert_punctuation"])
self.ui.release_ars.setChecked(self.config.setting["release_ars"])
self.ui.track_ars.setChecked(self.config.setting["track_ars"])
self.ui.folksonomy_tags.setChecked(self.config.setting["folksonomy_tags"])
self.ui.va_name.setText(self.config.setting["va_name"])
self.ui.nat_name.setText(self.config.setting["nat_name"])
self.ui.standardize_artists.setChecked(self.config.setting["standardize_artists"])
self.ui.convert_punctuation.setChecked(config.setting["convert_punctuation"])
self.ui.release_ars.setChecked(config.setting["release_ars"])
self.ui.track_ars.setChecked(config.setting["track_ars"])
self.ui.folksonomy_tags.setChecked(config.setting["folksonomy_tags"])
self.ui.va_name.setText(config.setting["va_name"])
self.ui.nat_name.setText(config.setting["nat_name"])
self.ui.standardize_artists.setChecked(config.setting["standardize_artists"])
def save(self):
self.config.setting["translate_artist_names"] = self.ui.translate_artist_names.isChecked()
self.config.setting["artist_locale"] = self.ui.artist_locale.itemData(self.ui.artist_locale.currentIndex())
self.config.setting["convert_punctuation"] = self.ui.convert_punctuation.isChecked()
self.config.setting["release_ars"] = self.ui.release_ars.isChecked()
self.config.setting["track_ars"] = self.ui.track_ars.isChecked()
self.config.setting["folksonomy_tags"] = self.ui.folksonomy_tags.isChecked()
self.config.setting["va_name"] = self.ui.va_name.text()
config.setting["translate_artist_names"] = self.ui.translate_artist_names.isChecked()
config.setting["artist_locale"] = self.ui.artist_locale.itemData(self.ui.artist_locale.currentIndex())
config.setting["convert_punctuation"] = self.ui.convert_punctuation.isChecked()
config.setting["release_ars"] = self.ui.release_ars.isChecked()
config.setting["track_ars"] = self.ui.track_ars.isChecked()
config.setting["folksonomy_tags"] = self.ui.folksonomy_tags.isChecked()
config.setting["va_name"] = self.ui.va_name.text()
nat_name = unicode(self.ui.nat_name.text())
if nat_name != self.config.setting["nat_name"]:
self.config.setting["nat_name"] = nat_name
if nat_name != config.setting["nat_name"]:
config.setting["nat_name"] = nat_name
self.tagger.nats.update()
self.config.setting["standardize_artists"] = self.ui.standardize_artists.isChecked()
config.setting["standardize_artists"] = self.ui.standardize_artists.isChecked()
def set_va_name_default(self):
self.ui.va_name.setText(self.options[0].default)

View File

@@ -21,7 +21,7 @@
import os.path
import sys
from PyQt4 import QtCore, QtGui
from picard.config import TextOption
from picard import config
from picard.util import encode_filename
from picard.ui.options import OptionsPage, register_options_page
from picard.ui.ui_options_plugins import Ui_PluginsOptionsPage
@@ -40,7 +40,7 @@ class PluginsOptionsPage(OptionsPage):
ACTIVE = True
options = [
TextOption("setting", "enabled_plugins", ""),
config.TextOption("setting", "enabled_plugins", ""),
]
def __init__(self, parent=None):
@@ -63,7 +63,7 @@ class PluginsOptionsPage(OptionsPage):
def load(self):
plugins = sorted(self.tagger.pluginmanager.plugins, cmp=cmp_plugins)
enabled_plugins = self.config.setting["enabled_plugins"].split()
enabled_plugins = config.setting["enabled_plugins"].split()
firstitem = None
for plugin in plugins:
enabled = plugin.module_name in enabled_plugins
@@ -107,7 +107,7 @@ class PluginsOptionsPage(OptionsPage):
for item, plugin in self.items.iteritems():
if item.checkState(0) == QtCore.Qt.Checked:
enabled_plugins.append(plugin.module_name)
self.config.setting["enabled_plugins"] = " ".join(enabled_plugins)
config.setting["enabled_plugins"] = " ".join(enabled_plugins)
def change_details(self):
plugin = self.items[self.ui.plugins.selectedItems()[0]]

View File

@@ -17,7 +17,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 picard.config import IntOption, TextOption, BoolOption
from picard import config
from picard.ui.options import OptionsPage, register_options_page
from picard.ui.ui_options_proxy import Ui_ProxyOptionsPage
@@ -31,11 +31,11 @@ class ProxyOptionsPage(OptionsPage):
ACTIVE = True
options = [
BoolOption("setting", "use_proxy", False),
TextOption("setting", "proxy_server_host", ""),
IntOption("setting", "proxy_server_port", 80),
TextOption("setting", "proxy_username", ""),
TextOption("setting", "proxy_password", ""),
config.BoolOption("setting", "use_proxy", False),
config.TextOption("setting", "proxy_server_host", ""),
config.IntOption("setting", "proxy_server_port", 80),
config.TextOption("setting", "proxy_username", ""),
config.TextOption("setting", "proxy_password", ""),
]
def __init__(self, parent=None):
@@ -44,18 +44,18 @@ class ProxyOptionsPage(OptionsPage):
self.ui.setupUi(self)
def load(self):
self.ui.web_proxy.setChecked(self.config.setting["use_proxy"])
self.ui.server_host.setText(self.config.setting["proxy_server_host"])
self.ui.server_port.setValue(self.config.setting["proxy_server_port"])
self.ui.username.setText(self.config.setting["proxy_username"])
self.ui.password.setText(self.config.setting["proxy_password"])
self.ui.web_proxy.setChecked(config.setting["use_proxy"])
self.ui.server_host.setText(config.setting["proxy_server_host"])
self.ui.server_port.setValue(config.setting["proxy_server_port"])
self.ui.username.setText(config.setting["proxy_username"])
self.ui.password.setText(config.setting["proxy_password"])
def save(self):
self.config.setting["use_proxy"] = self.ui.web_proxy.isChecked()
self.config.setting["proxy_server_host"] = unicode(self.ui.server_host.text())
self.config.setting["proxy_server_port"] = self.ui.server_port.value()
self.config.setting["proxy_username"] = unicode(self.ui.username.text())
self.config.setting["proxy_password"] = unicode(self.ui.password.text())
config.setting["use_proxy"] = self.ui.web_proxy.isChecked()
config.setting["proxy_server_host"] = unicode(self.ui.server_host.text())
config.setting["proxy_server_port"] = self.ui.server_port.value()
config.setting["proxy_username"] = unicode(self.ui.username.text())
config.setting["proxy_password"] = unicode(self.ui.password.text())
self.tagger.xmlws.setup_proxy()

View File

@@ -17,7 +17,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 picard.config import BoolOption, TextOption, IntOption
from picard import config
from picard.ui.options import OptionsPage, register_options_page
from picard.ui.ui_options_ratings import Ui_RatingsOptionsPage
@@ -31,10 +31,10 @@ class RatingsOptionsPage(OptionsPage):
ACTIVE = True
options = [
BoolOption("setting", "enable_ratings", False),
TextOption("setting", "rating_user_email", "users@musicbrainz.org"),
BoolOption("setting", "submit_ratings", True),
IntOption("setting", "rating_steps", 6),
config.BoolOption("setting", "enable_ratings", False),
config.TextOption("setting", "rating_user_email", "users@musicbrainz.org"),
config.BoolOption("setting", "submit_ratings", True),
config.IntOption("setting", "rating_steps", 6),
]
def __init__(self, parent=None):
@@ -43,14 +43,14 @@ class RatingsOptionsPage(OptionsPage):
self.ui.setupUi(self)
def load(self):
self.ui.enable_ratings.setChecked(self.config.setting["enable_ratings"])
self.ui.rating_user_email.setText(self.config.setting["rating_user_email"])
self.ui.submit_ratings.setChecked(self.config.setting["submit_ratings"])
self.ui.enable_ratings.setChecked(config.setting["enable_ratings"])
self.ui.rating_user_email.setText(config.setting["rating_user_email"])
self.ui.submit_ratings.setChecked(config.setting["submit_ratings"])
def save(self):
self.config.setting["enable_ratings"] = self.ui.enable_ratings.isChecked()
self.config.setting["rating_user_email"] = self.ui.rating_user_email.text()
self.config.setting["submit_ratings"] = self.ui.submit_ratings.isChecked()
config.setting["enable_ratings"] = self.ui.enable_ratings.isChecked()
config.setting["rating_user_email"] = self.ui.rating_user_email.text()
config.setting["submit_ratings"] = self.ui.submit_ratings.isChecked()
register_options_page(RatingsOptionsPage)

View File

@@ -20,7 +20,7 @@
from operator import itemgetter
from locale import strcoll
from PyQt4 import QtCore, QtGui
from picard.config import TextOption
from picard import config
from picard.util import load_release_type_scores, save_release_type_scores
from picard.ui.options import OptionsPage, register_options_page
from picard.ui.ui_options_releases import Ui_ReleasesOptionsPage
@@ -36,9 +36,9 @@ class ReleasesOptionsPage(OptionsPage):
ACTIVE = True
options = [
TextOption("setting", "release_type_scores", "Album 0.5 Single 0.5 EP 0.5 Compilation 0.5 Soundtrack 0.5 Spokenword 0.5 Interview 0.5 Audiobook 0.5 Live 0.5 Remix 0.5 Other 0.5"),
TextOption("setting", "preferred_release_countries", u""),
TextOption("setting", "preferred_release_formats", u""),
config.TextOption("setting", "release_type_scores", "Album 0.5 Single 0.5 EP 0.5 Compilation 0.5 Soundtrack 0.5 Spokenword 0.5 Interview 0.5 Audiobook 0.5 Live 0.5 Remix 0.5 Other 0.5"),
config.TextOption("setting", "preferred_release_countries", u""),
config.TextOption("setting", "preferred_release_formats", u""),
]
_release_type_sliders = {}
@@ -70,7 +70,7 @@ class ReleasesOptionsPage(OptionsPage):
self.ui.preferred_format_list.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection)
def load(self):
scores = load_release_type_scores(self.config.setting["release_type_scores"])
scores = load_release_type_scores(config.setting["release_type_scores"])
for (release_type, release_type_slider) in self._release_type_sliders.iteritems():
release_type_slider.setValue(int(scores.get(release_type, 0.5) * 100))
@@ -83,7 +83,7 @@ class ReleasesOptionsPage(OptionsPage):
scores = {}
for (release_type, release_type_slider) in self._release_type_sliders.iteritems():
scores[release_type] = float(release_type_slider.value()) / 100.0
self.config.setting["release_type_scores"] = save_release_type_scores(scores)
config.setting["release_type_scores"] = save_release_type_scores(scores)
self._save_list_items("preferred_release_countries", self.ui.preferred_country_list)
self._save_list_items("preferred_release_formats", self.ui.preferred_format_list)
@@ -115,7 +115,7 @@ class ReleasesOptionsPage(OptionsPage):
def _load_list_items(self, setting, source, list1, list2):
source_list = [(c[0], _(c[1])) for c in source.items()]
source_list.sort(key=itemgetter(1), cmp=strcoll)
saved_data = self.config.setting[setting].split(" ")
saved_data = config.setting[setting].split(" ")
move = []
for data, name in source_list:
item = QtGui.QListWidgetItem(name)
@@ -134,7 +134,7 @@ class ReleasesOptionsPage(OptionsPage):
for i in range(list1.count()):
item = list1.item(i)
data.append(unicode(item.data(QtCore.Qt.UserRole).toString()))
self.config.setting[setting] = " ".join(data)
config.setting[setting] = " ".join(data)
register_options_page(ReleasesOptionsPage)

View File

@@ -21,13 +21,14 @@
import os.path
import sys
from PyQt4 import QtCore, QtGui
from picard.config import BoolOption, TextOption
from picard import config
from picard.file import File
from picard.script import ScriptParser, SyntaxError, UnknownFunction
from picard.ui.options import OptionsPage, OptionsCheckError, register_options_page
from picard.ui.ui_options_renaming import Ui_RenamingOptionsPage
from picard.ui.options.scripting import TaggerScriptSyntaxHighlighter
class RenamingOptionsPage(OptionsPage):
NAME = "filerenaming"
@@ -37,15 +38,15 @@ class RenamingOptionsPage(OptionsPage):
ACTIVE = True
options = [
BoolOption("setting", "windows_compatible_filenames", True),
BoolOption("setting", "ascii_filenames", False),
BoolOption("setting", "rename_files", False),
TextOption("setting", "file_naming_format", "$if2(%albumartist%,%artist%)/%album%/$if($gt(%totaldiscs%,1),%discnumber%-,)$num(%tracknumber%,2)$if(%compilation%, %artist% -,) %title%"),
BoolOption("setting", "move_files", False),
TextOption("setting", "move_files_to", ""),
BoolOption("setting", "move_additional_files", False),
TextOption("setting", "move_additional_files_pattern", "*.jpg *.png"),
BoolOption("setting", "delete_empty_dirs", True),
config.BoolOption("setting", "windows_compatible_filenames", True),
config.BoolOption("setting", "ascii_filenames", False),
config.BoolOption("setting", "rename_files", False),
config.TextOption("setting", "file_naming_format", "$if2(%albumartist%,%artist%)/%album%/$if($gt(%totaldiscs%,1),%discnumber%-,)$num(%tracknumber%,2)$if(%compilation%, %artist% -,) %title%"),
config.BoolOption("setting", "move_files", False),
config.TextOption("setting", "move_files_to", ""),
config.BoolOption("setting", "move_additional_files", False),
config.TextOption("setting", "move_additional_files_pattern", "*.jpg *.png"),
config.BoolOption("setting", "delete_empty_dirs", True),
]
def __init__(self, parent=None):
@@ -91,8 +92,8 @@ class RenamingOptionsPage(OptionsPage):
'move_files_to': os.path.normpath(unicode(self.ui.move_files_to.text()))
}
try:
if self.config.setting["enable_tagger_script"]:
script = self.config.setting["tagger_script"]
if config.setting["enable_tagger_script"]:
script = config.setting["tagger_script"]
parser = ScriptParser()
parser.eval(script, file.metadata)
filename = file._make_filename(file.filename, file.metadata, settings)
@@ -116,16 +117,16 @@ class RenamingOptionsPage(OptionsPage):
self.ui.windows_compatible_filenames.setChecked(True)
self.ui.windows_compatible_filenames.setEnabled(False)
else:
self.ui.windows_compatible_filenames.setChecked(self.config.setting["windows_compatible_filenames"])
self.ui.rename_files.setChecked(self.config.setting["rename_files"])
self.ui.move_files.setChecked(self.config.setting["move_files"])
self.ui.ascii_filenames.setChecked(self.config.setting["ascii_filenames"])
self.ui.file_naming_format.setPlainText(self.config.setting["file_naming_format"])
self.ui.move_files_to.setText(self.config.setting["move_files_to"])
self.ui.windows_compatible_filenames.setChecked(config.setting["windows_compatible_filenames"])
self.ui.rename_files.setChecked(config.setting["rename_files"])
self.ui.move_files.setChecked(config.setting["move_files"])
self.ui.ascii_filenames.setChecked(config.setting["ascii_filenames"])
self.ui.file_naming_format.setPlainText(config.setting["file_naming_format"])
self.ui.move_files_to.setText(config.setting["move_files_to"])
self.ui.move_files_to.setCursorPosition(0)
self.ui.move_additional_files.setChecked(self.config.setting["move_additional_files"])
self.ui.move_additional_files_pattern.setText(self.config.setting["move_additional_files_pattern"])
self.ui.delete_empty_dirs.setChecked(self.config.setting["delete_empty_dirs"])
self.ui.move_additional_files.setChecked(config.setting["move_additional_files"])
self.ui.move_additional_files_pattern.setText(config.setting["move_additional_files_pattern"])
self.ui.delete_empty_dirs.setChecked(config.setting["delete_empty_dirs"])
self.update_examples()
def check(self):
@@ -144,17 +145,17 @@ class RenamingOptionsPage(OptionsPage):
raise OptionsCheckError("", _("The file naming format must not be empty."))
def save(self):
self.config.setting["windows_compatible_filenames"] = self.ui.windows_compatible_filenames.isChecked()
self.config.setting["ascii_filenames"] = self.ui.ascii_filenames.isChecked()
self.config.setting["rename_files"] = self.ui.rename_files.isChecked()
self.config.setting["file_naming_format"] = unicode(self.ui.file_naming_format.toPlainText())
self.tagger.window.enable_renaming_action.setChecked(self.config.setting["rename_files"])
self.config.setting["move_files"] = self.ui.move_files.isChecked()
self.config.setting["move_files_to"] = os.path.normpath(unicode(self.ui.move_files_to.text()))
self.config.setting["move_additional_files"] = self.ui.move_additional_files.isChecked()
self.config.setting["move_additional_files_pattern"] = unicode(self.ui.move_additional_files_pattern.text())
self.config.setting["delete_empty_dirs"] = self.ui.delete_empty_dirs.isChecked()
self.tagger.window.enable_moving_action.setChecked(self.config.setting["move_files"])
config.setting["windows_compatible_filenames"] = self.ui.windows_compatible_filenames.isChecked()
config.setting["ascii_filenames"] = self.ui.ascii_filenames.isChecked()
config.setting["rename_files"] = self.ui.rename_files.isChecked()
config.setting["file_naming_format"] = unicode(self.ui.file_naming_format.toPlainText())
self.tagger.window.enable_renaming_action.setChecked(config.setting["rename_files"])
config.setting["move_files"] = self.ui.move_files.isChecked()
config.setting["move_files_to"] = os.path.normpath(unicode(self.ui.move_files_to.text()))
config.setting["move_additional_files"] = self.ui.move_additional_files.isChecked()
config.setting["move_additional_files_pattern"] = unicode(self.ui.move_additional_files_pattern.text())
config.setting["delete_empty_dirs"] = self.ui.delete_empty_dirs.isChecked()
self.tagger.window.enable_moving_action.setChecked(config.setting["move_files"])
def display_error(self, error):
pass
@@ -194,8 +195,8 @@ class RenamingOptionsPage(OptionsPage):
file.metadata['title'] = 'Why? Oh Why?'
file.metadata['artist'] = 'The Fantasys'
file.metadata['artistsort'] = 'Fantasys, The'
file.metadata['albumartist'] = self.config.setting['va_name']
file.metadata['albumartistsort'] = self.config.setting['va_name']
file.metadata['albumartist'] = config.setting['va_name']
file.metadata['albumartistsort'] = config.setting['va_name']
file.metadata['tracknumber'] = '5'
file.metadata['totaltracks'] = '26'
file.metadata['discnumber'] = '2'

View File

@@ -18,7 +18,7 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
from PyQt4 import QtCore, QtGui
from picard.config import BoolOption, TextOption
from picard import config
from picard.script import ScriptParser
from picard.ui.options import OptionsPage, OptionsCheckError, register_options_page
from picard.ui.ui_options_script import Ui_ScriptingOptionsPage
@@ -66,8 +66,8 @@ class ScriptingOptionsPage(OptionsPage):
ACTIVE = True
options = [
BoolOption("setting", "enable_tagger_script", False),
TextOption("setting", "tagger_script", ""),
config.BoolOption("setting", "enable_tagger_script", False),
config.TextOption("setting", "tagger_script", ""),
]
STYLESHEET_ERROR = "QWidget { background-color: #f55; color: white; font-weight:bold }"
@@ -97,12 +97,12 @@ class ScriptingOptionsPage(OptionsPage):
raise OptionsCheckError(_("Script Error"), str(e))
def load(self):
self.ui.enable_tagger_script.setChecked(self.config.setting["enable_tagger_script"])
self.ui.tagger_script.document().setPlainText(self.config.setting["tagger_script"])
self.ui.enable_tagger_script.setChecked(config.setting["enable_tagger_script"])
self.ui.tagger_script.document().setPlainText(config.setting["tagger_script"])
def save(self):
self.config.setting["enable_tagger_script"] = self.ui.enable_tagger_script.isChecked()
self.config.setting["tagger_script"] = self.ui.tagger_script.toPlainText()
config.setting["enable_tagger_script"] = self.ui.enable_tagger_script.isChecked()
config.setting["tagger_script"] = self.ui.tagger_script.toPlainText()
def display_error(self, error):
pass

View File

@@ -18,7 +18,7 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
from PyQt4 import QtCore, QtGui
from picard.config import BoolOption, TextOption
from picard import config
from picard.ui.options import OptionsPage, register_options_page
from picard.ui.ui_options_tags import Ui_TagsOptionsPage
from picard.util.tags import TAG_NAMES
@@ -33,16 +33,16 @@ class TagsOptionsPage(OptionsPage):
ACTIVE = True
options = [
BoolOption("setting", "clear_existing_tags", False),
TextOption("setting", "preserved_tags", ""),
BoolOption("setting", "write_id3v1", True),
BoolOption("setting", "write_id3v23", True),
TextOption("setting", "id3v2_encoding", "utf-16"),
BoolOption("setting", "remove_id3_from_flac", False),
BoolOption("setting", "remove_ape_from_mp3", False),
BoolOption("setting", "tpe2_albumartist", False),
BoolOption("setting", "dont_write_tags", False),
BoolOption("setting", "preserve_timestamps", False),
config.BoolOption("setting", "clear_existing_tags", False),
config.TextOption("setting", "preserved_tags", ""),
config.BoolOption("setting", "write_id3v1", True),
config.BoolOption("setting", "write_id3v23", True),
config.TextOption("setting", "id3v2_encoding", "utf-16"),
config.BoolOption("setting", "remove_id3_from_flac", False),
config.BoolOption("setting", "remove_ape_from_mp3", False),
config.BoolOption("setting", "tpe2_albumartist", False),
config.BoolOption("setting", "dont_write_tags", False),
config.BoolOption("setting", "preserve_timestamps", False),
]
def __init__(self, parent=None):
@@ -58,41 +58,41 @@ class TagsOptionsPage(OptionsPage):
self.completer.activated.connect(self.completer_activated)
def load(self):
self.ui.write_tags.setChecked(not self.config.setting["dont_write_tags"])
self.ui.preserve_timestamps.setChecked(self.config.setting["preserve_timestamps"])
self.ui.clear_existing_tags.setChecked(self.config.setting["clear_existing_tags"])
self.ui.write_id3v1.setChecked(self.config.setting["write_id3v1"])
self.ui.write_id3v23.setChecked(self.config.setting["write_id3v23"])
if self.config.setting["id3v2_encoding"] == "iso-8859-1":
self.ui.write_tags.setChecked(not config.setting["dont_write_tags"])
self.ui.preserve_timestamps.setChecked(config.setting["preserve_timestamps"])
self.ui.clear_existing_tags.setChecked(config.setting["clear_existing_tags"])
self.ui.write_id3v1.setChecked(config.setting["write_id3v1"])
self.ui.write_id3v23.setChecked(config.setting["write_id3v23"])
if config.setting["id3v2_encoding"] == "iso-8859-1":
self.ui.enc_iso88591.setChecked(True)
elif self.config.setting["id3v2_encoding"] == "utf-16":
elif config.setting["id3v2_encoding"] == "utf-16":
self.ui.enc_utf16.setChecked(True)
else:
self.ui.enc_utf8.setChecked(True)
self.ui.remove_ape_from_mp3.setChecked(self.config.setting["remove_ape_from_mp3"])
self.ui.remove_id3_from_flac.setChecked(self.config.setting["remove_id3_from_flac"])
self.ui.preserved_tags.setText(self.config.setting["preserved_tags"])
self.ui.remove_ape_from_mp3.setChecked(config.setting["remove_ape_from_mp3"])
self.ui.remove_id3_from_flac.setChecked(config.setting["remove_id3_from_flac"])
self.ui.preserved_tags.setText(config.setting["preserved_tags"])
self.update_encodings()
def save(self):
self.config.setting["dont_write_tags"] = not self.ui.write_tags.isChecked()
self.config.setting["preserve_timestamps"] = self.ui.preserve_timestamps.isChecked()
config.setting["dont_write_tags"] = not self.ui.write_tags.isChecked()
config.setting["preserve_timestamps"] = self.ui.preserve_timestamps.isChecked()
clear_existing_tags = self.ui.clear_existing_tags.isChecked()
if clear_existing_tags != self.config.setting["clear_existing_tags"]:
self.config.setting["clear_existing_tags"] = clear_existing_tags
if clear_existing_tags != config.setting["clear_existing_tags"]:
config.setting["clear_existing_tags"] = clear_existing_tags
self.tagger.window.metadata_box.update()
self.config.setting["write_id3v1"] = self.ui.write_id3v1.isChecked()
self.config.setting["write_id3v23"] = self.ui.write_id3v23.isChecked()
config.setting["write_id3v1"] = self.ui.write_id3v1.isChecked()
config.setting["write_id3v23"] = self.ui.write_id3v23.isChecked()
if self.ui.enc_iso88591.isChecked():
self.config.setting["id3v2_encoding"] = "iso-8859-1"
config.setting["id3v2_encoding"] = "iso-8859-1"
elif self.ui.enc_utf16.isChecked():
self.config.setting["id3v2_encoding"] = "utf-16"
config.setting["id3v2_encoding"] = "utf-16"
else:
self.config.setting["id3v2_encoding"] = "utf-8"
self.config.setting["remove_ape_from_mp3"] = self.ui.remove_ape_from_mp3.isChecked()
self.config.setting["remove_id3_from_flac"] = self.ui.remove_id3_from_flac.isChecked()
self.config.setting["preserved_tags"] = unicode(self.ui.preserved_tags.text())
self.tagger.window.enable_tag_saving_action.setChecked(not self.config.setting["dont_write_tags"])
config.setting["id3v2_encoding"] = "utf-8"
config.setting["remove_ape_from_mp3"] = self.ui.remove_ape_from_mp3.isChecked()
config.setting["remove_id3_from_flac"] = self.ui.remove_id3_from_flac.isChecked()
config.setting["preserved_tags"] = unicode(self.ui.preserved_tags.text())
self.tagger.window.enable_tag_saving_action.setChecked(not config.setting["dont_write_tags"])
def update_encodings(self):
if self.ui.write_id3v23.isChecked():

View File

@@ -18,15 +18,15 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
from PyQt4 import QtCore, QtGui
from picard import config
from picard.ui.ui_passworddialog import Ui_PasswordDialog
from picard.config import BoolOption
from picard.util import rot13
class PasswordDialog(QtGui.QDialog):
options = [
BoolOption("persist", "save_authentication", True),
config.BoolOption("persist", "save_authentication", True),
]
def __init__(self, authenticator, reply, parent=None):
@@ -37,9 +37,9 @@ class PasswordDialog(QtGui.QDialog):
self.ui.info_text.setText(_("The server %s requires you to login. Please enter your username and password.") % reply.url().host())
# TODO: Implement proper password storage for arbitrary servers
if self._is_musicbrainz_server(reply.url().host(), reply.url().port()):
self.ui.save_authentication.setChecked(self.config.persist["save_authentication"])
self.ui.username.setText(self.config.setting["username"])
self.ui.password.setText(self.config.setting["password"])
self.ui.save_authentication.setChecked(config.persist["save_authentication"])
self.ui.username.setText(config.setting["username"])
self.ui.password.setText(config.setting["password"])
else:
self.ui.username.setText(reply.url().userName())
self.ui.password.setText(reply.url().password())
@@ -48,22 +48,22 @@ class PasswordDialog(QtGui.QDialog):
self.ui.buttonbox.accepted.connect(self.set_new_password)
def set_new_password(self):
self.config.persist["save_authentication"] = self.ui.save_authentication.isChecked()
if self.config.persist["save_authentication"]:
self.config.setting["username"] = unicode(self.ui.username.text())
self.config.setting["password"] = rot13(unicode(self.ui.password.text()))
config.persist["save_authentication"] = self.ui.save_authentication.isChecked()
if config.persist["save_authentication"]:
config.setting["username"] = unicode(self.ui.username.text())
config.setting["password"] = rot13(unicode(self.ui.password.text()))
self._authenticator.setUser(unicode(self.ui.username.text()))
self._authenticator.setPassword(unicode(self.ui.password.text()))
self.accept()
def _is_musicbrainz_server(self, host, port):
return host == self.config.setting["server_host"] and port == self.config.setting["server_port"]
return host == config.setting["server_host"] and port == config.setting["server_port"]
class ProxyDialog(QtGui.QDialog):
options = [
BoolOption("persist", "save_authentication", True),
config.BoolOption("persist", "save_authentication", True),
]
def __init__(self, authenticator, proxy, parent=None):
@@ -73,16 +73,16 @@ class ProxyDialog(QtGui.QDialog):
self.ui = Ui_PasswordDialog()
self.ui.setupUi(self)
self.ui.info_text.setText(_("The proxy %s requires you to login. Please enter your username and password.")
% self.config.setting["proxy_server_host"])
self.ui.save_authentication.setChecked(self.config.persist["save_authentication"])
self.ui.username.setText(self.config.setting["proxy_username"])
self.ui.password.setText(self.config.setting["proxy_password"])
% config.setting["proxy_server_host"])
self.ui.save_authentication.setChecked(config.persist["save_authentication"])
self.ui.username.setText(config.setting["proxy_username"])
self.ui.password.setText(config.setting["proxy_password"])
self.ui.save_authentication.hide()
self.ui.buttonbox.accepted.connect(self.set_proxy_password)
def set_proxy_password(self):
self.config.setting["proxy_username"] = unicode(self.ui.username.text())
self.config.setting["proxy_password"] = unicode(self.ui.password.text())
config.setting["proxy_username"] = unicode(self.ui.username.text())
config.setting["proxy_password"] = unicode(self.ui.password.text())
self._authenticator.setUser(unicode(self.ui.username.text()))
self._authenticator.setPassword(unicode(self.ui.password.text()))
self.accept()

View File

@@ -18,6 +18,7 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
from PyQt4 import QtCore, QtGui
from picard import config
class RatingWidget(QtGui.QWidget):
@@ -25,7 +26,7 @@ class RatingWidget(QtGui.QWidget):
def __init__(self, parent, track):
QtGui.QWidget.__init__(self, parent)
self._track = track
self._maximum = self.config.setting["rating_steps"] - 1
self._maximum = config.setting["rating_steps"] - 1
self._rating = int(track.metadata["~rating"] or 0)
self._highlight = 0
self._star_pixmap = QtGui.QPixmap(":/images/star.png")
@@ -79,7 +80,7 @@ class RatingWidget(QtGui.QWidget):
def _update_track(self):
track = self._track
track.metadata["~rating"] = unicode(self._rating)
if self.config.setting["submit_ratings"]:
if config.setting["submit_ratings"]:
ratings = {("recording", track.id): self._rating}
self.tagger.xmlws.submit_ratings(ratings, None)

View File

@@ -20,17 +20,18 @@
import re
import os.path
from PyQt4 import QtCore, QtGui
from picard.config import Option, TextOption
from picard import config
from picard.ui.util import StandardButton
from picard.ui.ui_tagsfromfilenames import Ui_TagsFromFileNamesDialog
from picard.util.tags import display_tag_name
class TagsFromFileNamesDialog(QtGui.QDialog):
options = [
TextOption("persist", "tags_from_filenames_format", ""),
Option("persist", "tags_from_filenames_position", QtCore.QPoint(), QtCore.QVariant.toPoint),
Option("persist", "tags_from_filenames_size", QtCore.QSize(560, 400), QtCore.QVariant.toSize),
config.TextOption("persist", "tags_from_filenames_format", ""),
config.Option("persist", "tags_from_filenames_position", QtCore.QPoint(), QtCore.QVariant.toPoint),
config.Option("persist", "tags_from_filenames_size", QtCore.QSize(560, 400), QtCore.QVariant.toSize),
]
def __init__(self, files, parent=None):
@@ -42,7 +43,7 @@ class TagsFromFileNamesDialog(QtGui.QDialog):
"%artist%/%album%/%tracknumber% - %title%",
"%artist%/%album - %tracknumber% - %title%",
]
format = self.config.persist["tags_from_filenames_format"]
format = config.persist["tags_from_filenames_format"]
if format and format not in items:
items.insert(0, format)
self.ui.format.addItems(items)
@@ -112,7 +113,7 @@ class TagsFromFileNamesDialog(QtGui.QDialog):
for name, value in metadata.iteritems():
file.metadata[name] = value
file.update()
self.config.persist["tags_from_filenames_format"] = self.ui.format.currentText()
config.persist["tags_from_filenames_format"] = self.ui.format.currentText()
self.saveWindowState()
QtGui.QDialog.accept(self)
@@ -127,11 +128,11 @@ class TagsFromFileNamesDialog(QtGui.QDialog):
def saveWindowState(self):
pos = self.pos()
if not pos.isNull():
self.config.persist["tags_from_filenames_position"] = pos
self.config.persist["tags_from_filenames_size"] = self.size()
config.persist["tags_from_filenames_position"] = pos
config.persist["tags_from_filenames_size"] = self.size()
def restoreWindowState(self):
pos = self.config.persist["tags_from_filenames_position"]
pos = config.persist["tags_from_filenames_position"]
if pos.x() > 0 and pos.y() > 0:
self.move(pos)
self.resize(self.config.persist["tags_from_filenames_size"])
self.resize(config.persist["tags_from_filenames_size"])

View File

@@ -80,7 +80,8 @@ _io_encoding = sys.getfilesystemencoding()
#// intentionally
def check_io_encoding():
if _io_encoding == "ANSI_X3.4-1968":
QtCore.QObject.log.warning("""
from picard import log
log.warning("""
System locale charset is ANSI_X3.4-1968
Your system's locale charset (i.e. the charset used to encode filenames)
is set to ANSI_X3.4-1968. It is highly unlikely that this has been done
@@ -294,7 +295,8 @@ def call_next(func):
result = func(self, *args, **kwargs)
except:
import traceback
self.log.error(traceback.format_exc())
from picard import log
log.error(traceback.format_exc())
next(error=sys.exc_info()[1])
else:
next(result=result)

View File

@@ -19,9 +19,10 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
import sys
from PyQt4.QtCore import (QFile, QRegExp)
from PyQt4.QtCore import QFile, QRegExp
LINUX_CDROM_INFO = '/proc/sys/dev/cdrom/info'
LINUX_CDROM_INFO = '/proc/sys/dev/cdrom/info'
if sys.platform == 'win32':
AUTO_DETECT_DRIVES = True
@@ -43,7 +44,7 @@ if sys.platform == 'win32':
elif sys.platform == 'linux2' and QFile.exists(LINUX_CDROM_INFO):
AUTO_DETECT_DRIVES = True
from PyQt4.QtCore import QIODevice, QString
# Read info from /proc/sys/dev/cdrom/info
def get_cdrom_drives():
drives = []
@@ -75,8 +76,7 @@ else:
AUTO_DETECT_DRIVES = False
def get_cdrom_drives():
from picard.tagger import Tagger
tagger = Tagger.instance()
from picard import config
# Need to filter out empty strings, particularly if the device list is empty
return filter(lambda string: (string != u''),
[d.strip() for d in tagger.config.setting["cd_lookup_device"].split(",")])
[d.strip() for d in config.setting["cd_lookup_device"].split(",")])

View File

@@ -57,7 +57,8 @@ class Thread(QtCore.QThread):
try:
result = func()
except:
self.log.error(traceback.format_exc())
from picard import log
log.error(traceback.format_exc())
self.to_main(next, priority, error=sys.exc_info()[1])
else:
self.to_main(next, priority, result=result)
@@ -93,7 +94,8 @@ class ThreadPool(QtCore.QObject):
try:
event.call()
except:
self.log.error(traceback.format_exc())
from picard import log
log.error(traceback.format_exc())
return True
return False

View File

@@ -31,7 +31,7 @@ from collections import deque, defaultdict
from PyQt4 import QtCore, QtNetwork
from PyQt4.QtGui import QDesktopServices
from PyQt4.QtCore import QUrl, QXmlStreamReader
from picard import version_string
from picard import version_string, config, log
from picard.util import partial
from picard.const import ACOUSTID_KEY, ACOUSTID_HOST
@@ -145,34 +145,34 @@ class XmlWebService(QtCore.QObject):
cache.setCacheDirectory(os.path.join(unicode(location), u'picard'))
cache.setMaximumCacheSize(cache_size_in_mb * 1024 * 1024)
self.manager.setCache(cache)
self.log.debug("NetworkDiskCache dir: %s", cache.cacheDirectory())
self.log.debug("NetworkDiskCache size: %s / %s", cache.cacheSize(),
log.debug("NetworkDiskCache dir: %s", cache.cacheDirectory())
log.debug("NetworkDiskCache size: %s / %s", cache.cacheSize(),
cache.maximumCacheSize())
def setup_proxy(self):
self.proxy = QtNetwork.QNetworkProxy()
if self.config.setting["use_proxy"]:
self.proxy.setType(QtNetwork.QNetworkProxy.HttpProxy)
self.proxy.setHostName(self.config.setting["proxy_server_host"])
self.proxy.setPort(self.config.setting["proxy_server_port"])
self.proxy.setUser(self.config.setting["proxy_username"])
self.proxy.setPassword(self.config.setting["proxy_password"])
self.manager.setProxy(self.proxy)
proxy = QtNetwork.QNetworkProxy()
if config.setting["use_proxy"]:
proxy.setType(QtNetwork.QNetworkProxy.HttpProxy)
proxy.setHostName(config.setting["proxy_server_host"])
proxy.setPort(config.setting["proxy_server_port"])
proxy.setUser(config.setting["proxy_username"])
proxy.setPassword(config.setting["proxy_password"])
self.manager.setProxy(proxy)
def _start_request(self, method, host, port, path, data, handler, xml,
mblogin=False, cacheloadcontrol=None):
self.log.debug("%s http://%s:%d%s", method, host, port, path)
log.debug("%s http://%s:%d%s", method, host, port, path)
url = QUrl.fromEncoded("http://%s:%d%s" % (host, port, path))
if mblogin:
url.setUserName(self.config.setting["username"])
url.setPassword(self.config.setting["password"])
url.setUserName(config.setting["username"])
url.setPassword(config.setting["password"])
request = QtNetwork.QNetworkRequest(url)
if cacheloadcontrol is not None:
request.setAttribute(QtNetwork.QNetworkRequest.CacheLoadControlAttribute,
cacheloadcontrol)
request.setRawHeader("User-Agent", "MusicBrainz-Picard/%s" % version_string)
if data is not None:
if method == "POST" and host == self.config.setting["server_host"]:
if method == "POST" and host == config.setting["server_host"]:
request.setHeader(QtNetwork.QNetworkRequest.ContentTypeHeader, "application/xml; charset=utf-8")
else:
request.setHeader(QtNetwork.QNetworkRequest.ContentTypeHeader, "application/x-www-form-urlencoded")
@@ -197,13 +197,13 @@ class XmlWebService(QtCore.QObject):
try:
request, handler, xml = self._active_requests.pop(reply)
except KeyError:
self.log.error("Error: Request not found for %s" % str(reply.request().url().toString()))
log.error("Error: Request not found for %s" % str(reply.request().url().toString()))
return
error = int(reply.error())
redirect = reply.attribute(QtNetwork.QNetworkRequest.RedirectionTargetAttribute).toUrl()
fromCache = reply.attribute(QtNetwork.QNetworkRequest.SourceIsFromCacheAttribute).toBool()
cached = ' (CACHED)' if fromCache else ''
self.log.debug("Received reply for %s: HTTP %d (%s) %s",
log.debug("Received reply for %s: HTTP %d (%s) %s",
reply.request().url().toString(),
reply.attribute(QtNetwork.QNetworkRequest.HttpStatusCodeAttribute).toInt()[0],
reply.attribute(QtNetwork.QNetworkRequest.HttpReasonPhraseAttribute).toString(),
@@ -211,7 +211,7 @@ class XmlWebService(QtCore.QObject):
)
if handler is not None:
if error:
self.log.error("Network request error for %s: %s (QT code %d, HTTP code %d)",
log.error("Network request error for %s: %s (QT code %d, HTTP code %d)",
reply.request().url().toString(),
reply.errorString(),
error,
@@ -219,7 +219,7 @@ class XmlWebService(QtCore.QObject):
# Redirect if found and not infinite
if not redirect.isEmpty() and not XmlWebService.urls_equivalent(redirect, reply.request().url()):
self.log.debug("Redirect to %s requested", redirect.toString())
log.debug("Redirect to %s requested", redirect.toString())
redirect_host = str(redirect.host())
redirect_port = redirect.port(80)
@@ -229,7 +229,7 @@ class XmlWebService(QtCore.QObject):
if ((original_host, original_port) in REQUEST_DELAY
and (redirect_host, redirect_port) not in REQUEST_DELAY):
self.log.debug("Setting rate limit for %s:%i to %i" %
log.debug("Setting rate limit for %s:%i to %i" %
(redirect_host, redirect_port,
REQUEST_DELAY[(original_host, original_port)]))
REQUEST_DELAY[(redirect_host, redirect_port)] =\
@@ -255,7 +255,7 @@ class XmlWebService(QtCore.QObject):
return self.add_task(func, host, port, priority, important=important)
def post(self, host, port, path, data, handler, xml=True, priority=True, important=True, mblogin=True):
self.log.debug("POST-DATA %r", data)
log.debug("POST-DATA %r", data)
func = partial(self._start_request, "POST", host, port, path, data, handler, xml, mblogin)
return self.add_task(func, host, port, priority, important=important)
@@ -284,12 +284,12 @@ class XmlWebService(QtCore.QObject):
request_delay = REQUEST_DELAY[key]
last_ms = (now - last) * 1000 if last is not None else request_delay
if last_ms >= request_delay:
self.log.debug("Last request to %s was %d ms ago, starting another one", key, last_ms)
log.debug("Last request to %s was %d ms ago, starting another one", key, last_ms)
d = request_delay
queue.popleft()()
else:
d = request_delay - last_ms
self.log.debug("Waiting %d ms before starting another request to %s", d, key)
log.debug("Waiting %d ms before starting another request to %s", d, key)
if d < delay:
delay = d
if delay < sys.maxint:
@@ -324,8 +324,8 @@ class XmlWebService(QtCore.QObject):
pass
def _get_by_id(self, entitytype, entityid, handler, inc=[], params=[], priority=False, important=False, mblogin=False):
host = self.config.setting["server_host"]
port = self.config.setting["server_port"]
host = config.setting["server_host"]
port = config.setting["server_port"]
path = "/ws/2/%s/%s?inc=%s" % (entitytype, entityid, "+".join(inc))
if params: path += "&" + "&".join(params)
return self.get(host, port, path, handler, priority=priority, important=important, mblogin=mblogin)
@@ -341,8 +341,8 @@ class XmlWebService(QtCore.QObject):
return self._get_by_id('discid', discid, handler, inc, params=["cdstubs=no"], priority=priority, important=important)
def _find(self, entitytype, handler, kwargs):
host = self.config.setting["server_host"]
port = self.config.setting["server_port"]
host = config.setting["server_host"]
port = config.setting["server_port"]
filters = []
query = []
for name, value in kwargs.items():
@@ -366,8 +366,8 @@ class XmlWebService(QtCore.QObject):
return self._find('recording', handler, kwargs)
def _browse(self, entitytype, handler, kwargs, inc=[], priority=False, important=False):
host = self.config.setting["server_host"]
port = self.config.setting["server_port"]
host = config.setting["server_host"]
port = config.setting["server_port"]
params = "&".join(["%s=%s" % (k, v) for k, v in kwargs.items()])
path = "/ws/2/%s?%s&inc=%s" % (entitytype, params, "+".join(inc))
return self.get(host, port, path, handler, priority=priority, important=important)
@@ -377,8 +377,8 @@ class XmlWebService(QtCore.QObject):
return self._browse("release", handler, kwargs, inc, priority=priority, important=important)
def submit_ratings(self, ratings, handler):
host = self.config.setting['server_host']
port = self.config.setting['server_port']
host = config.setting['server_host']
port = config.setting['server_port']
path = '/ws/2/rating/?client=' + USER_AGENT_STRING
recordings = (''.join(['<recording id="%s"><user-rating>%s</user-rating></recording>' %
(i[1], j*20) for i, j in ratings.items() if i[0] == 'recording']))
@@ -401,7 +401,7 @@ class XmlWebService(QtCore.QObject):
return self.post(host, port, '/v2/lookup', body, handler, mblogin=False)
def submit_acoustid_fingerprints(self, submissions, handler):
args = {'user': self.config.setting["acoustid_apikey"]}
args = {'user': config.setting["acoustid_apikey"]}
for i, submission in enumerate(submissions):
args['fingerprint.%d' % i] = str(submission.fingerprint)
args['duration.%d' % i] = str(submission.duration)
@@ -418,7 +418,7 @@ class XmlWebService(QtCore.QObject):
important=important, cacheloadcontrol=cacheloadcontrol)
def get_collection(self, id, handler, limit=100, offset=0):
host, port = self.config.setting['server_host'], self.config.setting['server_port']
host, port = config.setting['server_host'], config.setting['server_port']
path = "/ws/2/collection"
if id is not None:
inc = ["releases", "artist-credits", "media"]
@@ -435,11 +435,11 @@ class XmlWebService(QtCore.QObject):
yield "/ws/2/collection/%s/releases/%s?client=%s" % (id, ids, USER_AGENT_STRING)
def put_to_collection(self, id, releases, handler):
host, port = self.config.setting['server_host'], self.config.setting['server_port']
host, port = config.setting['server_host'], config.setting['server_port']
for path in self._collection_request(id, releases):
self.put(host, port, path, "", handler)
def delete_from_collection(self, id, releases, handler):
host, port = self.config.setting['server_host'], self.config.setting['server_port']
host, port = config.setting['server_host'], config.setting['server_port']
for path in self._collection_request(id, releases):
self.delete(host, port, path, handler)