~ubuntu-branches/ubuntu/trusty/idjc/trusty

« back to all changes in this revision

Viewing changes to idjcpython/mutagentagger.py

  • Committer: Package Import Robot
  • Author(s): Alessio Treglia
  • Date: 2011-12-03 16:33:59 UTC
  • mfrom: (0.2.6)
  • Revision ID: package-import@ubuntu.com-20111203163359-dq5fy9i756jpoy29
Tags: 0.8.6-1
* New upstream release.
* debian/control:
  - Wrap and sort.
  - Build-depend on autopoint.
  - Drop autotools-dev, unnecessary.
* Drop the whole patch set, none of them is still needed.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#!/usr/bin/python
2
 
 
3
 
#   mutagengui.py: GTK based file tagger.
4
 
#   Copyright (C) 2009 Stephen Fairchild (s-fairchild@users.sourceforge.net)
5
 
#
6
 
#   This program is free software: you can redistribute it and/or modify
7
 
#   it under the terms of the GNU General Public License as published by
8
 
#   the Free Software Foundation, either version 2 of the License, or
9
 
#   (at your option) any later version.
10
 
#
11
 
#   This program is distributed in the hope that it will be useful,
12
 
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 
#   GNU General Public License for more details.
15
 
#
16
 
#   You should have received a copy of the GNU General Public License
17
 
#   along with this program in the file entitled COPYING.
18
 
#   If not, see <http://www.gnu.org/licenses/>.
19
 
 
20
 
 
21
 
__all__ = ['MutagenGUI']
22
 
 
23
 
import os
24
 
import sys
25
 
import string
26
 
import re
27
 
import pango
28
 
 
29
 
import pygtk
30
 
pygtk.require('2.0')
31
 
import gtk
32
 
import mutagen
33
 
 
34
 
import mutagen.id3 as id3
35
 
 
36
 
from idjc_config import *
37
 
from IDJCfree import *
38
 
from ln_text import ln
39
 
from mutagen.mp3 import MP3
40
 
from mutagen.apev2 import APEv2, APETextValue
41
 
from mutagen.musepack import Musepack
42
 
from mutagen.monkeysaudio import MonkeysAudio
43
 
from mutagen.asf import ASF, ASFUnicodeAttribute
44
 
 
45
 
def set_tip(*args):
46
 
   """Dummy tooltips setter."""
47
 
   
48
 
   pass
49
 
 
50
 
 
51
 
class LeftLabel(gtk.HBox):
52
 
   """Use in place of gtk.Label where left justification is needed."""
53
 
   
54
 
   def __init__(self, text):
55
 
      gtk.HBox.__init__(self)
56
 
      self.label = gtk.Label(text)
57
 
      self.pack_start(self.label, False, False, 0)
58
 
 
59
 
 
60
 
class RightLabel(gtk.HBox):
61
 
   """Use in place of gtk.Label where right justification is needed."""
62
 
   
63
 
   def __init__(self, text):
64
 
      gtk.HBox.__init__(self)
65
 
      self.pack_end(gtk.Label(text), False, False, 0)
66
 
 
67
 
 
68
 
class FreeTagFrame(gtk.Frame):
69
 
   def __init__(self):
70
 
      gtk.Frame.__init__(self)
71
 
      sw = gtk.ScrolledWindow()
72
 
      sw.set_border_width(5)
73
 
      sw.set_policy(gtk.POLICY_NEVER, gtk.POLICY_ALWAYS)
74
 
      self.add(sw)
75
 
      sw.show()
76
 
      self.tb = gtk.TextBuffer()
77
 
      tv = gtk.TextView(self.tb)
78
 
      tv.set_wrap_mode(gtk.WRAP_CHAR)
79
 
      tv.modify_font(pango.FontDescription('sans 12'))
80
 
      sw.add(tv)
81
 
      tv.show()
82
 
 
83
 
 
84
 
