zaphyra's git: domsonic

subsonic web-client

1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 
25 
26 
27 
28 
29 
30 
31 
32 
33 
34 
35 
36 
37 
38 
39 
40 
41 
42 
43 
44 
45 
46 
47 
48 
49 
50 
51 
52 
53 
54 
55 
56 
57 
58 
59 
60 
61 
62 
63 
64 
65 
66 
67 
68 
69 
70 
71 
72 
73 
74 
75 
76 
77 
78 
79 
80 
81 
82 
83 
84 
85 
86 
87 
88 
89 
90 
91 
92 
93 
94 
95 
96 
97 
98 
99 
100 
101 
import { createApp, markRaw, watch } from 'vue'

import { createPinia } from 'pinia'

import { setupRouter } from './router'
import { createSubsonicApi } from './subsonicApi'

import { useMainStore } from './store/main'
import { useFavouriteStore } from './store/favourite'
import { usePlaylistStore } from './store/playlist'
import { setupAudio, usePlayerStore } from './store/player'

import { components } from './components'
import { RootView } from './view/Root.vine'

import './style/main.scss'

const APP_BASE = import.meta.env.BASE_URL ?? '/'

const bootstrapApp = async () => {
  window.history.scrollRestoration = 'manual'

  // Initialize stores and app
  const
    subsonicApi = createSubsonicApi(),
    pinia = createPinia().use(({ store }) => { store.subsonicApi = markRaw(subsonicApi) }),
    mainStore = useMainStore(pinia),
    app = createApp(RootView)

  // Register plugins
  app.use(pinia)
  app.use(subsonicApi)
  app.use(setupRouter(APP_BASE))

  // Register global properties
  app.config.globalProperties.appName = import.meta.env.APP_NAME ?? 'Domsonic'
  app.config.globalProperties.appBase = APP_BASE

  // Register components
  components.forEach(
    (component: any) => app.component(component.name, component)
  )

  // set theme color
  if (mainStore.themeColor !== null)
    mainStore.applyThemeColor()

  const
    serverUrl = mainStore.serverUrl,
    serverCredentials = mainStore.serverCredentials

  if (serverUrl && serverCredentials) {
    subsonicApi.setServerUrl(serverUrl)
    subsonicApi.setAuth(serverCredentials)
    subsonicApi.setStreamFormat(mainStore.streamFormat, mainStore.streamBitrate)
    subsonicApi.initialize()
  }

  // Watch logged-in state
  watch(
    mainStore.isAuthenticated,
    async () => {
      try {
        if (!subsonicApi.isInitialized())
          return

        const playerStore = usePlayerStore(pinia)

        // setup player once authenticated
        void setupAudio(playerStore, mainStore)
        await Promise.all([
          useFavouriteStore(pinia).load(),
          usePlaylistStore(pinia).load(),
          playerStore.loadQueue(),
        ])
      } catch (err) {
        console.error('Error loading user data', err)
      }
    },
    { immediate: true }
  )

  try {
    app.mount('#app')
  } catch (err) {
    console.error('App mount failed', err)
  }

  // Service Worker
  if ('serviceWorker' in navigator) {
    void navigator.serviceWorker.register(`${APP_BASE}service-worker.js`, { scope: APP_BASE })

    navigator.serviceWorker.addEventListener('message', (event) => {
      if (event.data?.type === 'UPDATE_READY')
        console.log('New version !')
    })
  }
}

// Run the bootstrap
void bootstrapApp()