Esempio n. 1
0
    def packets(self, from_beginning=True):
        """Yields one fully reassembled Ogg packet per pass.

        Packets are returned as binary strings."""

        if (from_beginning):
            self.stream.seek(0, 0)

        segment = cStringIO.StringIO()

        while (True):
            try:
                page = OggStreamReader.OGGS.parse_stream(self.stream)

                for length in page.segment_lengths:
                    if (length == 255):
                        segment.write(self.stream.read(length))
                    else:
                        segment.write(self.stream.read(length))
                        yield segment.getvalue()
                        segment = cStringIO.StringIO()

            except Con.core.FieldError:
                break
            except Con.ConstError:
                break
Esempio n. 2
0
    def query(self, disc_id):
        matches = []

        self.messenger.info(
            _(u"Sending Disc ID \"%(disc_id)s\" to server \"%(server)s\"") % \
                {"disc_id":str(disc_id).decode('ascii'),
                 "server":self.server.decode('ascii','replace')})

        self.write("cddb query " + disc_id.freedb_id())
        data = cStringIO.StringIO(self.read())
        (code, msg) = self.__parse_line__(data.readline())
        if (code == 200):
            matches.append(msg)
        elif ((code == 211) or (code == 210)):
            while (msg != "."):
                (code, msg) = self.__parse_line__(data.readline())
                if (msg != "."):
                    matches.append(msg)

        if (len(matches) == 1):
            self.messenger.info(_(u"1 match found"))
        else:
            self.messenger.info(_(u"%s matches found") % (len(matches)))

        return map(lambda m: m.split(" ", 2), matches)
Esempio n. 3
0
    def query(self, disc_id):
        """Given a DiscID, performs an album query and returns matches.

        Each match is a (category, id) pair, which the user may
        need to decide between."""

        matches = []

        self.messenger.info(
            _(u"Sending Disc ID \"%(disc_id)s\" to server \"%(server)s\"") % \
                {"disc_id": str(disc_id).decode('ascii'),
                 "server": self.server.decode('ascii', 'replace')})

        self.write("cddb query " + disc_id.freedb_id())
        data = cStringIO.StringIO(self.read())
        (code, msg) = self.__parse_line__(data.readline())
        if (code == 200):
            matches.append(msg)
        elif ((code == 211) or (code == 210)):
            while (msg != "."):
                (code, msg) = self.__parse_line__(data.readline())
                if (msg != "."):
                    matches.append(msg)

        if (len(matches) == 1):
            self.messenger.info(_(u"1 match found"))
        else:
            self.messenger.info(_(u"%s matches found") % (len(matches)))

        return map(lambda m: m.split(" ", 2), matches)
Esempio n. 4
0
    def __populate_metadata__(self):
        #set up some default values
        self.__bits_per_sample__ = 16
        self.__channels__ = 2
        self.__channel_mask__ = 0x3
        self.__sample_rate__ = 44100
        self.__total_frames__ = 0
        self.__blocks__ = []
        self.__format__ = None

        #grab a few pieces of technical metadata from the Shorten file itself
        #which requires a dry-run through the decoder
        try:
            decoder = audiotools.decoders.SHNDecoder(self.filename)
            try:

                self.__bits_per_sample__ = decoder.bits_per_sample
                self.__channels__ = decoder.channels
                (self.__total_frames__,
                 self.__blocks__) = decoder.metadata()
            finally:
                decoder.close()

            try:
                self.__channel_mask__ = ChannelMask.from_channels(
                    self.__channels__)
            except ValueError:
                self.__channel_mask__ = 0
        except (ValueError, IOError):
            #if we hit an error in SHNDecoder while reading
            #technical metadata, the default values will have to do
            return

        #the remainder requires parsing the file's VERBATIM blocks
        #which may contain Wave, AIFF or Sun AU info
        if (self.__blocks__[0] is not None):
            header = cStringIO.StringIO(self.__blocks__[0])
            for format in WaveAudio, AiffAudio:
                header.seek(0, 0)
                if (format.is_type(header)):
                    self.__format__ = format
                    break
            if (self.__format__ is WaveAudio):
                for (chunk_id, chunk_data) in self.__wave_chunks__():
                    if (chunk_id == 'fmt '):
                        fmt_chunk = WaveAudio.FMT_CHUNK.parse(chunk_data)
                        self.__sample_rate__ = fmt_chunk.sample_rate
                        if (fmt_chunk.compression == 0xFFFE):
                            self.__channel_mask__ = \
                                WaveAudio.fmt_chunk_to_channel_mask(
                                fmt_chunk.channel_mask)
            elif (self.__format__ is AiffAudio):
                for (chunk_id, chunk_data) in self.__aiff_chunks__():
                    if (chunk_id == 'COMM'):
                        comm_chunk = AiffAudio.COMM_CHUNK.parse(chunk_data)
                        self.__sample_rate__ = comm_chunk.sample_rate
Esempio n. 5
0
 def read_data(self, category, id, output):
     self.write("cddb read " + category + " " + id)
     data = cStringIO.StringIO(self.read())
     (code, msg) = self.__parse_line__(data.readline())
     if (code == 210):
         line = data.readline()
         while (line.strip() != "."):
             output.write(line)
             line = data.readline()
     else:
         print >> sys.stderr, (code, msg)