class MutagenTagger(gtk.VBox):
85
 
   """Base class for ID3Tagger and NativeTagger."""
86
 
   
87
 
   def __init__(self, pathname):
88
 
      gtk.VBox.__init__(self)
89
 
      self.pathname = pathname
90
 
 
91
 
class WMATagger(MutagenTagger):
92
 
   """Handles tagging of WMA files"""
93
 
   
94
 
   primary_data = ("Title", "Author")
95
 
   secondaries = ("WM/AlbumTitle", "WM/AlbumArtist", "WM/Year", "WM/Genre")
96
 
   
97
 
   def save_tag(self):
98
 
      """Updates the tag with the GUI data."""
99
 
       
100
 
      tag = self.tag
101
 
      tb = self.tag_frame.tb
102
 
       
103
 
      for key in self.text_set:
104
 
         try:
105
 
            del tag[key]
106
 
         except KeyError:
107
 
            pass
108
 
 
109
 
      for each in self.primary_line:
110
 
         val = each[1].get_text().strip()
111
 
         if val:
112
 
            tag[each[0]] = val
113
 
         else:
114
 
            try:
115
 
               del tag[each[0]]
116
 
            except KeyError:
117
 
               pass
118
 
             
119
 
      lines = tb.get_text(tb.get_start_iter(), tb.get_end_iter()).splitlines()
120
 
      for line in lines:
121
 
         try:
122
 
            key, val = line.split("=", 1)
123
 
         except ValueError:
124
 
            continue
125
 
         else:
126
 
            key = key.strip()
127
 
            val = val.strip()
128
 
            if val:
129
 
               try:
130
 
                  tag[key] += [ASFUnicodeAttribute(val.decode("utf-8"))]
131
 
               except (KeyError, AttributeError):
132
 
                  try:
133
 
                     tag[key] = [ASFUnicodeAttribute(val.decode("utf-8"))]
134
 
                  except KeyError:
135
 
                     print "Unacceptable key", key
136
 
      tag.save()
137
 
   
138
 
   def load_tag(self):
139
 
      """(re)Writes the tag data to the GUI."""
140
 
      
141
 
      tag = self.tag
142
 
      
143
 
      for each in self.primary_line:
144
 
         try:
145
 
            data = tag[each[0]]
146
 
         except KeyError:
147
 
            pass
148
 
         else:
149
 
            each[1].set_text("/".join(unicode(y) for y in data))
150
 
 
151
 
      additional = []
152
 
 
153
 
      for key in self.secondaries:
154
 
         values = tag.get(key, [ASFUnicodeAttribute("")])
155
 
         for val in values:
156
 
            additional.append(key.encode("utf-8") + "=" + unicode(val).encode("utf-8"))
157
 
 
158
 
      for key in self.text_set:
159
 
         if key not in self.primary_data and key not in self.secondaries:
160
 
            values = tag[key]
161
 
            for val in values:
162
 
               additional.append(key.encode("utf-8") + "=" + unicode(val).encode("utf-8"))
163
 
      
164
 
      self.tag_frame.tb.set_text("\n".join(additional))
165
 
   
166
 
   def __init__(self, pathname):
167
 
      MutagenTagger.__init__(self, pathname)
168
 
      try:
169
 
         self.tag = mutagen.asf.ASF(pathname)
170
 
         if not isinstance(self.tag, mutagen.asf.ASF):
171
 
            raise mutagen.asf.error
172
 
      except mutagen.asf.error:
173
 
         print "Not a real wma/asf file apparently."
174
 
         self.tag = None
175
 
         return
176
 
         
177
 
      hbox = gtk.HBox()
178
 
      hbox.set_border_width(5)
179
 
      hbox.set_spacing(8)
180
 
      self.pack_start(hbox, False, False, 0)
181
 
      vbox_text = gtk.VBox()
182
 
      hbox.pack_start(vbox_text, False, False, 0)
