mirror of
https://github.com/owntone/owntone-server.git
synced 2025-04-23 03:55:42 -04:00
Merge pull request #637 from chme/jsonapi_files
New JSON API endpoint for files view
This commit is contained in:
commit
0eae6d710c
@ -587,7 +587,12 @@ POST /api/queue/items/add
|
|||||||
|
|
||||||
**Response**
|
**Response**
|
||||||
|
|
||||||
On success returns the HTTP `204 No Content` success status response code.
|
On success returns the HTTP `200 OK` success status response code.
|
||||||
|
|
||||||
|
| Key | Type | Value |
|
||||||
|
| --------------- | -------- | ----------------------------------------- |
|
||||||
|
| count | integer | number of tracks added to the queue |
|
||||||
|
|
||||||
|
|
||||||
**Example**
|
**Example**
|
||||||
|
|
||||||
@ -595,6 +600,12 @@ On success returns the HTTP `204 No Content` success status response code.
|
|||||||
curl -X POST "http://localhost:3689/api/queue/items/add?uris=library:playlist:68,library:artist:2932599850102967727"
|
curl -X POST "http://localhost:3689/api/queue/items/add?uris=library:playlist:68,library:artist:2932599850102967727"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"count": 42
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
### Moving a queue item
|
### Moving a queue item
|
||||||
|
|
||||||
@ -673,6 +684,7 @@ curl -X PUT "http://localhost:3689/api/queue/items/2"
|
|||||||
| GET | [/api/library/albums/{id}/tracks](#list-album-tracks) | Get list of tracks for an album |
|
| GET | [/api/library/albums/{id}/tracks](#list-album-tracks) | Get list of tracks for an album |
|
||||||
| GET | [/api/library/genres](#list-genres) | Get list of genres |
|
| 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/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 |
|
||||||
| GET | [/api/update](#trigger-rescan) | Trigger a library rescan |
|
| GET | [/api/update](#trigger-rescan) | Trigger a library rescan |
|
||||||
|
|
||||||
|
|
||||||
@ -1205,7 +1217,7 @@ curl -X GET "http://localhost:3689/api/library/albums/1/tracks"
|
|||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
### list genres
|
### List genres
|
||||||
|
|
||||||
Get list of genres
|
Get list of genres
|
||||||
|
|
||||||
@ -1377,6 +1389,105 @@ curl -X GET "http://localhost:3689/api/library/count?expression=data_kind+is+fil
|
|||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### List local directories
|
||||||
|
|
||||||
|
List the local directories and the directory contents (tracks and playlists)
|
||||||
|
|
||||||
|
|
||||||
|
**Endpoint**
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /api/library/files
|
||||||
|
```
|
||||||
|
|
||||||
|
**Query parameters**
|
||||||
|
|
||||||
|
| Parameter | Value |
|
||||||
|
| --------------- | ----------------------------------------------------------- |
|
||||||
|
| directory | *(Optional)* A path to a directory in your local library. |
|
||||||
|
|
||||||
|
**Response**
|
||||||
|
|
||||||
|
| Key | Type | Value |
|
||||||
|
| --------------- | -------- | ----------------------------------------- |
|
||||||
|
| directories | array | Array of [`directory`](#directory-object) objects containing the sub directories |
|
||||||
|
| tracks | object | [`paging`](#paging-object) object containing [`track`](#track-object) objects that matches the `directory` |
|
||||||
|
| playlists | object | [`paging`](#paging-object) object containing [`playlist`](#playlist-object) objects that matches the `directory` |
|
||||||
|
|
||||||
|
|
||||||
|
**Example**
|
||||||
|
|
||||||
|
```shell
|
||||||
|
curl -X GET "http://localhost:3689/api/library/files?directory=/music/srv"
|
||||||
|
```
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"directories": [
|
||||||
|
{
|
||||||
|
"path": "/music/srv/Audiobooks"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "/music/srv/Music"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "/music/srv/Playlists"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "/music/srv/Podcasts"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tracks": {
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"title": "input.pipe",
|
||||||
|
"artist": "Unknown artist",
|
||||||
|
"artist_sort": "Unknown artist",
|
||||||
|
"album": "Unknown album",
|
||||||
|
"album_sort": "Unknown album",
|
||||||
|
"album_id": "4201163758598356043",
|
||||||
|
"album_artist": "Unknown artist",
|
||||||
|
"album_artist_sort": "Unknown artist",
|
||||||
|
"album_artist_id": "4187901437947843388",
|
||||||
|
"genre": "Unknown genre",
|
||||||
|
"year": 0,
|
||||||
|
"track_number": 0,
|
||||||
|
"disc_number": 0,
|
||||||
|
"length_ms": 0,
|
||||||
|
"play_count": 0,
|
||||||
|
"skip_count": 0,
|
||||||
|
"time_added": "2018-11-24T08:41:35Z",
|
||||||
|
"seek_ms": 0,
|
||||||
|
"media_kind": "music",
|
||||||
|
"data_kind": "pipe",
|
||||||
|
"path": "/music/srv/input.pipe",
|
||||||
|
"uri": "library:track:1",
|
||||||
|
"artwork_url": "/artwork/item/1"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"total": 1,
|
||||||
|
"offset": 0,
|
||||||
|
"limit": -1
|
||||||
|
},
|
||||||
|
"playlists": {
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"id": 8,
|
||||||
|
"name": "radio",
|
||||||
|
"path": "/music/srv/radio.m3u",
|
||||||
|
"smart_playlist": true,
|
||||||
|
"uri": "library:playlist:8"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"total": 1,
|
||||||
|
"offset": 0,
|
||||||
|
"limit": -1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
### Trigger rescan
|
### Trigger rescan
|
||||||
|
|
||||||
Trigger a library rescan
|
Trigger a library rescan
|
||||||
@ -1774,6 +1885,7 @@ curl --include \
|
|||||||
| ------------------ | -------- | ----------------------------------------- |
|
| ------------------ | -------- | ----------------------------------------- |
|
||||||
| id | string | Track id |
|
| id | string | Track id |
|
||||||
| title | string | Title |
|
| title | string | Title |
|
||||||
|
| title_sort | string | Sort title |
|
||||||
| artist | string | Track artist name |
|
| artist | string | Track artist name |
|
||||||
| artist_sort | string | Track artist sort name |
|
| artist_sort | string | Track artist sort name |
|
||||||
| album | string | Album name |
|
| album | string | Album name |
|
||||||
@ -1788,8 +1900,11 @@ curl --include \
|
|||||||
| track_number | integer | Track number |
|
| track_number | integer | Track number |
|
||||||
| disc_number | integer | Disc number |
|
| disc_number | integer | Disc number |
|
||||||
| length_ms | integer | Track length in milliseconds |
|
| length_ms | integer | Track length in milliseconds |
|
||||||
|
| rating | integer | Track rating (ranges from 0 to 100) |
|
||||||
| play_count | integer | How many times the track was played |
|
| play_count | integer | How many times the track was played |
|
||||||
|
| skip_count | integer | How many times the track was skipped |
|
||||||
| time_played | string | Timestamp in `ISO 8601` format |
|
| time_played | string | Timestamp in `ISO 8601` format |
|
||||||
|
| time_skipped | string | Timestamp in `ISO 8601` format |
|
||||||
| time_added | string | Timestamp in `ISO 8601` format |
|
| time_added | string | Timestamp in `ISO 8601` format |
|
||||||
| date_released | string | Date in the format `yyyy-mm-dd` |
|
| date_released | string | Date in the format `yyyy-mm-dd` |
|
||||||
| seek_ms | integer | Resume point in milliseconds (available only for podcasts and audiobooks) |
|
| seek_ms | integer | Resume point in milliseconds (available only for podcasts and audiobooks) |
|
||||||
@ -1817,6 +1932,12 @@ curl --include \
|
|||||||
| name | string | Name of genre |
|
| name | string | Name of genre |
|
||||||
|
|
||||||
|
|
||||||
|
### `directory` object
|
||||||
|
|
||||||
|
| Key | Type | Value |
|
||||||
|
| --------------- | -------- | ----------------------------------------- |
|
||||||
|
| path | string | Directory path |
|
||||||
|
|
||||||
|
|
||||||
### Artwork urls
|
### Artwork urls
|
||||||
|
|
||||||
|
40
src/db.c
40
src/db.c
@ -3850,7 +3850,7 @@ db_group_persistentid_byid(int id, int64_t *persistentid)
|
|||||||
|
|
||||||
/* Directories */
|
/* Directories */
|
||||||
int
|
int
|
||||||
db_directory_id_byvirtualpath(char *virtual_path)
|
db_directory_id_byvirtualpath(const char *virtual_path)
|
||||||
{
|
{
|
||||||
#define Q_TMPL "SELECT d.id FROM directories d WHERE d.virtual_path = '%q';"
|
#define Q_TMPL "SELECT d.id FROM directories d WHERE d.virtual_path = '%q';"
|
||||||
char *query;
|
char *query;
|
||||||
@ -3873,6 +3873,30 @@ db_directory_id_byvirtualpath(char *virtual_path)
|
|||||||
#undef Q_TMPL
|
#undef Q_TMPL
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
db_directory_id_bypath(const char *path)
|
||||||
|
{
|
||||||
|
#define Q_TMPL "SELECT d.id FROM directories d WHERE d.path = '%q';"
|
||||||
|
char *query;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
query = sqlite3_mprintf(Q_TMPL, path);
|
||||||
|
if (!query)
|
||||||
|
{
|
||||||
|
DPRINTF(E_LOG, L_DB, "Out of memory for query string\n");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = db_file_id_byquery(query);
|
||||||
|
|
||||||
|
sqlite3_free(query);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
#undef Q_TMPL
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
db_directory_enum_start(struct directory_enum *de)
|
db_directory_enum_start(struct directory_enum *de)
|
||||||
{
|
{
|
||||||
@ -3944,6 +3968,7 @@ db_directory_enum_fetch(struct directory_enum *de, struct directory_info *di)
|
|||||||
disabled = sqlite3_column_int64(de->stmt, 3);
|
disabled = sqlite3_column_int64(de->stmt, 3);
|
||||||
di->disabled = (disabled != 0);
|
di->disabled = (disabled != 0);
|
||||||
di->parent_id = sqlite3_column_int(de->stmt, 4);
|
di->parent_id = sqlite3_column_int(de->stmt, 4);
|
||||||
|
di->path = (char *)sqlite3_column_text(de->stmt, 5);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -3961,8 +3986,8 @@ db_directory_enum_end(struct directory_enum *de)
|
|||||||
static int
|
static int
|
||||||
db_directory_add(struct directory_info *di, int *id)
|
db_directory_add(struct directory_info *di, int *id)
|
||||||
{
|
{
|
||||||
#define QADD_TMPL "INSERT INTO directories (virtual_path, db_timestamp, disabled, parent_id)" \
|
#define QADD_TMPL "INSERT INTO directories (virtual_path, db_timestamp, disabled, parent_id, path)" \
|
||||||
" VALUES (TRIM(%Q), %d, %d, %d);"
|
" VALUES (TRIM(%Q), %d, %d, %d, TRIM(%Q));"
|
||||||
|
|
||||||
char *query;
|
char *query;
|
||||||
char *errmsg;
|
char *errmsg;
|
||||||
@ -3977,7 +4002,7 @@ db_directory_add(struct directory_info *di, int *id)
|
|||||||
DPRINTF(E_LOG, L_DB, "Directory name ends with space: '%s'\n", di->virtual_path);
|
DPRINTF(E_LOG, L_DB, "Directory name ends with space: '%s'\n", di->virtual_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
query = sqlite3_mprintf(QADD_TMPL, di->virtual_path, di->db_timestamp, di->disabled, di->parent_id);
|
query = sqlite3_mprintf(QADD_TMPL, di->virtual_path, di->db_timestamp, di->disabled, di->parent_id, di->path);
|
||||||
|
|
||||||
if (!query)
|
if (!query)
|
||||||
{
|
{
|
||||||
@ -4016,14 +4041,14 @@ db_directory_add(struct directory_info *di, int *id)
|
|||||||
static int
|
static int
|
||||||
db_directory_update(struct directory_info *di)
|
db_directory_update(struct directory_info *di)
|
||||||
{
|
{
|
||||||
#define QADD_TMPL "UPDATE directories SET virtual_path = TRIM(%Q), db_timestamp = %d, disabled = %d, parent_id = %d" \
|
#define QADD_TMPL "UPDATE directories SET virtual_path = TRIM(%Q), db_timestamp = %d, disabled = %d, parent_id = %d, path = TRIM(%Q)" \
|
||||||
" WHERE id = %d;"
|
" WHERE id = %d;"
|
||||||
char *query;
|
char *query;
|
||||||
char *errmsg;
|
char *errmsg;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* Add */
|
/* Add */
|
||||||
query = sqlite3_mprintf(QADD_TMPL, di->virtual_path, di->db_timestamp, di->disabled, di->parent_id, di->id);
|
query = sqlite3_mprintf(QADD_TMPL, di->virtual_path, di->db_timestamp, di->disabled, di->parent_id, di->path, di->id);
|
||||||
|
|
||||||
if (!query)
|
if (!query)
|
||||||
{
|
{
|
||||||
@ -4053,7 +4078,7 @@ db_directory_update(struct directory_info *di)
|
|||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
db_directory_addorupdate(char *virtual_path, int disabled, int parent_id)
|
db_directory_addorupdate(char *virtual_path, char *path, int disabled, int parent_id)
|
||||||
{
|
{
|
||||||
struct directory_info di;
|
struct directory_info di;
|
||||||
int id;
|
int id;
|
||||||
@ -4064,6 +4089,7 @@ db_directory_addorupdate(char *virtual_path, int disabled, int parent_id)
|
|||||||
di.id = id;
|
di.id = id;
|
||||||
di.parent_id = parent_id;
|
di.parent_id = parent_id;
|
||||||
di.virtual_path = virtual_path;
|
di.virtual_path = virtual_path;
|
||||||
|
di.path = path;
|
||||||
di.disabled = disabled;
|
di.disabled = disabled;
|
||||||
di.db_timestamp = (uint64_t)time(NULL);
|
di.db_timestamp = (uint64_t)time(NULL);
|
||||||
|
|
||||||
|
8
src/db.h
8
src/db.h
@ -412,6 +412,7 @@ enum directory_ids {
|
|||||||
struct directory_info {
|
struct directory_info {
|
||||||
uint32_t id;
|
uint32_t id;
|
||||||
char *virtual_path;
|
char *virtual_path;
|
||||||
|
char *path;
|
||||||
uint32_t db_timestamp;
|
uint32_t db_timestamp;
|
||||||
uint32_t disabled;
|
uint32_t disabled;
|
||||||
uint32_t parent_id;
|
uint32_t parent_id;
|
||||||
@ -698,7 +699,10 @@ db_group_persistentid_byid(int id, int64_t *persistentid);
|
|||||||
|
|
||||||
/* Directories */
|
/* Directories */
|
||||||
int
|
int
|
||||||
db_directory_id_byvirtualpath(char *virtual_path);
|
db_directory_id_byvirtualpath(const char *virtual_path);
|
||||||
|
|
||||||
|
int
|
||||||
|
db_directory_id_bypath(const char *path);
|
||||||
|
|
||||||
int
|
int
|
||||||
db_directory_enum_start(struct directory_enum *de);
|
db_directory_enum_start(struct directory_enum *de);
|
||||||
@ -710,7 +714,7 @@ void
|
|||||||
db_directory_enum_end(struct directory_enum *de);
|
db_directory_enum_end(struct directory_enum *de);
|
||||||
|
|
||||||
int
|
int
|
||||||
db_directory_addorupdate(char *virtual_path, int disabled, int parent_id);
|
db_directory_addorupdate(char *virtual_path, char *path, int disabled, int parent_id);
|
||||||
|
|
||||||
void
|
void
|
||||||
db_directory_ping_bymatch(char *virtual_path);
|
db_directory_ping_bymatch(char *virtual_path);
|
||||||
|
@ -161,7 +161,8 @@
|
|||||||
" virtual_path VARCHAR(4096) NOT NULL," \
|
" virtual_path VARCHAR(4096) NOT NULL," \
|
||||||
" db_timestamp INTEGER DEFAULT 0," \
|
" db_timestamp INTEGER DEFAULT 0," \
|
||||||
" disabled INTEGER DEFAULT 0," \
|
" disabled INTEGER DEFAULT 0," \
|
||||||
" parent_id INTEGER DEFAULT 0" \
|
" parent_id INTEGER DEFAULT 0," \
|
||||||
|
" path VARCHAR(4096) DEFAULT NULL" \
|
||||||
");"
|
");"
|
||||||
|
|
||||||
#define T_QUEUE \
|
#define T_QUEUE \
|
||||||
@ -239,17 +240,17 @@
|
|||||||
|
|
||||||
|
|
||||||
#define Q_DIR1 \
|
#define Q_DIR1 \
|
||||||
"INSERT INTO directories (id, virtual_path, db_timestamp, disabled, parent_id)" \
|
"INSERT INTO directories (id, virtual_path, db_timestamp, disabled, parent_id, path)" \
|
||||||
" VALUES (1, '/', 0, 0, 0);"
|
" VALUES (1, '/', 0, 0, 0, NULL);"
|
||||||
#define Q_DIR2 \
|
#define Q_DIR2 \
|
||||||
"INSERT INTO directories (id, virtual_path, db_timestamp, disabled, parent_id)" \
|
"INSERT INTO directories (id, virtual_path, db_timestamp, disabled, parent_id, path)" \
|
||||||
" VALUES (2, '/file:', 0, 0, 1);"
|
" VALUES (2, '/file:', 0, 0, 1, '/');"
|
||||||
#define Q_DIR3 \
|
#define Q_DIR3 \
|
||||||
"INSERT INTO directories (id, virtual_path, db_timestamp, disabled, parent_id)" \
|
"INSERT INTO directories (id, virtual_path, db_timestamp, disabled, parent_id, path)" \
|
||||||
" VALUES (3, '/http:', 0, 0, 1);"
|
" VALUES (3, '/http:', 0, 0, 1, NULL);"
|
||||||
#define Q_DIR4 \
|
#define Q_DIR4 \
|
||||||
"INSERT INTO directories (id, virtual_path, db_timestamp, disabled, parent_id)" \
|
"INSERT INTO directories (id, virtual_path, db_timestamp, disabled, parent_id, path)" \
|
||||||
" VALUES (4, '/spotify:', 0, 4294967296, 1);"
|
" VALUES (4, '/spotify:', 0, 4294967296, 1, NULL);"
|
||||||
|
|
||||||
#define Q_QUEUE_VERSION \
|
#define Q_QUEUE_VERSION \
|
||||||
"INSERT INTO admin (key, value) VALUES ('queue_version', '0');"
|
"INSERT INTO admin (key, value) VALUES ('queue_version', '0');"
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
* is a major upgrade. In other words minor version upgrades permit downgrading
|
* is a major upgrade. In other words minor version upgrades permit downgrading
|
||||||
* forked-daapd after the database was upgraded. */
|
* forked-daapd after the database was upgraded. */
|
||||||
#define SCHEMA_VERSION_MAJOR 19
|
#define SCHEMA_VERSION_MAJOR 19
|
||||||
#define SCHEMA_VERSION_MINOR 11
|
#define SCHEMA_VERSION_MINOR 12
|
||||||
|
|
||||||
int
|
int
|
||||||
db_init_indices(sqlite3 *hdl);
|
db_init_indices(sqlite3 *hdl);
|
||||||
|
@ -1698,6 +1698,27 @@ static const struct db_upgrade_query db_upgrade_v1911_queries[] =
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#define U_V1912_ALTER_DIRECTORIES_ADD_PATH \
|
||||||
|
"ALTER TABLE directories ADD COLUMN path VARCHAR(4096) DEFAULT NULL;"
|
||||||
|
|
||||||
|
#define U_V1912_UPDATE_FILE_DIRECTORIES_PATH \
|
||||||
|
"UPDATE directories SET path = SUBSTR(path, 7) WHERE virtual_path like '/file:/%';"
|
||||||
|
#define U_V1912_UPDATE_FILE_ROOT_PATH \
|
||||||
|
"UPDATE directories SET path = '/' WHERE virtual_path = '/file:';"
|
||||||
|
|
||||||
|
#define U_V1912_SCVER_MINOR \
|
||||||
|
"UPDATE admin SET value = '12' WHERE key = 'schema_version_minor';"
|
||||||
|
|
||||||
|
static const struct db_upgrade_query db_upgrade_v1912_queries[] =
|
||||||
|
{
|
||||||
|
{ U_V1912_ALTER_DIRECTORIES_ADD_PATH, "alter table directories add column path" },
|
||||||
|
{ U_V1912_UPDATE_FILE_DIRECTORIES_PATH, "set paths for '/file:' directories" },
|
||||||
|
{ U_V1912_UPDATE_FILE_ROOT_PATH, "set path for '/file:' directory" },
|
||||||
|
|
||||||
|
{ U_V1912_SCVER_MINOR, "set schema_version_minor to 12" },
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
db_upgrade(sqlite3 *hdl, int db_ver)
|
db_upgrade(sqlite3 *hdl, int db_ver)
|
||||||
{
|
{
|
||||||
@ -1884,6 +1905,14 @@ db_upgrade(sqlite3 *hdl, int db_ver)
|
|||||||
ret = db_generic_upgrade(hdl, db_upgrade_v1911_queries, ARRAY_SIZE(db_upgrade_v1911_queries));
|
ret = db_generic_upgrade(hdl, db_upgrade_v1911_queries, ARRAY_SIZE(db_upgrade_v1911_queries));
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
/* FALLTHROUGH */
|
||||||
|
|
||||||
|
case 1911:
|
||||||
|
ret = db_generic_upgrade(hdl, db_upgrade_v1912_queries, ARRAY_SIZE(db_upgrade_v1912_queries));
|
||||||
|
if (ret < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -182,6 +182,7 @@ track_to_json(struct db_media_file_info *dbmfi)
|
|||||||
|
|
||||||
safe_json_add_int_from_string(item, "id", dbmfi->id);
|
safe_json_add_int_from_string(item, "id", dbmfi->id);
|
||||||
safe_json_add_string(item, "title", dbmfi->title);
|
safe_json_add_string(item, "title", dbmfi->title);
|
||||||
|
safe_json_add_string(item, "title_sort", dbmfi->title_sort);
|
||||||
safe_json_add_string(item, "artist", dbmfi->artist);
|
safe_json_add_string(item, "artist", dbmfi->artist);
|
||||||
safe_json_add_string(item, "artist_sort", dbmfi->artist_sort);
|
safe_json_add_string(item, "artist_sort", dbmfi->artist_sort);
|
||||||
safe_json_add_string(item, "album", dbmfi->album);
|
safe_json_add_string(item, "album", dbmfi->album);
|
||||||
@ -197,6 +198,7 @@ track_to_json(struct db_media_file_info *dbmfi)
|
|||||||
safe_json_add_int_from_string(item, "disc_number", dbmfi->disc);
|
safe_json_add_int_from_string(item, "disc_number", dbmfi->disc);
|
||||||
safe_json_add_int_from_string(item, "length_ms", dbmfi->song_length);
|
safe_json_add_int_from_string(item, "length_ms", dbmfi->song_length);
|
||||||
|
|
||||||
|
safe_json_add_int_from_string(item, "rating", dbmfi->rating);
|
||||||
safe_json_add_int_from_string(item, "play_count", dbmfi->play_count);
|
safe_json_add_int_from_string(item, "play_count", dbmfi->play_count);
|
||||||
safe_json_add_int_from_string(item, "skip_count", dbmfi->skip_count);
|
safe_json_add_int_from_string(item, "skip_count", dbmfi->skip_count);
|
||||||
safe_json_add_time_from_string(item, "time_played", dbmfi->time_played, true);
|
safe_json_add_time_from_string(item, "time_played", dbmfi->time_played, true);
|
||||||
@ -266,6 +268,24 @@ genre_to_json(const char *genre)
|
|||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static json_object *
|
||||||
|
directory_to_json(struct directory_info *directory_info)
|
||||||
|
{
|
||||||
|
json_object *item;
|
||||||
|
|
||||||
|
if (directory_info == NULL)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
item = json_object_new_object();
|
||||||
|
safe_json_add_string(item, "path", directory_info->path);
|
||||||
|
// json_object_object_add(item, "id", json_object_new_int(directory_info->id));
|
||||||
|
// json_object_object_add(item, "parent_id", json_object_new_int(directory_info->parent_id));
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
fetch_tracks(struct query_params *query_params, json_object *items, int *total)
|
fetch_tracks(struct query_params *query_params, json_object *items, int *total)
|
||||||
@ -529,6 +549,38 @@ fetch_genres(struct query_params *query_params, json_object *items, int *total)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
fetch_directories(int parent_id, json_object *items)
|
||||||
|
{
|
||||||
|
json_object *item;
|
||||||
|
int ret;
|
||||||
|
struct directory_info subdir;
|
||||||
|
struct directory_enum dir_enum;
|
||||||
|
|
||||||
|
memset(&dir_enum, 0, sizeof(struct directory_enum));
|
||||||
|
dir_enum.parent_id = parent_id;
|
||||||
|
ret = db_directory_enum_start(&dir_enum);
|
||||||
|
if (ret < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
while ((ret = db_directory_enum_fetch(&dir_enum, &subdir)) == 0 && subdir.id > 0)
|
||||||
|
{
|
||||||
|
item = directory_to_json(&subdir);
|
||||||
|
if (!item)
|
||||||
|
{
|
||||||
|
ret = -1;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
json_object_array_add(items, item);
|
||||||
|
}
|
||||||
|
|
||||||
|
error:
|
||||||
|
db_directory_enum_end(&dir_enum);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
query_params_limit_set(struct query_params *query_params, struct httpd_request *hreq)
|
query_params_limit_set(struct query_params *query_params, struct httpd_request *hreq)
|
||||||
@ -1275,6 +1327,7 @@ static int
|
|||||||
play_item_at_position(const char *param)
|
play_item_at_position(const char *param)
|
||||||
{
|
{
|
||||||
uint32_t position;
|
uint32_t position;
|
||||||
|
struct player_status status;
|
||||||
struct db_queue_item *queue_item;
|
struct db_queue_item *queue_item;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
@ -1286,7 +1339,9 @@ play_item_at_position(const char *param)
|
|||||||
return HTTP_BADREQUEST;
|
return HTTP_BADREQUEST;
|
||||||
}
|
}
|
||||||
|
|
||||||
queue_item = db_queue_fetch_bypos(position, 0);
|
player_get_status(&status);
|
||||||
|
|
||||||
|
queue_item = db_queue_fetch_bypos(position, status.shuffle);
|
||||||
if (!queue_item)
|
if (!queue_item)
|
||||||
{
|
{
|
||||||
DPRINTF(E_LOG, L_WEB, "No queue item at position '%d'\n", position);
|
DPRINTF(E_LOG, L_WEB, "No queue item at position '%d'\n", position);
|
||||||
@ -1690,6 +1745,7 @@ jsonapi_reply_queue_tracks_add(struct httpd_request *hreq)
|
|||||||
const char *id;
|
const char *id;
|
||||||
int pos = -1;
|
int pos = -1;
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
json_object *reply;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
|
|
||||||
@ -1759,10 +1815,19 @@ jsonapi_reply_queue_tracks_add(struct httpd_request *hreq)
|
|||||||
|
|
||||||
free(uris);
|
free(uris);
|
||||||
|
|
||||||
|
if (ret == 0)
|
||||||
|
{
|
||||||
|
reply = json_object_new_object();
|
||||||
|
json_object_object_add(reply, "count", json_object_new_int(count));
|
||||||
|
|
||||||
|
ret = evbuffer_add_printf(hreq->reply, "%s", json_object_to_json_string(reply));
|
||||||
|
jparse_free(reply);
|
||||||
|
}
|
||||||
|
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return HTTP_INTERNAL;
|
return HTTP_INTERNAL;
|
||||||
|
|
||||||
return HTTP_NOCONTENT;
|
return HTTP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@ -2609,6 +2674,107 @@ jsonapi_reply_library_count(struct httpd_request *hreq)
|
|||||||
return HTTP_OK;
|
return HTTP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
jsonapi_reply_library_files(struct httpd_request *hreq)
|
||||||
|
{
|
||||||
|
const char *param;
|
||||||
|
int directory_id;
|
||||||
|
json_object *reply;
|
||||||
|
json_object *directories;
|
||||||
|
struct query_params query_params;
|
||||||
|
json_object *tracks;
|
||||||
|
json_object *tracks_items;
|
||||||
|
json_object *playlists;
|
||||||
|
json_object *playlists_items;
|
||||||
|
int total;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
param = evhttp_find_header(hreq->query, "directory");
|
||||||
|
|
||||||
|
directory_id = DIR_FILE;
|
||||||
|
if (param)
|
||||||
|
{
|
||||||
|
directory_id = db_directory_id_bypath(param);
|
||||||
|
if (directory_id <= 0)
|
||||||
|
return HTTP_INTERNAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
reply = json_object_new_object();
|
||||||
|
|
||||||
|
// Add sub directories to response
|
||||||
|
directories = json_object_new_array();
|
||||||
|
json_object_object_add(reply, "directories", directories);
|
||||||
|
|
||||||
|
ret = fetch_directories(directory_id, directories);
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add tracks to response
|
||||||
|
tracks = json_object_new_object();
|
||||||
|
json_object_object_add(reply, "tracks", tracks);
|
||||||
|
tracks_items = json_object_new_array();
|
||||||
|
json_object_object_add(tracks, "items", tracks_items);
|
||||||
|
memset(&query_params, 0, sizeof(struct query_params));
|
||||||
|
|
||||||
|
ret = query_params_limit_set(&query_params, hreq);
|
||||||
|
if (ret < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
query_params.type = Q_ITEMS;
|
||||||
|
query_params.sort = S_NAME;
|
||||||
|
query_params.filter = db_mprintf("(f.directory_id = %d)", directory_id);
|
||||||
|
|
||||||
|
ret = fetch_tracks(&query_params, tracks_items, &total);
|
||||||
|
free(query_params.filter);
|
||||||
|
|
||||||
|
if (ret < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
json_object_object_add(tracks, "total", json_object_new_int(total));
|
||||||
|
json_object_object_add(tracks, "offset", json_object_new_int(query_params.offset));
|
||||||
|
json_object_object_add(tracks, "limit", json_object_new_int(query_params.limit));
|
||||||
|
|
||||||
|
// Add playlists
|
||||||
|
playlists = json_object_new_object();
|
||||||
|
json_object_object_add(reply, "playlists", playlists);
|
||||||
|
playlists_items = json_object_new_array();
|
||||||
|
json_object_object_add(playlists, "items", playlists_items);
|
||||||
|
memset(&query_params, 0, sizeof(struct query_params));
|
||||||
|
|
||||||
|
ret = query_params_limit_set(&query_params, hreq);
|
||||||
|
if (ret < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
query_params.type = Q_PL;
|
||||||
|
query_params.sort = S_PLAYLIST;
|
||||||
|
query_params.filter = db_mprintf("(f.directory_id = %d)", directory_id);
|
||||||
|
|
||||||
|
ret = fetch_playlists(&query_params, playlists_items, &total);
|
||||||
|
free(query_params.filter);
|
||||||
|
|
||||||
|
if (ret < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
json_object_object_add(playlists, "total", json_object_new_int(total));
|
||||||
|
json_object_object_add(playlists, "offset", json_object_new_int(query_params.offset));
|
||||||
|
json_object_object_add(playlists, "limit", json_object_new_int(query_params.limit));
|
||||||
|
|
||||||
|
// Build JSON response
|
||||||
|
ret = evbuffer_add_printf(hreq->reply, "%s", json_object_to_json_string(reply));
|
||||||
|
if (ret < 0)
|
||||||
|
DPRINTF(E_LOG, L_WEB, "browse: Couldn't add directories to response buffer.\n");
|
||||||
|
|
||||||
|
error:
|
||||||
|
jparse_free(reply);
|
||||||
|
|
||||||
|
if (ret < 0)
|
||||||
|
return HTTP_INTERNAL;
|
||||||
|
|
||||||
|
return HTTP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
search_tracks(json_object *reply, struct httpd_request *hreq, const char *param_query, struct smartpl *smartpl_expression, enum media_kind media_kind)
|
search_tracks(json_object *reply, struct httpd_request *hreq, const char *param_query, struct smartpl *smartpl_expression, enum media_kind media_kind)
|
||||||
{
|
{
|
||||||
@ -2977,6 +3143,7 @@ static struct httpd_uri_map adm_handlers[] =
|
|||||||
{ EVHTTP_REQ_GET, "^/api/library/albums/[[:digit:]]+/tracks$", jsonapi_reply_library_album_tracks },
|
{ EVHTTP_REQ_GET, "^/api/library/albums/[[:digit:]]+/tracks$", jsonapi_reply_library_album_tracks },
|
||||||
{ EVHTTP_REQ_GET, "^/api/library/genres$", jsonapi_reply_library_genres},
|
{ EVHTTP_REQ_GET, "^/api/library/genres$", jsonapi_reply_library_genres},
|
||||||
{ EVHTTP_REQ_GET, "^/api/library/count$", jsonapi_reply_library_count },
|
{ EVHTTP_REQ_GET, "^/api/library/count$", jsonapi_reply_library_count },
|
||||||
|
{ EVHTTP_REQ_GET, "^/api/library/files$", jsonapi_reply_library_files },
|
||||||
|
|
||||||
{ EVHTTP_REQ_GET, "^/api/search$", jsonapi_reply_search },
|
{ EVHTTP_REQ_GET, "^/api/search$", jsonapi_reply_search },
|
||||||
|
|
||||||
|
@ -749,7 +749,7 @@ process_directory(char *path, int parent_id, int flags)
|
|||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
dir_id = db_directory_addorupdate(virtual_path, 0, parent_id);
|
dir_id = db_directory_addorupdate(virtual_path, path, 0, parent_id);
|
||||||
if (dir_id <= 0)
|
if (dir_id <= 0)
|
||||||
{
|
{
|
||||||
DPRINTF(E_LOG, L_SCAN, "Insert or update of directory failed '%s'\n", virtual_path);
|
DPRINTF(E_LOG, L_SCAN, "Insert or update of directory failed '%s'\n", virtual_path);
|
||||||
@ -876,7 +876,7 @@ process_parent_directories(char *path)
|
|||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
dir_id = db_directory_addorupdate(virtual_path, 0, dir_id);
|
dir_id = db_directory_addorupdate(virtual_path, buf, 0, dir_id);
|
||||||
if (dir_id <= 0)
|
if (dir_id <= 0)
|
||||||
{
|
{
|
||||||
DPRINTF(E_LOG, L_SCAN, "Insert or update of directory failed '%s'\n", virtual_path);
|
DPRINTF(E_LOG, L_SCAN, "Insert or update of directory failed '%s'\n", virtual_path);
|
||||||
|
@ -1250,7 +1250,7 @@ prepare_directories(const char *artist, const char *album)
|
|||||||
DPRINTF(E_LOG, L_SPOTIFY, "Virtual path exceeds PATH_MAX (/spotify:/%s)\n", artist);
|
DPRINTF(E_LOG, L_SPOTIFY, "Virtual path exceeds PATH_MAX (/spotify:/%s)\n", artist);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
dir_id = db_directory_addorupdate(virtual_path, 0, DIR_SPOTIFY);
|
dir_id = db_directory_addorupdate(virtual_path, NULL, 0, DIR_SPOTIFY);
|
||||||
if (dir_id <= 0)
|
if (dir_id <= 0)
|
||||||
{
|
{
|
||||||
DPRINTF(E_LOG, L_SPOTIFY, "Could not add or update directory '%s'\n", virtual_path);
|
DPRINTF(E_LOG, L_SPOTIFY, "Could not add or update directory '%s'\n", virtual_path);
|
||||||
@ -1262,7 +1262,7 @@ prepare_directories(const char *artist, const char *album)
|
|||||||
DPRINTF(E_LOG, L_SPOTIFY, "Virtual path exceeds PATH_MAX (/spotify:/%s/%s)\n", artist, album);
|
DPRINTF(E_LOG, L_SPOTIFY, "Virtual path exceeds PATH_MAX (/spotify:/%s/%s)\n", artist, album);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
dir_id = db_directory_addorupdate(virtual_path, 0, dir_id);
|
dir_id = db_directory_addorupdate(virtual_path, NULL, 0, dir_id);
|
||||||
if (dir_id <= 0)
|
if (dir_id <= 0)
|
||||||
{
|
{
|
||||||
DPRINTF(E_LOG, L_SPOTIFY, "Could not add or update directory '%s'\n", virtual_path);
|
DPRINTF(E_LOG, L_SPOTIFY, "Could not add or update directory '%s'\n", virtual_path);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user