Exemplo n.º 1
0
 def do_scan():
     yield "%i | Begin.\n" % int(time.time())
     all_files = {}
     for root, dirs, files in os.walk(unicode(app.config["MUSIC_PATH"])):
         if len(files) != 0:
             yield "%i | Scanning [%s].\n" % (int(time.time()), encode_filename(root))
         for name in files:
             name = encode_filename(os.path.join(root, name))
             all_files[name] = True
             song = Song.query.get(name)
             if song != None:
                 stat = os.stat(name)
                 if song.lastmodified == stat.st_mtime and song.filesize == stat.st_size:
                     continue
             else:
                 song = Song()
             try:
                 tags = readtags(name)
             except:
                 tags = None
             if tags == None:
                 yield "%i | Skipping [%s].\n" % (int(time.time()), name)
                 continue
             song.sync_picard(tags)
             db.session.add(song)
             yield "%i | Adding [%s].\n" % (int(time.time()), encode_filename(song.filename))
     for song in db.session.query(Song.filename):
         if song.filename not in all_files:
             Song.query.filter(Song.filename == song.filename).delete(False)
             yield "%i | Removing [%s].\n" % (int(time.time()), encode_filename(song.filename))
     db.session.commit()
     yield "%i | Done.\n" % int(time.time())
Exemplo n.º 2
0
 def _save(self, filename, metadata, settings):
     """Save metadata to the file."""
     self.log.debug("Saving file %r", filename)
     try:
         tags = mutagen.apev2.APEv2(encode_filename(filename))
     except mutagen.apev2.APENoHeaderError:
         tags = mutagen.apev2.APEv2()
     if settings["clear_existing_tags"]:
         tags.clear()
     elif settings['save_images_to_tags'] and metadata.images:
         for name, value in tags.items():
             if name.lower().startswith('cover art') and value.kind == mutagen.apev2.BINARY:
                 del tags[name]
     temp = {}
     for name, value in metadata.items():
         if name.startswith("~"):
             continue
         if name.startswith('lyrics:'):
             name = 'Lyrics'
         elif name == "date":
             name = "Year"
         # tracknumber/totaltracks => Track
         elif name == 'tracknumber':
             name = 'Track'
             if 'totaltracks' in metadata:
                 value = '%s/%s' % (value, metadata['totaltracks'])
         # discnumber/totaldiscs => Disc
         elif name == 'discnumber':
             name = 'Disc'
             if 'totaldiscs' in metadata:
                 value = '%s/%s' % (value, metadata['totaldiscs'])
         elif name in ('totaltracks', 'totaldiscs'):
             continue
         # "performer:Piano=Joe Barr" => "Performer=Joe Barr (Piano)"
         elif name.startswith('performer:') or name.startswith('comment:'):
             name, desc = name.split(':', 1)
             name = name.title()
             if desc:
                 value += ' (%s)' % desc
         elif name in self.__rtranslate:
             name = self.__rtranslate[name]
         else:
             name = name.title()
         temp.setdefault(name, []).append(value)
     for name, values in temp.items():
         tags[str(name)] = values
     if settings['save_images_to_tags']:
         for mime, data, _fname in metadata.images:
             cover_filename = 'Cover Art (Front)'
             cover_filename += mimetype.get_extension(mime, '.jpg')
             tags['Cover Art (Front)'] = cover_filename + '\0' + data
             break # can't save more than one item with the same name
                   # (mp3tags does this, but it's against the specs)
     tags.save(encode_filename(filename))
