feat: remove alert from services and stores

This commit is contained in:
Phan An 2022-04-24 20:58:12 +03:00
parent 063bbbaad4
commit 58e830984d
No known key found for this signature in database
GPG key ID: A81E4477F0BB6FDC
15 changed files with 70 additions and 88 deletions

View file

@ -15,6 +15,7 @@
<script lang="ts" setup>
import { reactive, ref, toRefs } from 'vue'
import { playlistStore } from '@/stores'
import { alerts } from '@/utils'
const props = defineProps<{ playlist: Playlist }>()
const { playlist } = toRefs(props)
@ -46,6 +47,7 @@ const update = async () => {
updating.value = true
await playlistStore.update(mutatedPlaylist)
alerts.success(`Updated playlist "${mutatedPlaylist.name}."`)
emit('updated', mutatedPlaylist)
}

View file

@ -28,7 +28,7 @@
<script lang="ts" setup>
import { computed, defineAsyncComponent, nextTick, ref, toRefs } from 'vue'
import { eventBus } from '@/utils'
import { alerts, eventBus, pluralize } from '@/utils'
import router from '@/router'
import { favoriteStore, playlistStore, songStore } from '@/stores'
@ -103,6 +103,7 @@ const handleDrop = (event: DragEvent) => {
favoriteStore.like(songs)
} else if (type.value === 'playlist') {
playlistStore.addSongs(playlist.value, songs)
alerts.success(`Added ${pluralize(songs.length, 'song')} into "${playlist.value.name}."`)
}
return false

View file

