Skip to content

Commit

Permalink
Add fetching lyrics in the JSON api
Browse files Browse the repository at this point in the history
  • Loading branch information
X-Ryl669 committed Sep 25, 2023
1 parent 52d7382 commit 887f32b
Show file tree
Hide file tree
Showing 4 changed files with 130 additions and 2 deletions.
48 changes: 47 additions & 1 deletion docs/json-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -798,6 +798,7 @@ curl -X PUT "http://localhost:3689/api/queue/items/2"
| GET | [/api/library/tracks/{id}/playlists](#list-playlists-for-a-track) | Get list of playlists for a track |
| PUT | [/api/library/tracks](#update-track-properties) | Update multiple track properties |
| PUT | [/api/library/tracks/{id}](#update-track-properties) | Update single track properties |
| GET | [/api/library/lyrics/{id}](#get-lyrics-for-track) | Fetch lyrics for a track |
| GET | [/api/library/genres](#list-genres) | Get list of genres |
| GET | [/api/library/count](#get-count-of-tracks-artists-and-albums) | Get count of tracks, artists and albums |
| GET | [/api/library/files](#list-local-directories) | Get list of directories in the local library |
Expand Down Expand Up @@ -1544,10 +1545,47 @@ curl -X GET "http://localhost:3689/api/library/tracks/1"
"data_kind": "file",
"path": "/music/srv/Incubus/Make Yourself/12 Pardon Me.mp3",
"uri": "library:track:1",
"artwork_url": "/artwork/item/1"
"artwork_url": "/artwork/item/1",
"lyrics": 1
}
```

### Get lyrics for track

Get lyrics for a specific track in your library

**Endpoint**

```http
GET /api/library/lyrics/{id}
```

**Path parameters**

| Parameter | Value |
| --------------- | -------------------- |
| id | Track id |

**Response**

On success returns the HTTP `200 OK` success status response code. With the response body holding the **[`lyrics`](#lyrics-object) object**.


**Example**

```shell
curl -X GET "http://localhost:3689/api/library/lyrics/1"
```

```json
{
"lyrics": "[00:01:12] Pardon Me
[00:01:14] Oh now",
"length_ms": 223170,
}
```



### List playlists for a track

Expand Down Expand Up @@ -2624,6 +2662,14 @@ curl --include \
| usermark | integer | User review marking of track (ranges from 0) |


### `lyrics` object

| Key | Type | Value |
| ------------------ | -------- | ----------------------------------------- |
| lyrics | string | Lyrics in LRC or plain text |
| length_ms | integer | Track length in milliseconds |


### `paging` object

| Key | Type | Value |
Expand Down
2 changes: 2 additions & 0 deletions src/db.c
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,7 @@ static const struct col_type_map mfi_cols_map[] =
{ "channels", mfi_offsetof(channels), DB_TYPE_INT },
{ "usermark", mfi_offsetof(usermark), DB_TYPE_INT },
{ "scan_kind", mfi_offsetof(scan_kind), DB_TYPE_INT },
{ "lyrics", mfi_offsetof(lyrics), DB_TYPE_STRING },
};

/* This list must be kept in sync with
Expand Down Expand Up @@ -371,6 +372,7 @@ static const ssize_t dbmfi_cols_map[] =
dbmfi_offsetof(channels),
dbmfi_offsetof(usermark),
dbmfi_offsetof(scan_kind),
dbmfi_offsetof(lyrics),
};

/* This list must be kept in sync with
Expand Down
1 change: 1 addition & 0 deletions src/db.h
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,7 @@ struct db_media_file_info {
char *channels;
char *usermark;
char *scan_kind;
char *lyrics;
};

#define dbmfi_offsetof(field) offsetof(struct db_media_file_info, field)
Expand Down
81 changes: 80 additions & 1 deletion src/httpd_jsonapi.c
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,13 @@ safe_json_add_string(json_object *obj, const char *key, const char *value)
json_object_object_add(obj, key, json_object_new_string(value));
}

static inline void
safe_json_add_int(json_object *obj, const char *key, int value)
{
json_object_object_add(obj, key, json_object_new_int(value));
}


static inline void
safe_json_add_string_from_int64(json_object *obj, const char *key, int64_t value)
{
Expand Down Expand Up @@ -322,17 +329,35 @@ track_to_json(struct db_media_file_info *dbmfi)

safe_json_add_string(item, "path", dbmfi->path);

ret = snprintf(uri, sizeof(uri), "%s:%s:%s", "library", "track", dbmfi->id);
ret = snprintf(uri, sizeof(uri), "library:track:%s", dbmfi->id);
if (ret < sizeof(uri))
json_object_object_add(item, "uri", json_object_new_string(uri));

ret = snprintf(artwork_url, sizeof(artwork_url), "/artwork/item/%s", dbmfi->id);
if (ret < sizeof(artwork_url))
json_object_object_add(item, "artwork_url", json_object_new_string(artwork_url));

if (dbmfi->lyrics != NULL)
safe_json_add_int(item, "lyrics", 1);
return item;
}

static json_object *
lyrics_to_json(struct db_media_file_info *dbmfi)
{
json_object *item;

item = json_object_new_object();

if (dbmfi->lyrics != NULL)
{
safe_json_add_string(item, "lyrics", dbmfi->lyrics);
safe_json_add_int_from_string(item, "length_ms", dbmfi->song_length);
}
return item;
}


// TODO Only partially implemented. A full implementation should use a mapping
// table, which should also be used above in track_to_json(). It should also
// return errors if there are incorrect/mispelled fields, but not sure how to
Expand Down Expand Up @@ -3311,6 +3336,59 @@ jsonapi_reply_library_tracks_get_byid(struct httpd_request *hreq)
return HTTP_OK;
}

static int
jsonapi_reply_library_lyrics_get_byid(struct httpd_request *hreq)
{
struct query_params query_params;
const char *track_id;
struct db_media_file_info dbmfi;
json_object *reply = NULL;
int ret = 0;
bool notfound = false;

if (!is_modified(hreq, DB_ADMIN_DB_MODIFIED))
return HTTP_NOTMODIFIED;

track_id = hreq->path_parts[3];

memset(&query_params, 0, sizeof(struct query_params));

query_params.type = Q_ITEMS;
query_params.filter = db_mprintf("(f.id = %q)", track_id);

ret = db_query_start(&query_params);
if (ret < 0)
goto error;

ret = db_query_fetch_file(&dbmfi, &query_params);
if (ret < 0)
goto error;
else if (ret == 1)
{
DPRINTF(E_LOG, L_WEB, "Track with id '%s' not found.\n", track_id);
ret = -1;
notfound = true;
goto error;
}

reply = lyrics_to_json(&dbmfi);

ret = evbuffer_add_printf(hreq->out_body, "%s", json_object_to_json_string(reply));
if (ret < 0)
DPRINTF(E_LOG, L_WEB, "browse: Couldn't add track to response buffer.\n");

error:
db_query_end(&query_params);
free(query_params.filter);
jparse_free(reply);

if (ret < 0)
return notfound ? HTTP_NOTFOUND : HTTP_INTERNAL;

return HTTP_OK;
}


static int
jsonapi_reply_library_tracks_put(struct httpd_request *hreq)
{
Expand Down Expand Up @@ -4688,6 +4766,7 @@ static struct httpd_uri_map adm_handlers[] =
{ HTTPD_METHOD_GET, "^/api/library/tracks/[[:digit:]]+/playlists$", jsonapi_reply_library_track_playlists },
{ HTTPD_METHOD_GET, "^/api/library/(genres|composers)$", jsonapi_reply_library_browse },
{ HTTPD_METHOD_GET, "^/api/library/(genres|composers)/.*$", jsonapi_reply_library_browseitem },
{ HTTPD_METHOD_GET, "^/api/library/lyrics/[[:digit:]]+$", jsonapi_reply_library_lyrics_get_byid },
{ HTTPD_METHOD_GET, "^/api/library/count$", jsonapi_reply_library_count },
{ HTTPD_METHOD_GET, "^/api/library/files$", jsonapi_reply_library_files },
{ HTTPD_METHOD_POST, "^/api/library/add$", jsonapi_reply_library_add },
Expand Down

0 comments on commit 887f32b

Please sign in to comment.