Exemplo n.º 3
0
    def _save(self, filename, metadata, settings):
        self.log.debug("Saving file %r", filename)
        file = MP4(encode_filename(self.filename))
        if file.tags is None:
            file.add_tags()

        if settings["clear_existing_tags"]:
            file.tags.clear()

        for name, values in metadata.rawitems():
            if name.startswith('lyrics:'):
                name = 'lyrics'
            if name in self.__r_text_tags:
                file.tags[self.__r_text_tags[name]] = values
            elif name in self.__r_bool_tags:
                file.tags[self.__r_bool_tags[name]] = (values[0] == '1')
            elif name in self.__r_int_tags:
                try:
                    file.tags[self.__r_int_tags[name]] = [int(value) for value in values]
                except ValueError:
                    pass
            elif name in self.__r_freeform_tags:
                values = [v.encode("utf-8") for v in values]
                file.tags[self.__r_freeform_tags[name]] = values
            elif name == "musicip_fingerprint":
                file.tags["----:com.apple.iTunes:fingerprint"] = ["MusicMagic Fingerprint%s" % str(v) for v in values]

        if "tracknumber" in metadata:
            if "totaltracks" in metadata:
                file.tags["trkn"] = [(int(metadata["tracknumber"]),
                                      int(metadata["totaltracks"]))]
            else:
                file.tags["trkn"] = [(int(metadata["tracknumber"]), 0)]

        if "discnumber" in metadata:
            if "totaldiscs" in metadata:
                file.tags["disk"] = [(int(metadata["discnumber"]),
                                      int(metadata["totaldiscs"]))]
            else:
                file.tags["disk"] = [(int(metadata["discnumber"]), 0)]

        if settings['save_images_to_tags']:
            covr = []
            for mime, data, _fname in metadata.images:
                if mime == "image/jpeg":
                    covr.append(MP4Cover(data, MP4Cover.FORMAT_JPEG))
                elif mime == "image/png":
                    covr.append(MP4Cover(data, MP4Cover.FORMAT_PNG))
            if covr:
                file.tags["covr"] = covr

        file.save()
Exemplo n.º 4
0
    def _load(self, filename):
        self.log.debug("Loading file %r", filename)
        f = wave.open(encode_filename(filename), "rb")
        metadata = Metadata()
        metadata['~#channels'] = f.getnchannels()
        metadata['~#bits_per_sample'] = f.getsampwidth() * 8
        metadata['~#sample_rate'] = f.getframerate()
        metadata.length = 1000 * f.getnframes() / f.getframerate()
        metadata['~format'] = 'Microsoft WAVE'

        file = Wave(f)

        self._info(metadata, file)
        return metadata
Exemplo n.º 5
0
 def _load(self, filename):
     self.log.debug("Loading file %r", filename)
     file = self._File(encode_filename(filename))
     metadata = Metadata()
     if file.tags:
         for origname, values in file.tags.items():
             if origname.lower().startswith("cover art") and values.kind == mutagen.apev2.BINARY:
                 if '\0' in values.value:
                     descr, data = values.value.split('\0', 1)
                     mime = mimetype.get_from_data(data, descr, 'image/jpeg')
                     metadata.add_image(mime, data)
             # skip EXTERNAL and BINARY values
             if values.kind != mutagen.apev2.TEXT:
                 continue
             for value in values:
                 name = origname
                 if name == "Year":
                     name = "date"
                     value = sanitize_date(value)
                 elif name == "Track":
                     name = "tracknumber"
                     track = value.split("/")
                     if len(track) > 1:
                         metadata["totaltracks"] = track[1]
                         value = track[0]
                 elif name == "Disc":
                     name = "discnumber"
                     disc = value.split("/")
                     if len(disc) > 1:
                         metadata["totaldiscs"] = disc[1]
                         value = disc[0]
                 elif name == 'Performer' or name == 'Comment':
                     name = name.lower() + ':'
                     if value.endswith(')'):
                         start = value.rfind(' (')
                         if start > 0:
                             name += value[start + 2:-1]
                             value = value[:start]
                 elif name in self.__translate:
                     name = self.__translate[name]
                 else:
                     name = name.lower()
                 metadata.add(name, value)
     self._info(metadata, file)
     return metadata