@ -24,7 +24,7 @@
</form>
<ul>
<PlaylistItem type="favorites" :playlist="{ name: 'Favorites', songs: favoriteState.songs }"/>
<PlaylistItem type="favorites" :playlist="{ name: 'Favorites', songs: favorites }"/>
<PlaylistItem type="recently-played" :playlist="{ name: 'Recently Played', songs: [] }"/>
<PlaylistItem
:playlist="playlist"
@ -39,9 +39,10 @@
</template>
<script lang="ts" setup>
import { defineAsyncComponent, nextTick, reactive, ref, toRef } from 'vue'
import { defineAsyncComponent, nextTick, ref, toRef } from 'vue'
import { favoriteStore, playlistStore } from '@/stores'
import router from '@/router'
import { alerts } from '@/utils'
const PlaylistItem = defineAsyncComponent(() => import('@/components/playlist/PlaylistSidebarItem.vue'))
const ContextMenu = defineAsyncComponent(() => import('@/components/playlist/CreateNewPlaylistContextMenu.vue'))
@ -49,7 +50,7 @@ const ContextMenu = defineAsyncComponent(() => import('@/components/playlist/Cre
const contextMenu = ref<InstanceType<typeof ContextMenu>>()
const playlists = toRef(playlistStore.state, 'playlists')
const favoriteState = reactive(favoriteStore.state)
const favorites = toRef(favoriteStore.state, 'songs')
const creating = ref(false)
const newName = ref('')
@ -58,6 +59,9 @@ const createPlaylist = async () => {
const playlist = await playlistStore.store(newName.value)
newName.value = ''
alerts.success(`Playlist "${playlist.name}" created.`)
// Activate the new playlist right away
await nextTick()
router.go(`playlist/${playlist.id}`)

View file

@ -73,6 +73,9 @@ const submit = async () => {
const playlist = await playlistStore.store(name.value, [], collectedRuleGroups.value)
loading.value = false
close()
alerts.success(`Playlist "${playlist.name}" created.`)
await nextTick()
router.go(`playlist/${playlist.id}`)
}

View file

@ -77,6 +77,7 @@ const submit = async () => {
await playlistStore.update(mutatedPlaylist)
Object.assign(playlist.value, mutatedPlaylist)
loading.value = false
alerts.success(`Updated playlist "${playlist.value.name}."`)
eventBus.emit('SMART_PLAYLIST_UPDATED', playlist.value)
close()
}

View file

@ -62,7 +62,7 @@
<script lang="ts" setup>
import { defineAsyncComponent, nextTick, ref, toRef } from 'vue'
import { eventBus, pluralize } from '@/utils'
import { alerts, eventBus, pluralize } from '@/utils'
import { playlistStore, commonStore } from '@/stores'
import { downloadService } from '@/services'
import { useSongList } from '@/composables'
@ -101,6 +101,7 @@ const removeSelected = () => {
playlistStore.removeSongs(playlist.value!, selectedSongs.value)
songs.value = difference(songs.value, selectedSongs.value)
alerts.success(`Removed ${pluralize(selectedSongs.value.length, 'song')} from "${playlist.value!.name}."`)
}
/**

View file

@ -61,7 +61,7 @@
<script lang="ts" setup>
import { computed, defineAsyncComponent, nextTick, reactive, ref, toRefs, watch } from 'vue'
import { pluralize } from '@/utils'
import { alerts, pluralize } from '@/utils'
import { playlistStore } from '@/stores'
import router from '@/router'
import { useSongMenuMethods } from '@/composables'
@ -102,6 +102,9 @@ const createNewPlaylistFromSongs = async () => {
const playlist = await playlistStore.store(newPlaylistName.value, songs.value)
newPlaylistName.value = ''
alerts.success(`Playlist "${playlist.name}" created.`)
// Activate the new playlist right away
await nextTick()
router.go(`playlist/${playlist.id}`)

View file

@ -109,7 +109,7 @@
import { computed, defineAsyncComponent, nextTick, reactive, ref, toRef, toRefs } from 'vue'
import { isEqual, union } from 'lodash'
import { alerts, arrayify, br2nl, getDefaultCover } from '@/utils'
import { alerts, arrayify, br2nl, getDefaultCover, pluralize } from '@/utils'
import { songInfo } from '@/services/info'
import { albumStore, artistStore, songStore } from '@/stores'
@ -276,6 +276,7 @@ const submit = async () => {
try {
await songStore.update(mutatedSongs.value, formData)
alerts.success(`Updated ${pluralize(mutatedSongs.value.length, 'song')}.`)
close()
} finally {
loading.value = false

View file

@ -1,6 +1,6 @@
import { favoriteStore, playlistStore } from '@/stores'
import { authService } from '.'
import { alerts, arrayify } from '@/utils'
import { arrayify } from '@/utils'
export const downloadService = {
fromSongs (songs: Song | Song[]): void {
@ -38,14 +38,9 @@ export const downloadService = {
const sep = uri.includes('?') ? '&' : '?'
const url = `${window.BASE_URL}download/${uri}${sep}api_token=${authService.getToken()}`
if (KOEL_ENV === 'app') {
require('electron').ipcRenderer.send('DOWNLOAD', url)
alerts.success('Download started!')
} else {
const iframe = document.createElement('iframe')
iframe.style.display = 'none'
iframe.setAttribute('src', url)
document.body.appendChild(iframe)
}
const iframe = document.createElement('iframe')
iframe.style.display = 'none'
iframe.setAttribute('src', url)
document.body.appendChild(iframe)
}
}

View file

@ -37,7 +37,7 @@ export const httpService = {
init () {
this.client = Axios.create({
baseURL: KOEL_ENV === 'app' ? `${localStorageService.get('koelHost')}api` : `${window.BASE_URL}api`
baseURL: `${window.BASE_URL}api`
})
// Intercept the request to make sure the token is injected into the header.

View file

@ -4,6 +4,7 @@ import { nextTick } from 'vue'
import isMobile from 'ismobilejs'
import { eventBus, isAudioContextSupported, isMediaSessionSupported } from '@/utils'
import {
commonStore,
preferenceStore as preferences,
@ -12,6 +13,7 @@ import {
songStore,
userStore
} from '@/stores'
import { audioService, socketService } from '@/services'
import { app } from '@/config'
import router from '@/router'
@ -58,15 +60,11 @@ export const playbackService = {
this.setMediaSessionActionHandlers()
}
// As of current, only the web-based version of Koel supports the remote controller
if (KOEL_ENV !== 'app') {
this.listenToSocketEvents()
}
this.listenToSocketEvents()
this.initialized = true
},
listenToSocketEvents (): void {
listenToSocketEvents () {
socketService.listen('SOCKET_TOGGLE_PLAYBACK', () => this.toggle())
.listen('SOCKET_PLAY_NEXT', () => this.playNext())
.listen('SOCKET_PLAY_PREV', () => this.playPrev())
@ -87,7 +85,7 @@ export const playbackService = {
.listen('SOCKET_SET_VOLUME', ({ volume }: { volume: number }) => this.setVolume(volume))
},
setMediaSessionActionHandlers (): void {
setMediaSessionActionHandlers () {
if (!isMediaSessionSupported) {
return
}
@ -98,7 +96,7 @@ export const playbackService = {
navigator.mediaSession!.setActionHandler('nexttrack', () => this.playNext())
},
listenToMediaEvents (mediaElement: HTMLMediaElement): void {
listenToMediaEvents (mediaElement: HTMLMediaElement) {
mediaElement.addEventListener('error', () => this.playNext(), true)
mediaElement.addEventListener('ended', () => {
@ -109,7 +107,7 @@ export const playbackService = {
preferences.repeatMode === 'REPEAT_ONE' ? this.restart() : this.playNext()
})
mediaElement.addEventListener('timeupdate', throttle((): void => {
mediaElement.addEventListener('timeupdate', throttle(() => {
const currentSong = queueStore.current!
if (!currentSong.playCountRegistered && !this.isTranscoding) {
@ -132,18 +130,18 @@ export const playbackService = {
}, 3000))
},
get isTranscoding (): boolean {
get isTranscoding () {
return isMobile.any && preferences.transcodeOnMobile
},
registerPlay (song: Song): void {
registerPlay (song: Song) {
recentlyPlayedStore.add(song)
songStore.registerPlay(song)
recentlyPlayedStore.fetchAll()
song.playCountRegistered = true
},
preload (song: Song): void {
preload (song: Song) {
const audioElement = document.createElement('audio')
audioElement.setAttribute('src', songStore.getSourceUrl(song))
audioElement.setAttribute('preload', 'auto')
@ -187,7 +185,7 @@ export const playbackService = {
await this.restart()
},
showNotification (song: Song): void {
showNotification (song: Song) {
if (!window.Notification || !preferences.notify) {
return
}
@ -198,7 +196,7 @@ export const playbackService = {
body: `${song.album.name} ${song.artist.name}`
})
notif.onclick = () => KOEL_ENV === 'app' ? this.mainWin.focus() : window.focus()
notif.onclick = () => window.focus()
window.setTimeout(() => notif.close(), 5000)
} catch (e) {
@ -247,7 +245,7 @@ export const playbackService = {
* The next song in the queue.
* If we're in REPEAT_ALL mode and there's no next song, just get the first song.
*/
get next (): Song | undefined {
get next () {
if (queueStore.next) {
return queueStore.next
}
@ -275,7 +273,7 @@ export const playbackService = {
* Circle through the repeat mode.
* The selected mode will be stored into local storage as well.
*/
changeRepeatMode (): void {
changeRepeatMode () {
let index = this.repeatModes.indexOf(preferences.repeatMode) + 1
if (index >= this.repeatModes.length) {
@ -321,7 +319,7 @@ export const playbackService = {
* @param {Number} volume 0-10
* @param {Boolean=true} persist Whether the volume should be saved into local storage
*/
setVolume (volume: number, persist = true): void {
setVolume (volume: number, persist = true) {
this.getPlayer().setVolume(volume)
if (persist) {
@ -331,11 +329,11 @@ export const playbackService = {
this.volumeInput.value = String(volume)
},
mute (): void {
mute () {
this.setVolume(0, false)
},
unmute (): void {
unmute () {
// If the saved volume is 0, we unmute to the default level (7).
if (preferences.volume === 0) {
preferences.volume = DEFAULT_VOLUME_VALUE
@ -394,7 +392,7 @@ export const playbackService = {
* @param {?Song[]} songs An array of song objects. Defaults to all songs if null.
* @param {Boolean=false} shuffled Whether to shuffle the songs before playing.
*/
async queueAndPlay (songs?: Song[], shuffled: boolean = false) {
async queueAndPlay (songs?: Song[], shuffled = false) {
if (!songs) {
songs = shuffle(songStore.all)
}
@ -415,7 +413,7 @@ export const playbackService = {
await this.play(queueStore.first)
},
getPlayer (): Plyr {
getPlayer () {
return this.player!
},

View file

@ -1,16 +1,13 @@
import { difference, union, orderBy } from 'lodash'
import { difference, orderBy, union } from 'lodash'
import stub from '@/stubs/playlist'
import { httpService } from '@/services'
import { alerts, pluralize, arrayify } from '@/utils'
import { arrayify } from '@/utils'
import { songStore } from '.'
import models from '@/config/smart-playlist/models'
import operators from '@/config/smart-playlist/operators'
import { reactive } from 'vue'
export const playlistStore = {
stub,
state: reactive({
playlists: [] as Playlist[]
}),
@ -100,7 +97,6 @@ export const playlistStore = {
playlist.songs = songs
this.populateContent(playlist)
this.add(playlist)
alerts.success(`Created playlist "${playlist.name}."`)
return playlist
},
@ -127,7 +123,6 @@ export const playlistStore = {
}
await httpService.put(`playlist/${playlist.id}/sync`, { songs: playlist.songs.map(song => song.id) })
alerts.success(`Added ${pluralize(songs.length, 'song')} into "${playlist.name}."`)
return playlist
},
@ -139,16 +134,13 @@ export const playlistStore = {
playlist.songs = difference(playlist.songs, songs)
await httpService.put(`playlist/${playlist.id}/sync`, { songs: playlist.songs.map(song => song.id) })
alerts.success(`Removed ${pluralize(songs.length, 'song')} from "${playlist.name}."`)
return playlist
},
async update (playlist: Playlist) {
const serializedRules = this.serializeSmartPlaylistRulesForStorage(playlist.rules)
await httpService.put(`playlist/${playlist.id}`, { name: playlist.name, rules: serializedRules })
alerts.success(`Updated playlist "${playlist.name}."`)
return playlist
},

View file

@ -3,9 +3,9 @@ import slugify from 'slugify'
import { orderBy, remove, take, unionBy, without } from 'lodash'
import isMobile from 'ismobilejs'
import { alerts, arrayify, pluralize, secondsToHis, use } from '@/utils'
import { authService, httpService, localStorageService } from '@/services'
import { albumStore, artistStore, favoriteStore, preferenceStore, commonStore } from '.'
import { arrayify, secondsToHis, use } from '@/utils'
import { authService, httpService } from '@/services'
import { albumStore, artistStore, commonStore, favoriteStore, preferenceStore } from '.'
import stub from '@/stubs/song'
interface BroadcastSongData {
@ -39,12 +39,12 @@ export const songStore = {
recentlyPlayed: [] as Song[]
}),
init (songs: Song[]): void {
init (songs: Song[]) {
this.all = songs
this.all.forEach(song => this.setupSong(song))
},
setupSong (song: Song): void {
setupSong (song: Song) {
song.fmtLength = secondsToHis(song.length)
const album = albumStore.byId(song.album_id)!
@ -75,7 +75,7 @@ export const songStore = {
*
* @param {Interaction[]} interactions The array of interactions of the current user
*/
initInteractions (interactions: Interaction[]): void {
initInteractions (interactions: Interaction[]) {
favoriteStore.clear()
interactions.forEach(interaction => {
@ -100,17 +100,17 @@ export const songStore = {
* @param songs
* @param {Boolean} formatted Whether to convert the duration into H:i:s format
*/
getLength: (songs: Song[], formatted: boolean = false): number | string => {
getLength: (songs: Song[], formatted: boolean = false) => {
const duration = songs.reduce((length, song) => length + song.length, 0)
return formatted ? secondsToHis(duration) : duration
},
getFormattedLength (songs: Song[]): string {
getFormattedLength (songs: Song[]) {
return String(this.getLength(songs, true))
},
get all (): Song[] {
get all () {
return this.state.songs
},
@ -118,11 +118,11 @@ export const songStore = {
this.state.songs = value
},
byId (id: string): Song | undefined {
byId (id: string) {
return this.cache[id]
},
byIds (ids: string[]): Song[] {
byIds (ids: string[]) {
const songs = [] as Song[]
arrayify(ids).forEach(id => use(this.byId(id), song => songs.push(song!)))
return songs
@ -132,7 +132,7 @@ export const songStore = {
* Guess a song by its title and album.
* Forget about Levenshtein distance, this implementation is good enough.
*/
guess: (title: string, album: Album): Song | null => {
guess: (title: string, album: Album) => {
title = slugify(title.toLowerCase())
for (const song of album.songs) {
@ -147,7 +147,7 @@ export const songStore = {
/**
* Increase a play count for a song.
*/
registerPlay: async (song: Song): Promise<void> => {
registerPlay: async (song: Song) => {
const oldCount = song.playCount
const interaction = await httpService.post<Interaction>('interaction/play', { song: song.id })
@ -158,11 +158,9 @@ export const songStore = {
song.artist.playCount += song.playCount - oldCount
},
scrobble: async (song: Song): Promise<void> => {
await httpService.post(`${song.id}/scrobble`, { timestamp: song.playStartTime })
},
scrobble: async (song: Song) => await httpService.post(`${song.id}/scrobble`, { timestamp: song.playStartTime }),
async update (songsToUpdate: Song[], data: any): Promise<Song[]> {
async update (songsToUpdate: Song[], data: any) {
const { songs, artists, albums } = await httpService.put<SongUpdateResult>('songs', {
data,
songs: songsToUpdate.map(song => song.id)
@ -193,27 +191,22 @@ export const songStore = {
artistStore.compact()
albumStore.compact()
alerts.success(`Updated ${pluralize(songs.length, 'song')}.`)
return songs
},
getSourceUrl: (song: Song): string => {
getSourceUrl: (song: Song) => {
return isMobile.any && preferenceStore.transcodeOnMobile
? `${commonStore.state.cdnUrl}play/${song.id}/1/128?api_token=${authService.getToken()}`
: `${commonStore.state.cdnUrl}play/${song.id}?api_token=${authService.getToken()}`
},
getShareableUrl: (song: Song): string => {
const baseUrl = KOEL_ENV === 'app' ? localStorageService.get<string>('koelHost') : window.BASE_URL
return `${baseUrl}#!/song/${song.id}`
},
getShareableUrl: (song: Song) => `${window.BASE_URL}#!/song/${song.id}`,
get recentlyPlayed (): Song[] {
get recentlyPlayed () {
return this.state.recentlyPlayed
},
getMostPlayed (n = 10): Song[] {
getMostPlayed (n = 10) {
const songs = take(orderBy(this.all, 'playCount', 'desc'), n)
// Remove those with playCount=0
@ -222,7 +215,7 @@ export const songStore = {
return songs
},
getRecentlyAdded (n = 10): Song[] {
getRecentlyAdded (n = 10) {
return take(orderBy(this.all, 'created_at', 'desc'), n)
},

View file

@ -1,11 +0,0 @@
// App (electron)-only methods
let mainWindow: any
if (KOEL_ENV === 'app') {
mainWindow = require('electron').remote.getCurrentWindow()
}
export const app = {
triggerMaximize: (): void =>
mainWindow && (mainWindow.isMaximized() ? mainWindow.unmaximize() : mainWindow.maximize())
}

View file

@ -5,7 +5,6 @@ export * from './formatters'
export * from './supports'
export * from './common'
export * from './$'
export * from './app'
export * from './helpers'
export * from './file-reader'
export * from './directory-reader'