Esempio n. 6
0
    def packets(self, from_beginning=True):
        if (from_beginning):
            self.stream.seek(0, 0)

        segment = cStringIO.StringIO()

        while (True):
            try:
                page = OggStreamReader.OGGS.parse_stream(self.stream)

                for length in page.segment_lengths:
                    if (length == 255):
                        segment.write(self.stream.read(length))
                    else:
                        segment.write(self.stream.read(length))
                        yield segment.getvalue()
                        segment = cStringIO.StringIO()

            except construct.core.FieldError:
                break
            except construct.ConstError:
                break
Esempio n. 7
0
    def __populate_metadata__(self):
        # Alteration for BootTunes:
        # Since the vast majority of files will match the defaults, and because this method crashes
        # Windows 7 and locks up Mac, just go with the defaults.          
        self.__bits_per_sample__ = 16
        self.__channels__ = 2
        self.__channel_mask__ = 0x3
        self.__sample_rate__ = 44100
        self.__total_frames__ = 0
        self.__blocks__ = []
        self.__format__ = None
        return        

        #grab a few pieces of technical metadata from the Shorten file itself
        #which requires a dry-run through the decoder
        decoder = audiotools.decoders.SHNDecoder(self.filename)
        self.__bits_per_sample__ = decoder.bits_per_sample
        self.__channels__ = decoder.channels
        (self.__total_frames__,
         self.__blocks__) = decoder.metadata()
        decoder.close()

        #set up some default values
        self.__sample_rate__ = 44100
        try:
            self.__channel_mask__ = ChannelMask.from_channels(self.__channels__)
        except ValueError:
            self.__channel_mask__ = 0
        self.__format__ = None

        #the remainder requires parsing the file's VERBATIM blocks
        #which may contain Wave, AIFF or Sun AU info
        if (self.__blocks__[0] is not None):
            header = cStringIO.StringIO(self.__blocks__[0])
            for format in WaveAudio,AiffAudio:
                header.seek(0,0)
                if (format.is_type(header)):
                    self.__format__ = format
                    break
            if (self.__format__ is WaveAudio):
                for (chunk_id,chunk_data) in self.__wave_chunks__():
                    if (chunk_id == 'fmt '):
                        fmt_chunk = WaveAudio.FMT_CHUNK.parse(chunk_data)
                        self.__sample_rate__ = fmt_chunk.sample_rate
                        if (fmt_chunk.compression == 0xFFFE):
                            self.__channel_mask__ = WaveAudio.fmt_chunk_to_channel_mask(fmt_chunk.channel_mask)
            elif (self.__format__ is AiffAudio):
                for (chunk_id,chunk_data) in self.__aiff_chunks__():
                    if (chunk_id == 'COMM'):
                        comm_chunk = AiffAudio.COMM_CHUNK.parse(chunk_data)
                        self.__sample_rate__ = comm_chunk.sample_rate
Esempio n. 8
0
    def set_metadata(self, metadata):
        """Takes a MetaData object and sets this track's metadata.

        This metadata includes track name, album name, and so on.
        Raises IOError if unable to write the file."""

        comment = VorbisComment.converted(metadata)

        if (comment is None):
            return

        reader = OggStreamReader(file(self.filename, 'rb'))
        new_file = cStringIO.StringIO()
        writer = OggStreamWriter(new_file)

        pages = reader.pages()

        #transfer our old header
        (header_page, header_data) = pages.next()
        writer.write_page(header_page, header_data)

        #skip the existing comment packet
        (page, data) = pages.next()
        while (page.segment_lengths[-1] == 255):
            (page, data) = pages.next()

        #write the pages for our new comment packet
        comment_pages = OggStreamWriter.build_pages(
            0, header_page.bitstream_serial_number,
            header_page.page_sequence_number + 1, comment.build())

        for (page, data) in comment_pages:
            writer.write_page(page, data)

        #write the rest of the pages, re-sequenced and re-checksummed
        sequence_number = comment_pages[-1][0].page_sequence_number + 1
        for (i, (page, data)) in enumerate(pages):
            page.page_sequence_number = i + sequence_number
            page.checksum = OggStreamReader.calculate_ogg_checksum(page, data)
            writer.write_page(page, data)

        reader.close()

        #re-write the file with our new data in "new_file"
        f = file(self.filename, "wb")
        f.write(new_file.getvalue())
        f.close()
        writer.close()

        self.__read_metadata__()
Esempio n. 9
0
    def read_data(self, category, id, output):
        """Reads the FreeDB entry matching category and id to output.

        category and id are raw strings, as returned by query().
        output is an open file object.
        """

        self.write("cddb read " + category + " " + id)
        data = cStringIO.StringIO(self.read())
        (code, msg) = self.__parse_line__(data.readline())
        if (code == 210):
            line = data.readline()
            while (line.strip() != "."):
                output.write(line)
                line = data.readline()
        else:
            print >> sys.stderr, (code, msg)
