mirror of
https://github.com/navidrome/navidrome.git
synced 2025-04-01 19:47:37 +03:00
Add option to allow share to be downloaded
This commit is contained in:
parent
a22eef39f7
commit
a7d3e6e1f1
13 changed files with 70 additions and 7 deletions
|
@ -59,6 +59,7 @@ type configOptions struct {
|
|||
EnableStarRating bool
|
||||
EnableUserEditing bool
|
||||
EnableSharing bool
|
||||
DefaultDownloadableShare bool
|
||||
DefaultTheme string
|
||||
DefaultLanguage string
|
||||
DefaultUIVolume int
|
||||
|
@ -306,6 +307,7 @@ func init() {
|
|||
viper.SetDefault("devautologinusername", "")
|
||||
viper.SetDefault("devactivitypanel", true)
|
||||
viper.SetDefault("enablesharing", false)
|
||||
viper.SetDefault("defaultdownloadableshare", false)
|
||||
viper.SetDefault("devenablebufferedscrobble", true)
|
||||
viper.SetDefault("devsidebarplaylists", true)
|
||||
viper.SetDefault("devshowartistpage", true)
|
||||
|
|
|
@ -125,7 +125,7 @@ func (r *shareRepositoryWrapper) Save(entity interface{}) (string, error) {
|
|||
}
|
||||
|
||||
func (r *shareRepositoryWrapper) Update(id string, entity interface{}, _ ...string) error {
|
||||
cols := []string{"description"}
|
||||
cols := []string{"description", "downloadable"}
|
||||
|
||||
// TODO Better handling of Share expiration
|
||||
if !entity.(*model.Share).ExpiresAt.IsZero() {
|
||||
|
|
|
@ -45,7 +45,7 @@ var _ = Describe("Share", func() {
|
|||
entity := &model.Share{}
|
||||
err := repo.Update("id", entity)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(mockedRepo.(*tests.MockShareRepo).Cols).To(ConsistOf("description"))
|
||||
Expect(mockedRepo.(*tests.MockShareRepo).Cols).To(ConsistOf("description", "downloadable"))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
23
db/migration/20230310222612_add_download_to_share.go
Normal file
23
db/migration/20230310222612_add_download_to_share.go
Normal file
|
@ -0,0 +1,23 @@
|
|||
package migrations
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
|
||||
"github.com/pressly/goose"
|
||||
)
|
||||
|
||||
func init() {
|
||||
goose.AddMigration(upAddDownloadToShare, downAddDownloadToShare)
|
||||
}
|
||||
|
||||
func upAddDownloadToShare(tx *sql.Tx) error {
|
||||
_, err := tx.Exec(`
|
||||
alter table share
|
||||
add downloadable bool not null default false;
|
||||
`)
|
||||
return err
|
||||
}
|
||||
|
||||
func downAddDownloadToShare(tx *sql.Tx) error {
|
||||
return nil
|
||||
}
|
|
@ -12,6 +12,7 @@ type Share struct {
|
|||
UserID string `structs:"user_id" json:"userId,omitempty" orm:"column(user_id)"`
|
||||
Username string `structs:"-" json:"username,omitempty" orm:"-"`
|
||||
Description string `structs:"description" json:"description,omitempty"`
|
||||
Downloadable bool `structs:"downloadable" json:"downloadable"`
|
||||
ExpiresAt time.Time `structs:"expires_at" json:"expiresAt,omitempty"`
|
||||
LastVisitedAt time.Time `structs:"last_visited_at" json:"lastVisitedAt,omitempty"`
|
||||
ResourceIDs string `structs:"resource_ids" json:"resourceIds,omitempty" orm:"column(resource_ids)"`
|
||||
|
|
|
@ -183,6 +183,7 @@
|
|||
"username": "Compartilhado por",
|
||||
"url": "Link",
|
||||
"description": "Descrição",
|
||||
"downloadable": "Permitir Baixar?",
|
||||
"contents": "Conteúdo",
|
||||
"expiresAt": "Dt. Expiração",
|
||||
"lastVisitedAt": "Última visita",
|
||||
|
@ -452,4 +453,4 @@
|
|||
"current_song": "Vai para música atual"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,6 +58,7 @@ func serveIndex(ds model.DataStore, fs fs.FS, shareInfo *model.Share) http.Handl
|
|||
"devActivityPanel": conf.Server.DevActivityPanel,
|
||||
"enableUserEditing": conf.Server.EnableUserEditing,
|
||||
"enableSharing": conf.Server.EnableSharing,
|
||||
"defaultDownloadableShare": conf.Server.DefaultDownloadableShare,
|
||||
"devSidebarPlaylists": conf.Server.DevSidebarPlaylists,
|
||||
"lastFMEnabled": conf.Server.LastFM.Enabled,
|
||||
"lastFMApiKey": conf.Server.LastFM.ApiKey,
|
||||
|
|
|
@ -245,6 +245,17 @@ var _ = Describe("serveIndex", func() {
|
|||
Expect(config).To(HaveKeyWithValue("enableSharing", false))
|
||||
})
|
||||
|
||||
It("sets the defaultDownloadableShare", func() {
|
||||
conf.Server.DefaultDownloadableShare = true
|
||||
r := httptest.NewRequest("GET", "/index.html", nil)
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
serveIndex(ds, fs, nil)(w, r)
|
||||
|
||||
config := extractAppConfig(w.Body.String())
|
||||
Expect(config).To(HaveKeyWithValue("defaultDownloadableShare", true))
|
||||
})
|
||||
|
||||
It("sets the defaultDownsamplingFormat", func() {
|
||||
r := httptest.NewRequest("GET", "/index.html", nil)
|
||||
w := httptest.NewRecorder()
|
||||
|
|
|
@ -22,6 +22,7 @@ const defaultConfig = {
|
|||
defaultUIVolume: 100,
|
||||
enableUserEditing: true,
|
||||
enableSharing: true,
|
||||
defaultDownloadableShare: true,
|
||||
devSidebarPlaylists: true,
|
||||
lastFMEnabled: true,
|
||||
lastFMApiKey: '9b94a5515ea66b2da3ec03c12300327e',
|
||||
|
|
|
@ -8,6 +8,7 @@ import {
|
|||
import {
|
||||
SimpleForm,
|
||||
TextInput,
|
||||
BooleanInput,
|
||||
useCreate,
|
||||
useNotify,
|
||||
useTranslate,
|
||||
|
@ -17,6 +18,7 @@ import { shareUrl } from '../utils'
|
|||
import { useTranscodingOptions } from './useTranscodingOptions'
|
||||
import { useDispatch, useSelector } from 'react-redux'
|
||||
import { closeShareMenu } from '../actions'
|
||||
import config from '../config'
|
||||
|
||||
export const ShareDialog = () => {
|
||||
const {
|
||||
|
@ -30,6 +32,9 @@ export const ShareDialog = () => {
|
|||
const notify = useNotify()
|
||||
const translate = useTranslate()
|
||||
const [description, setDescription] = useState('')
|
||||
const [downloadable, setDownloadable] = useState(
|
||||
config.defaultDownloadableShare
|
||||
)
|
||||
useEffect(() => {
|
||||
setDescription('')
|
||||
}, [ids])
|
||||
|
@ -41,6 +46,7 @@ export const ShareDialog = () => {
|
|||
resourceType: resource,
|
||||
resourceIds: ids?.join(','),
|
||||
description,
|
||||
downloadable,
|
||||
...(!originalFormat && { format }),
|
||||
...(!originalFormat && { maxBitRate }),
|
||||
},
|
||||
|
@ -105,12 +111,21 @@ export const ShareDialog = () => {
|
|||
<DialogContent>
|
||||
<SimpleForm toolbar={null} variant={'outlined'}>
|
||||
<TextInput
|
||||
source="description"
|
||||
resource={'share'}
|
||||
source={'description'}
|
||||
fullWidth
|
||||
onChange={(event) => {
|
||||
setDescription(event.target.value)
|
||||
}}
|
||||
/>
|
||||
<BooleanInput
|
||||
resource={'share'}
|
||||
source={'downloadable'}
|
||||
defaultValue={downloadable}
|
||||
onChange={(value) => {
|
||||
setDownloadable(value)
|
||||
}}
|
||||
/>
|
||||
<TranscodingOptionsInput
|
||||
fullWidth
|
||||
label={translate('message.shareOriginalFormat')}
|
||||
|
|
|
@ -184,6 +184,7 @@
|
|||
"username": "Shared By",
|
||||
"url": "URL",
|
||||
"description": "Description",
|
||||
"downloadable": "Allow Downloads?",
|
||||
"contents": "Contents",
|
||||
"expiresAt": "Expires",
|
||||
"lastVisitedAt": "Last Visited",
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import {
|
||||
DateTimeInput,
|
||||
BooleanInput,
|
||||
Edit,
|
||||
NumberField,
|
||||
SimpleForm,
|
||||
|
@ -19,6 +20,7 @@ export const ShareEdit = (props) => {
|
|||
{url}
|
||||
</Link>
|
||||
<TextInput source="description" />
|
||||
<BooleanInput source="downloadable" />
|
||||
<DateTimeInput source="expiresAt" />
|
||||
<TextInput source="contents" disabled />
|
||||
<TextInput source="format" disabled />
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import {
|
||||
Datagrid,
|
||||
FunctionField,
|
||||
BooleanField,
|
||||
List,
|
||||
NumberField,
|
||||
SimpleList,
|
||||
|
@ -24,6 +25,7 @@ export const FormatInfo = ({ record, size }) => {
|
|||
|
||||
const ShareList = (props) => {
|
||||
const isXsmall = useMediaQuery((theme) => theme.breakpoints.down('xs'))
|
||||
const isDesktop = useMediaQuery((theme) => theme.breakpoints.up('lg'))
|
||||
const translate = useTranslate()
|
||||
const notify = useNotify()
|
||||
|
||||
|
@ -101,10 +103,13 @@ const ShareList = (props) => {
|
|||
/>
|
||||
<TextField source="username" />
|
||||
<TextField source="description" />
|
||||
<TextField source="contents" />
|
||||
<FormatInfo source="format" />
|
||||
{isDesktop && <TextField source="contents" />}
|
||||
{isDesktop && <FormatInfo source="format" />}
|
||||
<BooleanField source="downloadable" />
|
||||
<NumberField source="visitCount" />
|
||||
<DateField source="lastVisitedAt" showTime sortByOrder={'DESC'} />
|
||||
{isDesktop && (
|
||||
<DateField source="lastVisitedAt" showTime sortByOrder={'DESC'} />
|
||||
)}
|
||||
<DateField source="expiresAt" showTime />
|
||||
</Datagrid>
|
||||
)}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue