Verified Commit d6c60983 authored by Agate's avatar Agate 💬

Added playlist track listing

parent b947f834
Pipeline #4565 passed with stages
in 2 minutes and 15 seconds
......@@ -92,6 +92,10 @@ def ignore_aiohttp_ssl_eror(loop):
loop.set_exception_handler(ignore_ssl_error)
def noop_decorator(f):
return f
def URL(v):
if v is NOOP:
raise click.ClickException(
......@@ -385,25 +389,57 @@ def get_pagination_data(payload):
return data
def get_ls_command(group, endpoint, output_conf):
def get_ls_command(
group,
endpoint,
output_conf,
pagination=True,
filter=True,
ordering=True,
with_id=False,
name="ls",
):
available_fields = sorted(
set(output_conf["labels"]) | set(output.FIELDS["*"].keys())
)
id_decorator = click.argument("id") if with_id else noop_decorator
page_decorator = (
click.option("--page", "-p", type=click.INT, default=1)
if pagination
else noop_decorator
)
page_size_decorator = (
click.option("--page-size", "-s", type=click.INT, default=None)
if pagination
else noop_decorator
)
limit_decorator = (
click.option("--limit", "-l", type=click.INT, default=1)
if pagination
else noop_decorator
)
ordering_decorator = (
click.option("--ordering", "-o", default=None) if ordering else noop_decorator
)
filter_decorator = (
click.option("--filter", "-f", multiple=True) if filter else noop_decorator
)
@group.command("ls")
@group.command(name)
@id_decorator
@click.argument("query", nargs=-1)
@RAW_DECORATOR
@click.option(
"--format", "-t", type=click.Choice(output.TABLE_FORMATS), default="simple"
)
@click.option("--no-headers", "-h", is_flag=True, default=False)
@click.option("--page", "-p", type=click.INT, default=1)
@click.option("--page-size", "-s", type=click.INT, default=None)
@click.option("--ordering", "-o", default=None)
@click.option("--filter", "-f", multiple=True)
@click.option("--ids", "-i", is_flag=True)
@click.option("--limit", "-l", type=click.INT, default=1)
@page_decorator
@page_size_decorator
@ordering_decorator
@filter_decorator
@limit_decorator
@click.option(
"--column",
"-c",
......@@ -414,33 +450,32 @@ def get_ls_command(group, endpoint, output_conf):
)
@click.pass_context
@async_command
async def ls(
ctx,
raw,
page,
page_size,
ordering,
filter,
query,
column,
format,
no_headers,
ids,
limit,
):
async def ls(ctx, raw, column, format, no_headers, ids, **kwargs):
id = kwargs.get("id")
limit = kwargs.get("limit")
page = kwargs.get("page")
page_size = kwargs.get("page_size")
ordering = kwargs.get("ordering")
filter = kwargs.get("filter")
query = kwargs.get("query")
if ids:
no_headers = True
column = [output_conf.get("id_field", "UUID")]
format = "plain"
base_url = endpoint
if with_id:
base_url = base_url.format(id)
next_page_url = None
page_count = 0
while True:
if limit and page_count >= limit:
break
async with ctx.obj["remote"]:
if page_count == 0:
url = endpoint
params = {"page": page}
if not pagination or page_count == 0:
url = base_url
params = {}
if page:
params["page"] = page
if page_size:
params["page_size"] = page_size
if ordering:
......@@ -460,7 +495,7 @@ def get_ls_command(group, endpoint, output_conf):
result = await ctx.obj["remote"].request("get", url, params=params)
result.raise_for_status()
payload = await result.json()
next_page_url = payload["next"]
next_page_url = payload.get("next")
page_count += 1
if raw:
click.echo(json.dumps(payload, sort_keys=True, indent=4))
......@@ -474,6 +509,8 @@ def get_ls_command(group, endpoint, output_conf):
headers=not no_headers,
)
)
if not pagination:
break
pagination_data = get_pagination_data(payload)
if pagination_data["page_size"]:
start = (
......@@ -499,17 +536,20 @@ def get_ls_command(group, endpoint, output_conf):
return ls
def get_show_command(group, url_template, output_conf, name='show', force_id=None):
def get_show_command(group, url_template, output_conf, name="show", force_id=None):
available_fields = sorted(
set(output_conf["labels"]) | set(output.FIELDS["*"].keys())
)
if force_id:
def id_decorator(f):
@functools.wraps(f)
def inner(raw, column, format):
return f(raw, force_id, column, format)
return inner
else:
id_decorator = click.argument("id")
......@@ -529,16 +569,12 @@ def get_show_command(group, url_template, output_conf, name='show', force_id=Non
)
@click.pass_context
@async_command
async def show(
ctx,
raw,
id,
column,
format,
):
async def show(ctx, raw, id, column, format):
async with ctx.obj["remote"]:
async with ctx.obj["remote"].request("get", url_template.format(id)) as result:
async with ctx.obj["remote"].request(
"get", url_template.format(id)
) as result:
result.raise_for_status()
payload = await result.json()
if raw:
......@@ -1052,6 +1088,42 @@ async def playlists_create(ctx, raw, name, visibility):
)
@playlists.command("tracks-add")
@click.argument("id")
@click.argument("track", nargs=-1)
@click.option(
"--no-duplicates",
is_flag=True,
default=False,
help="Prevent insertion of tracks that already exist in the playlist",
)
@click.pass_context
@async_command
async def playlists_tracks_add(ctx, id, track, no_duplicates):
async with ctx.obj["remote"]:
async with ctx.obj["remote"].request(
"post",
"api/v1/playlists/{}/".format(id),
data={"tracks": track, "allow_duplicates": not no_duplicates},
) as response:
response.raise_for_status()
playlists_tracks = get_ls_command(
playlists,
"api/v1/playlists/{}/tracks/",
name="tracks",
with_id=True,
pagination=False,
ordering=False,
filter=False,
output_conf={
"labels": ["Position", "ID", "Title", "Artist", "Album", "Created"],
"id_field": "ID",
"type": "PLAYLIST_TRACK",
},
)
@cli.group()
@click.pass_context
......@@ -1077,8 +1149,8 @@ users_me = get_show_command(
],
"type": "USER",
},
force_id='me',
name='me',
force_id="me",
name="me",
)
......
......@@ -50,6 +50,12 @@ FIELDS = {
"Tracks Count": {"field": "tracks_count"},
"User": {"field": "user.username"},
},
"PLAYLIST_TRACK": {
"Position": {"field": "index"},
"Title": {"field": "track.title"},
"Artist": {"field": "track.artist.name"},
"Album": {"field": "track.album.title"},
},
"USER": {
"Username": {"field": "username"},
"Federation ID": {"field": "full_username"},
......
......@@ -337,3 +337,28 @@ def test_playlists_rm(cli_ctx, session, responses, get_requests):
assert len(get_requests("delete", url + "1/")) == 1
assert len(get_requests("delete", url + "42/")) == 1
def test_playlists_tracks_add(cli_ctx, session, responses, get_requests):
command = cli.playlists_tracks_add
url = "https://test.funkwhale/api/v1/playlists/66/"
responses.post(url)
command.callback(id=66, track=[1, 42], no_duplicates=True, _async_reraise=True)
requests = get_requests("post", url)
assert len(requests) == 1
assert requests[0].kwargs["data"] == {"tracks": [1, 42], "allow_duplicates": False}
def test_playlists_tracks(cli_ctx, session, responses, get_requests):
command = cli.playlists_tracks
url = "https://test.funkwhale/api/v1/playlists/66/tracks/"
responses.get(url, payload={"results": [], "count": 0})
command.callback(
id=66, raw=False, column=None, format=None, no_headers=False, ids=False
)
requests = get_requests("get", url)
assert len(requests) == 1
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment