diff --git a/persistence/playlist_repository.go b/persistence/playlist_repository.go
index ecf92da46..e6c528a4f 100644
--- a/persistence/playlist_repository.go
+++ b/persistence/playlist_repository.go
@@ -77,15 +77,6 @@ func (r *playlistRepository) GetAll(options ...model.QueryOptions) (model.Playli
return res, err
}
-func (r *playlistRepository) Tracks(playlistId string) model.PlaylistTracksRepository {
- p := &playlistTracksRepository{}
- p.playlistId = playlistId
- p.ctx = r.ctx
- p.ormer = r.ormer
- p.tableName = "playlist_tracks"
- return p
-}
-
func (r *playlistRepository) updateTracks(id string, tracks model.MediaFiles) error {
// Remove old tracks
del := Delete("playlist_tracks").Where(Eq{"playlist_id": id})
@@ -94,10 +85,27 @@ func (r *playlistRepository) updateTracks(id string, tracks model.MediaFiles) er
return err
}
- // Add new tracks
- for i, t := range tracks {
- ins := Insert("playlist_tracks").Columns("playlist_id", "media_file_id", "id").
- Values(id, t.ID, i)
+ // Break the track list in chunks to avoid hitting SQLITE_MAX_FUNCTION_ARG limit
+ numTracks := len(tracks)
+ const chunkSize = 50
+ var chunks [][]model.MediaFile
+ for i := 0; i < numTracks; i += chunkSize {
+ end := i + chunkSize
+ if end > numTracks {
+ end = numTracks
+ }
+
+ chunks = append(chunks, tracks[i:end])
+ }
+
+ // Add new tracks, chunk by chunk
+ pos := 0
+ for i := range chunks {
+ ins := Insert("playlist_tracks").Columns("playlist_id", "media_file_id", "id")
+ for _, t := range chunks[i] {
+ ins = ins.Values(id, t.ID, pos)
+ pos++
+ }
_, err = r.executeSQL(ins)
if err != nil {
return err
@@ -159,5 +167,25 @@ func (r *playlistRepository) NewInstance() interface{} {
return &model.Playlist{}
}
+func (r *playlistRepository) Save(entity interface{}) (string, error) {
+ pls := entity.(*model.Playlist)
+ pls.Owner = loggedUser(r.ctx).UserName
+ err := r.Put(pls)
+ if err != nil {
+ return "", err
+ }
+ return pls.ID, err
+}
+
+func (r *playlistRepository) Update(entity interface{}, cols ...string) error {
+ pls := entity.(*model.Playlist)
+ err := r.Put(pls)
+ if err == model.ErrNotFound {
+ return rest.ErrNotFound
+ }
+ return err
+}
+
var _ model.PlaylistRepository = (*playlistRepository)(nil)
-var _ model.ResourceRepository = (*playlistRepository)(nil)
+var _ rest.Repository = (*playlistRepository)(nil)
+var _ rest.Persistable = (*playlistRepository)(nil)
diff --git a/persistence/playlist_tracks_repository.go b/persistence/playlist_tracks_repository.go
index 5459cd639..af2ff5041 100644
--- a/persistence/playlist_tracks_repository.go
+++ b/persistence/playlist_tracks_repository.go
@@ -12,6 +12,18 @@ type playlistTracksRepository struct {
playlistId string
}
+func (r *playlistRepository) Tracks(playlistId string) model.PlaylistTracksRepository {
+ p := &playlistTracksRepository{}
+ p.playlistId = playlistId
+ p.ctx = r.ctx
+ p.ormer = r.ormer
+ p.tableName = "playlist_tracks"
+ p.sortMappings = map[string]string{
+ "id": "playlist_tracks.id",
+ }
+ return p
+}
+
func (r *playlistTracksRepository) Count(options ...rest.QueryOptions) (int64, error) {
return r.count(Select().Where(Eq{"playlist_id": r.playlistId}), r.parseRestOptions(options...))
}
diff --git a/ui/src/App.js b/ui/src/App.js
index 9235bbece..22fa38ded 100644
--- a/ui/src/App.js
+++ b/ui/src/App.js
@@ -71,6 +71,7 @@ const App = () => (
),
,
,
+ ,
,
]}
diff --git a/ui/src/dataProvider.js b/ui/src/dataProvider/httpClient.js
similarity index 70%
rename from ui/src/dataProvider.js
rename to ui/src/dataProvider/httpClient.js
index 9a9a06784..e35b44c6d 100644
--- a/ui/src/dataProvider.js
+++ b/ui/src/dataProvider/httpClient.js
@@ -1,14 +1,11 @@
import { fetchUtils } from 'react-admin'
-import jsonServerProvider from 'ra-data-json-server'
-import baseUrl from './utils/baseUrl'
-import config from './config'
+import baseUrl from '../utils/baseUrl'
+import config from '../config'
-const restUrl = '/app/api'
const customAuthorizationHeader = 'X-ND-Authorization'
const httpClient = (url, options = {}) => {
url = baseUrl(url)
- url = url.replace(restUrl + '/albumSong', restUrl + '/song')
if (!options.headers) {
options.headers = new Headers({ Accept: 'application/json' })
}
@@ -27,6 +24,4 @@ const httpClient = (url, options = {}) => {
})
}
-const dataProvider = jsonServerProvider(restUrl, httpClient)
-
-export default dataProvider
+export default httpClient
diff --git a/ui/src/dataProvider/index.js b/ui/src/dataProvider/index.js
new file mode 100644
index 000000000..6828ab2c5
--- /dev/null
+++ b/ui/src/dataProvider/index.js
@@ -0,0 +1,3 @@
+import wrapperDataProvider from './wrapperDataProvider'
+
+export default wrapperDataProvider
diff --git a/ui/src/dataProvider/wrapperDataProvider.js b/ui/src/dataProvider/wrapperDataProvider.js
new file mode 100644
index 000000000..3ece0f882
--- /dev/null
+++ b/ui/src/dataProvider/wrapperDataProvider.js
@@ -0,0 +1,68 @@
+import jsonServerProvider from 'ra-data-json-server'
+import httpClient from './httpClient'
+
+const restUrl = '/app/api'
+
+const dataProvider = jsonServerProvider(restUrl, httpClient)
+
+const mapResource = (resource, params) => {
+ console.log('R: ', resource, 'P: ', params)
+ switch (resource) {
+ case 'albumSong':
+ return ['song', params]
+
+ case 'playlistTrack':
+ // /api/playlistTrack?playlist_id=123 => /api/playlist/123/tracks
+ let plsId = '0'
+ if (params.filter) {
+ plsId = params.filter.playlist_id
+ delete params.filter.playlist_id
+ }
+ return [`playlist/${plsId}/tracks`, params]
+
+ default:
+ return [resource, params]
+ }
+}
+
+const wrapperDataProvider = {
+ ...dataProvider,
+ getList: (resource, params) => {
+ const [r, p] = mapResource(resource, params)
+ return dataProvider.getList(r, p)
+ },
+ getOne: (resource, params) => {
+ const [r, p] = mapResource(resource, params)
+ return dataProvider.getOne(r, p)
+ },
+ getMany: (resource, params) => {
+ const [r, p] = mapResource(resource, params)
+ return dataProvider.getMany(r, p)
+ },
+ getManyReference: (resource, params) => {
+ const [r, p] = mapResource(resource, params)
+ return dataProvider.getManyReference(r, p)
+ },
+ update: (resource, params) => {
+ const [r, p] = mapResource(resource, params)
+ return dataProvider.update(r, p)
+ },
+ updateMany: (resource, params) => {
+ const [r, p] = mapResource(resource, params)
+ return dataProvider.updateMany(r, p)
+ },
+ create: (resource, params) => {
+ const [r, p] = mapResource(resource, params)
+ return dataProvider.create(r, p)
+ },
+ delete: (resource, params) => {
+ const [r, p] = mapResource(resource, params)
+ return dataProvider.delete(r, p)
+ },
+ deleteMany: (resource, params) => {
+ const [r, p] = mapResource(resource, params)
+ return dataProvider.deleteMany(r, p)
+ },
+}
+
+export default wrapperDataProvider
diff --git a/ui/src/playlist/PlaylistCreate.js b/ui/src/playlist/PlaylistCreate.js
new file mode 100644
index 000000000..a3e1f88b8
--- /dev/null
+++ b/ui/src/playlist/PlaylistCreate.js
@@ -0,0 +1,20 @@
+import React from 'react'
+import {
+ Create,
+ SimpleForm,
+ TextInput,
+ BooleanInput,
+ required,
+} from 'react-admin'
+
+const PlaylistCreate = (props) => (
+
+
+
+
+
+
+
+)
+
+export default PlaylistCreate
diff --git a/ui/src/playlist/PlaylistEdit.js b/ui/src/playlist/PlaylistEdit.js
new file mode 100644
index 000000000..d58b8ce26
--- /dev/null
+++ b/ui/src/playlist/PlaylistEdit.js
@@ -0,0 +1,20 @@
+import React from 'react'
+import {
+ Edit,
+ SimpleForm,
+ TextInput,
+ BooleanInput,
+ required,
+} from 'react-admin'
+
+const PlaylistEdit = (props) => (
+
+
+
+
+
+
+
+)
+
+export default PlaylistEdit
diff --git a/ui/src/playlist/PlaylistList.js b/ui/src/playlist/PlaylistList.js
index 680283e77..6b4b2f56e 100644
--- a/ui/src/playlist/PlaylistList.js
+++ b/ui/src/playlist/PlaylistList.js
@@ -1,22 +1,15 @@
import React from 'react'
import {
- List,
Datagrid,
TextField,
BooleanField,
NumberField,
DateField,
} from 'react-admin'
-import { DurationField, Title } from '../common'
+import { DurationField, List } from '../common'
const PlaylistList = (props) => (
-
- }
- exporter={false}
- >
+
diff --git a/ui/src/playlist/index.js b/ui/src/playlist/index.js
index e518832c3..d97692910 100644
--- a/ui/src/playlist/index.js
+++ b/ui/src/playlist/index.js
@@ -1,7 +1,11 @@
import PlaylistIcon from '../icons/Playlist'
import PlaylistList from './PlaylistList'
+import PlaylistEdit from './PlaylistEdit'
+import PlaylistCreate from './PlaylistCreate'
export default {
icon: PlaylistIcon,
list: PlaylistList,
+ create: PlaylistCreate,
+ edit: PlaylistEdit,
}