Exemplo n.º 1
0
def fetch_tracks(*args):
    kwargs = dict(provider=Provider.lastfm)
    if args:
        kwargs["id"] = lambda x: x in args

    # So wrong, but yaspin doesn't support nested spinners
    LastService.get_tags()
    with spinner("Fetching track lists") as sp:
        for playlist in PlaylistManager.find(**kwargs):
            tracklist = LastService.get_tracks(
                type=playlist.type, **playlist.arguments
            )

            track_ids: List[str] = []
            for entry in tracklist:
                id = TrackManager.set(
                    dict(artist=entry.artist.name, name=entry.name)
                ).id

                if id not in track_ids:
                    track_ids.append(id)

            sp.write(
                "Playlist: {} - {} tracks".format(playlist.id, len(track_ids))
            )
            PlaylistManager.update(playlist, dict(tracks=track_ids))
Exemplo n.º 2
0
def clean():
    """Cleanup orphan tracks and empty playlists."""

    tracks = []
    removed_playlists = 0
    for playlist in PlaylistManager.find():

        if len(playlist.tracks) == 0:
            PlaylistManager.remove(playlist.id)
            removed_playlists += 1
        else:
            tracks += playlist.tracks

    tracks = list(set(tracks))
    removed_tracks = 0
    for track in TrackManager.find():
        if track.id not in tracks:
            TrackManager.remove(track.id)
            removed_tracks += 1

    click.secho("Cleanup removed:", bold=True)
    click.secho(
        tabulate(  # type: ignore
            [
                (magenta("Tracks:"), removed_tracks),
                (magenta("Playlists:"), removed_playlists),
            ],
            tablefmt="plain",
            colalign=("right", "left"),
        ))
Exemplo n.º 3
0
def remove(ids: Tuple[str]):
    """Delete one or more playlists by id."""

    click.confirm("Do you want to continue?", abort=True)
    for id in ids:
        PlaylistManager.remove(id)
        click.secho("Removed playlist: {}!".format(id))
Exemplo n.º 4
0
    def test_update_sets_synced_if_tracks_are_updated(self):
        playlist = PlaylistManager.set(
            dict(id=1, type=None, provider=None, title="foo"))

        new = PlaylistManager.update(playlist, dict(tracks=[1, 2, 3]))
        self.assertEqual(
            datetime.fromtimestamp(new.synced).strftime("%Y-%m-%d %H:%M"),
            datetime.utcnow().strftime("%Y-%m-%d %H:%M"),
        )
Exemplo n.º 5
0
def push_playlists():
    playlists = PlaylistManager.find(youtube_id=None)
    message = "Creating playlists"
    with spinner(message) as sp:
        for playlist in playlists:
            sp.text = "{}: {}".format(message, playlist.title)
            youtube_id = YouService.create_playlist(playlist)
            PlaylistManager.update(playlist, dict(youtube_id=youtube_id))

        total = len(playlists)
        if total > 0:
            sp.text = "{0}: {1}/{1} ".format(message, total)
Exemplo n.º 6
0
 def complete(self, ctx, incomplete):
     self.init_registry()
     return [
         k
         for k in PlaylistManager.keys()
         if completion_configuration.match_incomplete(k, incomplete)
     ]
Exemplo n.º 7
0
def create_playlist(title, tracks, type, arguments):
    if not tracks:
        return click.secho("Tracklist is empty, aborting...")

    click.clear()
    click.secho("{}\n\n{}\n".format(
        tabulate(  # type: ignore
            [
                (magenta("Title:"), title),
                (magenta("Tracks:"), len(tracks)),
            ],
            tablefmt="plain",
            colalign=("right", "left"),
        ),
        tabulate(  # type: ignore
            [(i + 1, track[0], track[1]) for i, track in enumerate(tracks)],
            headers=("No", "Artist", "Track Name"),
        ),
    ))
    click.confirm("Are you sure you want to save this playlist?", abort=True)
    playlist = PlaylistManager.set(
        dict(
            type=type,
            title=title.strip(),
            arguments=arguments,
            provider=Provider.user,
            tracks=[
                TrackManager.set(dict(artist=artist, name=name)).id
                for artist, name in tracks
            ],
        ))
    click.secho("Added playlist: {}!".format(playlist.id))
Exemplo n.º 8
0
def fetch_playlists():
    with spinner("Fetching playlists info") as sp:
        playlists = YouService.get_playlists()
        for playlist in playlists:
            if not PlaylistManager.exists(playlist):
                items = YouService.get_playlist_items(playlist)
                track_ids = [
                    TrackManager.set(
                        dict(
                            artist=item.artist,
                            name=item.name,
                            youtube_id=item.video_id,
                        )).id for item in items
                ]
                playlist.tracks = track_ids
            PlaylistManager.set(playlist.asdict())

        total = len(playlists)
        if total > 0:
            sp.text = "Fetched {} playlist(s) info".format(magenta(total))
Exemplo n.º 9
0
def push_tracks():
    online_playlists = PlaylistManager.find(youtube_id=lambda x: x is not None)
    click.secho("Syncing playlists", bold=True)
    for playlist in online_playlists:
        add = items = remove = []
        with spinner("Fetching playlist items: {}".format(playlist.title)):
            items = YouService.get_playlist_items(playlist)
            online = set([item.video_id for item in items])
            offline = set([
                track.youtube_id for track in TrackManager.find(
                    youtube_id=lambda x: x is not None,
                    id=lambda x: x in playlist.tracks,
                )
            ])

            add = offline - online
            remove = online - offline

        message = "Adding new playlist items"
        with spinner(message) as sp:
            for video_id in sorted(add):
                sp.text = "{}: {}".format(message, video_id)
                YouService.create_playlist_item(playlist, video_id)

            if len(add) > 0:
                sp.text = "{}: {}".format(message, len(add))

        message = "Removing playlist items"
        with spinner(message) as sp:
            remove = [item for item in items if item.video_id in remove]
            for item in sorted(remove):
                sp.text = "{}: {}".format(message, video_id)
                YouService.remove_playlist_item(item)

            if len(remove) > 0:
                sp.text = "{}: {}".format(message, len(remove))

        if len(add) or len(remove):
            PlaylistManager.update(playlist, dict(uploaded=timestamp()))
