File: importexport.py

package info (click to toggle)
quodlibet-plugins 20080601-1
  • links: PTS
  • area: main
  • in suites: lenny
  • size: 352 kB
  • ctags: 725
  • sloc: python: 4,001; makefile: 23; sh: 11
file content (136 lines) | stat: -rw-r--r-- 5,125 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# Copyright 2005 Michael Urman
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 as
# published by the Free Software Foundation
#
# $Id: importexport.py 3861 2006-09-23 05:02:27Z mu $

import gtk
from qltk import ErrorMessage
from os.path import splitext, extsep, dirname
from const import HOME as lastfolder
from library import library
__all__ = ['Export', 'Import']

from plugins.songsmenu import SongsMenuPlugin

def filechooser(save, title):
    chooser = gtk.FileChooserDialog(
        title=(save and "Export %s Metadata to ..." or "Import %s Metadata from ...") % title,
        action=(save and gtk.FILE_CHOOSER_ACTION_SAVE or gtk.FILE_CHOOSER_ACTION_OPEN),
        buttons=(gtk.STOCK_OK, gtk.RESPONSE_ACCEPT, gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT))

    for name, pattern in [('Tag files (*.tags)','*.tags'), ('All Files','*')]:
        filter = gtk.FileFilter()
        filter.set_name(name)
        filter.add_pattern(pattern)
        chooser.add_filter(filter)

    chooser.set_current_folder(lastfolder)
    chooser.set_default_response(gtk.RESPONSE_ACCEPT)
    return chooser

class Export(SongsMenuPlugin):

    PLUGIN_ID = "ExportMeta"
    PLUGIN_NAME = _("Export Metadata")
    PLUGIN_ICON = 'gtk-save'

    def plugin_album(self, songs):

        songs.sort(lambda a, b: cmp(a('~#track'), b('~#track')) or cmp(a('~basename'), b('~basename')) or cmp(a, b))

        chooser = filechooser(save=True, title=songs[0]('album'))
        resp = chooser.run()
        fn = chooser.get_filename()
        chooser.destroy()
        if resp != gtk.RESPONSE_ACCEPT: return
        base, ext = splitext(fn)
        if not ext: fn = extsep.join([fn, 'tags'])

        global lastfolder
        lastfolder = dirname(fn)
        out = open(fn, 'wU')

        for song in songs:
            print>>out, str(song('~basename'))
            keys = song.keys()
            keys.sort()
            for key in keys:
                if key.startswith('~'): continue
                for val in song.list(key):
                    print>>out, '%s=%s' % (key, val.encode('utf-8'))
            print>>out

class Import(SongsMenuPlugin):

    PLUGIN_ID = "ImportMeta"
    PLUGIN_NAME = _("Import Metadata")
    PLUGIN_ICON = 'gtk-open'

    # Note: the usage of plugin_album here is sometimes NOT what you want. It
    # supports fixing up tags on several already-known albums just by walking
    # them via the plugin system and just selecting a new .tags; this mimics
    # export of several albums.
    #
    # However if one of the songs in your album is different from the rest (e.g.
    # one isn't tagged, or only one is) it will be passed in as two different
    # invocations, neither of which has the right size. If you find yourself in
    # that scenario a lot more than the previous one, change this to
    #   def plugin_songs(self, songs):
    # and comment out the songs.sort line for safety.
    def plugin_album(self, songs):

        songs.sort(lambda a, b: cmp(a('~#track'), b('~#track')) or cmp(a('~basename'), b('~basename')) or cmp(a, b))

        chooser = filechooser(save=False, title=songs[0]('album'))
        box = gtk.HBox()
        rename = gtk.CheckButton("Rename Files")
        rename.set_active(False)
        box.pack_start(rename)
        append = gtk.CheckButton("Append Metadata")
        append.set_active(True)
        box.pack_start(append)
        box.show_all()
        chooser.set_extra_widget(box)

        resp = chooser.run()
        append = append.get_active()
        rename = rename.get_active()
        fn = chooser.get_filename()
        chooser.destroy()
        if resp != gtk.RESPONSE_ACCEPT: return

        global lastfolder
        lastfolder = dirname(fn)

        metadata = []
        names = []
        index = 0
        for line in open(fn, 'rU'):
            if index == len(metadata):
                names.append(line[:line.rfind('.')])
                metadata.append({})
            elif line == '\n':
                index = len(metadata)
            else:
                key, value = line[:-1].split('=', 1)
                value = value.decode('utf-8')
                try: metadata[index][key].append(value)
                except KeyError: metadata[index][key] = [value]

        if not (len(songs) == len(metadata) == len(names)):
            ErrorMessage(None, "Songs mismatch", "There are %(select)d songs selected, but %(meta)d songs in the file. Aborting." % dict(select=len(songs), meta=len(metadata))).run()
            return

        for song, meta, name in zip(songs, metadata, names):
            for key, values in meta.iteritems():
                if append and key in song:
                    values = song.list(key) + values
                song[key] = '\n'.join(values)
            if rename:
                origname = song['~filename']
                newname = name + origname[origname.rfind('.'):]
                if library is not None: library.rename(origname, newname)
                else: song.rename(newname) # ex falso case doesn't use library