Esempio n. 10
0
    def to_string(self):
        def write_field(f, key, value):
            chars = list(value)
            encoded_value = "%s=" % (key)

            while ((len(chars) > 0) and
                   (len(encoded_value + chars[0].encode('utf-8', 'replace')) <
                    XMCD.LINE_LENGTH)):
                encoded_value += chars.pop(0).encode('utf-8', 'replace')

            f.write("%s\r\n" % (encoded_value))
            if (len(chars) > 0):
                write_field(f, key, u"".join(chars))

        output = cStringIO.StringIO()

        for comment in self.comments:
            output.write(comment.encode('utf-8'))
            output.write('\r\n')

        fields = set(self.fields.keys())
        for field in ['DISCID', 'DTITLE', 'DYEAR', 'DGENRE']:
            if (field in fields):
                write_field(output, field, self.fields[field])
                fields.remove(field)

        for i in xrange(len(self)):
            field = 'TTITLE%d' % (i)
            if (field in fields):
                write_field(output, field, self.fields[field])
                fields.remove(field)

        if ('EXTD' in fields):
            write_field(output, 'EXTD', self.fields['EXTD'])
            fields.remove('EXTD')

        for i in xrange(len(self)):
            field = 'EXTT%d' % (i)
            if (field in fields):
                write_field(output, field, self.fields[field])
                fields.remove(field)

        for field in fields:
            write_field(output, field, self.fields[field])

        return output.getvalue()
Esempio n. 11
0
    def __wave_chunks__(self):
        total_size = sum([len(block) for block in self.__blocks__
                          if block is not None])
        wave_data = cStringIO.StringIO("".join([block for block in
                                                self.__blocks__
                                                if block is not None]))

        wave_data.read(12)  # skip the RIFFxxxxWAVE header data
        total_size -= 12

        #iterate over all the non-data chunks
        while (total_size > 0):
            header = WaveAudio.CHUNK_HEADER.parse_stream(wave_data)
            total_size -= 8
            if (header.chunk_id != 'data'):
                yield (header.chunk_id, wave_data.read(header.chunk_length))
                total_size -= header.chunk_length
            else:
                continue
Esempio n. 12
0
    def __aiff_chunks__(self):
        total_size = sum([len(block) for block in self.__blocks__
                          if block is not None])
        aiff_data = cStringIO.StringIO("".join([block for block in
                                                self.__blocks__
                                                if block is not None]))

        aiff_data.read(12)  # skip the FORMxxxxAIFF header data
        total_size -= 12

        #iterate over all the non-ssnd chunks
        while (total_size > 0):
            header = AiffAudio.CHUNK_HEADER.parse_stream(aiff_data)
            total_size -= 8
            if (header.chunk_id != 'SSND'):
                yield (header.chunk_id, aiff_data.read(header.chunk_length))
                total_size -= header.chunk_length
            else:
                #not sure what Shorten does with the first 8 bytes
                #of the SSND chunk
                #it'll be a mess if it turns those into audio data
                continue
Esempio n. 13
0
 def __parse_image__(self, key, type):
     data = cStringIO.StringIO(str(self[key]))
     description = construct.CString(None).parse_stream(data).decode(
         'utf-8', 'replace')
     data = data.read()
     return Image.new(data, description, type)
Esempio n. 14
0
    def set_metadata(self, metadata):
        metadata = VorbisComment.converted(metadata)

        if (metadata is None): return

        reader = OggStreamReader(file(self.filename, 'rb'))
        new_file = cStringIO.StringIO()
        writer = OggStreamWriter(new_file)
        current_sequence_number = 0

        pages = reader.pages()

        #transfer our old header
        #this must always be the first packet and the first page
        (header_page, header_data) = pages.next()
        writer.write_page(header_page, header_data)
        current_sequence_number += 1

        #grab the current "comment" and "setup headers" packets
        #these may take one or more pages,
        #but will always end on a page boundary
        del (pages)
        packets = reader.packets(from_beginning=False)

        comment_packet = packets.next()
        headers_packet = packets.next()

        #write the pages for our new "comment" packet
        for (page, data) in OggStreamWriter.build_pages(
                0, header_page.bitstream_serial_number,
                current_sequence_number,
                VorbisAudio.COMMENT_HEADER.build(
                    construct.Container(packet_type=3, vorbis='vorbis')) +
                metadata.build()):
            writer.write_page(page, data)
            current_sequence_number += 1

        #write the pages for the old "setup headers" packet
        for (page, data) in OggStreamWriter.build_pages(
                0, header_page.bitstream_serial_number,
                current_sequence_number, headers_packet):
            writer.write_page(page, data)
            current_sequence_number += 1

        #write the rest of the pages, re-sequenced and re-checksummed
        del (packets)
        pages = reader.pages(from_beginning=False)

        for (i, (page, data)) in enumerate(pages):
            page.page_sequence_number = i + current_sequence_number
            page.checksum = OggStreamReader.calculate_ogg_checksum(page, data)
            writer.write_page(page, data)

        reader.close()

        #re-write the file with our new data in "new_file"
        f = file(self.filename, "wb")
        f.write(new_file.getvalue())
        f.close()
        writer.close()

        self.__read_metadata__()