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

« back to all changes in this revision

Viewing changes to mutagen/__init__.py

  • 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/env python
 
2
#
 
3
# mutagen aims to be an all purpose media tagging library
 
4
# Copyright (C) 2005  Michael Urman
 
5
#
 
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.
 
9
#
 
10
# $Id: __init__.py 2971 2006-03-13 22:16:49Z piman $
 
11
#
 
12
 
 
13
version = (1, 0, 0)
 
14
 
 
15
"""
 
16
mutagen aims to be an all purpose tagging library.
 
17
 
 
18
    import mutagen.[format]
 
19
    metadata = mutagen.[format].Open(filename)
 
20
 
 
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.
 
25
"""
 
26
 
 
27
class Metadata(dict):
 
28
    """Abstract dict-like object that each format inherits for managing
 
29
    metadata."""
 
30
 
 
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
 
38
 
 
39
    def save(self, filename=None):
 
40
        """Save metadata to previously referenced or newly specified file"""
 
41
        raise NotImplementedError
 
42
 
 
43
    def delete(self):
 
44
        """Remove tags from the open file"""
 
45
        raise NotImplementedError
 
46
 
 
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."""
 
50
        from mmap import mmap
 
51
        assert 0 < size
 
52
        assert 0 <= offset
 
53
        fobj.seek(0, 2)
 
54
        filesize = fobj.tell()
 
55
        movesize = filesize - offset
 
56
        fobj.write('\x00' * size)
 
57
        fobj.flush()
 
58
        map = mmap(fobj.fileno(), filesize + size)
 
59
        try:
 
60
            map.move(offset+size, offset, movesize)
 
61
        except ValueError: # handle broken python on 64bit
 
62
            map.close()
 
63
            fobj.truncate(filesize)
 
64
 
 
65
            fobj.seek(offset)
 
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)
 
72
                fobj.write(backbuf)
 
73
                backbuf = frontbuf
 
74
            fobj.write(backbuf)
 
75
 
 
76
    _insert_space = staticmethod(_insert_space)
 
77
 
 
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."""
 
81
        from mmap import mmap
 
82
        assert 0 < size
 
83
        assert 0 <= offset
 
84
        fobj.seek(0, 2)
 
85
        filesize = fobj.tell()
 
86
        movesize = filesize - offset - size
 
87
        assert 0 <= movesize
 
88
        if movesize > 0:
 
89
            fobj.flush()
 
90
            map = mmap(fobj.fileno(), filesize)
 
91
            try:
 
92
                map.move(offset, offset+size, movesize)
 
93
            except ValueError: # handle broken python on 64bit
 
94
                fobj.seek(offset + size)
 
95
                buf = fobj.read(size)
 
96
                while len(buf):
 
97
                    fobj.seek(-len(buf) - size, 1)
 
98
                    fobj.write(buf)
 
99
                    fobj.seek(size, 1)
 
100
                    buf = fobj.read(size)
 
101
        fobj.truncate(filesize - size)
 
102
        fobj.flush()
 
103
    _delete_bytes = staticmethod(_delete_bytes)
 
104
 
 
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
 
109
    attribute."""
 
110
 
 
111
    info = None
 
112
    tags = None
 
113
 
 
114
    def __getitem__(self, key):
 
115
        if self.tags is None: raise KeyError, key
 
116
        else: return self.tags[key]
 
117
 
 
118
    def __setitem__(self, key, value):
 
119
        if self.tags is None: self.add_tags()
 
120
        self.tags[key] = value
 
121
 
 
122
    def __delitem__(self, key):
 
123
        if self.tags is None: raise KeyError, key
 
124
        else: del(self.tags[key])
 
125
 
 
126
    def keys(self):
 
127
        if self.tags is None: return []
 
128
        else: return self.tags.keys()
 
129
 
 
130
    def values(self):
 
131
        if self.tags is None: return []
 
132
        else: return self.tags.values()
 
133
 
 
134
    def items(self):
 
135
        if self.tags is None: return []
 
136
        else: return self.tags.items()
 
137
 
 
138
    def delete(self):
 
139
        """Remove tags from a file."""
 
140
        if self.tags is not None: self.tags.delete()
 
141
 
 
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")