183
 
      vbox_entry = gtk.VBox()
184
 
      hbox.pack_start(vbox_entry, True, True, 0)
185
 
      
186
 
      self.primary_line = []
187
 
      for text, entry in ((x, gtk.Entry()) for x in self.primary_data):
188
 
         self.primary_line.append((text, entry))
189
 
         vbox_text.add(LeftLabel(text))
190
 
         vbox_entry.add(entry)
191
 
      hbox.show_all()
192
 
 
193
 
      self.tag_frame = FreeTagFrame()
194
 
      self.tag_frame.set_border_width(5)
195
 
      self.add(self.tag_frame)
196
 
      self.tag_frame.show()
197
 
 
198
 
      self.text_set = []
199
 
 
200
 
      for key, val in self.tag.iteritems():
201
 
         if key not in self.primary_line and all(isinstance(v, (ASFUnicodeAttribute, unicode)) for v in val):
202
 
            self.text_set.append(key)
203
 
 
204
 
 
205
 
class ID3Tagger(MutagenTagger):
206
 
   """ID3 tagging with Mutagen."""
207
 
   
208
 
   primary_data = (("TIT2", ln.id3title), ("TPE1", ln.id3artist),
209
 
                   ("TALB", ln.id3album), ("TRCK", ln.id3track),
210
 
                   ("TCON", ln.id3genre), ("TDRC", ln.id3recorddate))
211
 
   
212
 
   def save_tag(self):
213
 
      """Updates the tag with the GUI data."""
214
 
      
215
 
      tag = self.tag
216
 
      
217
 
      # Remove all text tags.
218
 
      for fid in tag.iterkeys():
219
 
         if fid[0] == "T":
220
 
            del tag[fid]
221
 
   
222
 
      # Add the primary tags.
223
 
      for fid, entry in self.primary_line:
224
 
         text = entry.get_text().strip()
225
 
         if text:
226
 
            frame = getattr(id3, fid)
227
 
            tag[fid] = frame(3, [text])
228
 
 
229
 
      # Add the freeform text tags.
230
 
      tb = self.tag_frame.tb
231
 
      lines = tb.get_text(tb.get_start_iter(), tb.get_end_iter()).splitlines()
232
 
          
233
 
      for line in lines:
234
 
         try:
235
 
            fid, val = line.split(":", 1)
236
 
         
237
 
         except ValueError:
238
 
            continue
239
 
         
240
 
         fid = fid.strip()
241
 
         val = val.strip().decode("utf-8")
242
 
         
243
 
         try:
244
 
            frame = id3.Frames[fid]
245
 
         except NameError:
246
 
            continue
247
 
 
248
 
         if not issubclass(frame, id3.TextFrame):
249
 
            continue
250
 
 
251
 
         if frame is id3.TXXX:
252
 
            try:
253
 
               key, val = val.split(u"=", 1)
254
 
            
255
 
            except ValueError:
256
 
               continue
257
 
            
258
 
            f = frame(3, key.strip(), [val.strip()])
259
 
            tag[f.HashKey] = f
260
 
            
261
 
         else:
262
 
            try:
263
 
               val_list = tag[fid].text
264
 
            except KeyError:
265
 
               tag[fid] = frame(3, [val])
266
 
            else:
267
 
               val_list.append(val)
268
 
 
269
 
      tag.save()
270
 
            
271
 
   def load_tag(self):
272
 
      """(re)Writes the tag data to the GUI."""
273
 
      
274
 
      additional = []
275
 
      done = []
276
 
      
277
 
      for fid, entry in self.primary_line:
278
 
         try:
279
 
            frame = self.tag[fid]
280
 
            if fid[0] == "T":
281
 
               try:
282
 
                  entry.set_text(frame.text[0])
283
 
               except TypeError:
284
 
                  # Handle occurrence of ID3Timestamp.
285
 
                  entry.set_text(str(frame.text[0]))
286
 
               for each in frame.text[1:]:
287
 
                  additional.append(fid + ":" + each.encode("utf-8"))
288
 
         except KeyError:
289
 
            entry.set_text("")
290
 
         
291
 
         done.append(fid)
292
 
            
293
 
      for fid, frame in self.tag.iteritems():
294
 
         if fid[0] == "T" and fid not in done:
295
 
            sep = "=" if fid.startswith("TXXX:") else ":"
296
 
            for text in frame.text:
297
 
               additional.append(fid + sep + text.encode("utf-8"))
298
 
            
299
 
      self.tag_frame.tb.set_text("\n".join(additional))
300
 
      
301
 
   def __init__(self, pathname, force=False):
302
 
      MutagenTagger.__init__(self, pathname)
303
 
      if force:
304
 
         try:
305
 
            self.tag = mutagen.File(pathname)
306
 
            if not isinstance(self.tag, MP3):
307
 
               raise mutagen.mp3.error
308
 
         except mutagen.mp3.error:
309
 
            print "Not a real mp3 file apparently."
310
 
            self.tag = None
311
 
            return
312
 
         try:
313
 
            self.tag.add_tags()
314
 
            print "Added ID3 tags to", pathname
315
 
         except mutagen.id3.error:
316
 
            print "Existing ID3 tags found."
317
 
      else:
318
 
         try:
319
 
            # Obtain ID3 tags from a non mp3 file.
320
 
            self.tag = mutagen.id3.ID3(pathname)
321
 
         except mutagen.id3.error:
322
 
            self.tag = None
323
 
            return
324
 
         
325
 
      hbox = gtk.HBox()
326
 
      hbox.set_border_width(5)
327
 
      hbox.set_spacing(8)
328
 
      self.pack_start(hbox, False, False, 0)
329
 
      vbox_frame = gtk.VBox()
330
 
      hbox.pack_start(vbox_frame, False, False, 0)
331
 
      vbox_text = gtk.VBox()
332
 
      hbox.pack_start(vbox_text, False, False, 0)
333
 
      vbox_entry = gtk.VBox()
334
 
      hbox.pack_start(vbox_entry, True, True, 0)
335
 
      
336
 
      self.primary_line = []
337
 
      for frame, text, entry in ((x, y, gtk.Entry()) for x, y in self.primary_data):
338
 
         self.primary_line.append((frame, entry))
339
 
         vbox_frame.add(LeftLabel(frame))
340
 
         vbox_text.add(RightLabel(text))
341
 
         vbox_entry.add(entry)
342
 
      hbox.show_all()
343
 
      
344
 
      self.tag_frame = FreeTagFrame()
345
 
      set_tip(self.tag_frame, ln.id3freeform)
346
 
      self.tag_frame.set_border_width(5)
347
 
      self.tag_frame.set_label(ln.id3textframes)
348
 
      self.add(self.tag_frame)
349
 
      self.tag_frame.show()
350
 
 
351
 
 
352
 
class MP4Tagger(MutagenTagger):
353
 
   """MP4 tagging with Mutagen."""
354
 
   
355
 
   primary_data = (("\xa9nam", ln.mp4title), ("\xa9ART", ln.mp4artist),
356
 
                   ("\xa9alb", ln.mp4album), ("trkn", ln.mp4track),
357
 
                   ("\xa9gen", ln.mp4genre), ("\xa9day", ln.mp4year))
358
 
   
359
 
   def save_tag(self):
360
 
      """Updates the tag with the GUI data."""
361
 
      
362
 
      tag = self.tag
363
 
      for fid, entry in self.primary_line:
364
 
         text = entry.get_text().strip()
365
 
         if fid == "trkn":
366
 
            mo1 = re.search("\d+", text)
367
 
            try:
368
 
               track = int(text[mo1.start():mo1.end()])
369
 
            except AttributeError:
370
 
               new_val = None
371
 
            else:
372
 
               text = text[mo1.end():]
373
 
               mo2 = re.search("\d+", text)
374
 
               try:
375
 
                  total = int(text[mo2.start():mo2.end()])
376
 
               except AttributeError:
377
 
                  new_val = [(track, 0)]
378
 
               else:
379
 
                  new_val = [(track, total)]
380
 
         else:
381
 
            new_val = [text] if text else None
382
 
 
383
 
         if new_val is not None:
384
 
            tag[fid] = new_val
385
 
         else:
386
 
            try:
387
 
               del tag[fid]
388
 
            except KeyError:
389
 
               pass
390
 
 
391
 
      tag.save()
392
 
            
393
 
   def load_tag(self):
394
 
      """(re)Writes the tag data to the GUI."""
395
 
      
396
 
      additional = []
397
 
      
398
 
      for fid, entry in self.primary_line:
399
 
         try:
400
 
            frame = self.tag[fid][0]
401
 
         except KeyError:
402
 
            entry.set_text("")
403
 
         else:
404
 
            if fid == "trkn":
405
 
               if frame[1]:
406
 
                  entry.set_text("%d/%d" % frame)
407
 
               else:
408
 
                  entry.set_text(str(frame[0]))
409
 
            else:
410
 
               entry.set_text(frame)
411
 
          
412
 
   def __init__(self, pathname):
413
 
      MutagenTagger.__init__(self, pathname)
414
 
      try:
415
 
         self.tag = mutagen.mp4.MP4(pathname)
416
 
         if not isinstance(self.tag, mutagen.mp4.MP4):
417
 
            raise mutagen.mp4.error
418
 
      except mutagen.mp4.error:
419
 
         print "Not a real mp4 file apparently."
420
 
         self.tag = None
421
 
         return
422
 
         
423
 
      hbox = gtk.HBox()
424
 
      hbox.set_border_width(5)
425
 
      hbox.set_spacing(8)
426
 
      self.pack_start(hbox, False, False, 0)
427
 
      vbox_text = gtk.VBox()
428
 
      hbox.pack_start(vbox_text, False, False, 0)
429
 
      vbox_entry = gtk.VBox()
430
 
      hbox.pack_start(vbox_entry, True, True, 0)
431
 
      
432
 
      self.primary_line = []
433
 
      for frame, text, entry in ((x, y, gtk.Entry()) for x, y in self.primary_data):
434
 
         self.primary_line.append((frame, entry))
435
 
         vbox_text.add(LeftLabel(text))
436
 
         vbox_entry.add(entry)
437
 
      hbox.show_all()
438
 
 
439
 
 
440
 
class NativeTagger(MutagenTagger):
441
 
   """Native format tagging with Mutagen. Mostly FLAC and Ogg."""
442
 
   
443
 
   blacklist = "coverart", "metadata_block_picture"
444
 
   
445
 
   def save_tag(self):
446
 
      """Updates the tag with the GUI data."""
447
 
      
448
 
      tag = self.tag
449
 
      
450
 
      for key in tag.iterkeys():
451
 
         if key not in self.blacklist:
452
 
            del tag[key]
453
 
            
454
 
      tb = self.tag_frame.tb
455
 
      lines = tb.get_text(tb.get_start_iter(), tb.get_end_iter()).splitlines()
456
 
      
457
 
      for line in lines:
458
 
         try:
459
 
            key, val = line.split("=", 1)
460
 
         except ValueError:
461
 
            continue
462
 
         else:
463
 
            key = key.strip()
464
 
            val = val.strip()
465
 
            if key not in self.blacklist and val:
466
 
               try:
467
 
                  tag[key] += [val.decode("utf-8")]
468
 
               except (KeyError, AttributeError):
469
 
                  try:
470
 
                     tag[key] = [val.decode("utf-8")]
471
 
                  except KeyError:
472
 
                     print "Unacceptable key", key
