3
# mutagen aims to be an all purpose media tagging library
4
# Copyright (C) 2005 Michael Urman
6
# This program is free software; you can redistribute it and/or modify
7
# it under the terms of version 2 of the GNU General Public License as
8
# published by the Free Software Foundation.
10
# $Id: __init__.py 2971 2006-03-13 22:16:49Z piman $
16
mutagen aims to be an all purpose tagging library.
18
import mutagen.[format]
19
metadata = mutagen.[format].Open(filename)
21
metadata acts like a dictionary of tags in the file. Tags are generally a
22
list of string-like values, but may have additional methods available
23
depending on tag or format. They may also be entirely different objects
24
for certain keys, again depending on format.
28
"""Abstract dict-like object that each format inherits for managing
31
def __init__(self, filename=None, fileobj=None):
32
"""Initializes a tag structure. If fileobj is specified it is the
33
source and must include a "read" method or an AttributeError will be
34
raised. Otherwise if filename is specified it must exist and be
35
readable or normal exceptions will be thrown. Finally for various kinds
36
of bad data, a subclass of ValueError may be thrown."""
37
raise NotImplementedError
39
def save(self, filename=None):
40
"""Save metadata to previously referenced or newly specified file"""
41
raise NotImplementedError
44
"""Remove tags from the open file"""
45
raise NotImplementedError
47
def _insert_space(fobj, size, offset):
48
"""insert size bytes of empty space starting at offset. fobj must be
49
an open file object, open rb+ or equivalent."""
54
filesize = fobj.tell()
55
movesize = filesize - offset
56
fobj.write('\x00' * size)
58
map = mmap(fobj.fileno(), filesize + size)
60
map.move(offset+size, offset, movesize)
61
except ValueError: # handle broken python on 64bit
63
fobj.truncate(filesize)
66
backbuf = fobj.read(size)
67
if len(backbuf) < size:
68
fobj.write('\x00' * (size - len(backbuf)))
69
while len(backbuf) == size:
70
frontbuf = fobj.read(size)
71
fobj.seek(-len(frontbuf), 1)
76
_insert_space = staticmethod(_insert_space)
78
def _delete_bytes(fobj, size, offset):
79
"""delete size bytes of data starting at offset. fobj must be
80
an open file object, open rb+ or equivalent."""
85
filesize = fobj.tell()
86
movesize = filesize - offset - size
90
map = mmap(fobj.fileno(), filesize)
92
map.move(offset, offset+size, movesize)
93
except ValueError: # handle broken python on 64bit
94
fobj.seek(offset + size)
97
fobj.seek(-len(buf) - size, 1)
100
buf = fobj.read(size)
101
fobj.truncate(filesize - size)
103
_delete_bytes = staticmethod(_delete_bytes)
105
class FileType(object):
106
"""Abstract object that provides a specific type of file format.
107
Any metadata tags are exposed as .tags (and looks basically like a dict),
108
and the audio info is exposed as .info, which has at least a length
114
def __getitem__(self, key):
115
if self.tags is None: raise KeyError, key
116
else: return self.tags[key]
118
def __setitem__(self, key, value):
119
if self.tags is None: self.add_tags()
120
self.tags[key] = value
122
def __delitem__(self, key):
123
if self.tags is None: raise KeyError, key
124
else: del(self.tags[key])
127
if self.tags is None: return []
128
else: return self.tags.keys()
131
if self.tags is None: return []
132
else: return self.tags.values()
135
if self.tags is None: return []
136
else: return self.tags.items()
139
"""Remove tags from a file."""
140
if self.tags is not None: self.tags.delete()
142
def save(self, filename=None, **kwargs):
143
if filename is None: filename = self.filename
144
if self.tags is not None:
145
self.tags.save(filename, **kwargs)
146
else: raise ValueError("no tags in file")