Exemplo n.º 6
0
    def _load(self, filename):
        self.log.debug("Loading file %r", filename)
        file = MP4(encode_filename(filename))
        if file.tags is None:
            file.add_tags()

        metadata = Metadata()
        for name, values in file.tags.items():
            if name in self.__text_tags:
                for value in values:
                    metadata.add(self.__text_tags[name], value)
            elif name in self.__bool_tags:
                metadata.add(self.__bool_tags[name], values and '1' or '0')
            elif name in self.__int_tags:
                for value in values:
                    metadata.add(self.__int_tags[name], unicode(value))
            elif name in self.__freeform_tags:
                for value in values:
                    value = value.strip("\x00").decode("utf-8", "replace")
                    metadata.add(self.__freeform_tags[name], value)
            elif name == "----:com.apple.iTunes:fingerprint":
                for value in values:
                    value = value.strip("\x00").decode("utf-8", "replace")
                    if value.startswith("MusicMagic Fingerprint"):
                        metadata.add("musicip_fingerprint", value[22:])
            elif name == "trkn":
                metadata["tracknumber"] = str(values[0][0])
                metadata["totaltracks"] = str(values[0][1])
            elif name == "disk":
                metadata["discnumber"] = str(values[0][0])
                metadata["totaldiscs"] = str(values[0][1])
            elif name == "covr":
                for value in values:
                    if value.format == value.FORMAT_JPEG:
                        metadata.add_image("image/jpeg", value)
                    elif value.format == value.FORMAT_PNG:
                        metadata.add_image("image/png", value)

        self._info(metadata, file)
        return metadata
Exemplo n.º 7
0
 def _load(self, filename):
     self.log.debug("Loading file %r", filename)
     file = ASF(encode_filename(filename))
     metadata = Metadata()
     for name, values in file.tags.items():
         if name == 'WM/Picture':
             for image in values:
                 (mime, data, type) = unpack_image(image.value)
                 if type == 3: # Only cover images
                     metadata.add_image(mime, data)
             continue
         elif name not in self.__RTRANS:
             continue
         elif name == 'WM/SharedUserRating':
             # Rating in WMA ranges from 0 to 99, normalize this to the range 0 to 5
             values[0] = int(round(int(unicode(values[0])) / 99.0 * (5 - 1)))
         name = self.__RTRANS[name]
         values = filter(bool, map(unicode, values))
         if values:
             metadata[name] = values
     self._info(metadata, file)
     return metadata
Exemplo n.º 8
0
    def _save(self, filename, metadata, settings):
        self.log.debug("Saving file %r", filename)
        file = ASF(encode_filename(filename))

        if settings['clear_existing_tags']:
            file.tags.clear()
        if settings['save_images_to_tags']:
            cover = []
            for mime, data, _fname in metadata.images:
                tag_data = pack_image(mime, data, 3)
                cover.append(ASFByteArrayAttribute(tag_data))
            if cover:
                file.tags['WM/Picture'] = cover

        for name, values in metadata.rawitems():
            if name.startswith('lyrics:'):
                name = 'lyrics'
            elif name == '~rating':
                values[0] = int(values[0]) * 99 / (settings['rating_steps'] - 1)
            if name not in self.__TRANS:
                continue
            name = self.__TRANS[name]
            file.tags[name] = map(unicode, values)
        file.save()