473
 
   
474
 
      tag.save() 
475
 
   
476
 
   def load_tag(self):
477
 
      """(re)Writes the tag data to the GUI."""
478
 
      
479
 
      tag = self.tag
480
 
      lines = []
481
 
      primaries = "title", "artist", "author", "album",\
482
 
                          "tracknumber", "tracktotal", "genre", "date"
483
 
      
484
 
      for key in primaries:
485
 
         try:
486
 
            values = tag[key]
487
 
         except KeyError:
488
 
            lines.append(key + "=")
489
 
         else:
490
 
            for val in values:
491
 
               lines.append(key + "=" + val.encode("utf-8"))
492
 
 
493
 
      for key, values in tag.iteritems():
494
 
         if key not in primaries and key not in self.blacklist:
495
 
            for val in values:
496
 
               lines.append(key + "=" + val.encode("utf-8"))
497
 
            
498
 
      self.tag_frame.tb.set_text("\n".join(lines))
499
 
   
500
 
   def __init__(self, pathname, ext):
501
 
      MutagenTagger.__init__(self, pathname)
502
 
      self.tag = mutagen.File(pathname)
503
 
      if isinstance(self.tag, (MP3, APEv2)):
504
 
         # MP3 and APEv2 have their own specialised tagger.
505
 
         self.tag = None
506
 
         return
507
 
      
508
 
      self.tag_frame = FreeTagFrame()
509
 
      self.add(self.tag_frame)
510
 
      self.tag_frame.show()
511
 
 
512
 
 
513
 
class ApeTagger(MutagenTagger):
514
 
   """APEv2 tagging with Mutagen."""
515
 
   
516
 
   opener = {"ape": MonkeysAudio, "mpc": Musepack }
517
 
   
518
 
   def save_tag(self):
519
 
      """Updates the tag with the GUI data."""
520
 
      
521
 
      tag = self.tag
522
 
      
523
 
      for key, values in tag.iteritems():
524
 
         if isinstance(values, APETextValue):
525
 
            del tag[key]
526
 
            
527
 
      tb = self.tag_frame.tb
528
 
      lines = tb.get_text(tb.get_start_iter(), tb.get_end_iter()).splitlines()
529
 
      
530
 
      for line in lines:
531
 
         try:
532
 
            key, val = line.split("=", 1)
533
 
         except ValueError:
534
 
            continue
535
 
         else:
536
 
            key = key.strip()
537
 
            val = val.strip()
538
 
            if val:
539
 
               try:
540
 
                  tag[key].value += "\0" + val.decode("utf-8")
541
 
               except (KeyError, AttributeError):
542
 
                  try:
543
 
                     tag[key] = APETextValue(val.decode("utf-8"), 0)
544
 
                  except KeyError:
545
 
                     print "Unacceptable key", key
546
 
   
547
 
      tag.save() 
548
 
   
549
 
   def load_tag(self):
550
 
      """(re)Writes the tag data to the GUI."""
551
 
      
552
 
      tag = self.tag
553
 
      lines = []
554
 
      primaries = "TITLE", "ARTIST", "AUTHOR", "ALBUM",\
555
 
                          "TRACKNUMBER", "TRACKTOTAL", "GENRE", "DATE"
556
 
      
557
 
      for key in primaries:
558
 
         try:
559
 
            values = tag[key]
560
 
         except KeyError:
561
 
            lines.append(key + "=")
562
 
         else:
563
 
            for val in values:
564
 
               lines.append(key + "=" + val.encode("utf-8"))
565
 
 
566
 
      for key, values in tag.iteritems():
567
 
         if key not in primaries and isinstance(values, APETextValue):
568
 
            for val in values:
569
 
               lines.append(key + "=" + val.encode("utf-8"))
570
 
            
571
 
      self.tag_frame.tb.set_text("\n".join(lines))
572
 
   
573
 
   def __init__(self, pathname, extension):
