more good stuff

This commit is contained in:
Phan An 2022-04-20 11:37:22 +02:00
parent 014e109b3a
commit ac83736192
No known key found for this signature in database
GPG key ID: A81E4477F0BB6FDC
19 changed files with 74 additions and 102 deletions

View file

@ -38,6 +38,7 @@
"@typescript-eslint/no-explicit-any": 0,
"@typescript-eslint/no-non-null-assertion": 0,
"@typescript-eslint/ban-ts-comment": 0,
"@typescript-eslint/no-empty-function": 0,
"vue/no-side-effects-in-computed-properties": 0,
"@typescript-eslint/explicit-module-boundary-types": 0,
"standard/no-callback-literal": 0,

View file

@ -31,7 +31,7 @@ import LoginForm from '@/components/auth/login-form.vue'
import MainWrapper from '@/components/layout/main-wrapper/index.vue'
import Overlay from '@/components/ui/overlay.vue'
import { $, eventBus, hideOverlay, showOverlay } from '@/utils'
import { $, eventBus, hideOverlay, showOverlay, arrayify } from '@/utils'
import { favoriteStore, preferenceStore as preferences, queueStore, sharedStore } from '@/stores'
import { auth, playback, socket } from '@/services'
@ -84,8 +84,8 @@ onMounted(async () => {
$.addClass(document.documentElement, navigator.userAgent.includes('Mac') ? 'mac' : 'non-mac')
})
eventBus.on('SONG_CONTEXT_MENU_REQUESTED', async (e: MouseEvent, songs: Song[]) => {
contextMenuSongs.value = ([] as Song[]).concat(songs)
eventBus.on('SONG_CONTEXT_MENU_REQUESTED', async (e: MouseEvent, songs: Song | Song[]) => {
contextMenuSongs.value = arrayify(songs)
await nextTick()
songContextMenu.value?.open(e.pageY, e.pageX)
})

View file

@ -1,8 +1,8 @@
<template>
<section id="queueWrapper">
<screen-header>
<ScreenHeader>
Current Queue
<controls-toggler :showing-controls="showingControls" @toggleControls="toggleControls"/>
<ControlsToggler :showing-controls="showingControls" @toggleControls="toggleControls"/>
<template v-slot:meta>
<span v-if="meta.songCount" data-test="list-meta">
@ -11,27 +11,27 @@
</template>
<template v-slot:controls>
<song-list-controls
v-if="state.songs.length && (!isPhone || showingControls)"
<SongListControls
v-if="songs.length && (!isPhone || showingControls)"
@playAll="playAll"
@playSelected="playSelected"
@clearQueue="clearQueue"
:songs="state.songs"
:songs="songs"
:config="songListControlConfig"
:selectedSongs="selectedSongs"
/>
</template>
</screen-header>
</ScreenHeader>
<song-list
v-if="state.songs.length"
:items="state.songs"
<SongList
v-if="songs.length"
:items="songs"
:config="{ sortable: false }"
type="queue"
ref="songList"
/>
<screen-placeholder v-else>
<ScreenPlaceholder v-else>
<template v-slot:icon>
<i class="fa fa-coffee"></i>
</template>
@ -41,7 +41,7 @@
How about
<a class="start" @click.prevent="shuffleAll">shuffling all songs</a>?
</span>
</screen-placeholder>
</ScreenPlaceholder>
</section>
</template>
@ -50,7 +50,7 @@ import { pluralize } from '@/utils'
import { queueStore, songStore } from '@/stores'
import { playback } from '@/services'
import { useSongList } from '@/composables'
import { computed, defineAsyncComponent, reactive } from 'vue'
import { computed, defineAsyncComponent, reactive, toRef } from 'vue'
const ScreenHeader = defineAsyncComponent(() => import('@/components/ui/screen-header.vue'))
const ScreenPlaceholder = defineAsyncComponent(() => import('@/components/ui/screen-placeholder.vue'))
@ -71,14 +71,13 @@ const {
clearQueue: true
})
const state = reactive(queueStore.state)
const songs = toRef(queueStore.state, 'songs')
const songState = reactive(songStore.state)
const shouldShowShufflingAllLink = computed(() => songState.songs.length > 0)
const playAll = () => {
// @ts-ignore
playback.queueAndPlay(state.songs.length ? songList.value?.getAllSongsWithSort() : songStore.all)
playback.queueAndPlay(songs.value.length ? songList.value.getAllSongsWithSort() : songStore.all)
}
const shuffleAll = async () => await playback.queueAndPlay(songStore.all, true)

View file

@ -31,23 +31,14 @@
</template>
<script lang="ts" setup>
import { computed, defineAsyncComponent, PropType, toRefs } from 'vue'
import { computed, defineAsyncComponent, toRefs } from 'vue'
import { eventBus, pluralize, startDragging } from '@/utils'
import { queueStore } from '@/stores'
import { playback } from '@/services'
const LikeButton = defineAsyncComponent(() => import('@/components/song/like-button.vue'))
const props = defineProps({
song: {
type: Object as PropType<Song>,
required: true
},
topPlayCount: {
type: Number,
default: 0
}
})
const props = withDefaults(defineProps<{ song: Song, topPlayCount?: number }>(), { topPlayCount: 0 })
const { song, topPlayCount } = toRefs(props)

View file

@ -112,7 +112,7 @@
import { computed, defineAsyncComponent, nextTick, reactive, ref, toRefs } from 'vue'
import { isEqual, union } from 'lodash'
import { alerts, br2nl, getDefaultCover } from '@/utils'
import { alerts, br2nl, getDefaultCover, arrayify } from '@/utils'
import { songInfo } from '@/services/info'
import { albumStore, artistStore, songStore } from '@/stores'
@ -234,7 +234,7 @@ const initCompilationStateCheckbox = async () => {
}
const open = async () => {
mutatedSongs.value = ([] as Song[]).concat(songs.value)
mutatedSongs.value = arrayify(songs.value)
currentView.value = initialTab!.value
const firstSong = mutatedSongs.value[0]

View file

@ -79,7 +79,7 @@ import {
} from 'vue'
import { RecycleScroller } from 'vue-virtual-scroller'
import 'vue-virtual-scroller/dist/vue-virtual-scroller.css'
import { $, eventBus, orderBy, startDragging } from '@/utils'
import { $, eventBus, orderBy, startDragging, arrayify } from '@/utils'
import { favoriteStore, playlistStore, queueStore } from '@/stores'
import { playback } from '@/services'
import router from '@/router'
@ -101,26 +101,10 @@ interface SongRow {
const SongItem = defineAsyncComponent(() => import('@/components/song/item.vue'))
// @ts-ignore
getCurrentInstance()!.__IS_SONG_LIST__ = true
const props = defineProps({
items: {
type: Array as PropType<Song[]>,
required: true
},
playlist: {
type: Object as PropType<Playlist>
},
type: {
type: String as PropType<SongListType>,
default: 'all-songs'
},
config: {
type: Object as PropType<Partial<SongListConfig>>,
default: () => ({})
}
})
const props = withDefaults(
defineProps<{ items: Song[], playlist?: Playlist, type?: SongListType, config?: Partial<SongListConfig> }>(),
{ type: 'all-songs', config: () => ({}) }
)
const { items, playlist, type, config } = toRefs(props)
@ -170,7 +154,7 @@ const sort = (field: SortField | SortField[] = [], order: SortOrder | null = nul
return
}
sortFields.value = ([] as SortField[]).concat(field)
sortFields.value = arrayify(field)
if (!sortFields.value.length && ['album', 'artist'].includes(type.value)) {
// by default, sort Album/Artist by track numbers for a more friendly UX

View file

@ -25,15 +25,9 @@
</template>
<script lang="ts" setup>
import { PropType, ref, toRefs, watchEffect } from 'vue'
const props = defineProps({
value: {
type: String as PropType<ArtistAlbumViewMode>,
default: 'thumbnails'
}
})
import { ref, toRefs, watchEffect } from 'vue'
const props = withDefaults(defineProps<{ value?: ArtistAlbumViewMode }>(), { value: 'thumbnails' })
const { value } = toRefs(props)
let modelValue = ref<ArtistAlbumViewMode>()

View file

@ -13,7 +13,7 @@ import SongListControls from '@/components/song/list-controls.vue'
import { songStore } from '@/stores'
export const useSongList = (controlsConfig: Partial<SongListControlsConfig> = {}) => {
const songList = ref(null)
const songList = ref<InstanceType<typeof SongList>>()
const state = reactive<SongListState>({ songs: [] })
const meta = reactive<SongListMeta>({
@ -35,7 +35,7 @@ export const useSongList = (controlsConfig: Partial<SongListControlsConfig> = {}
meta.totalLength = songStore.getFormattedLength(state.songs)
})
const getSongsToPlay = (): Song[] => (songList.value as any).getAllSongsWithSort()
const getSongsToPlay = (): Song[] => songList.value.getAllSongsWithSort()
const playAll = (shuffled: boolean) => playback.queueAndPlay(getSongsToPlay(), shuffled)
const playSelected = (shuffled: boolean) => playback.queueAndPlay(selectedSongs.value, shuffled)
const toggleControls = () => (showingControls.value = !showingControls.value)

View file

@ -5,6 +5,8 @@ import { favoriteStore, playlistStore, queueStore } from '@/stores'
* Each component including this mixin must have a `songs` array as either data, prop, or computed.
*/
export const useSongMenuMethods = (songs: Song[], close: TAnyFunction) => {
console.log(songs)
const queueSongsAfterCurrent = () => {
queueStore.queueAfterCurrent(songs)
close()

View file

@ -1,16 +1,10 @@
import { playlistStore, favoriteStore } from '@/stores'
import { favoriteStore, playlistStore } from '@/stores'
import { auth } from '.'
import { alerts } from '@/utils'
let events: any
if (KOEL_ENV === 'app') {
events = require('&/events').default
}
import { alerts, arrayify } from '@/utils'
export const download = {
fromSongs (songs: Song | Song[]): void {
const query = (<Song[]>[]).concat(songs).reduce((q, song) => `songs[]=${song.id}&${q}`, '')
const query = arrayify(songs).reduce((q, song) => `songs[]=${song.id}&${q}`, '')
this.trigger(`songs?${query}`)
},

View file

@ -4,7 +4,7 @@ import { union, difference, take, orderBy } from 'lodash'
import stub from '@/stubs/album'
import { artistStore } from '.'
import { http } from '@/services'
import { use } from '@/utils'
import { arrayify, use } from '@/utils'
const UNKNOWN_ALBUM_ID = 1
@ -53,7 +53,7 @@ export const albumStore = {
},
add (albums: Album | Album[]): void {
(<Album[]>[]).concat(albums).forEach(album => {
arrayify(albums).forEach(album => {
this.setupAlbum(album)
album.playCount = album.songs.reduce((count, song) => count + song.playCount, 0)
this.all.push(album)

View file

@ -2,7 +2,7 @@ import { difference, take, orderBy } from 'lodash'
import { http } from '@/services'
import stub from '@/stubs/artist'
import { use } from '@/utils'
import { arrayify, use } from '@/utils'
const UNKNOWN_ARTIST_ID = 1
const VARIOUS_ARTISTS_ID = 2
@ -50,7 +50,7 @@ export const artistStore = {
},
add (artists: Artist | Artist[]) {
(<Artist[]>[]).concat(artists).forEach(artist => {
arrayify(artists).forEach(artist => {
this.setupArtist(artist)
artist.playCount = artist.songs.reduce((count, song) => count + song.playCount, 0)
this.all.push(artist)

View file

@ -1,5 +1,6 @@
import { difference, union } from 'lodash'
import { http } from '@/services'
import { arrayify } from '@/utils'
export const favoriteStore = {
state: {
@ -29,14 +30,14 @@ export const favoriteStore = {
* Add a song/songs into the store.
*/
add (songs: Song | Song[]): void {
this.all = union(this.all, (<Song[]>[]).concat(songs))
this.all = union(this.all, arrayify(songs))
},
/**
* Remove a song/songs from the store.
*/
remove (songs: Song | Song[]): void {
this.all = difference(this.all, (<Song[]>[]).concat(songs))
this.all = difference(this.all, arrayify(songs))
},
clear (): void {

View file

@ -2,7 +2,7 @@ import { difference, union, orderBy } from 'lodash'
import stub from '@/stubs/playlist'
import { http } from '@/services'
import { alerts, pluralize } from '@/utils'
import { alerts, pluralize, arrayify } from '@/utils'
import { songStore } from '.'
import models from '@/config/smart-playlist/models'
import operators from '@/config/smart-playlist/operators'
@ -79,7 +79,7 @@ export const playlistStore = {
* Add a playlist/playlists into the store.
*/
add (playlists: Playlist | Playlist[]) {
const playlistsToAdd = (<Playlist[]>[]).concat(playlists)
const playlistsToAdd = arrayify(playlists)
playlistsToAdd.forEach(playlist => this.setupPlaylist(playlist))
this.all = this.sort(union(this.all, playlistsToAdd))
},
@ -88,7 +88,7 @@ export const playlistStore = {
* Remove a playlist/playlists from the store.
*/
remove (playlists: Playlist | Playlist[]) {
this.all = difference(this.all, (<Playlist[]>[]).concat(playlists))
this.all = difference(this.all, arrayify(playlists))
},
async store (name: string, songs: Song[] = [], rules: SmartPlaylistRuleGroup[] = []): Promise<Playlist> {
@ -169,7 +169,7 @@ export const playlistStore = {
/**
* Serialize the rule (groups) to be ready for database.
*/
serializeSmartPlaylistRulesForStorage: (ruleGroups: SmartPlaylistRuleGroup[]): object[] | null => {
serializeSmartPlaylistRulesForStorage: (ruleGroups: SmartPlaylistRuleGroup[]): any[] | null => {
if (!ruleGroups || !ruleGroups.length) {
return null
}

View file

@ -1,10 +1,12 @@
import { union, difference, shuffle } from 'lodash'
import { reactive } from 'vue'
import { arrayify } from '@/utils'
export const queueStore = {
state: {
state: reactive({
songs: [] as Song[],
current: undefined as Song | undefined
},
}),
init () {
// We don't have anything to do here yet.
@ -57,7 +59,7 @@ export const queueStore = {
*/
queue (songs: Song | Song[]): void {
this.unqueue(songs)
this.all = union(this.all, (<Song[]>[]).concat(songs))
this.all = union(this.all, arrayify(songs))
},
/**
@ -65,7 +67,7 @@ export const queueStore = {
* @param {Song|Song[]} songs The song, or an array of songs
*/
queueToTop (songs: Song | Song[]): void {
this.all = union((<Song[]>[]).concat(songs), this.all)
this.all = union(arrayify(songs), this.all)
},
/**
@ -73,7 +75,7 @@ export const queueStore = {
* @param {Song|Song[]} songs The song, or an array of songs
*/
replaceQueueWith (songs: Song | Song[]): void {
this.all = (<Song[]>[]).concat(songs)
this.all = arrayify(songs)
},
/**
@ -81,7 +83,7 @@ export const queueStore = {
* @param {Song|Song[]} songs The song, or an array of songs
*/
queueAfterCurrent (songs: Song | Song[]): void {
songs = (<Song[]>[]).concat(songs)
songs = arrayify(songs)
if (!this.current || !this.all.length) {
return this.queue(songs)
@ -95,7 +97,7 @@ export const queueStore = {
},
unqueue (songs: Song | Song[]): void {
this.all = difference(this.all, (<Song[]>[]).concat(songs))
this.all = difference(this.all, arrayify(songs))
},
/**
@ -106,7 +108,7 @@ export const queueStore = {
*/
move (songs: Song | Song[], target: Song): void {
const targetIndex = this.indexOf(target)
const movedSongs = (<Song[]>[]).concat(songs)
const movedSongs = arrayify(songs)
movedSongs.forEach(song => {
this.all.splice(this.indexOf(song), 1)

View file

@ -1,11 +1,11 @@
import Vue from 'vue'
import { reactive } from 'vue'
import slugify from 'slugify'
import { without, take, remove, orderBy, unionBy } from 'lodash'
import { orderBy, remove, take, unionBy, without } from 'lodash'
import isMobile from 'ismobilejs'
import { secondsToHis, alerts, pluralize, use } from '@/utils'
import { http, auth, ls } from '@/services'
import { sharedStore, favoriteStore, albumStore, artistStore, preferenceStore } from '.'
import { alerts, arrayify, pluralize, secondsToHis, use } from '@/utils'
import { auth, http, ls } from '@/services'
import { albumStore, artistStore, favoriteStore, preferenceStore, sharedStore } from '.'
import stub from '@/stubs/song'
interface BroadcastSongData {
@ -34,10 +34,10 @@ export const songStore = {
stub,
cache: {} as { [key: string]: Song },
state: {
state: reactive({
songs: [] as Song[],
recentlyPlayed: [] as Song[]
},
}),
init (songs: Song[]): void {
this.all = songs
@ -107,7 +107,7 @@ export const songStore = {
},
getFormattedLength (songs: Song[]): string {
return <string>this.getLength(songs, true)
return String(this.getLength(songs, true))
},
get all (): Song[] {
@ -124,7 +124,7 @@ export const songStore = {
byIds (ids: string[]): Song[] {
const songs = [] as Song[]
([] as string[]).concat(ids).forEach(id => use(this.byId(id), song => songs.push(song!)))
arrayify(ids).forEach(id => use(this.byId(id), song => songs.push(song!)))
return songs
},

View file

@ -1,5 +1,6 @@
declare module '*.jpg'
declare module '*.png'
declare module '*.svg'
declare type TAnyFunction = (...args: Array<unknown|any>) => unknown|any

View file

@ -1,5 +1,5 @@
import select from 'select'
import { eventBus, noop, pluralize } from '@/utils'
import { eventBus, noop, pluralize, arrayify } from '@/utils'
import defaultCover from '@/../img/covers/unknown-album.png'
/**
@ -81,7 +81,7 @@ export const startDragging = (event: DragEvent, dragged: Song | Song[] | Album |
switch (type) {
case 'Song':
dragged = (<Song[]>[]).concat(<Song>dragged)
dragged = arrayify(<Song>dragged)
text = dragged.length === 1
? `${dragged[0].title} by ${dragged[0].artist.name}`
: pluralize(dragged.length, 'song')

View file

@ -1,4 +1,4 @@
export const use = <T>(value: T, cb: (arg: T) => void): void => {
export const use = <T> (value: T, cb: (arg: T) => void) => {
if (typeof value === 'undefined' || value === null) {
return
}
@ -6,4 +6,7 @@ export const use = <T>(value: T, cb: (arg: T) => void): void => {
cb(value)
}
export const arrayify = <T> (maybeArray: T | Array<T>) => ([] as Array<T>).concat(maybeArray)
// @ts-ignore
export const noop = () => {}