This commit is contained in:
Lukáš Lalinský
2006-11-23 17:39:51 +01:00
15 changed files with 127 additions and 119 deletions

View File

@@ -38,9 +38,6 @@ class IFileOpener(Interface):
def get_supported_formats(self):
pass
def can_open_file(self, filename):
pass
def open_file(self, filename):
pass

View File

@@ -27,25 +27,6 @@ from picard.util import LockableObject, needs_write_lock, needs_read_lock, encod
class File(LockableObject):
NEW = 0
CHANGED = 1
TO_BE_SAVED = 2
SAVED = 3
def __init__(self, filename):
LockableObject.__init__(self)
self.id = self.new_id()
self.filename = filename
self.base_filename = os.path.basename(filename)
self.state = File.NEW
self.orig_metadata = Metadata()
self.metadata = Metadata()
self.similarity = 1.0
self.parent = None
def __str__(self):
return '<File #%d "%s">' % (self.id, self.base_filename)
__id_counter = 0
@staticmethod
@@ -53,8 +34,43 @@ class File(LockableObject):
File.__id_counter += 1
return File.__id_counter
PENDING = 0
NORMAL = 1
CHANGED = 2
ERROR = 3
SAVED = 4
def __init__(self, filename):
LockableObject.__init__(self)
self.id = self.new_id()
self.filename = filename
self.base_filename = os.path.basename(filename)
self.state = File.PENDING
self.orig_metadata = Metadata()
self.user_metadata = Metadata()
self.server_metadata = Metadata()
self.metadata = self.user_metadata
self.orig_metadata["~#length"] = 0
self.orig_metadata["title"] = os.path.basename(self.filename)
self.user_metadata.copy(self.orig_metadata)
self.server_metadata.copy(self.orig_metadata)
self.similarity = 1.0
self.parent = None
def __str__(self):
return '<File #%d "%s">' % (self.id, self.base_filename)
def load(self):
"""Save the metadata."""
self.read()
self.state = File.NORMAL
def save(self):
"""Save the file."""
"""Save the metadata."""
raise NotImplementedError
def save_images(self):
@@ -127,7 +143,6 @@ class File(LockableObject):
similarity = metadata1.compare(metadata2)
self.lock_for_write()
self.similarity = similarity
self.state = self.CHANGED
self.unlock()
if signal:
self.log.debug(u"Updating file %s", self)

View File

