Пример #1
0
def print_track_info(paths: Paths, tags=None, meta_only=False, trim=True):
    tags = {tag.upper() for tag in tags} if tags else None
    suffix = '' if meta_only else ':'
    for i, music_file in enumerate(iter_music_files(paths)):
        if i and not meta_only:
            print()

        uprint(
            f'{music_file.path.as_posix()} [{music_file.length_str}] ({music_file.tag_version}){suffix}'
        )
        if not meta_only:
            if music_file.tags is None:
                uprint('[No tags]')
                continue
            tag_name_map = TYPED_TAG_DISPLAY_NAME_MAP.get(
                music_file.tag_type, {})
            tbl = Table(SimpleColumn('Tag'),
                        SimpleColumn('Tag Name'),
                        SimpleColumn('Value'),
                        update_width=True)
            rows = []
            for tag, val in sorted(music_file.tags.items()):
                if trim and len(tag) > 4:
                    tag = tag[:4]

                if not tags or (tag in tags):
                    rows.append({
                        'Tag': tag,
                        'Tag Name': tag_name_map.get(tag, '[unknown]'),
                        'Value': tag_repr(val)
                    })
            if rows:
                tbl.print_rows(rows)
Пример #2
0
def print_processed_info(paths: Paths, expand=0, only_errors=False):
    for album_dir in iter_album_dirs(paths):
        if not only_errors:
            uprint(f'- Directory: {album_dir}')
        _print_one_or_set(album_dir, 'names', 'Album', only_errors=only_errors)
        single_artist = len(album_dir.all_artists) == 1
        if not expand or single_artist:
            _print_one_or_set(album_dir, 'artists', 'Artist',
                              lambda a: a.artist_str(), only_errors)
        if expand:
            print_tracks(album_dir, expand)
Пример #3
0
def show_matches(paths: Paths, sites: StrOrStrs = None):
    for album_dir in iter_album_dirs(paths):
        uprint(f'- Album: {album_dir}')
        try:
            artists = find_artists(album_dir, sites=sites)
        except NoArtistFoundException:
            log.error(f'    - Artist: No artist could be found',
                      extra={'color': 11})
        except Exception as e:
            log.error(f'    - Artist: {e}',
                      extra={'color': 'red'},
                      exc_info=True)
        else:
            if len(artists) == 1:
                artist = artists[0]
                try:
                    uprint(f'    - Artist: {artist} / {artist.names}')
                except Exception:
                    log.error(f'    - Artist: Error parsing name:',
                              extra={'color': 'red'},
                              exc_info=True)
            else:
                uprint(f'    - Artists ({len(artists)}):')
                for artist in artists:
                    uprint(f'        - {artist} / {artist.names}')

            try:
                album = find_album(album_dir, artists)
            except Exception as e:
                log.error(f'    - Album: {e}',
                          extra={'color': 'red'},
                          exc_info=True)
            else:
                print_de_part(album, 4)
Пример #4
0
def _print_one_or_set(obj,
                      attr: str,
                      singular: str,
                      str_fn=str,
                      only_errors=False,
                      indent=4):
    prefix = ' ' * indent
    plural = singular if singular == 'Processed' else singular + 's'
    try:
        objs = getattr(obj, attr)
    except Exception as e:
        if only_errors:
            uprint(f'- Directory: {obj}')
        log.error(f'{prefix}{plural:12s}: {e}',
                  extra={'color': 'red'},
                  exc_info=True)
    else:
        if not only_errors:
            if len(objs) == 1:
                uprint(f'{prefix}{singular:12s}: {str_fn(next(iter(objs)))}')
            else:
                text = f'{plural} ({len(objs)})'
                uprint(f'{prefix}{text:12s}:')
                for obj in objs:
                    uprint(f'{prefix}  - {str_fn(obj)} ')
Пример #5
0
def print_tracks(album_dir: AlbumDir, expand=0):
    single_artist = len(album_dir.all_artists) == 1
    uprint(f'    - Tracks ({len(album_dir)}):')
    for track in album_dir.songs:
        uprint(f'      - {track.path.name}:')
        uprint(f'         - Title       : {track.tag_title!r}')
        if not single_artist or expand > 1:
            uprint(f'         - Artist      : {track.tag_artist!r} =>')
            _print_one_or_set(track,
                              'artists',
                              'Processed',
                              lambda a: repr(a.artist_str()),
                              indent=11)
            uprint(f'         - Album Artist: {track.tag_album_artist!r} =>')
            _print_one_or_set(track,
                              'album_artists',
                              'Processed',
                              lambda a: repr(a.artist_str()),
                              indent=11)
Пример #6
0
def show_wiki_entity(identifier: str,
                     expand=0,
                     limit=0,
                     alb_types: Optional[Iterable[str]] = None,
                     etype: Optional[str] = None):
    alb_types = _album_types(alb_types)
    cls = EntertainmentEntity
    if etype:
        for _cls in EntertainmentEntity._subclasses:
            if _cls.__name__ == etype and issubclass(
                    _cls,
                    EntertainmentEntity):  # _subclasses is from WikiEntity
                cls = _cls
                break
        else:
            raise ValueError(
                f'Invalid EntertainmentEntity subclass: {etype!r}')

    if URL_MATCH(identifier):
        entity = cls.from_url(identifier)
    else:
        entity = cls.from_title(
            identifier,
            search=True,
            research=True,
            strict=1,
            # name=Name.from_enclosed(identifier)
        )
    uprint(f'{entity}:')

    if isinstance(entity, DiscographyEntry):
        print_disco_entry(entity, 2, expand > 0, limit, expand > 1)
    elif isinstance(entity, Artist):
        print_artist(entity, 2, expand, expand > 2, expand > 3, alb_types)
    elif isinstance(entity, Discography):
        print_discography(entity, 2, expand > 0, expand > 1, expand > 2,
                          alb_types, True)
    elif isinstance(entity, TVSeries):
        print_tv_series(entity, 2)
    else:
        uprint(
            f'  - No additional information is configured for {entity.__class__.__name__} entities'
        )
Пример #7
0
def main():
    args = parser().parse_args()
    init_logging(args.verbose, log_path=None)

    cache = DBCache(None, db_path=args.path)

    if args.action == 'list':
        for key, orig in normalized_keys(cache):
            uprint(key)
    elif args.action == 'delete':
        prefix = '[DRY RUN] Would delete' if args.dry_run else 'Deleting'
        for key, orig in normalized_keys(cache):
            if any(fnmatch(key, pat) for pat in args.patterns):
                log.info('{}: {}'.format(prefix, key))
                if not args.dry_run:
                    del cache[orig]
    elif args.action == 'get':
        entry = cache[args.key]
        log.info(entry)
    else:
        raise ValueError('Unconfigured action: {}'.format(args.action))
Пример #8
0
def print_artist(artist: Artist,
                 indent=0,
                 expand_disco=0,
                 editions=False,
                 track_info=False,
                 alb_types: AlbTypes = None):
    prefix = ' ' * indent
    uprint(f'{prefix}- {artist.name}:')
    if names := artist.names:
        uprint(f'{prefix}  Names:')
        for name in names:
            # uprint(f'{prefix}    - {name}')
            uprint(f'{prefix}    - {name.full_repr(include_versions=False)}')
            if name.versions:
                for version in name.versions:
                    # uprint(f'{prefix}       - {version}')
                    uprint(f'{prefix}       - {version.full_repr()}')
Пример #9
0
def print_disco_entry(disco_entry: DiscographyEntry,
                      indent=0,
                      editions=False,
                      limit=0,
                      track_info=False):
    prefix = ' ' * indent
    suffix = '' if disco_entry.editions else ' [{} info unavailable]'.format(
        'Edition' if editions else 'Part')
    uprint(f'{prefix}- {disco_entry}:{suffix}')
    if names := disco_entry.names:
        uprint(f'{prefix}  Names:')
        for name in names:
            # uprint(f'{prefix}    - {name}')
            uprint(f'{prefix}    - {name.full_repr(include_versions=False)}')
Пример #10
0
def test_match(paths: Paths, identifier: str):
    for album_dir in iter_album_dirs(paths):
        album_name = album_dir.name
        if not album_name:
            raise ValueError(
                f'Directories with multiple album names are not currently handled.'
            )

        if URL_MATCH(identifier):
            disco_entry = DiscographyEntry.from_url(identifier)
        else:
            disco_entry = DiscographyEntry.from_title(identifier,
                                                      search=True,
                                                      research=True)

        uprint(f'Match scores for {album_name!r}:')
        de_score = album_name.name._score(disco_entry.name)
        uprint(f'  - {disco_entry}: {de_score}')
        for edition in disco_entry:
            ed_score = album_name.name._score(edition.name)
            uprint(f'    - {edition}: {ed_score}')
            for part in edition:
                p_score = album_name.name._score(part.name)
                uprint(f'      - {part}: {p_score}')
Пример #11
0
def print_tag_changes(obj,
                      changes: Mapping[str, Tuple[Any, Any]],
                      dry_run: bool,
                      color=None):
    name_width = max(len(tag_name) for tag_name in changes) if changes else 0
    orig_width = max(
        max(len(r), mono_width(r))
        for r in (repr(orig)
                  for orig, _ in changes.values())) if changes else 0
    _fmt = '  - {{:<{}s}}{}{{:>{}s}}{}{{}}'

    if changes:
        uprint(
            colored(
                '{} {} by changing...'.format(
                    '[DRY RUN] Would update' if dry_run else 'Updating', obj),
                color))
        for tag_name, (orig_val, new_val) in changes.items():
            if tag_name == 'title':
                bg, reset, w = 20, False, 20
            else:
                bg, reset, w = None, True, 14

            orig_repr = repr(orig_val)
            fmt = _fmt.format(
                name_width + w,
                colored(' from ', 15, bg, reset=reset),
                orig_width - (mono_width(orig_repr) - len(orig_repr)) + w,
                colored(' to ', 15, bg, reset=reset),
            )

            uprint(
                colored(
                    fmt.format(
                        colored(tag_name, 14, bg, reset=reset),
                        colored(orig_repr, 11, bg, reset=reset),
                        colored(repr(new_val), 10, bg, reset=reset),
                    ),
                    bg_color=bg,
                ))
    else:
        prefix = '[DRY RUN] ' if dry_run else ''
        uprint(colored(f'{prefix}No changes necessary for {obj}', color))
Пример #12
0
def print_discography(
    entity: DiscographyMixin,
    indent=0,
    expand_disco=False,
    editions=False,
    track_info=False,
    alb_types: AlbTypes = None,
    header=False,
):
    prefix = ' ' * indent
    if header:
        # noinspection PyUnresolvedReferences
        uprint(f'{prefix}- {entity.name}:')
    if discography := entity.discography:
        uprint(f'{prefix}  Discography:')
        for disco_entry in sorted(discography):
            if not alb_types or disco_entry.type in alb_types:
                if expand_disco:
                    print_disco_entry(disco_entry,
                                      indent + 6,
                                      editions,
                                      track_info=track_info)
                else:
                    uprint(f'{prefix}    - {disco_entry}')
Пример #13
0
def print_tv_series(tv_series: TVSeries, indent=0):
    prefix = ' ' * indent
    if links := tv_series.soundtrack_links():
        uprint(f'{prefix}Discography Links:')
        for link in sorted(links):
            uprint(f'{prefix}  - {link!r}')
Пример #14
0
def print_de_part(part: DiscographyEntryPart, indent=0, track_info=False):
    prefix = ' ' * indent
    if part:
        uprint(f'{prefix}- {part}:')
        uprint(f'{prefix}    Tracks:')
        for track in part:
            uprint(f'{prefix}      - {track._repr()}')
            if track_info:
                uprint(f'{prefix}          Full name: {track.full_name()!r}')
                uprint(f'{prefix}          Name: {track.name.full_repr()}')
    else:
        uprint(f'{prefix}- {part}: [Track info unavailable]')
Пример #15
0
    elif isinstance(entity, TVSeries):
        print_tv_series(entity, 2)
    else:
        uprint(
            f'  - No additional information is configured for {entity.__class__.__name__} entities'
        )


def print_tv_series(tv_series: TVSeries, indent=0):
    prefix = ' ' * indent
    if links := tv_series.soundtrack_links():
        uprint(f'{prefix}Discography Links:')
        for link in sorted(links):
            uprint(f'{prefix}  - {link!r}')
    else:
        uprint(f'{prefix}Discography Links: [Unavailable]')


def print_artist(artist: Artist,
                 indent=0,
                 expand_disco=0,
                 editions=False,
                 track_info=False,
                 alb_types: AlbTypes = None):
    prefix = ' ' * indent
    uprint(f'{prefix}- {artist.name}:')
    if names := artist.names:
        uprint(f'{prefix}  Names:')
        for name in names:
            # uprint(f'{prefix}    - {name}')
            uprint(f'{prefix}    - {name.full_repr(include_versions=False)}')