How to use the tinytag.tinytag.TinyTag function in tinytag

To help you get started, we’ve selected a few tinytag examples, based on popular ways it is used in public projects.

Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.

github devsnd / tinytag / tinytag / tinytag.py View on Github external
self.bitrate = self.filesize / self.duration * 8 / 1024
            elif block_type == Flac.METADATA_VORBIS_COMMENT and not skip_tags:
                oggtag = Ogg(fh, 0)
                oggtag._parse_vorbis_comment(fh)
                self.update(oggtag)
            elif block_type >= 127:
                return  # invalid block type
            else:
                fh.seek(size, 1)  # seek over this block

            if is_last_block:
                return
            header_data = fh.read(4)


class Wma(TinyTag):
    ASF_CONTENT_DESCRIPTION_OBJECT = b'3&\xb2u\x8ef\xcf\x11\xa6\xd9\x00\xaa\x00b\xcel'
    ASF_EXTENDED_CONTENT_DESCRIPTION_OBJECT = b'@\xa4\xd0\xd2\x07\xe3\xd2\x11\x97\xf0\x00\xa0\xc9^\xa8P'
    STREAM_BITRATE_PROPERTIES_OBJECT = b'\xceu\xf8{\x8dF\xd1\x11\x8d\x82\x00`\x97\xc9\xa2\xb2'
    ASF_FILE_PROPERTY_OBJECT = b'\xa1\xdc\xab\x8cG\xa9\xcf\x11\x8e\xe4\x00\xc0\x0c Se'
    ASF_STREAM_PROPERTIES_OBJECT = b'\x91\x07\xdc\xb7\xb7\xa9\xcf\x11\x8e\xe6\x00\xc0\x0c Se'
    STREAM_TYPE_ASF_AUDIO_MEDIA = b'@\x9ei\xf8M[\xcf\x11\xa8\xfd\x00\x80_\\D+'
    # see:
    # http://web.archive.org/web/20131203084402/http://msdn.microsoft.com/en-us/library/bb643323.aspx
    # and (japanese, but none the less helpful)
    # http://uguisu.skr.jp/Windows/format_asf.html

    def __init__(self, filehandler, filesize):
        TinyTag.__init__(self, filehandler, filesize)
        self.__tag_parsed = False

    def _determine_duration(self, fh):
github devsnd / tinytag / tinytag / tinytag.py View on Github external
for segsize in segsizes:  # read all segments
                total += segsize
                if total < 255:  # less than 255 bytes means end of page
                    yield previous_page + fh.read(total)
                    previous_page = b''
                    total = 0
            if total != 0:
                if total % 255 == 0:
                    previous_page += fh.read(total)
                else:
                    yield previous_page + fh.read(total)
                    previous_page = b''
            header_data = fh.read(27)


class Wave(TinyTag):
    # https://sno.phy.queensu.ca/~phil/exiftool/TagNames/RIFF.html
    riff_mapping = {
        b'INAM': 'title',
        b'TITL': 'title',
        b'IART': 'artist',
        b'ICMT': 'comment',
        b'ICRD': 'year',
        b'IGNR': 'genre',
        b'TRCK': 'track',
        b'PRT1': 'track',
        b'PRT2': 'track_number',
        b'YEAR': 'year',
        # riff format is lacking the composer field.
    }

    def __init__(self, filehandler, filesize):
github devsnd / tinytag / tinytag / tinytag.py View on Github external
def get(cls, filename, tags=True, duration=True, image=False):
        filename = os.path.expanduser(str(filename))  # cast pathlib.Path to str
        size = os.path.getsize(filename)
        if not size > 0:
            return TinyTag(None, 0)
        if cls == TinyTag:  # if `get` is invoked on TinyTag, find parser by ext
            parser_class = cls._get_parser_for_filename(filename, exception=True)
        else:  # otherwise use the class on which `get` was invoked
            parser_class = cls
        with io.open(filename, 'rb') as af:
            tag = parser_class(af, size)
            tag.load(tags=tags, duration=duration, image=image)
            return tag
github devsnd / cherrymusic / tinytag / tinytag.py View on Github external
def _determine_duration(self, fh):
        raise NotImplementedError()

    def _parse_tag(self, fh):
        raise NotImplementedError()

    def update(self, other):
        """update the values of this tag with the values from another tag"""
        for key in ['track', 'track_total', 'title', 'artist',
                    'album', 'year', 'duration']:
            if not getattr(self, key) and getattr(other, key):
                setattr(self, key, getattr(other, key))


class ID3(TinyTag):
    FID_TO_FIELD = {  # Mapping from Frame ID to a field of the TinyTag
        'TRCK': 'track',  'TRK': 'track',
        'TYER': 'year',   'TYE': 'year',
        'TALB': 'album',  'TAL': 'album',
        'TPE1': 'artist', 'TP1': 'artist',
        'TIT2': 'title',  'TT2': 'title',
    }
    _MAX_ESTIMATION_SEC = 30

    def __init__(self, filehandler, filesize):
        TinyTag.__init__(self, filehandler, filesize)
        # save position after the ID3 tag for duration mesurement speedup
        self._bytepos_after_id3v2 = 0

    @classmethod
    def set_estimation_precision(cls, estimation_in_seconds):
github devsnd / tinytag / tinytag / tinytag.py View on Github external
elif callable(sub_path):
                for fieldname, value in sub_path(fh.read(atom_size)).items():
                    if DEBUG:
                        stderr(' ' * 4 * len(curr_path), 'FIELD: ', fieldname)
                    if fieldname:
                        self._set_field(fieldname, value)
            # if no action was specified using dict or callable, jump over atom
            else:
                fh.seek(atom_size, os.SEEK_CUR)
            # check if we have reached the end of this branch:
            if stop_pos and fh.tell() >= stop_pos:
                return  # return to parent (next parent node in tree)
            atom_header = fh.read(header_size)  # read next atom