574
 
      MutagenTagger.__init__(self, pathname)
575
 
      
576
 
      try:
577
 
         self.tag = self.opener[extension](pathname)
578
 
      except KeyError:
579
 
         try:
580
 
            self.tag = APEv2(pathname)
581
 
         except:
582
 
            print "ape tag not found"
583
 
            self.tag = None
584
 
            return
585
 
         else:
586
 
            print "ape tag found on non-native format"
587
 
      except:
588
 
         print "failed to create tagger for native format"
589
 
         self.tag = None
590
 
         return
591
 
      else:
592
 
         try:
593
 
            self.tag.add_tags()
594
 
         except:
595
 
            print "ape tag found on native format"
596
 
         else:
597
 
            print "no existing ape tags found"
598
 
         
599
 
      self.tag_frame = FreeTagFrame()
600
 
      self.add(self.tag_frame)
601
 
      self.tag_frame.show()
602
 
 
603
 
 
604
 
class MutagenGUI:
605
 
   ext2name = { "mp3": "ID3", "mp4": "MP4", "m4a": "MP4", "spx": "Speex",
606
 
               "flac": "FLAC", "ogg": "Ogg Vorbis", "oga": "XIPH Ogg audio",
607
 
               "m4b": "MP4", "m4p": "MP4", "wma": "Windows Media Audio" }
608
 
   
609
 
   def destroy_and_quit(self, widget, data = None):
610
 
      gtk.main_quit()
611
 
      sys.exit(0)
612
 
   
613
 
   def update_playlists(self, pathname, idjcroot):
614
 
      newplaylistdata = idjcroot.player_left.get_media_metadata(pathname)
615
 
      idjcroot.player_left.update_playlist(newplaylistdata)
616
 
      idjcroot.player_right.update_playlist(newplaylistdata)
617
 
   
618
 
   @staticmethod
619
 
   def is_supported(pathname):
620
 
      supported = [ "mp3", "ogg", "oga" ]
621
 
      if avcodec and avformat:
622
 
         supported += ["mp4", "m4a", "m4b", "m4p", "ape", "mpc", "wma"]
623
 
      if flacenabled:
624
 
         supported.append("flac")
625
 
      if speexenabled:
626
 
         supported.append("spx")
627
 
      extension = os.path.splitext(pathname)[1][1:].lower()
628
 
      if supported.count(extension) != 1:
629
 
         if extension:
630
 
            print "File type", extension, "is not supported for tagging"
631
 
         return False
632
 
      else:
633
 
         return extension
634
 
   
635
 
   def __init__(self, pathname, encoding, idjcroot = None):
636
 
      if not pathname:
637
 
         print "Tagger not supplied any pathname."
638
 
         return
639
 
      
640
 
      extension = self.is_supported(pathname)
641
 
      if extension == False:
642
 
         print "Tagger file extension", extension, "not supported."
643
 
         return
644
 
      
645
 
      global set_tip
646
 
      if idjcroot:
647
 
         set_tip = idjcroot.tooltips.set_tip
648
 
      
649
 
      self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
650
 
      if idjcroot is not None:
651
 
         idjcroot.window_group.add_window(self.window)
652
 
      self.window.set_size_request(550, 450)
653
 
      self.window.set_title(ln.tagger_window_title)
654
 
      self.window.set_destroy_with_parent(True)
655
 
      self.window.set_border_width(9)
656
 
      self.window.set_resizable(True)
657
 
      self.window.set_icon_from_file(pkgdatadir + "icon" + gfext)
658
 
      if idjcroot == None:
659
 
         self.window.connect("destroy", self.destroy_and_quit)
660
 
      vbox = gtk.VBox()
661
 
      self.window.add(vbox)
662
 
      vbox.show()
663
 
      label = gtk.Label()
664
 
      if idjcroot:
