~ubuntu-branches/debian/lenny/mutagen/lenny

« back to all changes in this revision

Viewing changes to tools/mid3v2

  • Committer: Bazaar Package Importer
  • Author(s): Sebastian Dröge
  • Date: 2006-03-27 14:55:08 UTC
  • Revision ID: james.westby@ubuntu.com-20060327145508-3itoo3b0evmw5dpt
Tags: upstream-1.0
Import upstream version 1.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/python
 
2
# Pretend to be /usr/bin/id3v2 from id3lib, sort of.
 
3
# Copyright 2005 Joe Wreschnig
 
4
#
 
5
# This program is free software; you can redistribute it and/or modify
 
6
# it under the terms of version 2 of the GNU General Public License as
 
7
# published by the Free Software Foundation.
 
8
#
 
9
# $Id: mid3v2 2962 2006-03-13 07:24:05Z piman $
 
10
 
 
11
import os
 
12
import sys
 
13
import locale
 
14
 
 
15
from optparse import OptionParser, SUPPRESS_HELP
 
16
 
 
17
VERSION = (1, 0)
 
18
 
 
19
class ID3OptionParser(OptionParser):
 
20
    def __init__(self):
 
21
        mutagen_version = ".".join(map(str, mutagen.version))
 
22
        my_version = ".".join(map(str, VERSION))
 
23
        version = "mid3v2 %s\nUses Mutagen %s" % (my_version, mutagen_version)
 
24
        return OptionParser.__init__(
 
25
            self, version=version,
 
26
            usage="%prog [OPTION] [FILE]...",
 
27
            description="Mutagen-based replacement for id3lib's id3v2.")
 
28
 
 
29
    def format_help(self, *args, **kwargs):
 
30
        text = OptionParser.format_help(self, *args, **kwargs)
 
31
        return text + """\
 
32
You can set the value for any ID3v2 frame by using '--' and then a frame ID.
 
33
For example:
 
34
        mid3v2 --TIT3 "Monkey!" file.mp3
 
35
would set the "Subtitle/Description" frame to "Monkey!".
 
36
 
 
37
Any editing operation will cause the ID3 tag to be upgraded to ID3v2.4.
 
38
"""
 
39
 
 
40
def list_frames(option, opt, value, parser):
 
41
    items = mutagen.id3.Frames.items()
 
42
    items.sort()
 
43
    for name, frame in items:
 
44
        print "    --%s    %s" % (name, frame.__doc__.split("\n")[0])
 
45
    raise SystemExit
 
46
 
 
47
def list_frames_2_2(option, opt, value, parser):
 
48
    items = mutagen.id3.Frames_2_2.items()
 
49
    items.sort()
 
50
    for name, frame in items:
 
51
        print "    --%s    %s" % (name, frame.__doc__.split("\n")[0])
 
52
    raise SystemExit
 
53
 
 
54
def list_genres(option, opt, value, parser):
 
55
    for i, genre in enumerate(mutagen.id3.TCON.GENRES):
 
56
        print "%3d: %s" % (i, genre)
 
57
    raise SystemExit
 
58
 
 
59
def delete_tags(filenames, v1, v2):
 
60
    for filename in filenames:
 
61
        print "deleting ID3 tag info in %s" % filename
 
62
        mutagen.id3.delete(filename, v1, v2)
 
63
 
 
64
def write_files(edits, filenames):
 
65
    enc = locale.getpreferredencoding()
 
66
    edits = [(frame[2:], value.decode(enc)) for (frame, value) in edits]
 
67
 
 
68
    for filename in filenames:
 
69
        print "Writing", filename
 
70
        try: id3 = mutagen.id3.ID3(filename)
 
71
        except mutagen.id3.ID3NoHeaderError:
 
72
            print "No ID3 header found; creating a new tag"
 
73
            id3 = mutagen.id3.ID3()
 
74
        except Exception, err:
 
75
            print str(err)
 
76
            continue
 
77
        for frame, value in edits:
 
78
            if frame == "COMM":
 
79
                values = value.split(":")
 
80
                if len(values) == 1:
 
81
                    value, desc, lang = values[0], "", "eng"
 
82
                elif len(values) == 2:
 
83
                    desc, value, lang = values[0], values[1], "eng"
 
84
                else:
 
85
                    value = ":".join(values[1:-1])
 
86
                    desc, lang = values[0], values[-1]
 
87
                frame = mutagen.id3.COMM(
 
88
                    encoding=3, text=value, lang=lang, desc=desc)
 
89
            else:
 
90
                frame = mutagen.id3.Frames[frame](encoding=3, text=value)
 
91
            id3.loaded_frame(frame)
 
92
        id3.save(filename)
 
93
 
 
94
def list_tags(filenames):
 
95
    enc = locale.getpreferredencoding()
 
96
    for filename in filenames:
 
97
        print "IDv2 tag info for %s:" % filename
 
98
        try: id3 = mutagen.id3.ID3(filename, translate=False)
 
99
        except Exception, err: print str(err)
 
100
        else: print id3.pprint().encode(enc, "replace")
 
101
 
 
102
def list_tags_raw(filenames):
 
103
    enc = locale.getpreferredencoding()
 
104
    for filename in filenames:
 