@@ -79,19 +79,19 @@ mutagen._util.delete_bytes = _delete_bytes
from picard.api import IFileOpener
from picard.component import Component, implements
from picard.plugins.picardmutagen.asf import MutagenASFFile
from picard.plugins.picardmutagen.mp4 import MP4File
from picard.plugins.picardmutagen.id3 import (
from picard.formats.asf import MutagenASFFile
from picard.formats.mp4 import MP4File
from picard.formats.id3 import (
MP3File,
TrueAudioFile,
)
from picard.plugins.picardmutagen.apev2 import (
from picard.formats.apev2 import (
MonkeysAudioFile,
MusepackFile,
OptimFROGFile,
WavPackFile,
)
from picard.plugins.picardmutagen.vorbis import (
from picard.formats.vorbis import (
FLACFile,
OggFLACFile,
OggSpeexFile,
@@ -128,16 +128,8 @@ class MutagenComponent(Component):
return [(key, value[1]) for key, value in
self.__supported_formats.items()]
def can_open_file(self, filename):
for ext in self.__supported_formats.keys():
if filename.lower().endswith(ext):
return True
return False
def open_file(self, filename):
for ext in self.__supported_formats.keys():
if filename.lower().endswith(ext):
file = self.__supported_formats[ext][0](filename)
file.read()
return (file,)
return self.__supported_formats[ext][0](filename)
return None

View File

@@ -21,7 +21,7 @@
from picard.file import File
from picard.util import encode_filename
from picard.plugins.picardmutagen.mutagenext.asf import ASF
from picard.formats.mutagenext.asf import ASF
class MutagenASFFile(File):

View File

@@ -22,7 +22,7 @@ import mutagen.mp3
import mutagen.trueaudio
from mutagen import id3
from picard.file import File
from picard.plugins.picardmutagen.mutagenext import compatid3
from picard.formats.mutagenext import compatid3
from picard.util import encode_filename
class ID3File(File):

View File

@@ -19,6 +19,5 @@
"""Built-in plugins."""
import picard.plugins.cuesheet
import picard.plugins.csv_opener
import picard.plugins.picardmutagen
#import picard.plugins.cuesheet
#import picard.plugins.csv_opener

View File

@@ -31,6 +31,7 @@ import imp
import picard.resources
import picard.plugins
import picard.formats
import picard.tagz
from picard import musicdns
@@ -248,53 +249,35 @@ class Tagger(QtGui.QApplication, ComponentManager, Component):
formats.extend(opener.get_supported_formats())
return formats
def add_files(self, files):
"""Load and add files."""
files = map(os.path.normpath, files)
self.log.debug(u"Adding files %r", files)
filenames = []
for filename in files:
not_found = True
for file in self.files:
if file.filename == filename:
not_found = False
break
if not_found:
for opener in self.file_openers:
if opener.can_open_file(filename):
filenames.append((filename, opener.open_file))
if filenames:
self.thread_assist.spawn(self.__add_files_thread, filenames,
thread=self.load_thread)
def __add_files_thread(self, filenames):
"""Load the files."""
files = []
for filename, opener in filenames:
try:
files.extend(opener(filename))
except:
import traceback; traceback.print_exc()
while files:
self.thread_assist.proxy_to_main(self.__add_files_finished,
files[:100])
files = files[100:]
def __add_files_finished(self, files):
"""Add loaded files to the tagger."""
for file in files:
self.files.append(file)
album_id = file.metadata["musicbrainz_albumid"]
if album_id:
album = self.get_album_by_id(album_id)
if not album:
album = self.load_album(album_id)
if album.loaded:
self.match_files_to_album([file], album)
else:
self._move_to_album.append((file, album))
if not file.parent:
def add_files(self, filenames):
"""Add files to the tagger."""
self.log.debug(u"Adding files %r", filenames)
for filename in filenames:
filename = os.path.normpath(filename)
if self.get_file_by_filename(filename):
continue
for opener in self.file_openers:
file = opener.open_file(filename)
if not file:
continue
file.move(self.unmatched_files)
self.files.append(file)
self.thread_assist.spawn(
self.__load_file_thread, file, thread=self.load_thread)
def __load_file_thread(self, file):
"""Load metadata from the file."""
self.log.debug(u"Loading file %r", file.filename)
file.load()
self.thread_assist.proxy_to_main(self.__load_file_finished, file)
def __load_file_finished(self, file):
"""Move loaded file to right album/cluster."""
file.update()
album_id = file.metadata["musicbrainz_albumid"]
if album_id:
album = self.load_album(album_id)
self.move_files_to_album([file], album)
def add_directory(self, directory):
"""Add all files from the directory ``directory`` to the tagger."""
@@ -305,23 +288,21 @@ class Tagger(QtGui.QApplication, ComponentManager, Component):
def __read_directory_thread(self, directory):
directories = [encode_filename(directory)]
while directories:
files = []
directory = directories.pop()
self.log.debug(u"Reading directory %r", directory)
self.thread_assist.proxy_to_main(self.__set_status_bar_message,
N_("Reading directory %s ..."),
directory)
self.thread_assist.proxy_to_main(
self.__set_status_bar_message,
N_("Reading directory %s ..."), decode_filename(directory))
filenames = []
for name in os.listdir(directory):
name = os.path.join(directory, name)
if os.path.isdir(name):
directories.append(name)
else:
files.append(decode_filename(name))
while files:
self.thread_assist.proxy_to_main(self.add_files, files[:100])
files = files[100:]
self.thread_assist.proxy_to_main(self.__set_status_bar_message,
N_("Done"))
filenames.append(decode_filename(name))
if filenames:
self.thread_assist.proxy_to_main(self.add_files, filenames)
self.thread_assist.proxy_to_main(self.__clear_status_bar_message)
def get_file_by_id(self, id):
"""Get file by a file ID."""
@@ -384,12 +365,9 @@ class Tagger(QtGui.QApplication, ComponentManager, Component):
def save(self, objects):
"""Save the specified objects."""
files = []
for file in self.get_files_from_objects(objects):
file.state = File.TO_BE_SAVED
files.append(file)
self.set_wait_cursor()
self.thread_assist.spawn(self.__save_thread, files)
self.thread_assist.spawn(self.__save_thread,
self.get_files_from_objects(objects))
def __rename_file(self, file):
file.lock_for_read()
@@ -464,6 +442,7 @@ class Tagger(QtGui.QApplication, ComponentManager, Component):
failed = False
try:
file.save()
file.state = File.SAVED
old_filename = self.__rename_file(file)
if (self.config.setting["move_files"] and
self.config.setting["move_additional_files"]):
@@ -712,6 +691,9 @@ class Tagger(QtGui.QApplication, ComponentManager, Component):
def analyze(self, objs):
"""Analyze the selected files."""
files = self.get_files_from_objects(objs)
for file in files:
file.state = File.PENDING
file.update()
self.thread_assist.spawn(self.__analyze_thread, files,
thread=self._analyze_thread)
@@ -734,6 +716,8 @@ class Tagger(QtGui.QApplication, ComponentManager, Component):
from picard.musicdns.webservice import TrackFilter, Query
ws = self.get_web_service(host="ofa.musicdns.org", pathPrefix="/ofa")
for file in files:
if file.state != File.PENDING:
continue
file.lock_for_read()
try:
filename = file.filename
@@ -776,6 +760,9 @@ class Tagger(QtGui.QApplication, ComponentManager, Component):
self.__lookup_puid(file)
else:
self.log.debug("Fingerprint looked up, no PUID found.")
if file.state == File.PENDING:
file.state = File.NORMAL
file.update()
def cluster(self, objs):
"""Group files with similar metadata to 'clusters'."""

View File

@@ -28,15 +28,6 @@ from picard.config import TextOption
__all__ = ["FileTreeView", "AlbumTreeView"]
def matchColor(similarity):
colors = ((255, 255, 255), (223, 125, 125))
res = [0, 0, 0]
#similarity = (1 - similarity) * (1 - similarity)
similarity = 1 - similarity
for i in range(3):
res[i] = colors[0][i] + (colors[1][i] - colors[0][i]) * similarity
return QtGui.QColor(res[0], res[1], res[2])
class BaseTreeView(QtGui.QTreeWidget):
options = [
@@ -76,6 +67,8 @@ class BaseTreeView(QtGui.QTreeWidget):
self.contextMenu.addAction(self.main_window.save_action)
self.contextMenu.addAction(self.main_window.remove_action)
self.__file_state_colors[File.NORMAL] = self.tagger.palette().text().color()
self.objectToItem = {}
self.itemToObject = {}
@@ -115,6 +108,25 @@ class BaseTreeView(QtGui.QTreeWidget):
def get_item_from_object(self, obj):
return self.objectToItem[obj]
__file_state_colors = {
File.PENDING: QtGui.QColor(128, 128, 128),
File.NORMAL: QtGui.QColor(0, 0, 0),
File.CHANGED: QtGui.QColor(0, 0, 64),
File.ERROR: QtGui.QColor(128, 0, 0),
File.SAVED: QtGui.QColor(0, 128, 0),
}
def get_file_state_color(self, state):
return self.__file_state_colors[state]
def get_file_match_color(self, similarity):
c1 = (255, 255, 255)
c2 = (223, 125, 125)
return QtGui.QColor(
c2[0] + (c1[0] - c2[0]) * similarity,
c2[1] + (c1[1] - c2[1]) * similarity,
c2[2] + (c1[2] - c2[2]) * similarity)
def supportedDropActions(self):
return QtCore.Qt.MoveAction | QtCore.Qt.CopyAction
@@ -275,9 +287,11 @@ class FileTreeView(BaseTreeView):
item.setText(0, metadata[u"title"])
item.setText(1, format_time(metadata.get(u"~#length", 0)))
item.setText(2, metadata[u"artist"])
color = matchColor(file.similarity)
fg_color = self.get_file_state_color(file.state)
bg_color = self.get_file_match_color(file.similarity)
for i in range(3):
item.setBackgroundColor(i, color)
item.setTextColor(i, fg_color)
item.setBackgroundColor(i, bg_color)
def update_file(self, file):
try:
@@ -385,6 +399,7 @@ class AlbumTreeView(BaseTreeView):
item = self.get_item_from_object(track)
if track.is_linked():
file = track.linked_file
state = file.state
if file.state == File.SAVED:
similarity = 1.0
icon = self.icon_saved
@@ -393,13 +408,16 @@ class AlbumTreeView(BaseTreeView):
icon = self.matchIcons[int(similarity * 5 + 0.5)]
else:
similarity = 1
state = File.NORMAL
icon = self.noteIcon
color = matchColor(similarity)
# Colors
fg_color = self.get_file_state_color(state)
bg_color = self.get_file_match_color(similarity)
for i in range(3):
item.setBackgroundColor(i, color)
item.setTextColor(i, fg_color)
item.setBackgroundColor(i, bg_color)
# Icon
item.setIcon(0, icon)
self._set_album_metadata(track.album)
def add_album(self, album):