665
 
         label.set_markup(u"<b>" + ln.tagger_filename + u" " + rich_safe(unicode(os.path.split(pathname)[1], encoding).encode("utf-8", "replace")) + u"</b>")
666
 
      else:
667
 
         label.set_markup(u"<b>" + ln.tagger_filename + u" " + rich_safe(unicode(os.path.split(pathname)[1], "latin1").encode("utf-8", "replace")) + u"</b>")
668
 
      vbox.pack_start(label, False, False, 6)
669
 
      label.show()
670
 
      
671
 
      hbox = gtk.HBox()
672
 
      hbox.set_border_width(2)
673
 
      apply_button = gtk.Button(None, gtk.STOCK_APPLY)
674
 
      if idjcroot is not None:
675
 
         apply_button.connect_object_after("clicked", self.update_playlists, pathname, idjcroot)
676
 
      hbox.pack_end(apply_button, False, False, 0)
677
 
      apply_button.show()
678
 
      close_button = gtk.Button(None, gtk.STOCK_CLOSE)
679
 
      close_button.connect_object("clicked", gtk.Window.destroy, self.window)
680
 
      hbox.pack_end(close_button, False, False, 10)
681
 
      close_button.show()
682
 
      reload_button = gtk.Button(None, gtk.STOCK_REVERT_TO_SAVED)
683
 
      hbox.pack_start(reload_button, False, False, 10)
684
 
      reload_button.show()
685
 
      vbox.pack_end(hbox, False, False, 0)
686
 
      hbox.show()
687
 
      hbox = gtk.HBox()
688
 
      vbox.pack_end(hbox, False, False, 2)
689
 
      hbox.show()
690
 
      
691
 
      notebook = gtk.Notebook()
692
 
      notebook.set_border_width(2)
693
 
      vbox.pack_start(notebook, True, True, 0)
694
 
      notebook.show()
695
 
      
696
 
      self.ape = ApeTagger(pathname, extension)
697
 
      
698
 
      if extension == "mp3":
699
 
         self.id3 = ID3Tagger(pathname, True)
700
 
         self.native = None
701
 
      else:
702
 
         self.id3 = ID3Tagger(pathname, False)
703
 
         if extension in ("mp4", "m4a", "m4b", "m4p"):
704
 
            self.native = MP4Tagger(pathname)
705
 
         elif extension == "wma":
706
 
            self.native = WMATagger(pathname)
707
 
         elif extension in ("ape", "mpc"):
708
 
            # APE tags are native to this format.
709
 
            self.native = None
710
 
         else:
711
 
            self.native = NativeTagger(pathname, ext=extension)
712
 
      
713
 
      if self.id3 is not None and self.id3.tag is not None:
714
 
         reload_button.connect("clicked", lambda x: self.id3.load_tag())
715
 
         apply_button.connect("clicked", lambda x: self.id3.save_tag())
716
 
         label = gtk.Label("ID3")
717
 
         notebook.append_page(self.id3, label)
718
 
         self.id3.show()
719
 
      
720
 
      if self.ape is not None and self.ape.tag is not None:
721
 
         reload_button.connect("clicked", lambda x: self.ape.load_tag())
722
 
         apply_button.connect("clicked", lambda x: self.ape.save_tag())
723
 
         label = gtk.Label("APE v2")
724
 
         notebook.append_page(self.ape, label)
725
 
         self.ape.show()   
726
 
      
727
 
      if self.native is not None and self.native.tag is not None:
728
 
         reload_button.connect("clicked", lambda x: self.native.load_tag())
729
 
         apply_button.connect("clicked", lambda x: self.native.save_tag())
730
 
         label = gtk.Label(ln.native + " (" + self.ext2name[extension] + ")")
731
 
         notebook.append_page(self.native, label)
732
 
         self.native.show()
733
 
      
734
 
      reload_button.clicked()
735
 
 
736
 
      apply_button.connect_object_after("clicked", gtk.Window.destroy, self.window)
737
 
      self.window.show()