class ID3(TinyTag):
    FRAME_ID_TO_FIELD = {  # Mapping from Frame ID to a field of the TinyTag
        'COMM': 'comment', 'COM': 'comment',
        'TRCK': 'track',  'TRK': 'track',
        'TYER': 'year',   'TYE': 'year',
        'TALB': 'album',  'TAL': 'album',
        'TPE1': 'artist', 'TP1': 'artist',
        'TIT2': 'title',  'TT2': 'title',
        'TCON': 'genre',  'TPOS': 'disc',
        'TPE2': 'albumartist', 'TCOM': 'composer',
    }
    IMAGE_FRAME_IDS = {'APIC', 'PIC'}
    PARSABLE_FRAME_IDS = set(FRAME_ID_TO_FIELD.keys()).union(IMAGE_FRAME_IDS)
    _MAX_ESTIMATION_SEC = 30
    _CBR_DETECTION_FRAME_COUNT = 5
    _USE_XING_HEADER = True  # much faster, but can be deactivated for testing
github devsnd / cherrymusic / tinytag / tinytag.py View on Github external
ret <<= 7       # bit is always set to zero, so it has to be
            ret += b & 127  # removed.
        return ret          #


class StringWalker(object):
    """file obj like string. probably there are buildins doing this already"""
    def __init__(self, string):
        self.string = string

    def read(self, nbytes):
        retstring, self.string = self.string[:nbytes], self.string[nbytes:]
        return retstring


class Ogg(TinyTag):
    def __init__(self, filehandler, filesize):
        TinyTag.__init__(self, filehandler, filesize)
        self._tags_parsed = False
        self._max_samplenum = 0  # maximum sample position ever read

    def _determine_duration(self, fh):
        MAX_PAGE_SIZE = 65536  # https://xiph.org/ogg/doc/libogg/ogg_page.html
        if not self._tags_parsed:
            self._parse_tag(fh)  # determine sample rate
            fh.seek(0)           # and rewind to start
        if self.filesize > MAX_PAGE_SIZE:
            fh.seek(-MAX_PAGE_SIZE, 2)  # go to last possible page position
        while True:
            b = fh.read(1)
            if len(b) == 0:
                return  # EOF
github devsnd / tinytag / tinytag / tinytag.py View on Github external
field = sub_fh.read(4)
            elif subchunkid == b'id3 ' or subchunkid == b'ID3 ':
                id3 = ID3(fh, 0)
                id3._parse_id3v2(fh)
                self.update(id3)
            else:  # some other chunk, just skip the data
                fh.seek(subchunksize, 1)
            chunk_header = fh.read(8)
        self._duration_parsed = True

    def _parse_tag(self, fh):
        if not self._duration_parsed:
            self._determine_duration(fh)  # parse whole file to determine tags:(


class Flac(TinyTag):
    METADATA_STREAMINFO = 0
    METADATA_VORBIS_COMMENT = 4

    def load(self, tags, duration, image=False):
        header = self._filehandler.peek(4)
        if header[:3] == b'ID3':  # parse ID3 header if it exists
            id3 = ID3(self._filehandler, 0)
            id3._parse_id3v2(self._filehandler)
            self.update(id3)
            header = self._filehandler.peek(4)  # after ID3 should be fLaC
        if header[:4] != b'fLaC':
            raise TinyTagException('Invalid flac header')
        self._filehandler.seek(4, os.SEEK_CUR)
        self._determine_duration(self._filehandler, skip_tags=not tags)

    def _determine_duration(self, fh, skip_tags=False):
github devsnd / tinytag / tinytag / tinytag.py View on Github external
def update(self, other):
        # update the values of this tag with the values from another tag
        for key in ['track', 'track_total', 'title', 'artist',
                    'album', 'albumartist', 'year', 'duration',
                    'genre', 'disc', 'disc_total', 'comment', 'composer']:
            if not getattr(self, key) and getattr(other, key):
                setattr(self, key, getattr(other, key))

    @staticmethod
    def _unpad(s):
        # strings in mp3 and asf *may* be terminated with a zero byte at the end
        return s[:s.index('\x00')] if '\x00' in s else s


class MP4(TinyTag):
    # see: https://developer.apple.com/library/mac/documentation/QuickTime/QTFF/Metadata/Metadata.html
    # and: https://developer.apple.com/library/mac/documentation/QuickTime/QTFF/QTFFChap2/qtff2.html

    class Parser:
        # https://developer.apple.com/library/mac/documentation/QuickTime/QTFF/Metadata/Metadata.html#//apple_ref/doc/uid/TP40000939-CH1-SW34
        ATOM_DECODER_BY_TYPE = {
            0: lambda x: x,  # 'reserved',
            1: lambda x: codecs.decode(x, 'utf-8', 'replace'),   # UTF-8
            2: lambda x: codecs.decode(x, 'utf-16', 'replace'),  # UTF-16
            3: lambda x: codecs.decode(x, 's/jis', 'replace'),   # S/JIS
            # 16: duration in millis
            13: lambda x: x,  # JPEG
            14: lambda x: x,  # PNG
            21: lambda x: struct.unpack('>b', x)[0],  # BE Signed int
            22: lambda x: struct.unpack('>B', x)[0],  # BE Unsigned int
            23: lambda x: struct.unpack('>f', x)[0],  # BE Float32