Exemplo n.º 10
0
    def test_removes_orphan_tracks_and_empty_playlists(self):
        [TrackManager.set(t.asdict()) for t in TrackFixture.get(2)]
        [PlaylistManager.set(p.asdict()) for p in PlaylistFixture.get(3)]

        playlist = PlaylistFixture.one(num=50)
        track = TrackFixture.one(num=5)
        playlist.tracks = [track.id]
        PlaylistManager.set(playlist.asdict())
        TrackManager.set(track.asdict())

        result = self.runner.invoke(cli, ["clean"])

        expected_output = (
            "Cleanup removed:",
            "   Tracks:  2",
            "Playlists:  3",
        )
        self.assertEqual(0, result.exit_code)
        self.assertOutput(expected_output, result.output)

        self.assertEqual(track.id, TrackManager.find()[0].id)
        self.assertEqual(playlist.id, PlaylistManager.find()[0].id)
Exemplo n.º 11
0
def country_playlist(ctx: click.Context, country: str, limit: int, title: str):
    """Add a top tracks playlist by country."""

    History.set(limit=limit)
    playlist = PlaylistManager.set(
        dict(
            type=PlaylistType.COUNTRY,
            provider=Provider.lastfm,
            arguments=dict(country=country, limit=limit),
            title=title.strip(),
        ))
    click.secho("{} playlist: {}!".format(
        "Updated" if playlist.synced else "Added", playlist.id))
    fetch_tracks(playlist.id)
Exemplo n.º 12
0
def show(id: Optional[str], mime: bool = False):
    """Show a playlist track list."""

    playlist = PlaylistManager.get(id)
    values = [
        (magenta("ID:"), playlist.id),
        (magenta("Provider:"), playlist.provider),
        (magenta("Title:"), playlist.title),
        (magenta("Type:"), playlist.type),
        (magenta("Arguments:"), playlist.display_arguments),
        (magenta("Synced:"), date(playlist.synced)),
        (magenta("Uploaded:"), date(playlist.uploaded)),
        (magenta("Youtube:"), playlist.youtube_url),
    ]

    if mime:
        values.append((magenta("Mime:"), playlist.mime))
    else:
        values.append((magenta("Tracks:"), ""))

    info = tabulate(  # type: ignore
        values, tablefmt="plain", colalign=("right", "left"))

    if mime:
        click.secho(info)
        click.secho("\nYou reached the 10 playlists limit per day on youtube?")
        click.secho("Create a playlist manually and add "
                    "in the bottom the above mime string")
        click.secho("The mime is base64 signature that "
                    "pytuber uses to link with youtube playlists")
        click.secho('Use "pytuber fetch youtube --playlists"'
                    " to sync, before you try to push any tracks")
        return

    tracks = tabulate(  # type: ignore
        [(
            t.artist,
            t.name,
            click.style("✔", fg="green") if t.youtube_id else "-",
        ) for t in [TrackManager.get(id) for id in playlist.tracks]],
        showindex="always",
        headers=("No", "Artist", "Track Name", "Youtube"),
        colalign=("left", "left", "left", "center"),
    )

    click.echo_via_pager("{}\n\n{}".format(info, tracks))
Exemplo n.º 13
0
def list(provider: str):
    """List playlists."""

    kwargs = dict(provider=provider) if provider else dict()
    playlists = PlaylistManager.find(**kwargs)

    if len(playlists) == 0:
        click.secho('No playlists found, use "pytuber add" or '
                    '"pytuber fetch youtube --playlists"')
    else:
        click.secho(
            tabulate(  # type: ignore
                [(
                    p.id,
                    p.title,
                    p.provider,
                    click.style("✔", fg="green") if p.youtube_id else "-",
                    len(p.tracks),
                ) for p in playlists],
                headers=("ID", "Title", "Provider", "Youtube", "Tracks"),
                colalign=("left", "left", "left", "center"),
            ))
Exemplo n.º 14
0
def user_playlist(ctx: click.Context, user: str, playlist_type: int,
                  limit: int, title: str):
    """
    Add a user type playlist. This type of playlists are based on a user's
    music preference and history.

    \b
    Playlist types:
    1. User loved tracks
    2. User top tracks
    3. User recent tracks
    4. User friends recent tracks
    """
    History.set(user=user, limit=limit)
    playlist = PlaylistManager.set(
        dict(
            type=UserPlaylistType.from_choice(playlist_type),
            provider=Provider.lastfm,
            arguments=dict(username=user, limit=limit),
            title=title.strip(),
        ))
    click.secho("{} playlist: {}!".format(
        "Updated" if playlist.synced else "Added", playlist.id))
    fetch_tracks(playlist.id)
Exemplo n.º 15
0
    def test_complete(self):
        [PlaylistManager.set(p.asdict()) for p in PlaylistFixture.get(2)]

        self.assertEqual(["id_a", "id_b"], self.param.complete(None, ""))
        self.assertEqual(["id_a"], self.param.complete(None, "id_a"))