Add playlist views

This commit is contained in:
Deluan 2020-05-11 21:27:00 -04:00 committed by Deluan Quintão
parent b1f5d35f73
commit 8a709c489a
10 changed files with 175 additions and 31 deletions

View File

@ -77,15 +77,6 @@ func (r *playlistRepository) GetAll(options ...model.QueryOptions) (model.Playli
return res, err 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 { func (r *playlistRepository) updateTracks(id string, tracks model.MediaFiles) error {
// Remove old tracks // Remove old tracks
del := Delete("playlist_tracks").Where(Eq{"playlist_id": id}) 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 return err
} }
// Add new tracks // Break the track list in chunks to avoid hitting SQLITE_MAX_FUNCTION_ARG limit
for i, t := range tracks { numTracks := len(tracks)
ins := Insert("playlist_tracks").Columns("playlist_id", "media_file_id", "id"). const chunkSize = 50
Values(id, t.ID, i) 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) _, err = r.executeSQL(ins)
if err != nil { if err != nil {
return err return err
@ -159,5 +167,25 @@ func (r *playlistRepository) NewInstance() interface{} {
return &model.Playlist{} 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.PlaylistRepository = (*playlistRepository)(nil)
var _ model.ResourceRepository = (*playlistRepository)(nil) var _ rest.Repository = (*playlistRepository)(nil)
var _ rest.Persistable = (*playlistRepository)(nil)

View File

@ -12,6 +12,18 @@ type playlistTracksRepository struct {
playlistId string 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) { func (r *playlistTracksRepository) Count(options ...rest.QueryOptions) (int64, error) {
return r.count(Select().Where(Eq{"playlist_id": r.playlistId}), r.parseRestOptions(options...)) return r.count(Select().Where(Eq{"playlist_id": r.playlistId}), r.parseRestOptions(options...))
} }

View File

@ -71,6 +71,7 @@ const App = () => (
), ),
<Resource name="albumSong" />, <Resource name="albumSong" />,
<Resource name="translation" />, <Resource name="translation" />,
<Resource name="playlistTrack" />,
<Player />, <Player />,
]} ]}
</Admin> </Admin>

View File

@ -1,14 +1,11 @@
import { fetchUtils } from 'react-admin' import { fetchUtils } from 'react-admin'
import jsonServerProvider from 'ra-data-json-server' import baseUrl from '../utils/baseUrl'
import baseUrl from './utils/baseUrl' import config from '../config'
import config from './config'
const restUrl = '/app/api'
const customAuthorizationHeader = 'X-ND-Authorization' const customAuthorizationHeader = 'X-ND-Authorization'
const httpClient = (url, options = {}) => { const httpClient = (url, options = {}) => {
url = baseUrl(url) url = baseUrl(url)
url = url.replace(restUrl + '/albumSong', restUrl + '/song')
if (!options.headers) { if (!options.headers) {
options.headers = new Headers({ Accept: 'application/json' }) options.headers = new Headers({ Accept: 'application/json' })
} }
@ -27,6 +24,4 @@ const httpClient = (url, options = {}) => {
}) })
} }
const dataProvider = jsonServerProvider(restUrl, httpClient) export default httpClient
export default dataProvider

View File

@ -0,0 +1,3 @@
import wrapperDataProvider from './wrapperDataProvider'
export default wrapperDataProvider

View File

@ -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

View File

@ -0,0 +1,20 @@
import React from 'react'
import {
Create,
SimpleForm,
TextInput,
BooleanInput,
required,
} from 'react-admin'
const PlaylistCreate = (props) => (
<Create {...props}>
<SimpleForm>
<TextInput source="name" validate={required()} />
<TextInput multiline source="comment" />
<BooleanInput source="public" initialValue={true} />
</SimpleForm>
</Create>
)
export default PlaylistCreate

View File

@ -0,0 +1,20 @@
import React from 'react'
import {
Edit,
SimpleForm,
TextInput,
BooleanInput,
required,
} from 'react-admin'
const PlaylistEdit = (props) => (
<Edit {...props}>
<SimpleForm>
<TextInput source="name" validate={required()} />
<TextInput source="comment" />
<BooleanInput source="public" />
</SimpleForm>
</Edit>
)
export default PlaylistEdit

View File

@ -1,22 +1,15 @@
import React from 'react' import React from 'react'
import { import {
List,
Datagrid, Datagrid,
TextField, TextField,
BooleanField, BooleanField,
NumberField, NumberField,
DateField, DateField,
} from 'react-admin' } from 'react-admin'
import { DurationField, Title } from '../common' import { DurationField, List } from '../common'
const PlaylistList = (props) => ( const PlaylistList = (props) => (
<List <List {...props} exporter={false}>
{...props}
title={
<Title subTitle={'resources.playlist.name'} args={{ smart_count: 2 }} />
}
exporter={false}
>
<Datagrid rowClick="edit"> <Datagrid rowClick="edit">
<TextField source="name" /> <TextField source="name" />
<TextField source="owner" /> <TextField source="owner" />

View File

@ -1,7 +1,11 @@
import PlaylistIcon from '../icons/Playlist' import PlaylistIcon from '../icons/Playlist'
import PlaylistList from './PlaylistList' import PlaylistList from './PlaylistList'
import PlaylistEdit from './PlaylistEdit'
import PlaylistCreate from './PlaylistCreate'
export default { export default {
icon: PlaylistIcon, icon: PlaylistIcon,
list: PlaylistList, list: PlaylistList,
create: PlaylistCreate,
edit: PlaylistEdit,
} }