Exemplo n.º 9
0
    def _save(self, filename, metadata, settings):
        """Save metadata to the file."""
        self.log.debug("Saving file %r", filename)
        file = self._File(encode_filename(filename))
        if file.tags is None:
            file.add_tags()
        if settings["clear_existing_tags"]:
            file.tags.clear()
        if self._File == mutagen.flac.FLAC and (
            settings["clear_existing_tags"] or
            (settings['save_images_to_tags'] and metadata.images)):
            file.clear_pictures()
        tags = {}
        for name, value in metadata.items():
            if name == '~rating':
                # Save rating according to http://code.google.com/p/quodlibet/wiki/Specs_VorbisComments
                if settings['rating_user_email']:
                    name = 'rating:%s' % settings['rating_user_email']
                else:
                    name = 'rating'
                value = unicode(float(value) / (settings['rating_steps'] - 1))
            # don't save private tags
            elif name.startswith("~"):
                continue
            if name.startswith('lyrics:'):
                name = 'lyrics'
            elif name == "date" or name == "originaldate":
                # YYYY-00-00 => YYYY
                value = sanitize_date(value)
            elif name.startswith('performer:') or name.startswith('comment:'):
                # transform "performer:Piano=Joe Barr" to "performer=Joe Barr (Piano)"
                name, desc = name.split(':', 1)
                if desc:
                    value += ' (%s)' % desc
            elif name == "musicip_fingerprint":
                name = "fingerprint"
                value = "MusicMagic Fingerprint%s" % value
            tags.setdefault(name.upper().encode('utf-8'), []).append(value)

        if "totaltracks" in metadata:
            tags.setdefault(u"TRACKTOTAL", []).append(metadata["totaltracks"])
        if "totaldiscs" in metadata:
            tags.setdefault(u"DISCTOTAL", []).append(metadata["totaldiscs"])

        if settings['save_images_to_tags']:
            for mime, data, filename in metadata.images:
                image = mutagen.flac.Picture()
                image.type = 3 # Cover image
                image.data = data
                image.mime = mime
                if self._File == mutagen.flac.FLAC:
                    file.add_picture(image)
                else:
                    tags.setdefault(u"METADATA_BLOCK_PICTURE", []).append(
                        base64.standard_b64encode(image.write()))
        file.tags.update(tags)
        kwargs = {}
        if self._File == mutagen.flac.FLAC and settings["remove_id3_from_flac"]:
            kwargs["deleteid3"] = True
        try:
            file.save(**kwargs)
        except TypeError:
            file.save()
Exemplo n.º 10
0
    def _load(self, filename):
        self.log.debug("Loading file %r", filename)
        file = self._File(encode_filename(filename))
        file.tags = file.tags or {}
        metadata = Metadata()
        for origname, values in file.tags.items():
            for value in values:
                name = origname
                if name == "date" or name == "originaldate":
                    # YYYY-00-00 => YYYY
                    value = sanitize_date(value)
                elif name == 'performer' or name == 'comment':
                    # transform "performer=Joe Barr (Piano)" to "performer:Piano=Joe Barr"
                    name += ':'
                    if value.endswith(')'):
                        start = len(value) - 2
                        count = 1
                        while count > 0 and start > 0:
                            if value[start] == ')':
                                count += 1
                            elif value[start] == '(':
                                count -= 1
                            start -= 1
                        if start > 0:
                            name += value[start + 2:-1]
                            value = value[:start]
                elif name.startswith('rating'):
                    try: name, email = name.split(':', 1)
                    except ValueError: email = ''
		    continue
                    if email != self.config.setting['rating_user_email']:
                        continue
                    name = '~rating'
                    value = unicode(int(round((float(value) * (5 - 1)))))
                elif name == "fingerprint" and value.startswith("MusicMagic Fingerprint"):
                    name = "musicip_fingerprint"
                    value = value[22:]
                elif name == "tracktotal":
                    if "totaltracks" in file.tags:
                        continue
                    name = "totaltracks"
                elif name == "disctotal":
                    if "totaldiscs" in file.tags:
                        continue
                    name = "totaldiscs"
                elif name == "metadata_block_picture":
                    image = mutagen.flac.Picture(base64.standard_b64decode(value))
                    metadata.add_image(image.mime, image.data)
                    continue
                metadata.add(name, value)
        if self._File == mutagen.flac.FLAC:
            for image in file.pictures:
                metadata.add_image(image.mime, image.data)
        # Read the unofficial COVERART tags, for backward compatibillity only
        if not "metadata_block_picture" in file.tags:
            try:
                for index, data in enumerate(file["COVERART"]):
                    metadata.add_image(file["COVERARTMIME"][index], base64.standard_b64decode(data))
            except KeyError:
                pass
        self._info(metadata, file)
        return metadata
Exemplo n.º 11
0
    def _save(self, filename, metadata, settings):
        """Save metadata to the file."""
        self.log.debug("Saving file %r", filename)
        try:
            tags = compatid3.CompatID3(encode_filename(filename))
        except mutagen.id3.ID3NoHeaderError:
            tags = compatid3.CompatID3()

        if settings['clear_existing_tags']:
            tags.clear()
        if settings['save_images_to_tags'] and metadata.images:
            tags.delall('APIC')

        if settings['write_id3v1']:
            v1 = 2
        else:
            v1 = 0
        encoding = {'utf-8': 3, 'utf-16': 1}.get(settings['id3v2_encoding'], 0)

        if 'tracknumber' in metadata:
            if 'totaltracks' in metadata:
                text = '%s/%s' % (metadata['tracknumber'], metadata['totaltracks'])
            else:
                text = metadata['tracknumber']
            tags.add(id3.TRCK(encoding=0, text=text))

        if 'discnumber' in metadata:
            if 'totaldiscs' in metadata:
                text = '%s/%s' % (metadata['discnumber'], metadata['totaldiscs'])
            else:
                text = metadata['discnumber']
            tags.add(id3.TPOS(encoding=0, text=text))

        if settings['save_images_to_tags']:
            for mime, data, _fname in metadata.images:
                tags.add(id3.APIC(encoding=0, mime=mime, type=3, desc='', data=data))

        tmcl = mutagen.id3.TMCL(encoding=encoding, people=[])
        tipl = mutagen.id3.TIPL(encoding=encoding, people=[])

        tags.delall('TCMP')
        for name, values in metadata.rawitems():
            if name.startswith('performer:'):
                role = name.split(':', 1)[1]
                for value in values:
                    tmcl.people.append([role, value])
            elif name.startswith('comment:'):
                desc = name.split(':', 1)[1]
                if desc.lower()[:4]=="itun":
                    tags.delall('COMM:' + desc)
                    tags.add(id3.COMM(encoding=0, desc=desc, lang='eng', text=[v+u'\x00' for v in values]))
                else:
                    tags.add(id3.COMM(encoding=encoding, desc=desc, lang='eng', text=values))
            elif name.startswith('lyrics:') or name == 'lyrics':
                if ':' in name:
                    desc = name.split(':', 1)[1]
                else:
                    desc = ''
                for value in values:
                    tags.add(id3.USLT(encoding=encoding, desc=desc, text=value))
            elif name in self.__rtipl_roles:
                for value in values:
                    tipl.people.append([self.__rtipl_roles[name], value])
            elif name == 'musicbrainz_trackid':
                tags.add(id3.UFID(owner='http://musicbrainz.org', data=str(values[0])))
            elif name == '~rating':
                # Search for an existing POPM frame to get the current playcount
                for frame in tags.values():
                    if frame.FrameID == 'POPM' and frame.email == settings['rating_user_email']:
                        count = getattr(frame, 'count', 0)
                        break
                else:
                    count = 0

                # Convert rating to range between 0 and 255
                rating = int(round(float(values[0]) * 255 / (settings['rating_steps'] - 1)))
                tags.add(id3.POPM(email=settings['rating_user_email'], rating=rating, count=count))
            elif name in self.__rtranslate:
                frameid = self.__rtranslate[name]
                if frameid.startswith('W'):
                    valid_urls = all([all(urlparse(v)[:2]) for v in values])
                    if frameid == 'WCOP':
                        # Only add WCOP if there is only one license URL, otherwise use TXXX:LICENSE
                        if len(values) > 1 or not valid_urls:
                            tags.add(id3.TXXX(encoding=encoding, desc=self.__rtranslate_freetext[name], text=values))
                        else:
                            tags.add(id3.WCOP(url=values[0]))
                    elif frameid == 'WOAR' and valid_urls:
                        for url in values:
                            tags.add(id3.WOAR(url=url))
                elif frameid.startswith('T'):
                    tags.add(getattr(id3, frameid)(encoding=encoding, text=values))
                    if frameid == 'TSOA':
                        tags.delall('XSOA')
                    elif frameid == 'TSOP':
                        tags.delall('XSOP')
                    elif frameid == 'TSO2':
                        tags.delall('TXXX:ALBUMARTISTSORT')
            elif name in self.__rtranslate_freetext:
                tags.add(id3.TXXX(encoding=encoding, desc=self.__rtranslate_freetext[name], text=values))
            elif name.startswith('~id3:'):
                name = name[5:]
                if name.startswith('TXXX:'):
                    tags.add(id3.TXXX(encoding=encoding, desc=name[5:], text=values))
                else:
                    frameclass = getattr(id3, name[:4], None)
                    if frameclass:
                        tags.add(frameclass(encoding=encoding, text=values))
            # don't save private / already stored tags
            elif not name.startswith("~") and not name in self.__other_supported_tags:
                tags.add(id3.TXXX(encoding=encoding, desc=name, text=values))

        if tmcl.people:
            tags.add(tmcl)
        if tipl.people:
            tags.add(tipl)

        if settings['write_id3v23']:
            tags.update_to_v23()
            tags.save(encode_filename(filename), v2=3, v1=v1)
        else:
            tags.update_to_v24()
            tags.save(encode_filename(filename), v2=4, v1=v1)

        if self._IsMP3 and settings["remove_ape_from_mp3"]:
            try: mutagen.apev2.delete(encode_filename(filename))
            except: pass
