Merge pull request #916 from whatdoineed2do/json-playlist-play-count-update

[json] enable playlist play_count
This commit is contained in:
Christian Meffert 2020-03-28 07:41:24 +01:00 committed by GitHub
commit 5bd32135ee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 144 additions and 6 deletions

View File

@ -747,6 +747,7 @@ curl -X PUT "http://localhost:3689/api/queue/items/2"
| GET | [/api/library/playlists](#list-playlists) | Get a list of playlists |
| GET | [/api/library/playlists/{id}](#get-a-playlist) | Get a playlist |
| GET | [/api/library/playlists/{id}/tracks](#list-playlist-tracks) | Get list of tracks for a playlist |
| PUT | [/api/library/playlists/{id}/tracks](#update-playlist-tracks) | Update play count of tracks for a playlist |
| GET | [/api/library/playlists/{id}/playlists](#list-playlists-in-a-playlist-folder) | Get list of playlists for a playlist folder |
| GET | [/api/library/artists](#list-artists) | Get a list of artists |
| GET | [/api/library/artists/{id}](#get-an-artist) | Get an artist |
@ -968,6 +969,34 @@ curl -X GET "http://localhost:3689/api/library/playlists/1/tracks"
}
```
### Update playlist tracks
Updates the play count for tracks in a playlists
**Endpoint**
```http
PUT /api/library/playlists/{id}/tracks
```
**Path parameters**
| Parameter | Value |
| --------------- | -------------------- |
| id | Playlist id |
**Query parameters**
| Parameter | Value |
| --------------- | ----------------------------------------------------------- |
| play_count | Either `increment`, `played` or `reset`. `increment` will increment `play_count` and update `time_played`, `played` will be like `increment` but only where `play_count` is 0, `reset` will set `play_count` and `skip_count` to zero and delete `time_played` and `time_skipped` |
**Example**
```shell
curl -X PUT "http://localhost:3689/api/library/playlists/1/tracks?play_count=played"
```
### List playlists in a playlist folder

View File

@ -2514,10 +2514,10 @@ db_files_get_count(uint32_t *nitems, uint32_t *nstreams, const char *filter)
return 0;
}
void
db_file_inc_playcount(int id)
static void
db_file_inc_playcount_byfilter(const char *filter)
{
#define Q_TMPL "UPDATE files SET play_count = play_count + 1, time_played = %" PRIi64 ", seek = 0 WHERE id = %d;"
#define Q_TMPL "UPDATE files SET play_count = play_count + 1, time_played = %" PRIi64 ", seek = 0 WHERE %s;"
/*
* Rating calculation is taken from from the beets plugin "mpdstats" (see https://beets.readthedocs.io/en/latest/plugins/mpdstats.html)
* and adapted to the forked-daapd rating rage (0 to 100).
@ -2536,14 +2536,16 @@ db_file_inc_playcount(int id)
"UPDATE files "\
" SET play_count = play_count + 1, time_played = %" PRIi64 ", seek = 0, "\
" rating = CAST(((play_count + 1.0) / (play_count + skip_count + 2.0) * 100 * 0.75) + ((rating + ((100.0 - rating) / 2.0)) * 0.25) AS INT)" \
" WHERE id = %d;"
" WHERE %s;"
char *query;
int ret;
if (db_rating_updates)
query = sqlite3_mprintf(Q_TMPL_WITH_RATING, (int64_t)time(NULL), id);
query = sqlite3_mprintf(Q_TMPL_WITH_RATING, (int64_t)time(NULL), filter);
else
query = sqlite3_mprintf(Q_TMPL, (int64_t)time(NULL), id);
query = sqlite3_mprintf(Q_TMPL, (int64_t)time(NULL), filter);
if (!query)
{
DPRINTF(E_LOG, L_DB, "Out of memory for query string\n");
@ -2558,6 +2560,41 @@ db_file_inc_playcount(int id)
#undef Q_TMPL_WITH_RATING
}
void
db_file_inc_playcount_byplid(int id, bool only_unplayed)
{
char *filter;
filter = sqlite3_mprintf("path IN (SELECT filepath FROM playlistitems WHERE playlistid = %d) %s",
id, only_unplayed ? "AND play_count = 0" : "");
db_file_inc_playcount_byfilter(filter);
sqlite3_free(filter);
}
void
db_file_inc_playcount_bysongalbumid(int64_t id, bool only_unplayed)
{
char *filter;
filter = sqlite3_mprintf("songalbumid = %" PRIi64 " %s",
id, only_unplayed ? "AND play_count = 0" : "");
db_file_inc_playcount_byfilter(filter);
sqlite3_free(filter);
}
void
db_file_inc_playcount(int id)
{
char *filter;
filter = sqlite3_mprintf("id = %d", id);
db_file_inc_playcount_byfilter(filter);
sqlite3_free(filter);
}
void
db_file_inc_skipcount(int id)
{

View File

@ -580,6 +580,12 @@ db_files_get_count(uint32_t *nitems, uint32_t *nstreams, const char *filter);
void
db_file_inc_playcount(int id);
void
db_file_inc_playcount_byplid(int id, bool only_unplayed);
void
db_file_inc_playcount_bysongalbumid(int64_t id, bool only_unplayed);
void
db_file_inc_skipcount(int id);

View File

@ -3043,6 +3043,38 @@ jsonapi_reply_library_album_tracks(struct httpd_request *hreq)
return HTTP_OK;
}
static int
jsonapi_reply_library_album_tracks_put_byid(struct httpd_request *hreq)
{
const char *param;
int64_t album_id;;
int ret;
ret = safe_atoi64(hreq->uri_parsed->path_parts[3], &album_id);
if (ret < 0)
return HTTP_INTERNAL;
param = evhttp_find_header(hreq->query, "play_count");
if (!param)
return HTTP_BADREQUEST;
if (strcmp(param, "increment") == 0)
{
db_file_inc_playcount_bysongalbumid(album_id, false);
}
else if (strcmp(param, "played") == 0)
{
db_file_inc_playcount_bysongalbumid(album_id, true);
}
else
{
DPRINTF(E_WARN, L_WEB, "Ignoring invalid play_count param '%s'\n", param);
return HTTP_BADREQUEST;
}
return HTTP_OK;
}
static int
jsonapi_reply_library_tracks_get_byid(struct httpd_request *hreq)
{
@ -3358,6 +3390,38 @@ jsonapi_reply_library_playlist_playlists(struct httpd_request *hreq)
return HTTP_OK;
}
static int
jsonapi_reply_library_playlist_tracks_put_byid(struct httpd_request *hreq)
{
const char *param;
int playlist_id;
int ret;
ret = safe_atoi32(hreq->uri_parsed->path_parts[3], &playlist_id);
if (ret < 0)
return HTTP_INTERNAL;
param = evhttp_find_header(hreq->query, "play_count");
if (!param)
return HTTP_BADREQUEST;
if (strcmp(param, "increment") == 0)
{
db_file_inc_playcount_byplid(playlist_id, false);
}
else if (strcmp(param, "played") == 0)
{
db_file_inc_playcount_byplid(playlist_id, true);
}
else
{
DPRINTF(E_WARN, L_WEB, "Ignoring invalid play_count param '%s'\n", param);
return HTTP_BADREQUEST;
}
return HTTP_OK;
}
static int
jsonapi_reply_queue_save(struct httpd_request *hreq)
{
@ -3993,6 +4057,7 @@ static struct httpd_uri_map adm_handlers[] =
{ EVHTTP_REQ_GET, "^/api/library/playlists$", jsonapi_reply_library_playlists },
{ EVHTTP_REQ_GET, "^/api/library/playlists/[[:digit:]]+$", jsonapi_reply_library_playlist },
{ EVHTTP_REQ_GET, "^/api/library/playlists/[[:digit:]]+/tracks$", jsonapi_reply_library_playlist_tracks },
{ EVHTTP_REQ_PUT, "^/api/library/playlists/[[:digit:]]+/tracks", jsonapi_reply_library_playlist_tracks_put_byid},
// { EVHTTP_REQ_POST, "^/api/library/playlists/[[:digit:]]+/tracks$", jsonapi_reply_library_playlists_tracks },
// { EVHTTP_REQ_DELETE, "^/api/library/playlists/[[:digit:]]+$", jsonapi_reply_library_playlist_tracks },
{ EVHTTP_REQ_GET, "^/api/library/playlists/[[:digit:]]+/playlists", jsonapi_reply_library_playlist_playlists },
@ -4002,6 +4067,7 @@ static struct httpd_uri_map adm_handlers[] =
{ EVHTTP_REQ_GET, "^/api/library/albums$", jsonapi_reply_library_albums },
{ EVHTTP_REQ_GET, "^/api/library/albums/[[:digit:]]+$", jsonapi_reply_library_album },
{ EVHTTP_REQ_GET, "^/api/library/albums/[[:digit:]]+/tracks$", jsonapi_reply_library_album_tracks },
{ EVHTTP_REQ_PUT, "^/api/library/albums/[[:digit:]]+/tracks$", jsonapi_reply_library_album_tracks_put_byid },
{ EVHTTP_REQ_GET, "^/api/library/tracks/[[:digit:]]+$", jsonapi_reply_library_tracks_get_byid },
{ EVHTTP_REQ_PUT, "^/api/library/tracks/[[:digit:]]+$", jsonapi_reply_library_tracks_put_byid },
{ EVHTTP_REQ_GET, "^/api/library/genres$", jsonapi_reply_library_genres},