Fix auto-fixable linter issues
This commit is contained in:
parent
73b1dc8f30
commit
bbdb3dcb9d
|
@ -73,6 +73,7 @@
|
||||||
"eslint-config-standard": "17.0.0",
|
"eslint-config-standard": "17.0.0",
|
||||||
"eslint-plugin-html": "6.2.0",
|
"eslint-plugin-html": "6.2.0",
|
||||||
"eslint-plugin-import": "2.26.0",
|
"eslint-plugin-import": "2.26.0",
|
||||||
|
"eslint-plugin-n": "^15.2.4",
|
||||||
"eslint-plugin-node": "11.1.0",
|
"eslint-plugin-node": "11.1.0",
|
||||||
"eslint-plugin-promise": "6.0.0",
|
"eslint-plugin-promise": "6.0.0",
|
||||||
"eslint-plugin-vue": "9.2.0",
|
"eslint-plugin-vue": "9.2.0",
|
||||||
|
|
|
@ -23,7 +23,7 @@ const shortDescription = computed(() => get(nodeinfo.value, 'metadata.shortDescr
|
||||||
const stats = computed(() => {
|
const stats = computed(() => {
|
||||||
const users = get(nodeinfo.value, 'usage.users.activeMonth', null)
|
const users = get(nodeinfo.value, 'usage.users.activeMonth', null)
|
||||||
const hours = get(nodeinfo.value, 'metadata.library.music.hours', 0)
|
const hours = get(nodeinfo.value, 'metadata.library.music.hours', 0)
|
||||||
|
|
||||||
if (users === null) {
|
if (users === null) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
@ -39,8 +39,8 @@ const headerStyle = computed(() => {
|
||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
backgroundImage: `url(${store.getters['instance/absoluteUrl'](banner.value)})`
|
backgroundImage: `url(${store.getters['instance/absoluteUrl'](banner.value)})`
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -53,8 +53,8 @@ const headerStyle = computed(() => {
|
||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
backgroundImage: `url(${store.getters['instance/absoluteUrl'](banner.value)})`
|
backgroundImage: `url(${store.getters['instance/absoluteUrl'](banner.value)})`
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
@ -138,7 +138,7 @@ const headerStyle = computed(() => {
|
||||||
About this pod
|
About this pod
|
||||||
</translate>
|
</translate>
|
||||||
</h2>
|
</h2>
|
||||||
<sanitized-html
|
<sanitized-html
|
||||||
v-if="longDescription"
|
v-if="longDescription"
|
||||||
:html="markdown.makeHtml(longDescription)"
|
:html="markdown.makeHtml(longDescription)"
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -35,7 +35,7 @@ const defaultUploadQuota = computed(() => get(nodeinfo.value, 'metadata.defaultU
|
||||||
const stats = computed(() => {
|
const stats = computed(() => {
|
||||||
const users = get(nodeinfo.value, 'usage.users.activeMonth', null)
|
const users = get(nodeinfo.value, 'usage.users.activeMonth', null)
|
||||||
const hours = get(nodeinfo.value, 'metadata.library.music.hours', 0)
|
const hours = get(nodeinfo.value, 'metadata.library.music.hours', 0)
|
||||||
|
|
||||||
if (users === null) {
|
if (users === null) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
@ -48,8 +48,8 @@ const headerStyle = computed(() => {
|
||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
backgroundImage: `url(${store.getters['instance/absoluteUrl'](banner.value)})`
|
backgroundImage: `url(${store.getters['instance/absoluteUrl'](banner.value)})`
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ import { useGettext } from 'vue3-gettext'
|
||||||
const path = window.location.href
|
const path = window.location.href
|
||||||
|
|
||||||
const { $pgettext } = useGettext()
|
const { $pgettext } = useGettext()
|
||||||
const labels = computed(() => ({
|
const labels = computed(() => ({
|
||||||
title: $pgettext('Head/*/Title', 'Page Not Found')
|
title: $pgettext('Head/*/Title', 'Page Not Found')
|
||||||
}))
|
}))
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -8,7 +8,7 @@ import TrackFavoriteIcon from '~/components/favorites/TrackFavoriteIcon.vue'
|
||||||
import TrackPlaylistIcon from '~/components/playlists/TrackPlaylistIcon.vue'
|
import TrackPlaylistIcon from '~/components/playlists/TrackPlaylistIcon.vue'
|
||||||
import Draggable from 'vuedraggable'
|
import Draggable from 'vuedraggable'
|
||||||
import { whenever, useTimeoutFn, useWindowScroll, useWindowSize } from '@vueuse/core'
|
import { whenever, useTimeoutFn, useWindowScroll, useWindowSize } from '@vueuse/core'
|
||||||
import { useGettext } from "vue3-gettext"
|
import { useGettext } from 'vue3-gettext'
|
||||||
import useQueue from '~/composables/audio/useQueue'
|
import useQueue from '~/composables/audio/useQueue'
|
||||||
import usePlayer from '~/composables/audio/usePlayer'
|
import usePlayer from '~/composables/audio/usePlayer'
|
||||||
|
|
||||||
|
@ -42,8 +42,8 @@ onMounted(async () => {
|
||||||
|
|
||||||
const { $pgettext } = useGettext()
|
const { $pgettext } = useGettext()
|
||||||
|
|
||||||
const {
|
const {
|
||||||
playing,
|
playing,
|
||||||
loading: isLoadingAudio,
|
loading: isLoadingAudio,
|
||||||
errored,
|
errored,
|
||||||
focused: playerFocused,
|
focused: playerFocused,
|
||||||
|
@ -54,10 +54,10 @@ const {
|
||||||
bufferProgress,
|
bufferProgress,
|
||||||
currentTime,
|
currentTime,
|
||||||
pause,
|
pause,
|
||||||
resume,
|
resume
|
||||||
} = usePlayer()
|
} = usePlayer()
|
||||||
|
|
||||||
const {
|
const {
|
||||||
focused: queueFocused,
|
focused: queueFocused,
|
||||||
currentTrack,
|
currentTrack,
|
||||||
hasNext,
|
hasNext,
|
||||||
|
|
|
@ -29,16 +29,15 @@ const type = ref(props.initialType)
|
||||||
const id = ref(props.initialId)
|
const id = ref(props.initialId)
|
||||||
const errors = ref([] as string[])
|
const errors = ref([] as string[])
|
||||||
|
|
||||||
|
|
||||||
const { $pgettext } = useGettext()
|
const { $pgettext } = useGettext()
|
||||||
const labels = computed(() => ({
|
const labels = computed(() => ({
|
||||||
title: type.value === 'rss'
|
title: type.value === 'rss'
|
||||||
? $pgettext('Head/Fetch/Title', 'Subscribe to a podcast RSS feed')
|
? $pgettext('Head/Fetch/Title', 'Subscribe to a podcast RSS feed')
|
||||||
: $pgettext('Head/Fetch/Title', 'Subscribe to a podcast hosted on the Fediverse'),
|
: $pgettext('Head/Fetch/Title', 'Subscribe to a podcast hosted on the Fediverse'),
|
||||||
fieldLabel: type.value === 'rss'
|
fieldLabel: type.value === 'rss'
|
||||||
? $pgettext('*/*/*', 'RSS feed location')
|
? $pgettext('*/*/*', 'RSS feed location')
|
||||||
: $pgettext('*/*/*', 'Fediverse object'),
|
: $pgettext('*/*/*', 'Fediverse object'),
|
||||||
fieldPlaceholder: type.value === 'rss'
|
fieldPlaceholder: type.value === 'rss'
|
||||||
? $pgettext('Head/Fetch/Field.Placeholder', 'https://website.example.com/rss.xml')
|
? $pgettext('Head/Fetch/Field.Placeholder', 'https://website.example.com/rss.xml')
|
||||||
: $pgettext('Head/Fetch/Field.Placeholder', '@username@example.com')
|
: $pgettext('Head/Fetch/Field.Placeholder', '@username@example.com')
|
||||||
}))
|
}))
|
||||||
|
|
|
@ -8,7 +8,7 @@ interface Props {
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = withDefaults(defineProps<Props>(), {
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
tag: 'div'
|
tag: 'div'
|
||||||
})
|
})
|
||||||
|
|
||||||
const html = computed(() => DOMPurify.sanitize(props.html))
|
const html = computed(() => DOMPurify.sanitize(props.html))
|
||||||
|
@ -17,4 +17,4 @@ const root = () => h(props.tag, { innerHTML: html.value })
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<root />
|
<root />
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -39,7 +39,7 @@ const labels = computed(() => ({
|
||||||
selectTrack: $pgettext('Sidebar/Player/Hidden text', 'Play this track'),
|
selectTrack: $pgettext('Sidebar/Player/Hidden text', 'Play this track'),
|
||||||
pendingFollows: $pgettext('Sidebar/Notifications/Hidden text', 'Pending follow requests'),
|
pendingFollows: $pgettext('Sidebar/Notifications/Hidden text', 'Pending follow requests'),
|
||||||
pendingReviewEdits: $pgettext('Sidebar/Moderation/Hidden text', 'Pending review edits'),
|
pendingReviewEdits: $pgettext('Sidebar/Moderation/Hidden text', 'Pending review edits'),
|
||||||
pendingReviewReports: $pgettext('Sidebar/Moderation/Hidden text', 'Pending review reports'),
|
pendingReviewReports: $pgettext('Sidebar/Moderation/Hidden text', 'Pending review reports'),
|
||||||
language: $pgettext('Sidebar/Settings/Dropdown.Label/Short, Verb', 'Language'),
|
language: $pgettext('Sidebar/Settings/Dropdown.Label/Short, Verb', 'Language'),
|
||||||
theme: $pgettext('Sidebar/Settings/Dropdown.Label/Short, Verb', 'Theme'),
|
theme: $pgettext('Sidebar/Settings/Dropdown.Label/Short, Verb', 'Theme'),
|
||||||
addContent: $pgettext('*/Library/*/Verb', 'Add content'),
|
addContent: $pgettext('*/Library/*/Verb', 'Add content'),
|
||||||
|
@ -51,11 +51,11 @@ const expanded = ref<SidebarMenuTabs>('explore')
|
||||||
|
|
||||||
const ROUTE_MAPPINGS: Record<SidebarMenuTabs, RouteRecordName[]> = {
|
const ROUTE_MAPPINGS: Record<SidebarMenuTabs, RouteRecordName[]> = {
|
||||||
explore: [
|
explore: [
|
||||||
'search',
|
'search',
|
||||||
'library.index',
|
'library.index',
|
||||||
'library.podcasts.browse',
|
'library.podcasts.browse',
|
||||||
'library.albums.browse',
|
'library.albums.browse',
|
||||||
'library.albums.detail',
|
'library.albums.detail',
|
||||||
'library.artists.browse',
|
'library.artists.browse',
|
||||||
'library.artists.detail',
|
'library.artists.detail',
|
||||||
'library.tracks.detail',
|
'library.tracks.detail',
|
||||||
|
@ -88,10 +88,10 @@ watchEffect(() => {
|
||||||
expanded.value = store.state.auth.authenticated ? 'myLibrary' : 'explore'
|
expanded.value = store.state.auth.authenticated ? 'myLibrary' : 'explore'
|
||||||
})
|
})
|
||||||
|
|
||||||
const moderationNotifications = computed(() =>
|
const moderationNotifications = computed(() =>
|
||||||
store.state.ui.notifications.pendingReviewEdits
|
store.state.ui.notifications.pendingReviewEdits +
|
||||||
+ store.state.ui.notifications.pendingReviewReports
|
store.state.ui.notifications.pendingReviewReports +
|
||||||
+ store.state.ui.notifications.pendingReviewRequests
|
store.state.ui.notifications.pendingReviewRequests
|
||||||
)
|
)
|
||||||
|
|
||||||
Promise.resolve().then(async () => {
|
Promise.resolve().then(async () => {
|
||||||
|
|
|
@ -53,7 +53,7 @@ const save = async () => {
|
||||||
let contentType = 'application/json'
|
let contentType = 'application/json'
|
||||||
|
|
||||||
if (fileSettings.value.length > 0) {
|
if (fileSettings.value.length > 0) {
|
||||||
const fileSettingsIDs = fileSettings.value.map((setting) => setting.identifier)
|
const fileSettingsIDs = fileSettings.value.map((setting) => setting.identifier)
|
||||||
const data = settings.value.reduce((data, setting) => {
|
const data = settings.value.reduce((data, setting) => {
|
||||||
if (fileSettingsIDs.includes(setting.identifier)) {
|
if (fileSettingsIDs.includes(setting.identifier)) {
|
||||||
const input = fileRefs[setting.identifier]
|
const input = fileRefs[setting.identifier]
|
||||||
|
@ -69,7 +69,7 @@ const save = async () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
return data
|
return data
|
||||||
}, {} as Record<string, string | File>)
|
}, {} as Record<string, string | File>)
|
||||||
|
|
||||||
contentType = 'multipart/form-data'
|
contentType = 'multipart/form-data'
|
||||||
postData = useFormData(data)
|
postData = useFormData(data)
|
||||||
|
|
|
@ -7,7 +7,6 @@ import useQueue from '~/composables/audio/useQueue'
|
||||||
import usePlayer from '~/composables/audio/usePlayer'
|
import usePlayer from '~/composables/audio/usePlayer'
|
||||||
import { computed } from 'vue'
|
import { computed } from 'vue'
|
||||||
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
// TODO (wvffle): Is it correct type?
|
// TODO (wvffle): Is it correct type?
|
||||||
entry: Track
|
entry: Track
|
||||||
|
|
|
@ -90,7 +90,7 @@ export default {
|
||||||
const params = clone(this.filters)
|
const params = clone(this.filters)
|
||||||
params.page_size = this.limit
|
params.page_size = this.limit
|
||||||
params.include_channels = true
|
params.include_channels = true
|
||||||
axios.get(url, { params: params }).then((response) => {
|
axios.get(url, { params }).then((response) => {
|
||||||
self.nextPage = response.data.next
|
self.nextPage = response.data.next
|
||||||
self.isLoading = false
|
self.isLoading = false
|
||||||
self.objects = self.objects.concat(response.data.results)
|
self.objects = self.objects.concat(response.data.results)
|
||||||
|
|
|
@ -71,7 +71,7 @@ export default {
|
||||||
const params = clone(this.filters)
|
const params = clone(this.filters)
|
||||||
params.page_size = this.limit
|
params.page_size = this.limit
|
||||||
params.include_channels = true
|
params.include_channels = true
|
||||||
axios.get(url, { params: params }).then((response) => {
|
axios.get(url, { params }).then((response) => {
|
||||||
self.nextPage = response.data.next
|
self.nextPage = response.data.next
|
||||||
self.isLoading = false
|
self.isLoading = false
|
||||||
self.objects = self.objects.concat(response.data.results)
|
self.objects = self.objects.concat(response.data.results)
|
||||||
|
|
|
@ -32,7 +32,7 @@ const iframeSrc = computed(() => {
|
||||||
const bParam = !window.location.href.startsWith(instanceUrl)
|
const bParam = !window.location.href.startsWith(instanceUrl)
|
||||||
? `&b=${instanceUrl}`
|
? `&b=${instanceUrl}`
|
||||||
: ''
|
: ''
|
||||||
|
|
||||||
return `${base}embed.html?&type=${props.type}&id=${props.id}${bParam}`
|
return `${base}embed.html?&type=${props.type}&id=${props.id}${bParam}`
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -51,10 +51,10 @@ const props = withDefaults(defineProps<Props>(), {
|
||||||
paused: () => false
|
paused: () => false
|
||||||
})
|
})
|
||||||
|
|
||||||
const {
|
const {
|
||||||
playable,
|
playable,
|
||||||
filterableArtist,
|
filterableArtist,
|
||||||
filterArtist,
|
filterArtist,
|
||||||
enqueue,
|
enqueue,
|
||||||
enqueueNext,
|
enqueueNext,
|
||||||
replacePlay,
|
replacePlay,
|
||||||
|
@ -75,14 +75,14 @@ const labels = computed(() => ({
|
||||||
addToPlaylist: $pgettext('Sidebar/Player/Icon.Tooltip/Verb', 'Add to playlist…'),
|
addToPlaylist: $pgettext('Sidebar/Player/Icon.Tooltip/Verb', 'Add to playlist…'),
|
||||||
hideArtist: $pgettext('*/Queue/Dropdown/Button/Label/Short', 'Hide content from this artist'),
|
hideArtist: $pgettext('*/Queue/Dropdown/Button/Label/Short', 'Hide content from this artist'),
|
||||||
replacePlay: props.track
|
replacePlay: props.track
|
||||||
? $pgettext('*/Queue/Dropdown/Button/Title', 'Play track')
|
? $pgettext('*/Queue/Dropdown/Button/Title', 'Play track')
|
||||||
: props.album
|
: props.album
|
||||||
? $pgettext('*/Queue/Dropdown/Button/Title', 'Play album')
|
? $pgettext('*/Queue/Dropdown/Button/Title', 'Play album')
|
||||||
: props.artist
|
: props.artist
|
||||||
? $pgettext('*/Queue/Dropdown/Button/Title', 'Play artist')
|
? $pgettext('*/Queue/Dropdown/Button/Title', 'Play artist')
|
||||||
: props.playlist
|
: props.playlist
|
||||||
? $pgettext('*/Queue/Dropdown/Button/Title', 'Play playlist')
|
? $pgettext('*/Queue/Dropdown/Button/Title', 'Play playlist')
|
||||||
: $pgettext('*/Queue/Dropdown/Button/Title', 'Play tracks')
|
: $pgettext('*/Queue/Dropdown/Button/Title', 'Play tracks')
|
||||||
}))
|
}))
|
||||||
|
|
||||||
const title = computed(() => {
|
const title = computed(() => {
|
||||||
|
|
|
@ -284,7 +284,7 @@ const switchTab = () => {
|
||||||
>
|
>
|
||||||
{{ currentTimeFormatted }}
|
{{ currentTimeFormatted }}
|
||||||
</span>
|
</span>
|
||||||
|
|
|
|
||||||
<span class="total">{{ durationFormatted }}</span>
|
<span class="total">{{ durationFormatted }}</span>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -125,7 +125,7 @@ export default {
|
||||||
query: this.query
|
query: this.query
|
||||||
}
|
}
|
||||||
axios.get('search', {
|
axios.get('search', {
|
||||||
params: params
|
params
|
||||||
}).then((response) => {
|
}).then((response) => {
|
||||||
self.results = self.castResults(response.data)
|
self.results = self.castResults(response.data)
|
||||||
self.isLoading = false
|
self.isLoading = false
|
||||||
|
|
|
@ -17,7 +17,7 @@ const sliderVolume = computed({
|
||||||
})
|
})
|
||||||
|
|
||||||
const { $pgettext } = useGettext()
|
const { $pgettext } = useGettext()
|
||||||
const labels = computed(() => ({
|
const labels = computed(() => ({
|
||||||
unmute: $pgettext('Sidebar/Player/Icon.Tooltip/Verb', 'Unmute'),
|
unmute: $pgettext('Sidebar/Player/Icon.Tooltip/Verb', 'Unmute'),
|
||||||
mute: $pgettext('Sidebar/Player/Icon.Tooltip/Verb', 'Mute'),
|
mute: $pgettext('Sidebar/Player/Icon.Tooltip/Verb', 'Mute'),
|
||||||
slider: $pgettext('Sidebar/Player/Icon.Tooltip/Verb', 'Adjust volume')
|
slider: $pgettext('Sidebar/Player/Icon.Tooltip/Verb', 'Adjust volume')
|
||||||
|
|
|
@ -107,7 +107,7 @@ export default {
|
||||||
const params = { q: this.query, ...this.filters }
|
const params = { q: this.query, ...this.filters }
|
||||||
params.page_size = this.limit
|
params.page_size = this.limit
|
||||||
params.offset = this.offset
|
params.offset = this.offset
|
||||||
axios.get(url, { params: params }).then((response) => {
|
axios.get(url, { params }).then((response) => {
|
||||||
self.previousPage = response.data.previous
|
self.previousPage = response.data.previous
|
||||||
self.nextPage = response.data.next
|
self.nextPage = response.data.next
|
||||||
self.isLoading = false
|
self.isLoading = false
|
||||||
|
|
|
@ -103,7 +103,7 @@ export default {
|
||||||
const params = { q: this.query, ...this.filters }
|
const params = { q: this.query, ...this.filters }
|
||||||
params.page_size = this.limit
|
params.page_size = this.limit
|
||||||
params.offset = this.offset
|
params.offset = this.offset
|
||||||
axios.get(url, { params: params }).then((response) => {
|
axios.get(url, { params }).then((response) => {
|
||||||
self.previousPage = response.data.previous
|
self.previousPage = response.data.previous
|
||||||
self.nextPage = response.data.next
|
self.nextPage = response.data.next
|
||||||
self.isLoading = false
|
self.isLoading = false
|
||||||
|
|
|
@ -47,22 +47,22 @@ const store = useStore()
|
||||||
const isFavorite = computed(() => store.getters['favorites/isFavorite'](props.track.id))
|
const isFavorite = computed(() => store.getters['favorites/isFavorite'](props.track.id))
|
||||||
|
|
||||||
const { $pgettext } = useGettext()
|
const { $pgettext } = useGettext()
|
||||||
const favoriteButton = computed(() => isFavorite.value
|
const favoriteButton = computed(() => isFavorite.value
|
||||||
? $pgettext('Content/Track/Icon.Tooltip/Verb', 'Remove from favorites')
|
? $pgettext('Content/Track/Icon.Tooltip/Verb', 'Remove from favorites')
|
||||||
: $pgettext('Content/Track/*/Verb', 'Add to favorites')
|
: $pgettext('Content/Track/*/Verb', 'Add to favorites')
|
||||||
)
|
)
|
||||||
|
|
||||||
const trackDetailsButton = computed(() => props.track.artist?.content_category === 'podcast'
|
const trackDetailsButton = computed(() => props.track.artist?.content_category === 'podcast'
|
||||||
? $pgettext('*/Queue/Dropdown/Button/Label/Short', 'Episode details')
|
? $pgettext('*/Queue/Dropdown/Button/Label/Short', 'Episode details')
|
||||||
: $pgettext('*/Queue/Dropdown/Button/Label/Short', 'Track details')
|
: $pgettext('*/Queue/Dropdown/Button/Label/Short', 'Track details')
|
||||||
)
|
)
|
||||||
|
|
||||||
const albumDetailsButton = computed(() => props.track.artist?.content_category === 'podcast'
|
const albumDetailsButton = computed(() => props.track.artist?.content_category === 'podcast'
|
||||||
? $pgettext('*/Queue/Dropdown/Button/Label/Short', 'View series')
|
? $pgettext('*/Queue/Dropdown/Button/Label/Short', 'View series')
|
||||||
: $pgettext('*/Queue/Dropdown/Button/Label/Short', 'View album')
|
: $pgettext('*/Queue/Dropdown/Button/Label/Short', 'View album')
|
||||||
)
|
)
|
||||||
|
|
||||||
const artistDetailsButton = computed(() => props.track.artist?.content_category === 'podcast'
|
const artistDetailsButton = computed(() => props.track.artist?.content_category === 'podcast'
|
||||||
? $pgettext('*/Queue/Dropdown/Button/Label/Short', 'View channel')
|
? $pgettext('*/Queue/Dropdown/Button/Label/Short', 'View channel')
|
||||||
: $pgettext('*/Queue/Dropdown/Button/Label/Short', 'View artist')
|
: $pgettext('*/Queue/Dropdown/Button/Label/Short', 'View artist')
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { Track, Artist, Album, Playlist, Library, Channel, Actor } from '~/types'
|
import type { Track, Artist, Album, Playlist, Library, Channel, Actor, /* Track, */ Cover } from '~/types'
|
||||||
import type { PlayOptionsProps } from '~/composables/audio/usePlayOptions'
|
import type { PlayOptionsProps } from '~/composables/audio/usePlayOptions'
|
||||||
import type { /* Track, */ Cover } from '~/types'
|
|
||||||
|
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import PlayButton from '~/components/audio/PlayButton.vue'
|
import PlayButton from '~/components/audio/PlayButton.vue'
|
||||||
|
|
|
@ -73,7 +73,6 @@ withDefaults(defineProps<Props>(), {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div :class="['track-table', 'ui', 'unstackable', 'grid', 'tablet-and-below']">
|
<div :class="['track-table', 'ui', 'unstackable', 'grid', 'tablet-and-below']">
|
||||||
|
|
||||||
<!-- For each item, build a row -->
|
<!-- For each item, build a row -->
|
||||||
|
|
||||||
<track-mobile-row
|
<track-mobile-row
|
||||||
|
|
|
@ -47,22 +47,22 @@ const store = useStore()
|
||||||
const isFavorite = computed(() => store.getters['favorites/isFavorite'](props.track.id))
|
const isFavorite = computed(() => store.getters['favorites/isFavorite'](props.track.id))
|
||||||
|
|
||||||
const { $pgettext } = useGettext()
|
const { $pgettext } = useGettext()
|
||||||
const favoriteButton = computed(() => isFavorite.value
|
const favoriteButton = computed(() => isFavorite.value
|
||||||
? $pgettext('Content/Track/Icon.Tooltip/Verb', 'Remove from favorites')
|
? $pgettext('Content/Track/Icon.Tooltip/Verb', 'Remove from favorites')
|
||||||
: $pgettext('Content/Track/*/Verb', 'Add to favorites')
|
: $pgettext('Content/Track/*/Verb', 'Add to favorites')
|
||||||
)
|
)
|
||||||
|
|
||||||
const trackDetailsButton = computed(() => props.track.artist?.content_category === 'podcast'
|
const trackDetailsButton = computed(() => props.track.artist?.content_category === 'podcast'
|
||||||
? $pgettext('*/Queue/Dropdown/Button/Label/Short', 'Episode details')
|
? $pgettext('*/Queue/Dropdown/Button/Label/Short', 'Episode details')
|
||||||
: $pgettext('*/Queue/Dropdown/Button/Label/Short', 'Track details')
|
: $pgettext('*/Queue/Dropdown/Button/Label/Short', 'Track details')
|
||||||
)
|
)
|
||||||
|
|
||||||
const albumDetailsButton = computed(() => props.track.artist?.content_category === 'podcast'
|
const albumDetailsButton = computed(() => props.track.artist?.content_category === 'podcast'
|
||||||
? $pgettext('*/Queue/Dropdown/Button/Label/Short', 'View series')
|
? $pgettext('*/Queue/Dropdown/Button/Label/Short', 'View series')
|
||||||
: $pgettext('*/Queue/Dropdown/Button/Label/Short', 'View album')
|
: $pgettext('*/Queue/Dropdown/Button/Label/Short', 'View album')
|
||||||
)
|
)
|
||||||
|
|
||||||
const artistDetailsButton = computed(() => props.track.artist?.content_category === 'podcast'
|
const artistDetailsButton = computed(() => props.track.artist?.content_category === 'podcast'
|
||||||
? $pgettext('*/Queue/Dropdown/Button/Label/Short', 'View channel')
|
? $pgettext('*/Queue/Dropdown/Button/Label/Short', 'View channel')
|
||||||
: $pgettext('*/Queue/Dropdown/Button/Label/Short', 'View artist')
|
: $pgettext('*/Queue/Dropdown/Button/Label/Short', 'View artist')
|
||||||
)
|
)
|
||||||
|
|
|
@ -69,9 +69,9 @@ const active = computed(() => props.track.id === currentTrack.value?.id && props
|
||||||
!hover
|
!hover
|
||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
<button
|
<button
|
||||||
v-else-if="
|
v-else-if="
|
||||||
!playing &&
|
!playing &&
|
||||||
active &&
|
active &&
|
||||||
!hover
|
!hover
|
||||||
"
|
"
|
||||||
|
@ -79,9 +79,9 @@ const active = computed(() => props.track.id === currentTrack.value?.id && props
|
||||||
>
|
>
|
||||||
<i class="play icon" />
|
<i class="play icon" />
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
v-else-if="
|
v-else-if="
|
||||||
playing &&
|
playing &&
|
||||||
active &&
|
active &&
|
||||||
hover
|
hover
|
||||||
"
|
"
|
||||||
|
|
|
@ -24,7 +24,7 @@ interface Props {
|
||||||
isAlbum?: boolean
|
isAlbum?: boolean
|
||||||
isPodcast?: boolean
|
isPodcast?: boolean
|
||||||
|
|
||||||
// TODO (wvffle): Find correct type
|
// TODO (wvffle): Find correct type
|
||||||
filters?: object
|
filters?: object
|
||||||
|
|
||||||
nextUrl?: string | null
|
nextUrl?: string | null
|
||||||
|
@ -227,9 +227,9 @@ const updatePage = (page: number) => {
|
||||||
|
|
||||||
<track-row
|
<track-row
|
||||||
v-for="(track, index) in allTracks"
|
v-for="(track, index) in allTracks"
|
||||||
|
:key="track.id + track.position"
|
||||||
:data-track-id="track.id"
|
:data-track-id="track.id"
|
||||||
:data-track-position="track.position"
|
:data-track-position="track.position"
|
||||||
:key="track.id + track.position"
|
|
||||||
:track="track"
|
:track="track"
|
||||||
:index="index"
|
:index="index"
|
||||||
:tracks="allTracks"
|
:tracks="allTracks"
|
||||||
|
|
|
@ -45,7 +45,7 @@ const fetchData = async (url = props.url) => {
|
||||||
nextPage.value = response.data.next
|
nextPage.value = response.data.next
|
||||||
count.value = response.data.count
|
count.value = response.data.count
|
||||||
|
|
||||||
const newObjects = !props.isActivity
|
const newObjects = !props.isActivity
|
||||||
? response.data.results.map((track: Track) => { track })
|
? response.data.results.map((track: Track) => { track })
|
||||||
: response.data.results
|
: response.data.results
|
||||||
|
|
||||||
|
@ -127,7 +127,10 @@ if (props.websocketHandlers.includes('Listen')) {
|
||||||
{{ object.track.title }}
|
{{ object.track.title }}
|
||||||
</router-link>
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="object.track.artist" class="meta ellipsis">
|
<div
|
||||||
|
v-if="object.track.artist"
|
||||||
|
class="meta ellipsis"
|
||||||
|
>
|
||||||
<span>
|
<span>
|
||||||
<router-link
|
<router-link
|
||||||
class="discrete link"
|
class="discrete link"
|
||||||
|
|
|
@ -18,7 +18,7 @@ const props = withDefaults(defineProps<Props>(), {
|
||||||
const defaults = reactive({
|
const defaults = reactive({
|
||||||
name: props.name,
|
name: props.name,
|
||||||
scopes: props.scopes,
|
scopes: props.scopes,
|
||||||
redirectUris: props.redirectUris,
|
redirectUris: props.redirectUris
|
||||||
})
|
})
|
||||||
|
|
||||||
const { $pgettext } = useGettext()
|
const { $pgettext } = useGettext()
|
||||||
|
|
|
@ -219,7 +219,7 @@ export default {
|
||||||
return this.knownScopes.map(s => {
|
return this.knownScopes.map(s => {
|
||||||
const id = s.id
|
const id = s.id
|
||||||
return {
|
return {
|
||||||
id: id,
|
id,
|
||||||
icon: s.icon,
|
icon: s.icon,
|
||||||
label: self.sharedLabels.scopes[s.id].label,
|
label: self.sharedLabels.scopes[s.id].label,
|
||||||
description: self.sharedLabels.scopes[s.id].description,
|
description: self.sharedLabels.scopes[s.id].description,
|
||||||
|
|
|
@ -73,7 +73,10 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<template v-if="plugin.conf?.length > 0">
|
<template v-if="plugin.conf?.length > 0">
|
||||||
<template v-for="(field, key) in plugin.conf" :key="key">
|
<template
|
||||||
|
v-for="(field, key) in plugin.conf"
|
||||||
|
:key="key"
|
||||||
|
>
|
||||||
<div
|
<div
|
||||||
v-if="field.type === 'text'"
|
v-if="field.type === 'text'"
|
||||||
class="field"
|
class="field"
|
||||||
|
|
|
@ -601,7 +601,7 @@ export default {
|
||||||
async fetchDraftUploads (channel) {
|
async fetchDraftUploads (channel) {
|
||||||
const self = this
|
const self = this
|
||||||
this.draftUploads = null
|
this.draftUploads = null
|
||||||
const response = await axios.get('uploads', { params: { import_status: 'draft', channel: channel } })
|
const response = await axios.get('uploads', { params: { import_status: 'draft', channel } })
|
||||||
this.draftUploads = response.data.results
|
this.draftUploads = response.data.results
|
||||||
this.draftUploads.forEach((u) => {
|
this.draftUploads.forEach((u) => {
|
||||||
self.uploadImportData[u.uuid] = u.import_metadata
|
self.uploadImportData[u.uuid] = u.import_metadata
|
||||||
|
|
|
@ -33,4 +33,4 @@ withDefaults(defineProps<Props>(), {
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -8,4 +8,4 @@ defineProps<Props>()
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<span>{{ username }}</span>
|
<span>{{ username }}</span>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { RouteWithPreferences } from '~/store/ui'
|
import type { RouteWithPreferences, OrderingField } from '~/store/ui'
|
||||||
import type { Track } from '~/types'
|
import type { Track } from '~/types'
|
||||||
import type { OrderingField } from '~/store/ui'
|
|
||||||
import type { OrderingProps } from '~/composables/useOrdering'
|
import type { OrderingProps } from '~/composables/useOrdering'
|
||||||
|
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
|
@ -77,7 +76,7 @@ const fetchFavorites = async () => {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
logger.time('Loading user favorites')
|
logger.time('Loading user favorites')
|
||||||
const response = await axios.get('tracks/', { params: params })
|
const response = await axios.get('tracks/', { params })
|
||||||
|
|
||||||
results.length = 0
|
results.length = 0
|
||||||
results.push(...response.data.results)
|
results.push(...response.data.results)
|
||||||
|
|
|
@ -89,7 +89,7 @@ export default {
|
||||||
const params = clone({})
|
const params = clone({})
|
||||||
params.page_size = this.limit
|
params.page_size = this.limit
|
||||||
params.offset = this.offset
|
params.offset = this.offset
|
||||||
axios.get(url, { params: params }).then((response) => {
|
axios.get(url, { params }).then((response) => {
|
||||||
self.previousPage = response.data.previous
|
self.previousPage = response.data.previous
|
||||||
self.nextPage = response.data.next
|
self.nextPage = response.data.next
|
||||||
self.isLoading = false
|
self.isLoading = false
|
||||||
|
|
|
@ -44,14 +44,14 @@ const fetchData = async () => {
|
||||||
const albumResponse = await axios.get(`albums/${props.id}/`, { params: { refresh: 'true' } })
|
const albumResponse = await axios.get(`albums/${props.id}/`, { params: { refresh: 'true' } })
|
||||||
const [artistResponse, tracksResponse] = await Promise.all([
|
const [artistResponse, tracksResponse] = await Promise.all([
|
||||||
axios.get(`artists/${albumResponse.data.artist.id}/`),
|
axios.get(`artists/${albumResponse.data.artist.id}/`),
|
||||||
axios.get('tracks/', {
|
axios.get('tracks/', {
|
||||||
params: {
|
params: {
|
||||||
ordering: 'disc_number,position',
|
ordering: 'disc_number,position',
|
||||||
album: props.id,
|
album: props.id,
|
||||||
page_size: paginateBy.value,
|
page_size: paginateBy.value,
|
||||||
page: page.value,
|
page: page.value,
|
||||||
include_channels: true
|
include_channels: true
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
])
|
])
|
||||||
|
|
||||||
|
@ -60,7 +60,6 @@ const fetchData = async () => {
|
||||||
artist.value.channel.artist = artist.value
|
artist.value.channel.artist = artist.value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
object.value = albumResponse.data
|
object.value = albumResponse.data
|
||||||
if (object.value) {
|
if (object.value) {
|
||||||
object.value.tracks = tracksResponse.data.results
|
object.value.tracks = tracksResponse.data.results
|
||||||
|
|
|
@ -180,4 +180,4 @@ const remove = () => emit('remove')
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -80,7 +80,6 @@ const fetchData = async () => {
|
||||||
nextTracksUrl.value = tracksResponse.data.next
|
nextTracksUrl.value = tracksResponse.data.next
|
||||||
totalTracks.value = tracksResponse.data.count
|
totalTracks.value = tracksResponse.data.count
|
||||||
|
|
||||||
|
|
||||||
nextAlbumsUrl.value = albumsResponse.data.next
|
nextAlbumsUrl.value = albumsResponse.data.next
|
||||||
totalAlbums.value = albumsResponse.data.count
|
totalAlbums.value = albumsResponse.data.count
|
||||||
|
|
||||||
|
|
|
@ -86,7 +86,7 @@ export default {
|
||||||
const self = this
|
const self = this
|
||||||
const params = clone(this.filters)
|
const params = clone(this.filters)
|
||||||
params.page_size = this.limit
|
params.page_size = this.limit
|
||||||
axios.get(url, { params: params }).then((response) => {
|
axios.get(url, { params }).then((response) => {
|
||||||
self.previousPage = response.data.previous
|
self.previousPage = response.data.previous
|
||||||
self.nextPage = response.data.next
|
self.nextPage = response.data.next
|
||||||
self.isLoading = false
|
self.isLoading = false
|
||||||
|
|
|
@ -36,7 +36,7 @@ const fetchData = async () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await axios.get('artists/', { params: params })
|
const response = await axios.get('artists/', { params })
|
||||||
artists.value = response.data.results
|
artists.value = response.data.results
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// TODO (wvffle): Handle error
|
// TODO (wvffle): Handle error
|
||||||
|
|
|
@ -58,9 +58,9 @@ const escapeHtml = (unsafe: string) => document.createTextNode(unsafe).textConte
|
||||||
const subtitle = computed(() => {
|
const subtitle = computed(() => {
|
||||||
if (track.value?.attributed_to) {
|
if (track.value?.attributed_to) {
|
||||||
return $pgettext(
|
return $pgettext(
|
||||||
'Content/Track/Paragraph',
|
'Content/Track/Paragraph',
|
||||||
'Uploaded by <a class="internal" href="%{ uploaderUrl }">%{ uploader }</a> on <time title="%{ date }" datetime="%{ date }">%{ prettyDate }</time>',
|
'Uploaded by <a class="internal" href="%{ uploaderUrl }">%{ uploader }</a> on <time title="%{ date }" datetime="%{ date }">%{ prettyDate }</time>',
|
||||||
{
|
{
|
||||||
uploaderUrl: attributedToUrl.value,
|
uploaderUrl: attributedToUrl.value,
|
||||||
uploader: escapeHtml(`@${track.value.attributed_to.full_username}`),
|
uploader: escapeHtml(`@${track.value.attributed_to.full_username}`),
|
||||||
date: escapeHtml(track.value.creation_date),
|
date: escapeHtml(track.value.creation_date),
|
||||||
|
@ -70,7 +70,7 @@ const subtitle = computed(() => {
|
||||||
}
|
}
|
||||||
|
|
||||||
return $pgettext(
|
return $pgettext(
|
||||||
'Content/Track/Paragraph',
|
'Content/Track/Paragraph',
|
||||||
'Uploaded on <time title="%{ date }" datetime="%{ date }">%{ prettyDate }</time>',
|
'Uploaded on <time title="%{ date }" datetime="%{ date }">%{ prettyDate }</time>',
|
||||||
{
|
{
|
||||||
date: escapeHtml(track.value?.creation_date ?? ''),
|
date: escapeHtml(track.value?.creation_date ?? ''),
|
||||||
|
@ -79,7 +79,6 @@ const subtitle = computed(() => {
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
const { $pgettext } = useGettext()
|
const { $pgettext } = useGettext()
|
||||||
const labels = computed(() => ({
|
const labels = computed(() => ({
|
||||||
title: $pgettext('*/*/*/Noun', 'Track'),
|
title: $pgettext('*/*/*/Noun', 'Track'),
|
||||||
|
|
|
@ -19,12 +19,12 @@ interface Props {
|
||||||
filter: {
|
filter: {
|
||||||
type: string
|
type: string
|
||||||
label: string
|
label: string
|
||||||
fields: {
|
fields: {
|
||||||
name: string
|
name: string
|
||||||
placeholder: string
|
placeholder: string
|
||||||
type: 'list'
|
type: 'list'
|
||||||
subtype: 'number'
|
subtype: 'number'
|
||||||
autocomplete?: string
|
autocomplete?: string
|
||||||
autocomplete_qs: string
|
autocomplete_qs: string
|
||||||
autocomplete_fields: {
|
autocomplete_fields: {
|
||||||
remoteValues?: unknown
|
remoteValues?: unknown
|
||||||
|
@ -103,7 +103,7 @@ const fetchCandidates = async () => {
|
||||||
const params = {
|
const params = {
|
||||||
filters: [{
|
filters: [{
|
||||||
...clone(props.config),
|
...clone(props.config),
|
||||||
type: props.filter.type,
|
type: props.filter.type
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { PrivacyLevel } from '~/types'
|
import type { PrivacyLevel } from '~/types'
|
||||||
import type { RouteWithPreferences } from '~/store/ui'
|
import type { RouteWithPreferences, OrderingField } from '~/store/ui'
|
||||||
import type { OrderingField } from '~/store/ui'
|
|
||||||
import type { SmartSearchProps } from '~/composables/useSmartSearch'
|
import type { SmartSearchProps } from '~/composables/useSmartSearch'
|
||||||
import type { OrderingProps } from '~/composables/useOrdering'
|
import type { OrderingProps } from '~/composables/useOrdering'
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { RouteWithPreferences } from '~/store/ui'
|
import type { RouteWithPreferences, OrderingField } from '~/store/ui'
|
||||||
import type { OrderingField } from '~/store/ui'
|
|
||||||
import type { SmartSearchProps } from '~/composables/useSmartSearch'
|
import type { SmartSearchProps } from '~/composables/useSmartSearch'
|
||||||
import type { OrderingProps } from '~/composables/useOrdering'
|
import type { OrderingProps } from '~/composables/useOrdering'
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { ImportStatus, PrivacyLevel } from '~/types'
|
import type { ImportStatus, PrivacyLevel, Upload } from '~/types'
|
||||||
import type { RouteWithPreferences } from '~/store/ui'
|
import type { RouteWithPreferences, OrderingField } from '~/store/ui'
|
||||||
import type { OrderingField } from '~/store/ui'
|
|
||||||
import type { Upload } from '~/types'
|
|
||||||
import type { OrderingProps } from '~/composables/useOrdering'
|
import type { OrderingProps } from '~/composables/useOrdering'
|
||||||
import type { SmartSearchProps } from '~/composables/useSmartSearch'
|
import type { SmartSearchProps } from '~/composables/useSmartSearch'
|
||||||
|
|
||||||
|
|
|
@ -39,7 +39,7 @@ const fetchData = async () => {
|
||||||
|
|
||||||
target_account_domain: props.type === 'actor'
|
target_account_domain: props.type === 'actor'
|
||||||
? domain
|
? domain
|
||||||
: undefined,
|
: undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
isLoading.value = true
|
isLoading.value = true
|
||||||
|
|
|
@ -10,7 +10,6 @@ import { useStore } from '~/store'
|
||||||
import SemanticModal from '~/components/semantic/Modal.vue'
|
import SemanticModal from '~/components/semantic/Modal.vue'
|
||||||
import useLogger from '~/composables/useLogger'
|
import useLogger from '~/composables/useLogger'
|
||||||
|
|
||||||
|
|
||||||
const logger = useLogger()
|
const logger = useLogger()
|
||||||
const { $pgettext } = useGettext()
|
const { $pgettext } = useGettext()
|
||||||
|
|
||||||
|
|
|
@ -16,9 +16,9 @@
|
||||||
<sanitized-html
|
<sanitized-html
|
||||||
tag="span"
|
tag="span"
|
||||||
class="link"
|
class="link"
|
||||||
|
:html="notificationData.message"
|
||||||
@click="navigate"
|
@click="navigate"
|
||||||
@keypress.enter="navigate"
|
@keypress.enter="navigate"
|
||||||
:html="notificationData.message"
|
|
||||||
/>
|
/>
|
||||||
</router-link>
|
</router-link>
|
||||||
<sanitized-html
|
<sanitized-html
|
||||||
|
|
|
@ -16,7 +16,7 @@ const store = useStore()
|
||||||
const images = computed(() => {
|
const images = computed(() => {
|
||||||
const urls = props.playlist.album_covers.slice(0, 4).map(url => store.getters['instance/absoluteUrl'](url))
|
const urls = props.playlist.album_covers.slice(0, 4).map(url => store.getters['instance/absoluteUrl'](url))
|
||||||
|
|
||||||
while (urls.length < 4) {
|
while (urls.length < 4) {
|
||||||
urls.push(defaultCover)
|
urls.push(defaultCover)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -152,8 +152,8 @@ const insertMany = async (insertedTracks: Track[], allowDuplicates: boolean) =>
|
||||||
<template>
|
<template>
|
||||||
<div class="ui text container component-playlist-editor">
|
<div class="ui text container component-playlist-editor">
|
||||||
<playlist-form
|
<playlist-form
|
||||||
:title="false"
|
|
||||||
v-model:playlist="playlist"
|
v-model:playlist="playlist"
|
||||||
|
:title="false"
|
||||||
/>
|
/>
|
||||||
<h3 class="ui top attached header">
|
<h3 class="ui top attached header">
|
||||||
<translate translate-context="Content/Playlist/Title">
|
<translate translate-context="Content/Playlist/Title">
|
||||||
|
|
|
@ -69,7 +69,7 @@ const submit = async () => {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const url = props.create ? 'playlists/' : `playlists/${playlist.value!.id}/`
|
const url = props.create ? 'playlists/' : `playlists/${playlist.value!.id}/`
|
||||||
const method = props.create ? 'post' : 'patch'
|
const method = props.create ? 'post' : 'patch'
|
||||||
|
|
||||||
const data = {
|
const data = {
|
||||||
name: name.value,
|
name: name.value,
|
||||||
|
@ -94,7 +94,6 @@ const submit = async () => {
|
||||||
isLoading.value = false
|
isLoading.value = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
|
@ -26,7 +26,7 @@ const playlists = computed(() => store.state.playlists.playlists)
|
||||||
const track = computed(() => store.state.playlists.modalTrack)
|
const track = computed(() => store.state.playlists.modalTrack)
|
||||||
|
|
||||||
const { $pgettext } = useGettext()
|
const { $pgettext } = useGettext()
|
||||||
const labels = computed(() => ({
|
const labels = computed(() => ({
|
||||||
addToPlaylist: $pgettext('Popup/Playlist/Table.Button.Tooltip/Verb', 'Add to this playlist'),
|
addToPlaylist: $pgettext('Popup/Playlist/Table.Button.Tooltip/Verb', 'Add to this playlist'),
|
||||||
filterPlaylistField: $pgettext('Popup/Playlist/Form/Placeholder', 'Enter playlist name')
|
filterPlaylistField: $pgettext('Popup/Playlist/Form/Placeholder', 'Enter playlist name')
|
||||||
}))
|
}))
|
||||||
|
@ -51,7 +51,7 @@ const duplicateTrackAddInfo = ref({} as { playlist_name?: string })
|
||||||
const addToPlaylist = async (playlistId: number, allowDuplicates: boolean) => {
|
const addToPlaylist = async (playlistId: number, allowDuplicates: boolean) => {
|
||||||
lastSelectedPlaylist.value = playlistId
|
lastSelectedPlaylist.value = playlistId
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await axios.post(`playlists/${playlistId}/add/`, {
|
await axios.post(`playlists/${playlistId}/add/`, {
|
||||||
tracks: [track.value?.id].filter(i => i),
|
tracks: [track.value?.id].filter(i => i),
|
||||||
allow_duplicates: allowDuplicates
|
allow_duplicates: allowDuplicates
|
||||||
|
@ -106,7 +106,10 @@ store.dispatch('playlists/fetchOwn')
|
||||||
</translate>
|
</translate>
|
||||||
</h4>
|
</h4>
|
||||||
<div class="scrolling content">
|
<div class="scrolling content">
|
||||||
<playlist-form :create="true" :key="formKey" />
|
<playlist-form
|
||||||
|
:key="formKey"
|
||||||
|
:create="true"
|
||||||
|
/>
|
||||||
<div class="ui divider" />
|
<div class="ui divider" />
|
||||||
<div v-if="playlists.length > 0">
|
<div v-if="playlists.length > 0">
|
||||||
<div
|
<div
|
||||||
|
@ -249,9 +252,9 @@ store.dispatch('playlists/fetchOwn')
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-else
|
v-else
|
||||||
class="ui placeholder segment"
|
class="ui placeholder segment"
|
||||||
>
|
>
|
||||||
<div class="ui icon header">
|
<div class="ui icon header">
|
||||||
<i class="list icon" />
|
<i class="list icon" />
|
||||||
|
|
|
@ -107,7 +107,7 @@ export default {
|
||||||
const params = clone(this.filters)
|
const params = clone(this.filters)
|
||||||
params.page_size = this.limit
|
params.page_size = this.limit
|
||||||
params.offset = this.offset
|
params.offset = this.offset
|
||||||
axios.get(url, { params: params }).then((response) => {
|
axios.get(url, { params }).then((response) => {
|
||||||
self.previousPage = response.data.previous
|
self.previousPage = response.data.previous
|
||||||
self.nextPage = response.data.next
|
self.nextPage = response.data.next
|
||||||
self.isLoading = false
|
self.isLoading = false
|
||||||
|
|
|
@ -27,12 +27,12 @@ const running = computed(() => {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
return store.state.radios.current?.type === props.type
|
return store.state.radios.current?.type === props.type &&
|
||||||
&& store.state.radios.current?.customRadioId === props.customRadioId
|
store.state.radios.current?.customRadioId === props.customRadioId &&
|
||||||
&& (
|
(
|
||||||
typeof props.objectId === 'string'
|
typeof props.objectId === 'string' ||
|
||||||
|| store.state.radios.current?.objectId.fullUsername === props.objectId?.fullUsername
|
store.state.radios.current?.objectId.fullUsername === props.objectId?.fullUsername
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
const { $pgettext } = useGettext()
|
const { $pgettext } = useGettext()
|
||||||
|
|
|
@ -3,7 +3,7 @@ import type { ContentFilter } from '~/store/moderation'
|
||||||
|
|
||||||
import { useStore } from '~/store'
|
import { useStore } from '~/store'
|
||||||
import { useGettext } from 'vue3-gettext'
|
import { useGettext } from 'vue3-gettext'
|
||||||
import { computed, ref } from "vue"
|
import { computed, ref } from 'vue'
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import usePlayer from '~/composables/audio/usePlayer'
|
import usePlayer from '~/composables/audio/usePlayer'
|
||||||
import useQueue from '~/composables/audio/useQueue'
|
import useQueue from '~/composables/audio/useQueue'
|
||||||
|
@ -36,8 +36,8 @@ export default (props: PlayOptionsProps) => {
|
||||||
if (props.track) {
|
if (props.track) {
|
||||||
return props.track.uploads?.length > 0
|
return props.track.uploads?.length > 0
|
||||||
} else if (props.artist) {
|
} else if (props.artist) {
|
||||||
return props.artist.tracks_count > 0
|
return props.artist.tracks_count > 0 ||
|
||||||
|| props.artist.albums.some((album) => album.is_playable === true)
|
props.artist.albums.some((album) => album.is_playable === true)
|
||||||
} else if (props.tracks) {
|
} else if (props.tracks) {
|
||||||
return props.tracks.some((track) => (track.uploads?.length ?? 0) > 0)
|
return props.tracks.some((track) => (track.uploads?.length ?? 0) > 0)
|
||||||
}
|
}
|
||||||
|
@ -55,7 +55,7 @@ export default (props: PlayOptionsProps) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
store.commit('ui/addMessage', {
|
store.commit('ui/addMessage', {
|
||||||
content: $npgettext('*/Queue/Message', '%{ count } track was added to your queue', '%{ count } tracks were added to your queue', tracks.length, {
|
content: $npgettext('*/Queue/Message', '%{ count } track was added to your queue', '%{ count } tracks were added to your queue', tracks.length, {
|
||||||
count: tracks.length.toString()
|
count: tracks.length.toString()
|
||||||
}),
|
}),
|
||||||
date: new Date()
|
date: new Date()
|
||||||
|
@ -70,8 +70,8 @@ export default (props: PlayOptionsProps) => {
|
||||||
|
|
||||||
// when fetching artists/or album tracks, sometimes, we may have to fetch
|
// when fetching artists/or album tracks, sometimes, we may have to fetch
|
||||||
// multiple pages
|
// multiple pages
|
||||||
const response = await axios.get('tracks/', {
|
const response = await axios.get('tracks/', {
|
||||||
params: {
|
params: {
|
||||||
...params,
|
...params,
|
||||||
page_size: 100,
|
page_size: 100,
|
||||||
page,
|
page,
|
||||||
|
@ -136,7 +136,7 @@ export default (props: PlayOptionsProps) => {
|
||||||
jQuery(el.value).find('.ui.dropdown').dropdown('hide')
|
jQuery(el.value).find('.ui.dropdown').dropdown('hide')
|
||||||
|
|
||||||
const tracks = await getPlayableTracks()
|
const tracks = await getPlayableTracks()
|
||||||
store.dispatch('queue/appendMany', { tracks: tracks }).then(() => addMessage(tracks))
|
store.dispatch('queue/appendMany', { tracks }).then(() => addMessage(tracks))
|
||||||
}
|
}
|
||||||
|
|
||||||
const enqueueNext = async (next = false) => {
|
const enqueueNext = async (next = false) => {
|
||||||
|
@ -188,7 +188,7 @@ export default (props: PlayOptionsProps) => {
|
||||||
replacePlay()
|
replacePlay()
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
playable,
|
playable,
|
||||||
filterableArtist,
|
filterableArtist,
|
||||||
filterArtist,
|
filterArtist,
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import type { Track } from "~/types"
|
import type { Track } from '~/types'
|
||||||
|
|
||||||
import { useTimeoutFn, useThrottleFn, useTimeAgo, useNow, whenever } from '@vueuse/core'
|
import { useTimeoutFn, useThrottleFn, useTimeAgo, useNow, whenever } from '@vueuse/core'
|
||||||
import { Howler } from 'howler'
|
import { Howler } from 'howler'
|
||||||
import { gettext } from '~/init/locale'
|
import { gettext } from '~/init/locale'
|
||||||
import { ref, computed } from "vue"
|
import { ref, computed } from 'vue'
|
||||||
import { sum } from 'lodash-es'
|
import { sum } from 'lodash-es'
|
||||||
import store from "~/store"
|
import store from '~/store'
|
||||||
|
|
||||||
const { $pgettext } = gettext
|
const { $pgettext } = gettext
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ const previous = () => store.dispatch('queue/previous')
|
||||||
|
|
||||||
const focused = computed(() => store.state.ui.queueFocused === 'queue')
|
const focused = computed(() => store.state.ui.queueFocused === 'queue')
|
||||||
|
|
||||||
//
|
//
|
||||||
// Track list
|
// Track list
|
||||||
//
|
//
|
||||||
const tracksChangeBuffer = ref<Track[] | null>(null)
|
const tracksChangeBuffer = ref<Track[] | null>(null)
|
||||||
|
@ -44,7 +44,7 @@ const reorder = (oldIndex: number, newIndex: number) => {
|
||||||
tracksChangeBuffer.value = null
|
tracksChangeBuffer.value = null
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Shuffle
|
// Shuffle
|
||||||
//
|
//
|
||||||
const isShuffling = ref(false)
|
const isShuffling = ref(false)
|
||||||
|
@ -88,12 +88,12 @@ const endsIn = useTimeAgo(computed(() => {
|
||||||
}))
|
}))
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
return {
|
return {
|
||||||
currentTrack,
|
currentTrack,
|
||||||
currentIndex,
|
currentIndex,
|
||||||
hasNext,
|
hasNext,
|
||||||
hasPrevious,
|
hasPrevious,
|
||||||
isEmpty,
|
isEmpty,
|
||||||
isShuffling,
|
isShuffling,
|
||||||
|
|
||||||
removeTrack,
|
removeTrack,
|
||||||
|
@ -110,4 +110,4 @@ export default () => {
|
||||||
endsIn,
|
endsIn,
|
||||||
focused
|
focused
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
import type { Track } from '~/types'
|
import type { Track } from '~/types'
|
||||||
|
|
||||||
import { ref, computed } from "vue"
|
import { ref, computed } from 'vue'
|
||||||
import { Howl } from 'howler'
|
import { Howl } from 'howler'
|
||||||
import useTrackSources from '~/composables/audio/useTrackSources'
|
import useTrackSources from '~/composables/audio/useTrackSources'
|
||||||
import useSoundCache from '~/composables/audio/useSoundCache'
|
import useSoundCache from '~/composables/audio/useSoundCache'
|
||||||
import usePlayer from '~/composables/audio/usePlayer'
|
import usePlayer from '~/composables/audio/usePlayer'
|
||||||
import store from "~/store"
|
import store from '~/store'
|
||||||
import { createEventHook } from "@vueuse/core"
|
import { createEventHook } from '@vueuse/core'
|
||||||
|
|
||||||
interface Sound {
|
interface Sound {
|
||||||
id?: number
|
id?: number
|
||||||
|
@ -152,4 +152,4 @@ export default () => {
|
||||||
currentSound,
|
currentSound,
|
||||||
onSoundProgress: soundProgress.on
|
onSoundProgress: soundProgress.on
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import type { Howl } from "howler"
|
import type { Howl } from 'howler'
|
||||||
|
|
||||||
import { sortBy } from "lodash-es"
|
import { sortBy } from 'lodash-es'
|
||||||
import { reactive, watchEffect, ref } from "vue"
|
import { reactive, watchEffect, ref } from 'vue'
|
||||||
|
|
||||||
const MAX_PRELOADED = 3
|
const MAX_PRELOADED = 3
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ const soundCache = reactive(new Map<string, CachedSound>())
|
||||||
const cleaningCache = ref(false)
|
const cleaningCache = ref(false)
|
||||||
|
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
let toRemove = soundCache.size - MAX_PRELOADED
|
const toRemove = soundCache.size - MAX_PRELOADED
|
||||||
|
|
||||||
if (toRemove > 0 && !cleaningCache.value) {
|
if (toRemove > 0 && !cleaningCache.value) {
|
||||||
cleaningCache.value = true
|
cleaningCache.value = true
|
||||||
|
@ -33,7 +33,6 @@ watchEffect(() => {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
return soundCache
|
return soundCache
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import type { Track } from "~/types"
|
import type { Track } from '~/types'
|
||||||
|
|
||||||
import store from '~/store'
|
import store from '~/store'
|
||||||
import updateQueryString from '~/composables/updateQueryString'
|
import updateQueryString from '~/composables/updateQueryString'
|
||||||
|
|
||||||
export interface TrackSource {
|
export interface TrackSource {
|
||||||
url: string
|
url: string
|
||||||
type: string
|
type: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,23 +29,23 @@ export default (trackData: Track): TrackSource[] => {
|
||||||
sources.push({
|
sources.push({
|
||||||
type: 'mp3',
|
type: 'mp3',
|
||||||
url: updateQueryString(
|
url: updateQueryString(
|
||||||
store.getters['instance/absoluteUrl'](trackData.listen_url),
|
store.getters['instance/absoluteUrl'](trackData.listen_url),
|
||||||
'to',
|
'to',
|
||||||
'mp3'
|
'mp3'
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
const token = store.state.auth.scopedTokens.listen
|
const token = store.state.auth.scopedTokens.listen
|
||||||
if (store.state.auth.authenticated && token !== null) {
|
if (store.state.auth.authenticated && token !== null) {
|
||||||
// we need to send the token directly in url
|
// we need to send the token directly in url
|
||||||
// so authentication can be checked by the backend
|
// so authentication can be checked by the backend
|
||||||
// because for audio files we cannot use the regular Authentication
|
// because for audio files we cannot use the regular Authentication
|
||||||
// header
|
// header
|
||||||
return sources.map(source => ({
|
return sources.map(source => ({
|
||||||
...source,
|
...source,
|
||||||
url: updateQueryString(source.url, 'token', token)
|
url: updateQueryString(source.url, 'token', token)
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
return sources
|
return sources
|
||||||
}
|
}
|
||||||
|
|
|
@ -134,7 +134,7 @@ const report = (obj: ReportableObject) => {
|
||||||
store.dispatch('moderation/report', obj.target)
|
store.dispatch('moderation/report', obj.target)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default () => ({
|
export default () => ({
|
||||||
getReportableObjects,
|
getReportableObjects,
|
||||||
report
|
report
|
||||||
})
|
})
|
||||||
|
|
|
@ -83,7 +83,7 @@ export const install: InitModule = ({ store, router }) => {
|
||||||
case 500:
|
case 500:
|
||||||
error.backendErrors.push('A server error occurred')
|
error.backendErrors.push('A server error occurred')
|
||||||
break
|
break
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if (error.response?.data as object) {
|
if (error.response?.data as object) {
|
||||||
const data = error.response?.data as Record<string, unknown>
|
const data = error.response?.data as Record<string, unknown>
|
||||||
|
|
|
@ -11,4 +11,4 @@ export const hasPermissions = (permission: Permission) => (to: RouteLocationNorm
|
||||||
|
|
||||||
console.log('Not authenticated. Redirecting to library.')
|
console.log('Not authenticated. Redirecting to library.')
|
||||||
next({ name: 'library.index' })
|
next({ name: 'library.index' })
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,5 +61,5 @@ export default [
|
||||||
path: '/logout',
|
path: '/logout',
|
||||||
name: 'logout',
|
name: 'logout',
|
||||||
component: () => import('~/components/auth/Logout.vue')
|
component: () => import('~/components/auth/Logout.vue')
|
||||||
},
|
}
|
||||||
] as RouteRecordRaw[]
|
] as RouteRecordRaw[]
|
||||||
|
|
|
@ -37,5 +37,5 @@ export default [
|
||||||
name: 'content.remote.index',
|
name: 'content.remote.index',
|
||||||
component: () => import('~/views/content/remote/Home.vue')
|
component: () => import('~/views/content/remote/Home.vue')
|
||||||
}]
|
}]
|
||||||
},
|
}
|
||||||
] as RouteRecordRaw[]
|
] as RouteRecordRaw[]
|
||||||
|
|
|
@ -104,4 +104,4 @@ export default [
|
||||||
name: '404',
|
name: '404',
|
||||||
component: () => import('~/components/PageNotFound.vue')
|
component: () => import('~/components/PageNotFound.vue')
|
||||||
}
|
}
|
||||||
] as RouteRecordRaw[]
|
] as RouteRecordRaw[]
|
||||||
|
|
|
@ -178,5 +178,5 @@ export default [
|
||||||
props: true
|
props: true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
}
|
||||||
] as RouteRecordRaw[]
|
] as RouteRecordRaw[]
|
||||||
|
|
|
@ -26,5 +26,5 @@ export default [
|
||||||
name: 'settings.applications.edit',
|
name: 'settings.applications.edit',
|
||||||
component: () => import('~/components/auth/ApplicationEdit.vue'),
|
component: () => import('~/components/auth/ApplicationEdit.vue'),
|
||||||
props: true
|
props: true
|
||||||
},
|
}
|
||||||
] as RouteRecordRaw[]
|
] as RouteRecordRaw[]
|
||||||
|
|
|
@ -3,7 +3,7 @@ import type { RouteRecordRaw } from 'vue-router'
|
||||||
import store from '~/store'
|
import store from '~/store'
|
||||||
|
|
||||||
export default [
|
export default [
|
||||||
{ suffix: '.full', path: '/@:username@:domain' },
|
{ suffix: '.full', path: '/@:username@:domain' },
|
||||||
{ suffix: '', path: '/@:username' }
|
{ suffix: '', path: '/@:username' }
|
||||||
].map((route) => {
|
].map((route) => {
|
||||||
return {
|
return {
|
||||||
|
@ -31,4 +31,4 @@ export default [
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}) as RouteRecordRaw[]
|
}) as RouteRecordRaw[]
|
||||||
|
|
|
@ -71,7 +71,7 @@ const store: Module<State, RootState> = {
|
||||||
page_size: 50,
|
page_size: 50,
|
||||||
ordering: '-creation_date'
|
ordering: '-creation_date'
|
||||||
}
|
}
|
||||||
const promise = axios.get('favorites/tracks/all/', { params: params })
|
const promise = axios.get('favorites/tracks/all/', { params })
|
||||||
return promise.then((response) => {
|
return promise.then((response) => {
|
||||||
logger.info('Fetched a batch of ' + response.data.results.length + ' favorites')
|
logger.info('Fetched a batch of ' + response.data.results.length + ' favorites')
|
||||||
response.data.results.forEach((result: { track: string }) => {
|
response.data.results.forEach((result: { track: string }) => {
|
||||||
|
|
|
@ -110,7 +110,7 @@ export default createStore<RootState>({
|
||||||
mbid: track.mbid,
|
mbid: track.mbid,
|
||||||
uploads: track.uploads,
|
uploads: track.uploads,
|
||||||
listen_url: track.listen_url,
|
listen_url: track.listen_url,
|
||||||
artist: artist,
|
artist,
|
||||||
album: {}
|
album: {}
|
||||||
}
|
}
|
||||||
if (track.album) {
|
if (track.album) {
|
||||||
|
@ -119,7 +119,7 @@ export default createStore<RootState>({
|
||||||
title: track.album.title,
|
title: track.album.title,
|
||||||
mbid: track.album.mbid,
|
mbid: track.album.mbid,
|
||||||
cover: track.album.cover,
|
cover: track.album.cover,
|
||||||
artist: artist
|
artist
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return data
|
return data
|
||||||
|
|
|
@ -60,7 +60,7 @@ const store: Module<State, RootState> = {
|
||||||
commit('follows', { library: uuid, follow: null })
|
commit('follows', { library: uuid, follow: null })
|
||||||
}, () => {
|
}, () => {
|
||||||
logger.info('Error while unsubscribing from library')
|
logger.info('Error while unsubscribing from library')
|
||||||
commit('follows', { library: uuid, follow: follow })
|
commit('follows', { library: uuid, follow })
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -139,7 +139,7 @@ const store: Module<State, RootState> = {
|
||||||
page_size: 100,
|
page_size: 100,
|
||||||
ordering: '-creation_date'
|
ordering: '-creation_date'
|
||||||
}
|
}
|
||||||
promise = axios.get('moderation/content-filters/', { params: params })
|
promise = axios.get('moderation/content-filters/', { params })
|
||||||
}
|
}
|
||||||
return promise.then((response) => {
|
return promise.then((response) => {
|
||||||
logger.info('Fetched a batch of ' + response.data.results.length + ' filters')
|
logger.info('Fetched a batch of ' + response.data.results.length + ' filters')
|
||||||
|
|
|
@ -34,7 +34,7 @@ const store: Module<State, RootState> = {
|
||||||
currentTime: 0,
|
currentTime: 0,
|
||||||
errored: false,
|
errored: false,
|
||||||
bufferProgress: 0,
|
bufferProgress: 0,
|
||||||
looping: 0
|
looping: 0
|
||||||
},
|
},
|
||||||
mutations: {
|
mutations: {
|
||||||
reset (state) {
|
reset (state) {
|
||||||
|
|
|
@ -96,7 +96,7 @@ const store: Module<State, RootState> = {
|
||||||
|
|
||||||
const total = tracks.length
|
const total = tracks.length
|
||||||
tracks.forEach((track: Track, i: number) => {
|
tracks.forEach((track: Track, i: number) => {
|
||||||
const promise = dispatch('append', { track: track, index: index })
|
const promise = dispatch('append', { track, index })
|
||||||
index += 1
|
index += 1
|
||||||
|
|
||||||
if (callback && i + 1 === total) {
|
if (callback && i + 1 === total) {
|
||||||
|
|
|
@ -86,7 +86,7 @@ const store: Module<State, RootState> = {
|
||||||
radio_type: type,
|
radio_type: type,
|
||||||
related_object_id: objectId,
|
related_object_id: objectId,
|
||||||
custom_radio: customRadioId,
|
custom_radio: customRadioId,
|
||||||
config: config
|
config
|
||||||
}
|
}
|
||||||
|
|
||||||
if (clientOnly) {
|
if (clientOnly) {
|
||||||
|
|
|
@ -3,6 +3,8 @@ import type { Store } from 'vuex'
|
||||||
import type { Router } from 'vue-router'
|
import type { Router } from 'vue-router'
|
||||||
import type { AxiosError } from 'axios'
|
import type { AxiosError } from 'axios'
|
||||||
import type { RootState } from '~/store'
|
import type { RootState } from '~/store'
|
||||||
|
|
||||||
|
// eslint-disable-next-line
|
||||||
import type { ComponentPublicInstance } from '@vue/runtime-core'
|
import type { ComponentPublicInstance } from '@vue/runtime-core'
|
||||||
|
|
||||||
export type FunctionRef = Element | ComponentPublicInstance | null
|
export type FunctionRef = Element | ComponentPublicInstance | null
|
||||||
|
@ -100,7 +102,6 @@ export interface Track {
|
||||||
is_local: boolean
|
is_local: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export interface Channel {
|
export interface Channel {
|
||||||
id: string
|
id: string
|
||||||
uuid: string
|
uuid: string
|
||||||
|
@ -195,6 +196,7 @@ export interface Listening {
|
||||||
}
|
}
|
||||||
|
|
||||||
// API stuff
|
// API stuff
|
||||||
|
// eslint-disable-next-line
|
||||||
export interface APIErrorResponse extends Record<string, APIErrorResponse | string[] | { code: string }[]> {}
|
export interface APIErrorResponse extends Record<string, APIErrorResponse | string[] | { code: string }[]> {}
|
||||||
|
|
||||||
export interface BackendError extends AxiosError {
|
export interface BackendError extends AxiosError {
|
||||||
|
@ -360,4 +362,4 @@ export interface Note {
|
||||||
author: Actor // TODO (wvffle): Check if is valid
|
author: Actor // TODO (wvffle): Check if is valid
|
||||||
summary: string
|
summary: string
|
||||||
creation_date: string
|
creation_date: string
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
import $ from 'jquery'
|
import $ from 'jquery'
|
||||||
import { tryOnMounted, useCurrentElement } from '@vueuse/core'
|
import { tryOnMounted, useCurrentElement } from '@vueuse/core'
|
||||||
|
|
||||||
|
|
||||||
export const getDropdown = (selector = '.ui.dropdown'): JQuery => {
|
export const getDropdown = (selector = '.ui.dropdown'): JQuery => {
|
||||||
const el = useCurrentElement()
|
const el = useCurrentElement()
|
||||||
return $(el.value).find(selector)
|
return $(el.value).find(selector)
|
||||||
|
@ -11,7 +10,7 @@ export const getDropdown = (selector = '.ui.dropdown'): JQuery => {
|
||||||
|
|
||||||
export const setupDropdown = (selector: string | HTMLElement = '.ui.dropdown') => tryOnMounted(() => {
|
export const setupDropdown = (selector: string | HTMLElement = '.ui.dropdown') => tryOnMounted(() => {
|
||||||
const el = useCurrentElement()
|
const el = useCurrentElement()
|
||||||
const $dropdown = typeof selector === 'string'
|
const $dropdown = typeof selector === 'string'
|
||||||
? $(el.value).find(selector)
|
? $(el.value).find(selector)
|
||||||
: $(selector)
|
: $(selector)
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,7 @@ export function parseAPIErrors (responseData: APIErrorResponse, parentField?: st
|
||||||
}))
|
}))
|
||||||
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle nested errors
|
// Handle nested errors
|
||||||
errors.push(...parseAPIErrors(value, fieldName))
|
errors.push(...parseAPIErrors(value, fieldName))
|
||||||
|
|
|
@ -286,7 +286,7 @@ export default {
|
||||||
},
|
},
|
||||||
fetch (params) {
|
fetch (params) {
|
||||||
this.isLoading = true
|
this.isLoading = true
|
||||||
axios.get('federation/inbox/', { params: params }).then(response => {
|
axios.get('federation/inbox/', { params }).then(response => {
|
||||||
this.isLoading = false
|
this.isLoading = false
|
||||||
this.notifications = response.data
|
this.notifications = response.data
|
||||||
})
|
})
|
||||||
|
|
|
@ -201,9 +201,9 @@
|
||||||
Description
|
Description
|
||||||
</translate>
|
</translate>
|
||||||
</td>
|
</td>
|
||||||
<sanitized-html
|
<sanitized-html
|
||||||
tag="td"
|
tag="td"
|
||||||
:html="object.artist.description.html"
|
:html="object.artist.description.html"
|
||||||
/>
|
/>
|
||||||
</tr>
|
</tr>
|
||||||
<tr v-if="object.actor.url">
|
<tr v-if="object.actor.url">
|
||||||
|
|
|
@ -74,7 +74,7 @@ const title = computed(() => labels.value[props.type])
|
||||||
:default-query="defaultQuery"
|
:default-query="defaultQuery"
|
||||||
:ordering-config-name="null"
|
:ordering-config-name="null"
|
||||||
/>
|
/>
|
||||||
<invitations-table
|
<invitations-table
|
||||||
v-else-if="type === 'invitations'"
|
v-else-if="type === 'invitations'"
|
||||||
:ordering-config-name="null"
|
:ordering-config-name="null"
|
||||||
/>
|
/>
|
||||||
|
@ -102,7 +102,7 @@ const title = computed(() => labels.value[props.type])
|
||||||
:default-query="defaultQuery"
|
:default-query="defaultQuery"
|
||||||
:ordering-config-name="null"
|
:ordering-config-name="null"
|
||||||
/>
|
/>
|
||||||
<users-table
|
<users-table
|
||||||
v-else-if="type === 'users'"
|
v-else-if="type === 'users'"
|
||||||
:ordering-config-name="null"
|
:ordering-config-name="null"
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -4,7 +4,6 @@ import type { SettingsGroup as SettingsGroupType } from '~/types'
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import $ from 'jquery'
|
import $ from 'jquery'
|
||||||
|
|
||||||
|
|
||||||
import SettingsGroup from '~/components/admin/SettingsGroup.vue'
|
import SettingsGroup from '~/components/admin/SettingsGroup.vue'
|
||||||
|
|
||||||
import { useCurrentElement } from '@vueuse/core'
|
import { useCurrentElement } from '@vueuse/core'
|
||||||
|
|
|
@ -212,9 +212,9 @@
|
||||||
Description
|
Description
|
||||||
</translate>
|
</translate>
|
||||||
</td>
|
</td>
|
||||||
<sanitized-html
|
<sanitized-html
|
||||||
tag="td"
|
tag="td"
|
||||||
:html="object.description.html"
|
:html="object.description.html"
|
||||||
/>
|
/>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|
|
@ -211,9 +211,9 @@
|
||||||
Description
|
Description
|
||||||
</translate>
|
</translate>
|
||||||
</td>
|
</td>
|
||||||
<sanitized-html
|
<sanitized-html
|
||||||
tag="td"
|
tag="td"
|
||||||
:html="object.description.html"
|
:html="object.description.html"
|
||||||
/>
|
/>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|
|
@ -348,9 +348,9 @@ const getQuery = (field: string, value: string) => `${field}:"${value}"`
|
||||||
Description
|
Description
|
||||||
</translate>
|
</translate>
|
||||||
</td>
|
</td>
|
||||||
<sanitized-html
|
<sanitized-html
|
||||||
tag="td"
|
tag="td"
|
||||||
:html="track.description.html"
|
:html="track.description.html"
|
||||||
/>
|
/>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|
|
@ -73,7 +73,6 @@ const fetchData = async () => {
|
||||||
} else {
|
} else {
|
||||||
await router.replace({ name: 'channels.detail', params: { id: actor.full_username } })
|
await router.replace({ name: 'channels.detail', params: { id: actor.full_username } })
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// TODO (wvffle): Handle error
|
// TODO (wvffle): Handle error
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { ImportStatus } from '~/types'
|
import type { ImportStatus } from '~/types'
|
||||||
import type { RouteWithPreferences } from '~/store/ui'
|
import type { RouteWithPreferences, OrderingField } from '~/store/ui'
|
||||||
import type { OrderingField } from '~/store/ui'
|
|
||||||
import type { OrderingProps } from '~/composables/useOrdering'
|
import type { OrderingProps } from '~/composables/useOrdering'
|
||||||
import type { SmartSearchProps } from '~/composables/useSmartSearch'
|
import type { SmartSearchProps } from '~/composables/useSmartSearch'
|
||||||
|
|
||||||
|
|
|
@ -34,13 +34,13 @@ const scanProgress = computed(() => Math.min(latestScan.value.processed_files *
|
||||||
const scanStatus = computed(() => latestScan.value?.status ?? 'unknown')
|
const scanStatus = computed(() => latestScan.value?.status ?? 'unknown')
|
||||||
const canLaunchScan = computed(() => scanStatus.value !== 'pending' && scanStatus.value !== 'scanning')
|
const canLaunchScan = computed(() => scanStatus.value !== 'pending' && scanStatus.value !== 'scanning')
|
||||||
const radioPlayable = computed(() => (
|
const radioPlayable = computed(() => (
|
||||||
(library.value.actor.is_local || scanStatus.value === 'finished')
|
(library.value.actor.is_local || scanStatus.value === 'finished') &&
|
||||||
&& (library.value.privacy_level === 'everyone' || library.value.follow?.approved)
|
(library.value.privacy_level === 'everyone' || library.value.follow?.approved)
|
||||||
))
|
))
|
||||||
|
|
||||||
const { $pgettext } = useGettext()
|
const { $pgettext } = useGettext()
|
||||||
const labels = computed(() => ({
|
const labels = computed(() => ({
|
||||||
tooltips: {
|
tooltips: {
|
||||||
me: $pgettext('Content/Library/Card.Help text', 'This library is private and your approval from its owner is needed to access its content'),
|
me: $pgettext('Content/Library/Card.Help text', 'This library is private and your approval from its owner is needed to access its content'),
|
||||||
everyone: $pgettext('Content/Library/Card.Help text', 'This library is public and you can access its content freely')
|
everyone: $pgettext('Content/Library/Card.Help text', 'This library is public and you can access its content freely')
|
||||||
}
|
}
|
||||||
|
@ -364,4 +364,4 @@ watch(showScan, (shouldShow) => {
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -25,10 +25,10 @@ const object = ref<Library | null>(null)
|
||||||
|
|
||||||
const isOwner = computed(() => store.state.auth.authenticated && object.value?.actor.full_username === store.state.auth.fullUsername)
|
const isOwner = computed(() => store.state.auth.authenticated && object.value?.actor.full_username === store.state.auth.fullUsername)
|
||||||
const isPlayable = computed(() => (object.value?.uploads_count ?? 0) > 0 && (
|
const isPlayable = computed(() => (object.value?.uploads_count ?? 0) > 0 && (
|
||||||
isOwner.value
|
isOwner.value ||
|
||||||
|| object.value?.privacy_level === 'everyone'
|
object.value?.privacy_level === 'everyone' ||
|
||||||
|| (object.value?.privacy_level === 'instance' && store.state.auth.authenticated && object.value.actor.domain === store.getters['instance/domain'])
|
(object.value?.privacy_level === 'instance' && store.state.auth.authenticated && object.value.actor.domain === store.getters['instance/domain']) ||
|
||||||
|| (store.getters['libraries/follow'](object.value?.uuid) || {}).approved === true
|
(store.getters['libraries/follow'](object.value?.uuid) || {}).approved === true
|
||||||
))
|
))
|
||||||
|
|
||||||
const { $pgettext } = useGettext()
|
const { $pgettext } = useGettext()
|
||||||
|
|
|
@ -59,7 +59,10 @@ const updateApproved = async (follow: LibraryFollow, approved: boolean) => {
|
||||||
Library contents
|
Library contents
|
||||||
</translate>
|
</translate>
|
||||||
</h2>
|
</h2>
|
||||||
<library-files-table :filters="{library: object.uuid}" :ordering-config-name="null" />
|
<library-files-table
|
||||||
|
:filters="{library: object.uuid}"
|
||||||
|
:ordering-config-name="null"
|
||||||
|
/>
|
||||||
|
|
||||||
<div class="ui hidden divider" />
|
<div class="ui hidden divider" />
|
||||||
<h2 class="ui header">
|
<h2 class="ui header">
|
||||||
|
|
|
@ -44,7 +44,7 @@ const fetchData = async () => {
|
||||||
try {
|
try {
|
||||||
const [playlistResponse, tracksResponse] = await Promise.all([
|
const [playlistResponse, tracksResponse] = await Promise.all([
|
||||||
axios.get(`playlists/${props.id}/`),
|
axios.get(`playlists/${props.id}/`),
|
||||||
axios.get(`playlists/${props.id}/tracks/`),
|
axios.get(`playlists/${props.id}/tracks/`)
|
||||||
])
|
])
|
||||||
|
|
||||||
playlist.value = playlistResponse.data
|
playlist.value = playlistResponse.data
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { Track, Radio } from "~/types"
|
import type { Track, Radio } from '~/types'
|
||||||
|
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import TrackTable from '~/components/audio/track/Table.vue'
|
import TrackTable from '~/components/audio/track/Table.vue'
|
||||||
|
@ -35,7 +35,7 @@ const fetchData = async () => {
|
||||||
const radioResponse = await axios.get(url)
|
const radioResponse = await axios.get(url)
|
||||||
radio.value = radioResponse.data
|
radio.value = radioResponse.data
|
||||||
|
|
||||||
const tracksResponse = await axios.get(url + 'tracks/', { params: { page: page.value }})
|
const tracksResponse = await axios.get(url + 'tracks/', { params: { page: page.value } })
|
||||||
totalTracks.value = tracksResponse.data.count
|
totalTracks.value = tracksResponse.data.count
|
||||||
tracks.value = tracksResponse.data.results
|
tracks.value = tracksResponse.data.results
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
|
@ -2616,6 +2616,13 @@ builtin-modules@^3.1.0:
|
||||||
resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.3.0.tgz#cae62812b89801e9656336e46223e030386be7b6"
|
resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.3.0.tgz#cae62812b89801e9656336e46223e030386be7b6"
|
||||||
integrity sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==
|
integrity sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==
|
||||||
|
|
||||||
|
builtins@^5.0.1:
|
||||||
|
version "5.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/builtins/-/builtins-5.0.1.tgz#87f6db9ab0458be728564fa81d876d8d74552fa9"
|
||||||
|
integrity sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==
|
||||||
|
dependencies:
|
||||||
|
semver "^7.0.0"
|
||||||
|
|
||||||
buntis@0.2.1:
|
buntis@0.2.1:
|
||||||
version "0.2.1"
|
version "0.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/buntis/-/buntis-0.2.1.tgz#a043aabc7d64f2243bfaa53e34e999c2dd790e82"
|
resolved "https://registry.yarnpkg.com/buntis/-/buntis-0.2.1.tgz#a043aabc7d64f2243bfaa53e34e999c2dd790e82"
|
||||||
|
@ -3448,6 +3455,14 @@ eslint-plugin-es@^3.0.0:
|
||||||
eslint-utils "^2.0.0"
|
eslint-utils "^2.0.0"
|
||||||
regexpp "^3.0.0"
|
regexpp "^3.0.0"
|
||||||
|
|
||||||
|
eslint-plugin-es@^4.1.0:
|
||||||
|
version "4.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/eslint-plugin-es/-/eslint-plugin-es-4.1.0.tgz#f0822f0c18a535a97c3e714e89f88586a7641ec9"
|
||||||
|
integrity sha512-GILhQTnjYE2WorX5Jyi5i4dz5ALWxBIdQECVQavL6s7cI76IZTDWleTHkxz/QT3kvcs2QlGHvKLYsSlPOlPXnQ==
|
||||||
|
dependencies:
|
||||||
|
eslint-utils "^2.0.0"
|
||||||
|
regexpp "^3.0.0"
|
||||||
|
|
||||||
eslint-plugin-html@6.2.0:
|
eslint-plugin-html@6.2.0:
|
||||||
version "6.2.0"
|
version "6.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/eslint-plugin-html/-/eslint-plugin-html-6.2.0.tgz#715bc00b50bbd0d996e28f953c289a5ebec69d43"
|
resolved "https://registry.yarnpkg.com/eslint-plugin-html/-/eslint-plugin-html-6.2.0.tgz#715bc00b50bbd0d996e28f953c289a5ebec69d43"
|
||||||
|
@ -3474,6 +3489,20 @@ eslint-plugin-import@2.26.0:
|
||||||
resolve "^1.22.0"
|
resolve "^1.22.0"
|
||||||
tsconfig-paths "^3.14.1"
|
tsconfig-paths "^3.14.1"
|
||||||
|
|
||||||
|
eslint-plugin-n@^15.2.4:
|
||||||
|
version "15.2.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/eslint-plugin-n/-/eslint-plugin-n-15.2.4.tgz#d62021a0821ae650701ed459756aaf478a9b6056"
|
||||||
|
integrity sha512-tjnVMv2fiXYMnuiIFI8QMtyUFI42SckEEWvi8h68SWGWshfqO6SSCASy24dGMGAiy7NUk6DZt90DM0iNUsmQ5w==
|
||||||
|
dependencies:
|
||||||
|
builtins "^5.0.1"
|
||||||
|
eslint-plugin-es "^4.1.0"
|
||||||
|
eslint-utils "^3.0.0"
|
||||||
|
ignore "^5.1.1"
|
||||||
|
is-core-module "^2.9.0"
|
||||||
|
minimatch "^3.1.2"
|
||||||
|
resolve "^1.10.1"
|
||||||
|
semver "^7.3.7"
|
||||||
|
|
||||||
eslint-plugin-node@11.1.0:
|
eslint-plugin-node@11.1.0:
|
||||||
version "11.1.0"
|
version "11.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz#c95544416ee4ada26740a30474eefc5402dc671d"
|
resolved "https://registry.yarnpkg.com/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz#c95544416ee4ada26740a30474eefc5402dc671d"
|
||||||
|
@ -5806,7 +5835,7 @@ semver@7.0.0:
|
||||||
resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e"
|
resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e"
|
||||||
integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==
|
integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==
|
||||||
|
|
||||||
semver@7.x, semver@^7.3.5, semver@^7.3.6, semver@^7.3.7:
|
semver@7.x, semver@^7.0.0, semver@^7.3.5, semver@^7.3.6, semver@^7.3.7:
|
||||||
version "7.3.7"
|
version "7.3.7"
|
||||||
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f"
|
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f"
|
||||||
integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==
|
integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==
|
||||||
|
|
Loading…
Reference in New Issue