~jmuc/picard/default-ascii

« back to all changes in this revision

Viewing changes to picard/album.py

  • Committer: Michael Wiencek
  • Date: 2011-07-17 16:47:06 UTC
  • mfrom: (1083.1.92 gsoc-ngs)
  • Revision ID: mwtuea@gmail.com-20110717164706-dtu2wqjw9debmve4
Merging with gsoc-ngs branch, minus collections-related features.

Show diffs side-by-side

added added

removed removed

Lines of Context:
19
19
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20
20
 
21
21
import traceback
 
22
from collections import deque
22
23
from PyQt4 import QtCore
23
 
from picard.metadata import Metadata, run_album_metadata_processors
 
24
from picard.metadata import Metadata, run_album_metadata_processors, run_track_metadata_processors
24
25
from picard.dataobj import DataObject
25
26
from picard.file import File
26
27
from picard.track import Track
28
29
from picard.ui.item import Item
29
30
from picard.util import format_time, partial, translate_artist, queue, mbid_validate
30
31
from picard.cluster import Cluster
31
 
from picard.mbxml import release_to_metadata, track_to_metadata
32
 
from picard.const import RELEASE_FORMATS, VARIOUS_ARTISTS_ID
 
32
from picard.mbxml import release_to_metadata, track_to_metadata, media_formats_from_node
 
33
from picard.const import VARIOUS_ARTISTS_ID
33
34
 
34
35
 
35
36
class Album(DataObject, Item):
38
39
        DataObject.__init__(self, id)
39
40
        self.metadata = Metadata()
40
41
        self.tracks = []
 
42
        self.format_str = ""
 
43
        self.tracks_str = ""
41
44
        self.loaded = False
42
45
        self.rgloaded = False
 
46
        self.rgid = None
43
47
        self._files = 0
44
48
        self._requests = 0
45
49
        self._discid = discid
46
50
        self._after_load_callbacks = queue.Queue()
 
51
        self._metadata_plugins = deque()
47
52
        self.other_versions = []
48
53
        self.unmatched_files = Cluster(_("Unmatched Files"), special=True, related_album=self, hide_if_empty=True)
49
54
 
78
83
        m.length = 0
79
84
        release_to_metadata(release_node, m, config=self.config, album=self)
80
85
 
 
86
        self.format_str = media_formats_from_node(release_node.medium_list[0])
 
87
        self.rgid = release_node.release_group[0].id
81
88
        if self._discid:
82
89
            m['musicbrainz_discid'] = self._discid
83
90
 
84
 
        if not self.rgloaded:
85
 
            releasegroupid = release_node.release_group[0].id
86
 
            self.tagger.xmlws.get_release_group_by_id(releasegroupid, self._release_group_request_finished)
87
 
 
88
91
        # 'Translate' artist name
89
92
        if self.config.setting['translate_artist_names']:
90
93
            m['albumartist'] = m['artist'] = translate_artist(m['artist'], m['artistsort'])
93
96
        if m['musicbrainz_artistid'] == VARIOUS_ARTISTS_ID:
94
97
            m['albumartistsort'] = m['artistsort'] = m['albumartist'] = m['artist'] = self.config.setting['va_name']
95
98
 
96
 
        # Album metadata plugins
97
 
        try:
98
 
            run_album_metadata_processors(self, m, release_node)
99
 
        except:
100
 
            self.log.error(traceback.format_exc())
101
 
 
102
 
        # Prepare parser for user's script
103
 
        if self.config.setting["enable_tagger_script"]:
104
 
            script = self.config.setting["tagger_script"]
105
 
            parser = ScriptParser()
106
 
        else:
107
 
            script = parser = None
108
 
 
109
99
        # Strip leading/trailing whitespace
110
100
        m.strip_whitespace()
111
101
 
112
102
        ignore_tags = [s.strip() for s in self.config.setting['ignore_tags'].split(',')]
113
 
        artists = set()
 
103
        first_artist = None
 
104
        compilation = False
 
105
        track_counts = []
114
106
 
115
107
        m['totaldiscs'] = release_node.medium_list[0].count
116
108
 
 
109
        plugins = partial(run_album_metadata_processors, self, m, release_node)
 
110
        self._metadata_plugins.append(plugins)
 
111
 
117
112
        for medium in release_node.medium_list[0].medium:
118
113
            discnumber = medium.position[0].text
119
114
            track_list = medium.track_list[0]
120
115
            totaltracks = track_list.count
 
116
            track_counts.append(totaltracks)
121
117
            discsubtitle = medium.title[0].text if "title" in medium.children else ""
122
118
            format = medium.format[0].text if "format" in medium.children else ""
123
119
 
134
130
                if format: tm['media'] = format
135
131
 
136
132
                track_to_metadata(node, config=self.config, track=t)
137
 
                t._customize_metadata(node, release_node, script, parser, ignore_tags)
138
 
 
139
 
                artists.add(tm['musicbrainz_artistid'])
140
133
                m.length += tm.length
141
134
 
142
 
        if len(artists) > 1:
143
 
            for t in self._new_tracks:
144
 
                t.metadata['compilation'] = '1'
145
 
 
146
 
        if script:
147
 
            # Run tagger script for the album itself
148
 
            try:
149
 
                parser.eval(script, m)
150
 
            except:
151
 
                self.log.error(traceback.format_exc())
 
135
                artist_id = tm['musicbrainz_artistid']
 
136
                if compilation is False:
 
137
                    if first_artist is None:
 
138
                        first_artist = artist_id
 
139
                    if first_artist != artist_id:
 
140
                        compilation = True
 
141
                        for track in self._new_tracks:
 
142
                            track.metadata['compilation'] = '1'
 
143
                else:
 
144
                    tm['compilation'] = '1'
 
145
 
 
146
                t._customize_metadata(ignore_tags)
 
147
                plugins = partial(run_track_metadata_processors, self, tm, release_node, node)
 
148
                self._metadata_plugins.append(plugins)
 
149
 
 
150
        self.tracks_str = " + ".join(track_counts)
152
151
 
153
152
        return True
154
153
 
155
 
    def _parse_release_group(self, document):
156
 
        releases = document.metadata[0].release_group[0].release_list[0].release
157
 
        for release in releases:
158
 
            version = {}
159
 
            version["mbid"] = release.id
160
 
            if "date" in release.children:
161
 
                version["date"] = release.date[0].text
162
 
            if "country" in release.children:
163
 
                version["country"] = release.country[0].text
164
 
            version["totaltracks"] = [int(m.track_list[0].count) for m in release.medium_list[0].medium]
165
 
            formats = {}
166
 
            for medium in release.medium_list[0].medium:
167
 
                if "format" in medium.children:
168
 
                    f = medium.format[0].text
169
 
                    if f in formats: formats[f] += 1
170
 
                    else: formats[f] = 1
171
 
            if formats:
172
 
                version["media"] = " + ".join(["%s%s" % (str(j)+u"×" if j>1 else "", RELEASE_FORMATS[i])
173
 
                    for i, j in formats.items()])
174
 
            self.other_versions.append(version)
175
 
        self.other_versions.sort(key=lambda x: x["date"])
176
 
 
177
154
    def _release_request_finished(self, document, http, error):
178
155
        parsed = False
179
156
        try:
200
177
            if parsed or error:
201
178
                self._finalize_loading(error)
202
179
 
 
180
    def _parse_release_group(self, document):
 
181
        releases = document.metadata[0].release_group[0].release_list[0].release
 
182
        for release in releases:
 
183
            version = {}
 
184
            version["mbid"] = release.id
 
185
            if "date" in release.children:
 
186
                version["date"] = release.date[0].text
 
187
            if "country" in release.children:
 
188
                version["country"] = release.country[0].text
 
189
            version["tracks"] = " + ".join([m.track_list[0].count for m in release.medium_list[0].medium])
 
190
            version["format"] = media_formats_from_node(release.medium_list[0])
 
191
            self.other_versions.append(version)
 
192
        self.other_versions.sort(key=lambda x: x["date"])
 
193
 
203
194
    def _release_group_request_finished(self, document, http, error):
204
195
        try:
205
196
            if error:
212
203
                    self.log.error(traceback.format_exc())
213
204
        finally:
214
205
            self.rgloaded = True
 
206
            self.emit(QtCore.SIGNAL("release_group_loaded"))
215
207
 
216
208
    def _finalize_loading(self, error):
217
209
        if error:
220
212
            del self._new_metadata
221
213
            del self._new_tracks
222
214
            self.update()
223
 
        else:
224
 
            if not self._requests:
225
 
                for track in self.tracks:
226
 
                    for file in list(track.linked_files):
227
 
                        file.move(self.unmatched_files)
228
 
                self.metadata = self._new_metadata
229
 
                self.tracks = self._new_tracks
230
 
                del self._new_metadata
231
 
                del self._new_tracks
232
 
                self.loaded = True
233
 
                self.match_files(self.unmatched_files.files)
234
 
                self.update()
235
 
                self.tagger.window.set_statusbar_message('Album %s loaded', self.id, timeout=3000)
236
 
                while self._after_load_callbacks.qsize() > 0:
237
 
                    func = self._after_load_callbacks.get()
238
 
                    func()
 
215
            return
 
216
 
 
217
        # Run metadata plugins
 
218
        while self._metadata_plugins:
 
219
            try:
 
220
                self._metadata_plugins.pop()()
 
221
            except:
 
222
                self.log.error(traceback.format_exc())
 
223
 
 
224
        if not self._requests:
 
225
            # Prepare parser for user's script
 
226
            if self.config.setting["enable_tagger_script"]:
 
227
                script = self.config.setting["tagger_script"]
 
228
                if script:
 
229
                    parser = ScriptParser()
 
230
                    # Run tagger script for each track
 
231
                    for track in self._new_tracks:
 
232
                        try:
 
233
                            parser.eval(script, track.metadata)
 
234
                        except:
 
235
                            self.log.error(traceback.format_exc())
 
236
                        # Strip leading/trailing whitespace
 
237
                        track.metadata.strip_whitespace()
 
238
                    # Run tagger script for the album itself
 
239
                    try:
 
240
                        parser.eval(script, self._new_metadata)
 
241
                    except:
 
242
                        self.log.error(traceback.format_exc())
 
243
 
 
244
            for track in self.tracks:
 
245
                for file in list(track.linked_files):
 
246
                    file.move(self.unmatched_files)
 
247
            self.metadata = self._new_metadata
 
248
            self.tracks = self._new_tracks
 
249
            del self._new_metadata
 
250
            del self._new_tracks
 
251
            self.loaded = True
 
252
            self.match_files(self.unmatched_files.files)
 
253
            self.update()
 
254
            self.tagger.window.set_statusbar_message('Album %s loaded', self.id, timeout=3000)
 
255
            while self._after_load_callbacks.qsize() > 0:
 
256
                func = self._after_load_callbacks.get()
 
257
                func()
239
258
 
240
259
    def load(self):
241
260
        if self._requests:
361
380
        if not self.tracks:
362
381
            return False
363
382
        for track in self.tracks:
364
 
            if len(track.linked_files) != 1:
 
383
            if track.num_linked_files != 1:
365
384
                return False
366
385
        else:
367
386
            return True
421
440
            for file in track.linked_files:
422
441
                track.update_file_metadata(file)
423
442
        super(NatAlbum, self).update(update_tracks)
 
443
 
 
444
    def _finalize_loading(self, error):
 
445
        self.update()