Exemplo n.º 1
0
    def _getArtist(self, session, name, resolved_artist):
        artist_rows = session.query(Artist).filter_by(name=name).all()
        if artist_rows:
            if len(artist_rows) > 1 and resolved_artist:
                # Use previously resolved artist for this directory.
                artist = resolved_artist
            elif len(artist_rows) > 1:
                # Resolve artist
                try:
                    heading = "Multiple artists names '%s'" % \
                              artist_rows[0].name
                    artist = console.selectArtist(fg.blue(heading),
                                                  choices=artist_rows,
                                                  allow_create=True)
                except PromptExit:
                    log.warn("Duplicate artist requires user "
                             "intervention to resolve.")
                    artist = None
                else:
                    if artist not in artist_rows:
                        session.add(artist)
                        session.flush()
                        print(fg.yellow("Updating artist") + ": " + name)
                    resolved_artist = artist
            else:
                # Artist match
                artist = artist_rows[0]
        else:
            # New artist
            artist = Artist(name=name)
            session.add(artist)
            session.flush()
            print(fg.green("Adding artist") + ": " + name)

        return artist, resolved_artist
Exemplo n.º 2
0
    def handleDirectory(self, d, _):
        audio_files = list(self._file_cache)
        self._file_cache = []

        image_files = self._dir_images
        self._dir_images = []

        if not audio_files:
            return

        d_datetime = datetime.fromtimestamp(getctime(d))

        # This directory of files can be:
        # 1) an album by a single artist (tag.artist, or tag.albun_srtist and
        #    tag.album all equal)
        # 2) a comp (tag.album equal, tag.artist differ)
        # 3) not associated with a collection (tag.artist and tag.album differ)
        artists = set([f.tag.artist for f in audio_files if f.tag])
        album_artists = set([f.tag.album_artist for f in audio_files if f.tag])
        albums = set([f.tag.album for f in audio_files if f.tag])
        for s in artists, album_artists, albums:
            if None in s:
                s.remove(None)

        is_various = (len(artists) > 1 and len(album_artists) == 0 and
                      len(albums) == 1)

        def type_hint():
            hints = set()
            for tag in [f.tag for f in audio_files if f.tag]:
                hint_frame = tag.user_text_frames.get(TXXX_ALBUM_TYPE)
                if hint_frame:
                    hints.add(hint_frame.text)
            if len(hints) > 1:
                log.warn("Inconsistent type hints: %s" % str(hints))
                return None
            else:
                return hints.pop() if hints else None

        album_type = type_hint() or LP_TYPE
        if is_various and album_type not in (None, VARIOUS_TYPE):
            # is_various overrides
            log.warn("Using type various despite files saying %s" % album_type)
        album_type = VARIOUS_TYPE if is_various else album_type

        # Used when a duplicate artist is resolved for the entire directory.
        resolved_artist = None
        resolved_album_artist = None

        album = None
        session = self._db_session
        for audio_file in audio_files:
            path = audio_file.path
            info = audio_file.info
            tag = audio_file.tag

            if not info or not tag:
                log.warn("File missing %s, skipping: %s" %
                         ("audio" if not info else "tag/metadata", path))
                continue
            elif None in (tag.title, tag.artist):
                log.warn("File missing required artist and/or title "
                         "metadata, skipping: %s" % path)
                continue

            try:
                track = session.query(Track).filter_by(path=path).one()
            except NoResultFound:
                track = None
            else:
                if datetime.fromtimestamp(getctime(path)) == track.ctime:
                    # Track is in DB and the file is not modified.
                    # stash the album though, we'll look for artwork
                    # updates later
                    album = track.album
                    continue

            # Either adding the track (track == None)
            # or modifying (track != None)

            artist, resolved_artist = self._getArtist(session, tag.artist,
                                                      resolved_artist)
            if tag.album_type != SINGLE_TYPE:
                if tag.album_artist and tag.artist != tag.album_artist:
                    album_artist, resolved_album_artist = \
                            self._getArtist(session, tag.album_artist,
                                            resolved_album_artist)
                else:
                    album_artist = artist

                if artist is None:
                    # see PromptExit
                    continue

                album_artist_id = album_artist.id if not is_various \
                                                  else VARIOUS_ARTISTS_ID
                album_rows = session.query(Album)\
                                    .filter_by(title=tag.album,
                                               artist_id=album_artist_id)\
                                    .all()
                rel_date = tag.release_date
                rec_date = tag.recording_date
                or_date = tag.original_release_date

                if album_rows:
                    if len(album_rows) > 1:
                        # This artist has more than one album with the same
                        # title.
                        raise NotImplementedError("FIXME")
                    album = album_rows[0]

                    album.type = album_type
                    album.release_date = rel_date
                    album.original_release_date = or_date
                    album.recording_date = rec_date
                    print(fg.yellow("Updating album") + ": " + album.title)
                elif tag.album:
                    album = Album(title=tag.album,
                                  artist_id=album_artist_id,
                                  type=album_type,
                                  release_date=rel_date,
                                  original_release_date=or_date,
                                  recording_date=rec_date,
                                  date_added=d_datetime)
                    session.add(album)
                    print(fg.green("Adding album") + ": " + album.title)

                session.flush()

            if not track:
                track = Track(audio_file=audio_file)
                self._num_added += 1
                print(fg.green("Adding track") + ": " + path)
            else:
                track.update(audio_file)
                self._num_modified += 1
                print(fg.yellow("Updating track") + ": " + path)

            genre = tag.genre
            genre_tag = None
            if genre:
                try:
                    genre_tag = session.query(Tag).filter_by(name=genre.name)\
                                       .one()
                except NoResultFound:
                    genre_tag = Tag(name=genre.name)
                    session.add(genre_tag)
                    session.flush()

            track.artist_id = artist.id
            track.album_id = album.id if album else None
            if genre_tag:
                track.tags.append(genre_tag)
            session.add(track)

            if album:
                # Tag images
                for img in tag.images:
                    for img_type in art.TO_ID3_ART_TYPES:
                        if img.picture_type in \
                                art.TO_ID3_ART_TYPES[img_type]:
                            break
                        img_type = None

                    if img_type is None:
                        log.warn("Skipping unsupported image type: %s" %
                                 img.picture_type)
                        continue

                    new_img = Image.fromTagFrame(img, img_type)
                    if new_img:
                        syncImage(new_img,
                                  album if img_type in IMAGE_TYPES["album"]
                                        else album.artist,
                                  session)
                    else:
                        log.warn("Invalid image in tag")

        if album:
            # Directory images.
            for img_file in image_files:
                img_type = art.matchArtFile(img_file)
                if img_type is None:
                    log.warn("Skipping unrecognized image file: %s" %
                              img_file)
                    continue

                new_img = Image.fromFile(img_file, img_type)
                if new_img:
                    new_img.description = os.path.basename(img_file)
                    syncImage(new_img, album if img_type in IMAGE_TYPES["album"]
                                             else album.artist,
                              session)
                else:
                    log.warn("Invalid image file: " + img_file)