Exemplo n.º 12
0
    def _load(self, filename):
        self.log.debug("Loading file %r", filename)
        file = self._File(encode_filename(filename), ID3=compatid3.CompatID3)
        tags = file.tags or {}
        # upgrade custom 2.3 frames to 2.4
        for old, new in self.__upgrade.items():
            if old in tags and new not in tags:
                f = tags.pop(old)
                tags.add(getattr(id3, new)(encoding=f.encoding, text=f.text))
        metadata = Metadata()
        for frame in tags.values():
            frameid = frame.FrameID
            if frameid in self.__translate:
                name = self.__translate[frameid]
                if frameid.startswith('T'):
                    for text in frame.text:
                        if text:
                            metadata.add(name, unicode(text))
                elif frameid == 'COMM':
                    for text in frame.text:
                        if text:
                            metadata.add('%s:%s' % (name, frame.desc), unicode(text))
                else:
                    metadata.add(name, unicode(frame))
            elif frameid == "TMCL":
                for role, name in frame.people:
                    if role or name:
                        metadata.add('performer:%s' % role, name)
            elif frameid == "TIPL":
                for role, name in frame.people:
                    if role in self.__tipl_roles and name:
                        metadata.add(self.__tipl_roles[role], name)
            elif frameid == 'TXXX':
                if frame.desc in self.__translate_freetext:
                    name = self.__translate_freetext[frame.desc]
                else:
                    name = str(frame.desc.lower())
                for text in frame.text:
                    metadata.add(name, unicode(text))
            elif frameid == 'USLT':
                name = 'lyrics'
                if frame.desc:
                    name += ':%s' % frame.desc
                metadata.add(name, unicode(frame.text))
            elif frameid == 'UFID' and frame.owner == 'http://musicbrainz.org':
                metadata['musicbrainz_trackid'] = unicode(frame.data)
            elif frameid == 'TRCK':
                value = frame.text[0].split('/')
                if len(value) > 1:
                    metadata['tracknumber'], metadata['totaltracks'] = value[:2]
                else:
                    metadata['tracknumber'] = value[0]
            elif frameid == 'TPOS':
                value = frame.text[0].split('/')
                if len(value) > 1:
                    metadata['discnumber'], metadata['totaldiscs'] = value[:2]
                else:
                    metadata['discnumber'] = value[0]
            elif frameid == 'APIC':
                metadata.add_image(frame.mime, frame.data)
            elif frameid == 'POPM':
                # Rating in ID3 ranges from 0 to 255, normalize this to the range 0 to 5
                if False:
                    rating = unicode(int(round(frame.rating / 255.0 * (5 - 1))))
                    metadata.add('~rating', rating)

        if 'date' in metadata:
            metadata['date'] = sanitize_date(metadata.getall('date')[0])

        self._info(metadata, file)
        return metadata