105
        print "Raw IDv2 tag info for %s:" % filename
 
106
        try: id3 = mutagen.id3.ID3(filename, translate=False)
 
107
        except Exception, err: print str(err)
 
108
        else:
 
109
            for frame in id3.values(): print repr(frame)
 
110
 
 
111
def main(argv):
 
112
    parser = ID3OptionParser()
 
113
    parser.add_option(
 
114
        "-f", "--list-frames", action="callback", callback=list_frames,
 
115
        help="Display all possible frames for ID3v2.3 / ID3v2.4")
 
116
    parser.add_option(
 
117
        "--list-frames-v2.2", action="callback", callback=list_frames_2_2,
 
118
        help="Display all possible frames for ID3v2.2")
 
119
    parser.add_option(
 
120
        "-L", "--list-genres", action="callback", callback=list_genres,
 
121
        help="Lists all ID3v1 genres")
 
122
    parser.add_option(
 
123
        "-l", "--list", action="store_const", dest="action", const="list",
 
124
        help="Lists the tag(s) on the file(s)")
 
125
    parser.add_option(
 
126
        "--list-raw", action="store_const", dest="action", const="list-raw",
 
127
        help="Lists the tag(s) on the file(s) in Python format")
 
128
    parser.add_option(
 
129
        "-d", "--delete-v2", action="store_const", dest="action",
 
130
        const="delete-v2", help="Deletes ID3v2 tags")
 
131
    parser.add_option(
 
132
        "-s", "--delete-v1", action="store_const", dest="action",
 
133
        const="delete-v1", help="Deletes ID3v1 tags")
 
134
    parser.add_option(
 
135
        "-D", "--delete-all", action="store_const", dest="action",
 
136
        const="delete-v1-v2", help="Deletes ID3v1 and ID3v2 tags")
 
137
    parser.add_option(
 
138
        "-C", "--convert", action="store_const", dest="action",
 
139
        const="convert",
 
140
        help="Convert tags to ID3v2.4 (any editing will do this)")
 
141
 
 
142
    parser.add_option(
 
143
        "-a", "--artist", metavar='"ARTIST"', action="callback",
 
144
        help="Set the artist information", type="string",
 
145
        callback=lambda *args: args[3].edits.append(("--TPE1", args[2])))
 
146
    parser.add_option(
 
147
        "-A", "--album", metavar='"ALBUM"', action="callback",
 
148
        help="Set the album title information", type="string",
 
149
        callback=lambda *args: args[3].edits.append(("--TALB", args[2])))
 
150
    parser.add_option(
 
151
        "-t", "--song", metavar='"SONG"', action="callback",
 
152
        help="Set the song title information", type="string",
 
153
        callback=lambda *args: args[3].edits.append(("--TIT2", args[2])))
 
154
    parser.add_option(
 
155
        "-c", "--comment", metavar='"DESCRIPTION":"COMMENT":"LANGUAGE"',
 
156
        action="callback", help="Set the comment information", type="string",
 
157
        callback=lambda *args: args[3].edits.append(("--COMM", args[2])))
 
158
    parser.add_option(
 
159
        "-g", "--genre", metavar='"GENRE"', action="callback",
 
160
        help="Set the genre or genre number", type="string",
 
161
        callback=lambda *args: args[3].edits.append(("--TCON", args[2])))
 
162
    parser.add_option(
 
163
        "-y", "--year", "--date", metavar='YYYY[-MM-DD]', action="callback",
 
164
        help="Set the year/date", type="string",
 
165
        callback=lambda *args: args[3].edits.append(("--TDRC", args[2])))
 
166
    parser.add_option(
 
167
        "-T", "--track", metavar='"num/num"', action="callback",
 
168
        help="Set the track number/(optional) total tracks", type="string",
 
169
        callback=lambda *args: args[3].edits.append(("--TRCK", args[2])))
 
170
 
 
171
    for frame in mutagen.id3.Frames:
 
172
        if issubclass(mutagen.id3.Frames[frame], mutagen.id3.TextFrame):
 
173
            parser.add_option(
 
174
                "--" + frame, action="callback", help=SUPPRESS_HELP,
 
175
                type='string', metavar="value", # optparse blows up with this
 
176
                callback=lambda *args: args[3].edits.append(args[1:3]))
 
177
 
 
178
    parser.edits = []
 
179
    (options, args) = parser.parse_args(argv[1:])
 
180
 
 
181
    if args:
 
182
        if parser.edits: write_files(parser.edits, args)
 
183
        elif options.action in [None, 'list']: list_tags(args)
 
184
        elif options.action == "list-raw": list_tags_raw(args)
 
185
        elif options.action == "convert": write_files([], args)
 
186
        elif options.action.startswith("delete"):
 
187
            delete_tags(args, "v1" in options.action, "v2" in options.action)
 
188
        else: parser.print_help()
 
189
    else: parser.print_help()
 
190
 
 
191
if __name__ == "__main__":
 
192
    try: import mutagen, mutagen.id3
 
193
    except ImportError:
 
194
        # Run as ./mid3v2 out of tools/
 
195
        sys.path.append(os.path.abspath("../"))
 
196
        import mutagen, mutagen.id3
 
197
    main(sys.argv)