{"version":3,"file":"SongStore-CCZHThnx.js","sources":["../../Vue/src/models/DataType.ts","../../Vue/src/functions/WindowHandler.ts","../../Vue/node_modules/pkce-challenge/dist/index.browser.js","../../Vue/src/functions/full-song-tokens.ts","../../Vue/src/stores/SpotifyStore.ts","../../Vue/src/stores/AppleMusicStore.ts","../../Vue/src/models/frontend-only/MediaPlayerRepeatMode.ts","../../Vue/src/stores/MediaPlayerStore.ts","../../Vue/src/stores/FullSongPlaybackStore.ts","../../Vue/src/stores/SongStore.ts"],"sourcesContent":["\r\n// DO NOT DIRECTLY MODIFY THIS FILE\r\n// It was generated automatically, from the C# file: DataType.cs\r\n// Any changes made directly here would be lost next time the C# class was changed\r\n\r\n// It was created using Visual Studio extension 'TypeWriter', using the template in VueModels.tst\r\n// More info: http://frhagn.github.io/Typewriter/\r\n\r\n\r\n\r\n\r\n\r\n\r\nexport enum DataType { \r\n    Song = 1,\r\n    Arrangement = 2,\r\n}","export function openWindow(url: string, queryParams: any, useSameWindow = false) {\r\n\r\n  const query = new URLSearchParams(queryParams);\r\n  const queryString = query.toString();\r\n  const fullUrl = url + (queryString ? '?' + queryString : '');\r\n\r\n  if (useSameWindow) {\r\n    document.location.href = fullUrl;\r\n    return null;\r\n  }\r\n\r\n  const w = 770, h = 675;\r\n  const wLeft = window.screenLeft ? window.screenLeft : window.screenX;\r\n  const wTop = window.screenTop ? window.screenTop : window.screenY;\r\n  const left = wLeft + (window.innerWidth / 2) - (w / 2);\r\n  const top = wTop + (window.innerHeight / 2) - (h / 2);\r\n\r\n  return window.open(fullUrl, 'songselect-popup', 'resizable,height=' + h + ',width=' + w + ',top=' + top + ',left=' + left);\r\n}","let crypto;\ncrypto = globalThis.crypto; // web browsers\n/**\n * Creates an array of length `size` of random bytes\n * @param size\n * @returns Array of random ints (0 to 255)\n */\nfunction getRandomValues(size) {\n    return crypto.getRandomValues(new Uint8Array(size));\n}\n/** Generate cryptographically strong random string\n * @param size The desired length of the string\n * @returns The random string\n */\nfunction random(size) {\n    const mask = \"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._~\";\n    let result = \"\";\n    const randomUints = getRandomValues(size);\n    for (let i = 0; i < size; i++) {\n        // cap the value of the randomIndex to mask.length - 1\n        const randomIndex = randomUints[i] % mask.length;\n        result += mask[randomIndex];\n    }\n    return result;\n}\n/** Generate a PKCE challenge verifier\n * @param length Length of the verifier\n * @returns A random verifier `length` characters long\n */\nfunction generateVerifier(length) {\n    return random(length);\n}\n/** Generate a PKCE code challenge from a code verifier\n * @param code_verifier\n * @returns The base64 url encoded code challenge\n */\nexport async function generateChallenge(code_verifier) {\n    const buffer = await crypto.subtle.digest(\"SHA-256\", new TextEncoder().encode(code_verifier));\n    // Generate base64url string\n    // btoa is deprecated in Node.js but is used here for web browser compatibility\n    // (which has no good replacement yet, see also https://github.com/whatwg/html/issues/6811)\n    return btoa(String.fromCharCode(...new Uint8Array(buffer)))\n        .replace(/\\//g, '_')\n        .replace(/\\+/g, '-')\n        .replace(/=/g, '');\n}\n/** Generate a PKCE challenge pair\n * @param length Length of the verifer (between 43-128). Defaults to 43.\n * @returns PKCE challenge pair\n */\nexport default async function pkceChallenge(length) {\n    if (!length)\n        length = 43;\n    if (length < 43 || length > 128) {\n        throw `Expected a length between 43 and 128. Received ${length}.`;\n    }\n    const verifier = generateVerifier(length);\n    const challenge = await generateChallenge(verifier);\n    return {\n        code_verifier: verifier,\n        code_challenge: challenge,\n    };\n}\n/** Verify that a code_verifier produces the expected code challenge\n * @param code_verifier\n * @param expectedChallenge The code challenge to verify\n * @returns True if challenges are equal. False otherwise.\n */\nexport async function verifyChallenge(code_verifier, expectedChallenge) {\n    const actualChallenge = await generateChallenge(code_verifier);\n    return actualChallenge === expectedChallenge;\n}\n","export async function getFullSongIntegrationTokens() {\r\n  const debug = useDebug();\r\n  const profile = useProfileStore();\r\n  debug.log(\"getting full song playback settings\");\r\n  await profile.profilePromise;\r\n\r\n  let authInfo: any = null;\r\n  let service: \"apple\" | \"spotify\" | null = null;\r\n  if (\r\n    profile.profile?.signedIn &&\r\n    profile.profile?.musicPlayerPreferences.authInfo\r\n  ) {\r\n    authInfo = JSON.parse(profile.profile.musicPlayerPreferences.authInfo);\r\n  }\r\n\r\n  if (profile.profile?.musicPlayerPreferences.service) {\r\n    service = profile.profile?.musicPlayerPreferences.service?.toLowerCase() as\r\n      | \"apple\"\r\n      | \"spotify\"\r\n      | null;\r\n  }\r\n\r\n  return {\r\n    authInfo,\r\n    service,\r\n  };\r\n}\r\n","import { AppConstants } from \"@/config/AppConstants\";\r\nimport { openWindow } from \"@/functions/WindowHandler\";\r\nimport { FEMediaUrl } from \"@/models/frontend-only/FEMediaItem\";\r\nimport { MediaPlayerStatus } from \"@/models/frontend-only/MediaPlayerStatus\";\r\nimport { BroadcastChannel } from \"broadcast-channel\";\r\nimport { defineStore } from \"pinia\";\r\nimport { RaygunFunctions } from \"@/config/RayGun\";\r\nimport pkceChallenge from \"pkce-challenge\";\r\n\r\ndeclare let window: {\r\n  onSpotifyWebPlaybackSDKReady: () => void;\r\n  player: () => void;\r\n} & Window;\r\ndeclare let Spotify: any;\r\n\r\nconst clientId = AppConstants.SPOTIFY.CLIENT_ID;\r\nconst callbackUrl = window.location.origin + \"/callback/spotify\";\r\nconst scopes = \"streaming user-read-private user-read-email\";\r\n\r\nexport const useSpotifyStore = defineStore(\"spotify\", () => {\r\n  const toastStore = useToastStore();\r\n  const { t } = useI18n();\r\n  const fullPlaybackStore = useFullSongPlaybackStore();\r\n  const debug = useDebug();\r\n\r\n  const authorized = ref(false);\r\n  let playState = false;\r\n  const status = ref<MediaPlayerStatus>(MediaPlayerStatus.Unloaded);\r\n  let error = \"\";\r\n  let player: any = null;\r\n  let playerState: any;\r\n  let playerId = \"\";\r\n  const playerReady = ref(false);\r\n  let pollIntervalRef: number | null = null;\r\n  const currentTime = ref(0);\r\n  const duration = ref(0);\r\n  let songId = \"\";\r\n\r\n  const SpotifySettings = {\r\n    expires: 0,\r\n    refreshToken: \"\",\r\n    accessToken: \"\",\r\n  };\r\n\r\n  async function getSettings() {\r\n    debug.log(\"loading tokens from user meta - spotify\");\r\n    const settings = await getFullSongIntegrationTokens();\r\n    if (\r\n      settings.service === \"spotify\" &&\r\n      settings.authInfo &&\r\n      settings.authInfo.refreshToken &&\r\n      settings.authInfo.expires\r\n    ) {\r\n      SpotifySettings.expires = settings.authInfo.expires;\r\n      SpotifySettings.refreshToken = settings.authInfo.refreshToken;\r\n      SpotifySettings.accessToken = settings.authInfo.accessToken || \"\";\r\n    } else {\r\n      clearTokensFromUserMeta(true);\r\n    }\r\n  }\r\n\r\n  function saveSettings() {\r\n    const service = SpotifySettings.accessToken ? \"spotify\" : null;\r\n    fullPlaybackStore.saveSettings(\r\n      {\r\n        accessToken: SpotifySettings.accessToken,\r\n        refreshToken: SpotifySettings.refreshToken,\r\n        expires: SpotifySettings.expires,\r\n      },\r\n      service,\r\n    );\r\n  }\r\n\r\n  let authState = \"\";\r\n  let pkcePair: {\r\n    code_verifier: string;\r\n    code_challenge: string;\r\n  } | null = null;\r\n\r\n  let seekOnPlay: {\r\n    time: number;\r\n    songId: string;\r\n  } | null = null;\r\n\r\n  function accessTokenExpired() {\r\n    const now = new Date().getTime();\r\n    const expires = SpotifySettings.expires;\r\n    return now > expires;\r\n  }\r\n\r\n  async function refreshAccessToken() {\r\n    if (!SpotifySettings.expires || !SpotifySettings.refreshToken) {\r\n      return;\r\n    }\r\n\r\n    if (!accessTokenExpired()) {\r\n      return;\r\n    }\r\n\r\n    debug.log(\"refreshing spotify token\");\r\n    const params = {\r\n      grant_type: \"refresh_token\",\r\n      refresh_token: SpotifySettings.refreshToken,\r\n      client_id: AppConstants.SPOTIFY.CLIENT_ID,\r\n    };\r\n    try {\r\n      const response = await fetch(\"https://accounts.spotify.com/api/token\", {\r\n        method: \"POST\",\r\n        headers: {\r\n          \"Content-Type\": \"application/x-www-form-urlencoded\",\r\n        },\r\n        body: new URLSearchParams(params),\r\n      });\r\n      if (!response.ok) {\r\n        throw new Error(\"Failed to refresh token\");\r\n      }\r\n      const data = await response.json();\r\n      SpotifySettings.accessToken = data.access_token;\r\n      SpotifySettings.refreshToken = data.refresh_token;\r\n      setExpires(data.expires_in);\r\n      saveSettings();\r\n    } catch (err) {\r\n      toastStore.errorToast(t(\"SV.MES_SpotifyConnectionError\"));\r\n      await unauthorize(false);\r\n    }\r\n  }\r\n\r\n  async function init() {\r\n    if (import.meta.env.VITE_ENABLE_SPOTIFY !== \"1\") {\r\n      return;\r\n    }\r\n    debug.log(\"spotify init\");\r\n    status.value = MediaPlayerStatus.Loading;\r\n    await getSettings();\r\n    await refreshAccessToken();\r\n    authorized.value = !!SpotifySettings.accessToken;\r\n    if (authorized.value) {\r\n      await connectToSpotify();\r\n    }\r\n    debug.log(\"spotify init complete\");\r\n  }\r\n\r\n  async function authorize(isMobile = false) {\r\n    authState = Math.random().toString(36).substring(7);\r\n    pkcePair = await pkceChallenge(128);\r\n\r\n    const params = {\r\n      client_id: clientId,\r\n      response_type: \"code\",\r\n      redirect_uri: callbackUrl,\r\n      code_challenge_method: \"S256\",\r\n      code_challenge: pkcePair.code_challenge,\r\n      scope: scopes,\r\n      state: authState,\r\n    };\r\n    const url = \"https://accounts.spotify.com/authorize\";\r\n\r\n    openedWindow.value = openWindow(url, params, isMobile);\r\n\r\n    if (!openedWindow.value) {\r\n      toastStore.errorToast(t(\"SV.MES_ErrorOpeningNewWindow\"));\r\n      throw new Error(\"Error creating window\");\r\n    }\r\n\r\n    broadcastChannel.addEventListener(\"message\", authorizeCallback);\r\n\r\n    const timerRef = setInterval(() => {\r\n      if (openedWindow.value && openedWindow.value.closed) {\r\n        clearInterval(timerRef);\r\n        openedWindow.value = null;\r\n        broadcastChannel.removeEventListener(\"message\", authorizeCallback);\r\n      }\r\n    }, 100);\r\n  }\r\n\r\n  const openedWindow = ref<Window | null>(null);\r\n\r\n  const connecting = computed(() => !!openedWindow.value);\r\n  const broadcastChannel = new BroadcastChannel(\"spotify-auth-callback\");\r\n\r\n  function onError(msg: string) {\r\n    error = msg;\r\n    status.value = MediaPlayerStatus.Error;\r\n    debug.log(msg);\r\n  }\r\n\r\n  function toastErrorAuth() {\r\n    toastStore.errorToast(t(\"SV.MES_SpotifyConnectionError\"));\r\n  }\r\n\r\n  function setExpires(expiresIn: number) {\r\n    // typically 3600 seconds or 1 hr\r\n    const now = new Date();\r\n    SpotifySettings.expires = now.getTime() + expiresIn * 1000;\r\n  }\r\n\r\n  async function authorizeCallback(event: {\r\n    state: string;\r\n    error: string;\r\n    code: string;\r\n  }) {\r\n    broadcastChannel.removeEventListener(\"message\", authorizeCallback);\r\n\r\n    if (openedWindow.value) {\r\n      debug.log(\"attempting to close window\");\r\n      openedWindow.value.close();\r\n      openedWindow.value = null;\r\n    }\r\n\r\n    if (event.state !== authState) {\r\n      toastErrorAuth();\r\n      throw new Error(\"Spotify Auth State values do not match\");\r\n    }\r\n\r\n    if (event.error) {\r\n      toastErrorAuth();\r\n      throw event.error;\r\n    }\r\n\r\n    if (!event.code) {\r\n      toastErrorAuth();\r\n      throw new Error(\"Missing spotify Auth Code\");\r\n    }\r\n\r\n    if (!pkcePair) {\r\n      toastErrorAuth();\r\n      throw new Error(\"PKCEPair value missing\");\r\n    }\r\n\r\n    const params = {\r\n      client_id: AppConstants.SPOTIFY.CLIENT_ID,\r\n      grant_type: \"authorization_code\",\r\n      code: event.code,\r\n      redirect_uri: callbackUrl,\r\n      code_verifier: pkcePair.code_verifier,\r\n    };\r\n\r\n    let data: any;\r\n    try {\r\n      const response = await fetch(\"https://accounts.spotify.com/api/token\", {\r\n        method: \"POST\",\r\n        headers: {\r\n          \"Content-Type\": \"application/x-www-form-urlencoded\",\r\n        },\r\n        body: new URLSearchParams(params),\r\n      });\r\n      data = await response.json();\r\n    } catch (err) {\r\n      toastStore.errorToast(t(\"SV.MES_SpotifyConnectionError\"));\r\n      throw err;\r\n    }\r\n\r\n    SpotifySettings.accessToken = data.access_token;\r\n    SpotifySettings.refreshToken = data.refresh_token;\r\n\r\n    setExpires(data.expires_in);\r\n\r\n    authorized.value = true;\r\n    await nextTick();\r\n    saveSettings();\r\n    debug.log(\"spotify auth access granted\");\r\n\r\n    if (!(await verifyUserHasPremium())) {\r\n      return;\r\n    }\r\n\r\n    toastStore.successToast(t(\"SV.LIT_ConnectedToSpotify\"));\r\n    connectToSpotify();\r\n  }\r\n\r\n  function pollForStatus() {\r\n    if (!pollIntervalRef) {\r\n      debug.log(\"poll for status\");\r\n      pollIntervalRef = window.setInterval(checkStatus, 200);\r\n    }\r\n  }\r\n\r\n  function unpollForStatus() {\r\n    if (pollIntervalRef) {\r\n      debug.log(\"unpoll for status\");\r\n      clearInterval(pollIntervalRef);\r\n      pollIntervalRef = null;\r\n    }\r\n  }\r\n\r\n  async function checkStatus() {\r\n    if (!player || !playerReady.value) {\r\n      status.value = MediaPlayerStatus.Loading;\r\n      return;\r\n    }\r\n\r\n    playerState = await player.getCurrentState();\r\n\r\n    if (!playerState || playerState.loading) {\r\n      status.value = MediaPlayerStatus.Loading;\r\n      return;\r\n    }\r\n\r\n    if (\r\n      status.value === MediaPlayerStatus.Playing &&\r\n      currentTime.value !== 0 &&\r\n      playerState.paused &&\r\n      playerState.position === 0\r\n    ) {\r\n      //$emit('ended');\r\n    }\r\n\r\n    if (!playerState.paused) {\r\n      status.value = MediaPlayerStatus.Playing;\r\n      if (!seekOnPlay) {\r\n        // debug.log(\"currentTime: checkStatus \", playerState.position / 1000);\r\n        currentTime.value = playerState.position / 1000;\r\n      }\r\n    } else {\r\n      status.value = MediaPlayerStatus.Paused;\r\n    }\r\n\r\n    duration.value = playerState.duration / 1000;\r\n\r\n    checkSeekTime();\r\n  }\r\n\r\n  async function checkSeekTime() {\r\n    if (!seekOnPlay) {\r\n      return;\r\n    }\r\n\r\n    if (seekOnPlay.songId !== songId || error || seekOnPlay.time === 0) {\r\n      seekOnPlay = null;\r\n      return;\r\n    }\r\n\r\n    if (\r\n      !playState ||\r\n      status.value !== MediaPlayerStatus.Playing ||\r\n      playerState.disallows.seeking\r\n    ) {\r\n      return;\r\n    }\r\n\r\n    playerState = await player.getCurrentState();\r\n    await player.setVolume(1);\r\n    await seek(seekOnPlay.time);\r\n    seekOnPlay = null;\r\n    player.resume();\r\n  }\r\n\r\n  function seek(time: number) {\r\n    debug.log(\"currentTime: seek \", time);\r\n    currentTime.value = time;\r\n    const minTime = Math.max(time * 1000, 1);\r\n    // set to min of 1 to avoid error in seeking 0.\r\n    return player.seek(minTime);\r\n  }\r\n\r\n  async function getSongFromISRC(isrc: string) {\r\n    const profile = useProfileStore();\r\n    const api = useApiStore();\r\n\r\n    await waitUntilTrue(() => profile.profile);\r\n\r\n    if (!profile.profile) {\r\n      throw new Error(\"Profile not found\");\r\n    }\r\n\r\n    const cacheKey = `spotify-search:${isrc}`;\r\n    const countryCode = profile.profile.countryCode;\r\n    //check to see if this isrc exists on songselect first\r\n    const cachedItem = await api\r\n      .post(\r\n        `/GetTerritoryCachedItem?key=${cacheKey}&countryCode=${countryCode}`,\r\n      )\r\n      .catch((err) => {\r\n        RaygunFunctions.sendSilentError(\"Failed to get cache item\", {\r\n          key: cacheKey,\r\n          countryCode: countryCode,\r\n          err,\r\n        });\r\n      });\r\n\r\n    const debug = useDebug();\r\n    debug.log(\"getting cached item\", cacheKey, countryCode, cachedItem);\r\n\r\n    if (cachedItem) {\r\n      const jsonParsed = JSON.parse(cachedItem);\r\n      return jsonParsed as {\r\n        id: string;\r\n        url: string;\r\n        source: string;\r\n        artwork: string;\r\n        title: string;\r\n        subtitle: string;\r\n      };\r\n    }\r\n\r\n    let items: SpotifyTrack[] = [];\r\n    try {\r\n      items =\r\n        (\r\n          (await request({\r\n            method: \"GET\",\r\n            path: `/search`,\r\n            query: {\r\n              q: `isrc:${isrc}`,\r\n              type: \"track\",\r\n              market: profile.profile?.countryCode || \"US\",\r\n              limit: \"1\",\r\n              include_external: \"audio\",\r\n            },\r\n          })) as SpotifySearchResults\r\n        )?.tracks.items || [];\r\n    } catch (err) {\r\n      debug.log(\"error getting song from isrc\", err);\r\n    }\r\n    const track = items[0];\r\n    if (!track) {\r\n      return null;\r\n    }\r\n\r\n    const data = {\r\n      id: track.id,\r\n      url: track.album.external_urls.spotify,\r\n      source: \"Spotify\",\r\n      artwork: track.album.images[0]?.url || \"\",\r\n      title: track.album.name,\r\n      subtitle: track.artists.map((a) => a.name).join(\", \"),\r\n    } as FEMediaUrl;\r\n\r\n    api\r\n      .post(\r\n        `/SetTerritoryCachedItem?key=${cacheKey}&countryCode=${countryCode}`,\r\n        JSON.stringify(data),\r\n      )\r\n      .catch((err) =>\r\n        RaygunFunctions.sendSilentError(\"Failed to set cache item\", {\r\n          key: cacheKey,\r\n          countryCode: countryCode,\r\n          data,\r\n          err,\r\n        }),\r\n      );\r\n    return data;\r\n  }\r\n\r\n  async function connectToSpotify() {\r\n    if (!(await verifyUserHasPremium())) {\r\n      return;\r\n    }\r\n\r\n    const el = document.querySelector(\"#spotify-musicsdk-script\");\r\n    if (!el) {\r\n      await new Promise<void>((resolve) => {\r\n        window.onSpotifyWebPlaybackSDKReady = () => {\r\n          resolve();\r\n        };\r\n        const script = document.createElement(\"script\");\r\n        script.id = \"spotify-musicsdk-script\";\r\n        script.setAttribute(\"src\", \"https://sdk.scdn.co/spotify-player.js\");\r\n        document.body.appendChild(script);\r\n        debug.log(\"appended script to body\");\r\n      });\r\n      debug.log(\"loaded spotify to body\");\r\n    }\r\n\r\n    player = new Spotify.Player({\r\n      name: \"SongSelect Spotify Player\",\r\n      getOAuthToken: (cb: (token: string) => void) => {\r\n        cb(SpotifySettings.accessToken);\r\n      },\r\n    });\r\n\r\n    // Error handling\r\n    player.addListener(\"initialization_error\", (data: { message: string }) => {\r\n      onError(data.message);\r\n      status.value === MediaPlayerStatus.Paused;\r\n      playState = false;\r\n    });\r\n\r\n    player.addListener(\"authentication_error\", (data: { message: string }) => {\r\n      onError(data.message);\r\n      status.value === MediaPlayerStatus.Paused;\r\n      playState = false;\r\n    });\r\n\r\n    player.addListener(\"account_error\", (data: { message: string }) => {\r\n      onError(data.message);\r\n      status.value === MediaPlayerStatus.Paused;\r\n      playState = false;\r\n    });\r\n\r\n    player.addListener(\"playback_error\", (data: { message: string }) => {\r\n      onError(data.message);\r\n      status.value === MediaPlayerStatus.Paused;\r\n      playState = false;\r\n    });\r\n\r\n    player.addListener(\"player_state_changed\", async () => {\r\n      const state = await player.getCurrentState();\r\n      if (!state.paused) {\r\n        pollForStatus();\r\n      } else {\r\n        unpollForStatus();\r\n      }\r\n    });\r\n\r\n    // Ready\r\n    player.addListener(\"ready\", async (data: { device_id: string }) => {\r\n      playerReady.value = true;\r\n      playerId = data.device_id;\r\n      window.player = player;\r\n      //bus.$emit('spotifyReady');\r\n      debug.log(\"SPOTIFY Ready with Device ID\", data.device_id);\r\n    });\r\n\r\n    // Not Ready\r\n    player.addListener(\"not_ready\", (data: { device_id: string }) => {\r\n      unpollForStatus();\r\n      playerReady.value = false;\r\n      playerId = data.device_id;\r\n      debug.log(\"SPOTIFY Device ID has gone offline\", data.device_id);\r\n    });\r\n\r\n    // Connect to the player!\r\n    player.connect();\r\n  }\r\n\r\n  async function request(data: {\r\n    path: string;\r\n    method: \"GET\" | \"POST\" | \"PUT\" | \"DELETE\";\r\n    data?: any;\r\n    params?: any;\r\n    query?: any;\r\n    headers?: any;\r\n  }) {\r\n    await refreshAccessToken();\r\n\r\n    if (!SpotifySettings.accessToken) {\r\n      return Promise.reject({ status: 401 });\r\n    }\r\n\r\n    // set up search query\r\n    let url = \"https://api.spotify.com/v1\" + data.path;\r\n    if (data.query) {\r\n      const searchQuery = new URLSearchParams(data.query || {}).toString();\r\n      url += \"?\" + searchQuery;\r\n    }\r\n\r\n    // set up headers\r\n    const requestHeaders: any = {};\r\n\r\n    if (data.headers) {\r\n      Object.assign(requestHeaders, data.headers);\r\n    }\r\n\r\n    requestHeaders[\"Authorization\"] = `Bearer ${SpotifySettings.accessToken}`;\r\n\r\n    // setup body\r\n    let body = \"{}\";\r\n    if (data.method !== \"GET\" && data.data) {\r\n      body = JSON.stringify(data.data);\r\n    }\r\n\r\n    const response = await fetch(url, {\r\n      method: data.method,\r\n      headers: {\r\n        ...requestHeaders,\r\n        \"Content-Type\": \"application/json\",\r\n      },\r\n      ...((data.method !== \"GET\" && {\r\n        body: body,\r\n      }) ||\r\n        {}),\r\n    });\r\n\r\n    if (!response.ok && response.status === 401) {\r\n      toastStore.errorToast(t(\"SV.MES_SpotifyConnectionError\"));\r\n      await unauthorize(false);\r\n      return null;\r\n    }\r\n\r\n    try {\r\n      const responseData = await response.json();\r\n      debug.log(\"Spotify Response\", responseData);\r\n      return responseData;\r\n    } catch (err) {\r\n      console.warn(\"spotify json response failed\", response);\r\n    }\r\n  }\r\n\r\n  async function clearTokensFromUserMeta(skipSaving = false) {\r\n    SpotifySettings.expires = 0;\r\n    SpotifySettings.refreshToken = \"\";\r\n    SpotifySettings.accessToken = \"\";\r\n    if (!skipSaving) {\r\n      saveSettings();\r\n    }\r\n  }\r\n\r\n  function playSong(id: string, atTime?: number | null) {\r\n    debug.log(\"playSong\", id);\r\n    status.value === MediaPlayerStatus.Loading;\r\n    if (atTime) {\r\n      seekOnPlay = {\r\n        time: atTime,\r\n        songId: id,\r\n      };\r\n    }\r\n\r\n    songId = id;\r\n    playState = true;\r\n    debug.log(\"currentTime: play song \", atTime);\r\n    currentTime.value = atTime || 0;\r\n\r\n    debug.log(\"PLAY SPOTIFY\");\r\n    if (atTime) {\r\n      player.setVolume(0);\r\n    }\r\n\r\n    debug.log(\"play Song\", id, playerId);\r\n    return request({\r\n      method: \"PUT\",\r\n      path: `/me/player/play?device_id=${playerId}`,\r\n      data: { uris: [`spotify:track:${id}`] },\r\n    }).catch(() => {});\r\n  }\r\n\r\n  async function play() {\r\n    debug.log(\"spotify play\");\r\n    if (!player || !playerReady.value || !authorized.value) {\r\n      playState = false;\r\n      status.value === MediaPlayerStatus.Loading;\r\n      return;\r\n    }\r\n\r\n    if (!playState) {\r\n      if (!playerState?.track_window?.current_track?.id) {\r\n        await playSong(songId);\r\n      } else {\r\n        playState = true;\r\n        player.resume();\r\n        status.value === MediaPlayerStatus.Loading;\r\n      }\r\n    }\r\n  }\r\n\r\n  function pause() {\r\n    playState = false;\r\n    status.value = MediaPlayerStatus.Paused;\r\n    if (\r\n      !player ||\r\n      !playerReady.value ||\r\n      !authorized.value ||\r\n      !playerState?.track_window?.current_track?.id\r\n    ) {\r\n      return;\r\n    }\r\n    player.pause();\r\n  }\r\n\r\n  function unauthorize(showMsg = true) {\r\n    authState = \"\";\r\n    pkcePair = null;\r\n    pause();\r\n    authorized.value = false;\r\n\r\n    player = null;\r\n    playerReady.value = false;\r\n    duration.value = 0;\r\n    clearTokensFromUserMeta();\r\n    if (showMsg) {\r\n      toastStore.successToast(t(\"SV.LIT_SpotifyDisconnected\"));\r\n    }\r\n  }\r\n\r\n  async function verifyUserHasPremium() {\r\n    const spotifyUserData = await request({\r\n      method: \"GET\",\r\n      path: \"/me\",\r\n    });\r\n    if (!spotifyUserData || !spotifyUserData.product) {\r\n      return false;\r\n    }\r\n\r\n    if (spotifyUserData.product !== \"premium\") {\r\n      unauthorize(false);\r\n      toastStore.errorToast(t(\"SV.MES_SpotifyPremiumError\"));\r\n      return false;\r\n    }\r\n    return true;\r\n  }\r\n\r\n  function seekTo(time: number) {\r\n    player.seek(time * 1000);\r\n  }\r\n  init();\r\n\r\n  return {\r\n    authorize,\r\n    authorizeCallback,\r\n    unauthorize,\r\n    play,\r\n    pause,\r\n    seekTo,\r\n    playSong,\r\n    connecting,\r\n    openedWindow,\r\n    authorized,\r\n    currentTime,\r\n    duration,\r\n    status,\r\n    getSongFromISRC,\r\n    playerReady,\r\n  };\r\n});\r\n","import { loadScript } from \"@/functions/misc\";\r\nimport { MediaPlayerStatus } from \"@/models/frontend-only/MediaPlayerStatus\";\r\nimport { defineStore } from \"pinia\";\r\n\r\ndeclare interface MusicKitInstance {\r\n  currentPlaybackTime: number;\r\n  currentPlaybackDuration: number;\r\n  playbackState: number;\r\n  isAuthorized: boolean;\r\n  removeEventListener: (event: string, callback: () => void) => void;\r\n  addEventListener: (event: string, callback: () => void) => void;\r\n  authorize: () => Promise<void>;\r\n  unauthorize: () => Promise<void>;\r\n  play: () => Promise<void>;\r\n  pause: () => Promise<void>;\r\n  stop: () => Promise<void>;\r\n  seekToTime: (time: number) => Promise<void>;\r\n}\r\n\r\ndeclare const document: Document & { apple: MusicKitInstance };\r\n\r\nexport const useAppleMusicStore = defineStore(\"apple\", () => {\r\n  const toastStore = useToastStore();\r\n  const api = useApiStore();\r\n  const { t } = useI18n();\r\n  const debug = useDebug();\r\n  let instance: MusicKitInstance | null = null;\r\n  const authorized = ref(false);\r\n\r\n  const status = ref<MediaPlayerStatus>(MediaPlayerStatus.Unloaded);\r\n  const currentTime = ref(0);\r\n  const duration = ref(0);\r\n  const connecting = ref(false);\r\n  const error = ref(\"\");\r\n\r\n  let token = \"\";\r\n\r\n  function onProgressUpdate() {\r\n    if (!instance) {\r\n      return;\r\n    }\r\n\r\n    duration.value = instance.currentPlaybackDuration;\r\n    currentTime.value = instance.currentPlaybackTime;\r\n  }\r\n  function onPlaybackStateChange() {\r\n    if (instance?.playbackState === MusicKit.PlaybackStates.ended) {\r\n      status.value = MediaPlayerStatus.Ended;\r\n    }\r\n\r\n    if (instance?.playbackState === MusicKit.PlaybackStates.playing) {\r\n      status.value = MediaPlayerStatus.Playing;\r\n    }\r\n  }\r\n\r\n  function getStatusUpdates() {\r\n    authorized.value = instance?.isAuthorized || false;\r\n  }\r\n\r\n  async function getLatestToken() {\r\n    debug.log(\"apple script loaded\");\r\n    if (instance) {\r\n      instance.removeEventListener(\"playbackTimeDidChange\", onProgressUpdate);\r\n      instance.removeEventListener(\r\n        \"playbackStateDidChange\",\r\n        onPlaybackStateChange,\r\n      );\r\n    }\r\n\r\n    document.removeEventListener(\"musickitloaded\", getLatestToken);\r\n\r\n    try {\r\n      token = await api.post(\"/GetAppleApiToken\");\r\n      debug.log(\"apple jwt token\", token);\r\n\r\n      document.apple = (await MusicKit.configure({\r\n        developerToken: token,\r\n        app: {\r\n          name: \"CCLI SongSelect\",\r\n          build: import.meta.env.VITE_BUILD_VERSION,\r\n        },\r\n      })) as unknown as MusicKitInstance;\r\n      debug.log(\"instance created\", document.apple);\r\n      instance = document.apple;\r\n\r\n      getStatusUpdates();\r\n      instance?.addEventListener(\"playbackTimeDidChange\", onProgressUpdate);\r\n      instance?.addEventListener(\r\n        \"playbackStateDidChange\",\r\n        onPlaybackStateChange,\r\n      );\r\n      instance?.addEventListener(\r\n        \"authorizationStatusDidChange\",\r\n        getStatusUpdates,\r\n      );\r\n      debug.log(\"apple store loaded\");\r\n    } catch (err) {\r\n      debug.log(err);\r\n      error.value = \"Error connecting to Apple Music\";\r\n      toastErrorAuth();\r\n      throw err;\r\n    }\r\n  }\r\n\r\n  async function init() {\r\n    debug.log(\"apple init\");\r\n    await loadTokensFromUserMeta();\r\n    debug.log(\"apple store loading\");\r\n    document.addEventListener(\"musickitloaded\", getLatestToken);\r\n    loadScript(\r\n      \"https://js-cdn.music.apple.com/musickit/v3/musickit.js\",\r\n      \"apple-musickit-js\",\r\n    );\r\n  }\r\n\r\n  function instanceAvailable(throwErrorIfNotAvailable = true) {\r\n    if (instance) {\r\n      return true;\r\n    }\r\n\r\n    if (throwErrorIfNotAvailable) {\r\n      status.value = MediaPlayerStatus.Error;\r\n      error.value = \"Error connecting to Apple Music\";\r\n      debug.log(\"Music instance not found\");\r\n      toastErrorAuth();\r\n    }\r\n    return false;\r\n  }\r\n\r\n  async function loadTokensFromUserMeta() {\r\n    clearTokensFromUserMeta();\r\n    const settings = await getFullSongIntegrationTokens();\r\n\r\n    if (settings.service === \"apple\" && settings.authInfo) {\r\n      const authInfo = settings.authInfo as {\r\n        key: string;\r\n        value: string;\r\n      }[];\r\n      authInfo.forEach((k) => {\r\n        localStorage.setItem(k.key, k.value);\r\n      });\r\n    } else {\r\n      saveTokensFromUserMeta();\r\n    }\r\n  }\r\n\r\n  async function saveTokensFromUserMeta() {\r\n    const fullPlaybackStore = useFullSongPlaybackStore();\r\n    const keys = Object.keys(localStorage).filter((k) => /^music./.test(k));\r\n    const keysAndValues = keys.map((k) => ({\r\n      key: k,\r\n      value: localStorage.getItem(k),\r\n    }));\r\n    debug.log(\r\n      \"keys and values\",\r\n      keysAndValues,\r\n      JSON.stringify(keysAndValues).length,\r\n    );\r\n    fullPlaybackStore.saveSettings(keysAndValues, \"apple\");\r\n  }\r\n\r\n  async function clearTokensFromUserMeta() {\r\n    const keys = Object.keys(localStorage).filter((k) => /^music./.test(k));\r\n    keys.forEach((k) => localStorage.removeItem(k));\r\n  }\r\n\r\n  async function authorize() {\r\n    if (!instanceAvailable() || !instance || instance.isAuthorized) {\r\n      return;\r\n    }\r\n\r\n    connecting.value = true;\r\n\r\n    try {\r\n      await instance.authorize();\r\n    } catch (err) {\r\n      toastErrorAuth();\r\n      connecting.value = false;\r\n      console.error(\"error authorizing\", err);\r\n      throw err;\r\n    }\r\n    connecting.value = false;\r\n    toastStore.successToast(t(\"SV.LIT_ConnectedToAppleMusic\"));\r\n    saveTokensFromUserMeta();\r\n  }\r\n\r\n  function unauthorize() {\r\n    if (!instanceAvailable(false) || !instance || !instance.isAuthorized) {\r\n      return;\r\n    }\r\n    pause();\r\n    instance.unauthorize();\r\n    toastStore.successToast(t(\"SV.LIT_AppleMusicDisconnected\"));\r\n    clearTokensFromUserMeta();\r\n  }\r\n\r\n  function toastErrorAuth() {\r\n    toastStore.errorToast(t(\"SV.MES_AppleConnectionError\"));\r\n  }\r\n\r\n  async function seekTo(time: number) {\r\n    if (!instanceAvailable(false) || !instance) {\r\n      return;\r\n    }\r\n\r\n    await instance.seekToTime(time);\r\n  }\r\n\r\n  async function playSong(id: string) {\r\n    error.value = \"\";\r\n    if (!instanceAvailable(false) || !instance || !instance.isAuthorized) {\r\n      return;\r\n    }\r\n\r\n    status.value = MediaPlayerStatus.Loading;\r\n\r\n    try {\r\n      await (instance as any).setQueue({ song: id });\r\n      await (instance as any).changeToMediaItem(id);\r\n    } catch (err) {\r\n      error.value = \"Playback is not available for this song\";\r\n      toastStore.errorToast(t(\"SV.MES_SongNotAvailableForPlayback\"));\r\n      status.value = MediaPlayerStatus.Error;\r\n\r\n      debug.log(\"error playing song\", err);\r\n      throw err;\r\n    }\r\n\r\n    status.value = MediaPlayerStatus.Playing;\r\n  }\r\n\r\n  async function play() {\r\n    error.value = \"\";\r\n    if (!instanceAvailable(false) || !instance) {\r\n      return;\r\n    }\r\n\r\n    status.value = MediaPlayerStatus.Loading;\r\n    try {\r\n      await instance.play();\r\n      status.value = MediaPlayerStatus.Playing;\r\n    } catch (err) {\r\n      error.value = \"Playback is not available for this song\";\r\n      status.value = MediaPlayerStatus.Error;\r\n      debug.log(err);\r\n    }\r\n  }\r\n\r\n  function pause() {\r\n    error.value = \"\";\r\n\r\n    if (!instanceAvailable(false) || !instance) {\r\n      return;\r\n    }\r\n\r\n    status.value = MediaPlayerStatus.Paused;\r\n    if (currentTime.value) {\r\n      return instance.pause();\r\n    } else {\r\n      return instance.stop();\r\n    }\r\n  }\r\n\r\n  init();\r\n\r\n  return {\r\n    pause,\r\n    play,\r\n    playSong,\r\n    authorize,\r\n    unauthorize,\r\n    authorized,\r\n    status,\r\n    seekTo,\r\n    error,\r\n    duration,\r\n    connecting,\r\n    instance,\r\n    currentTime,\r\n  };\r\n});\r\n","export enum MediaPlayerRepeatMode {\r\n  NoRepeat = 0,\r\n  RepeatPlaylist,\r\n  RepeatSong\r\n}","import { MediaItem } from \"@/models/MediaItem\";\r\nimport { MediaPlayerRepeatMode } from \"@/models/frontend-only/MediaPlayerRepeatMode\";\r\nimport { MediaPlayerStatus } from \"@/models/frontend-only/MediaPlayerStatus\";\r\nimport { FEMediaItem, FEMediaUrl } from \"@/models/frontend-only/FEMediaItem\";\r\n\r\nexport const useMediaPlayerStore = defineStore(\"media-player\", () => {\r\n  const debug = useDebug();\r\n  const store = useSongStore();\r\n  const toast = useToastStore();\r\n  const { t } = useI18n();\r\n  const song = computed(() => store.song);\r\n  const mediaItems = computed(() => song.value?.media as FEMediaItem[]);\r\n\r\n  const spotifyStore = useSpotifyStore();\r\n  const fullSongPlaybackStore = useFullSongPlaybackStore();\r\n  const appleStore = useAppleMusicStore();\r\n  const audioPlayer = useAltAudioPlayback();\r\n  const youtubeStore = useYoutubeStore();\r\n  const nowPlayingId = ref(\"\");\r\n  const error = ref<string | null>(null);\r\n  const previewMode = computed(() => !fullSongPlaybackStore.integration);\r\n  const authenticatedMediaSource = computed(\r\n    () => fullSongPlaybackStore.integration,\r\n  );\r\n\r\n  type MediaPlayerTypes = \"youtube\" | \"html-audio\" | \"apple\" | \"spotify\" | \"\";\r\n\r\n  const mediaPlayer = computed<MediaPlayerTypes>(\r\n    () => (nowPlaying.value && determineMediaPlayer(nowPlaying.value)) || \"\",\r\n  );\r\n\r\n  function determineMediaPlayer(media: FEMediaItem) {\r\n    if (!media) {\r\n      return \"\";\r\n    } else if (media.type === \"video\") {\r\n      return \"youtube\";\r\n    } else if (media.type === \"song\") {\r\n      if (\r\n        authenticatedMediaSource.value === \"spotify\" &&\r\n        media.urls.find((u) => u.source === \"Spotify\") &&\r\n        media.isrc\r\n      ) {\r\n        return \"spotify\";\r\n      } else if (\r\n        authenticatedMediaSource.value === \"apple\" &&\r\n        media.urls.find((u) => u.source === \"iTunes\") &&\r\n        media.applesongid\r\n      ) {\r\n        return \"apple\";\r\n      } else {\r\n        return \"html-audio\";\r\n      }\r\n    }\r\n    return \"\";\r\n  }\r\n\r\n  const status = computed(() => {\r\n    if (mediaPlayer.value === \"html-audio\") {\r\n      return audioPlayer.status;\r\n    } else if (mediaPlayer.value === \"spotify\") {\r\n      return spotifyStore.status;\r\n    } else if (mediaPlayer.value === \"apple\") {\r\n      return appleStore.status;\r\n    } else if (mediaPlayer.value === \"youtube\") {\r\n      return youtubeStore.status;\r\n    }\r\n    return MediaPlayerStatus.Unloaded;\r\n  });\r\n\r\n  const progress = computed(() => {\r\n    if (mediaPlayer.value === \"html-audio\") {\r\n      return audioPlayer.currentTime;\r\n    } else if (mediaPlayer.value === \"spotify\") {\r\n      return spotifyStore.currentTime;\r\n    } else if (mediaPlayer.value === \"apple\") {\r\n      return appleStore.currentTime;\r\n    } else if (mediaPlayer.value === \"youtube\") {\r\n      return youtubeStore.currentTime;\r\n    }\r\n    return 0;\r\n  });\r\n\r\n  const duration = computed(() => {\r\n    if (mediaPlayer.value === \"html-audio\") {\r\n      return audioPlayer.maxTime;\r\n    } else if (mediaPlayer.value === \"spotify\") {\r\n      return spotifyStore.duration;\r\n    } else if (mediaPlayer.value === \"apple\") {\r\n      return appleStore.duration;\r\n    } else if (mediaPlayer.value === \"youtube\") {\r\n      return youtubeStore.duration;\r\n    }\r\n    return 0;\r\n  });\r\n\r\n  const nowPlaying = computed(() => {\r\n    if (!mediaItems.value) {\r\n      return null;\r\n    }\r\n    if (!nowPlayingId.value) {\r\n      return null;\r\n    }\r\n    return mediaItems.value.find((i) => i.id === nowPlayingId.value) ?? null;\r\n  });\r\n\r\n  function togglePlay() {\r\n    debug.log(\"toggle play\");\r\n    if (mediaPlayer.value === \"html-audio\") {\r\n      debug.log(\"toggle play - html-audio\");\r\n      toggleAudioPlayback();\r\n    } else {\r\n      switch (status.value) {\r\n        case MediaPlayerStatus.Error:\r\n        case MediaPlayerStatus.Paused:\r\n        case MediaPlayerStatus.Ended:\r\n          debug.log(\"toggle play - play()\");\r\n          play();\r\n          break;\r\n\r\n        default:\r\n          debug.log(\"toggle play - pause()\");\r\n          pause();\r\n          break;\r\n      }\r\n    }\r\n  }\r\n\r\n  function toggleAudioPlayback() {\r\n    if (status.value !== MediaPlayerStatus.Playing) {\r\n      audioPlayer.play();\r\n    } else {\r\n      audioPlayer.pause();\r\n    }\r\n  }\r\n\r\n  function play() {\r\n    if (mediaPlayer.value === \"html-audio\") {\r\n      audioPlayer.play();\r\n    } else if (mediaPlayer.value === \"spotify\") {\r\n      spotifyStore.play();\r\n    } else if (mediaPlayer.value === \"apple\") {\r\n      appleStore.play();\r\n    } else if (mediaPlayer.value === \"youtube\") {\r\n      youtubeStore.play();\r\n    }\r\n  }\r\n\r\n  function pause() {\r\n    audioPlayer.pause();\r\n    if (mediaPlayer.value === \"spotify\") {\r\n      spotifyStore.pause();\r\n    } else if (mediaPlayer.value === \"apple\") {\r\n      appleStore.pause();\r\n    } else if (mediaPlayer.value === \"youtube\") {\r\n      youtubeStore.pause();\r\n    }\r\n  }\r\n\r\n  async function goToTime(time: number, final = false) {\r\n    if (mediaPlayer.value === \"html-audio\") {\r\n      if (final) {\r\n        audioPlayer.goToTime(time);\r\n      }\r\n    } else if (mediaPlayer.value === \"spotify\") {\r\n      if (final) {\r\n        spotifyStore.seekTo(time);\r\n      }\r\n    } else if (mediaPlayer.value === \"apple\") {\r\n      if (final) {\r\n        await appleStore.seekTo(time);\r\n        await asyncWait(50); // without this, sometime the seekTo doesn't work.\r\n      }\r\n    } else if (mediaPlayer.value === \"youtube\") {\r\n      youtubeStore.seekTo(time);\r\n    }\r\n  }\r\n\r\n  function playNextSong() {\r\n    if (!mediaItems.value) {\r\n      return;\r\n    }\r\n    let index = mediaItems.value.findIndex((i) => i.id === nowPlayingId.value);\r\n    index++;\r\n    if (index >= mediaItems.value.length) {\r\n      index = 0;\r\n    }\r\n    playMediaItem(mediaItems.value[index].id);\r\n  }\r\n\r\n  function playPreviousSong() {\r\n    if (!mediaItems.value) {\r\n      return;\r\n    }\r\n    let index = mediaItems.value.findIndex((i) => i.id === nowPlayingId.value);\r\n    index--;\r\n    if (index < 0) {\r\n      index = mediaItems.value.length - 1;\r\n    }\r\n    playMediaItem(mediaItems.value[index].id);\r\n  }\r\n\r\n  async function startMediaPlayback() {\r\n    debug.log(\"waiting for spotify to complete - \", mediaPlayer.value);\r\n    if (mediaPlayer.value === \"spotify\") {\r\n      await waitUntilTrue(() => spotifyStore.playerReady);\r\n    }\r\n\r\n    debug.log(\"start media playback\", nowPlaying.value, mediaPlayer.value);\r\n    if (!nowPlaying.value) {\r\n      return;\r\n    }\r\n\r\n    error.value = null;\r\n    if (mediaPlayer.value === \"spotify\") {\r\n      const spotifyInfo: FEMediaUrl | null =\r\n        nowPlaying.value.urls.find((url) => url.source === \"Spotify\") || null;\r\n      debug.log(\"trying to play song\", spotifyInfo);\r\n      if (!spotifyInfo) {\r\n        toast.errorToast(t(\"SV.MES_SpotifyConnectionError\"));\r\n        throw new Error(\"Item does not contain isrc\");\r\n      }\r\n      spotifyStore.playSong(spotifyInfo.id);\r\n    } else if (mediaPlayer.value === \"apple\") {\r\n      debug.log(\"playing apple item\", nowPlaying.value.applesongid);\r\n      if (!nowPlaying.value.applesongid) {\r\n        console.error(\"apple song id missing\");\r\n        throw new Error(\"apple song id missing\");\r\n      }\r\n      appleStore.playSong(nowPlaying.value.applesongid).catch((err) => {\r\n        nowPlayingId.value = \"\";\r\n        throw err;\r\n      });\r\n    } else if (mediaPlayer.value === \"html-audio\") {\r\n      if (!nowPlaying.value.previewUrl) {\r\n        toast.errorToast(t(\"SV.MES_SongCannotPlayError\"));\r\n        throw new Error(\"Item does not contain a url\");\r\n      }\r\n      audioPlayer.loadUrl(nowPlaying.value.previewUrl);\r\n    } else if (mediaPlayer.value === \"youtube\") {\r\n      audioPlayer.pause();\r\n    } else {\r\n      if (!nowPlaying.value.previewUrl) {\r\n        return \"\";\r\n      }\r\n\r\n      audioPlayer.loadUrl(nowPlaying.value.previewUrl);\r\n      audioPlayer.play();\r\n    }\r\n  }\r\n\r\n  async function playMediaItem(mediaId: string, dontStart = false) {\r\n    if (\r\n      status.value === MediaPlayerStatus.Loading ||\r\n      status.value === MediaPlayerStatus.Playing\r\n    ) {\r\n      pause();\r\n    }\r\n    nowPlayingId.value = mediaId;\r\n    if (!dontStart) {\r\n      startMediaPlayback();\r\n    }\r\n  }\r\n\r\n  const repeatMode = ref<MediaPlayerRepeatMode>(MediaPlayerRepeatMode.NoRepeat);\r\n\r\n  function toggleRepeatMode() {\r\n    switch (repeatMode.value) {\r\n      case MediaPlayerRepeatMode.NoRepeat:\r\n        repeatMode.value = MediaPlayerRepeatMode.RepeatPlaylist;\r\n        break;\r\n      case MediaPlayerRepeatMode.RepeatPlaylist:\r\n        repeatMode.value = MediaPlayerRepeatMode.RepeatSong;\r\n        break;\r\n      case MediaPlayerRepeatMode.RepeatSong:\r\n        repeatMode.value = MediaPlayerRepeatMode.NoRepeat;\r\n        break;\r\n    }\r\n  }\r\n\r\n  function reset() {\r\n    pause();\r\n    nowPlayingId.value = \"\";\r\n  }\r\n\r\n  function getYoutubeUrl(m: MediaItem | FEMediaItem) {\r\n    return m.urls.find((url) => url.source === \"youtube\")?.url || null;\r\n  }\r\n\r\n  emitter.on(\"youtubeVideoEnded\", () => (nowPlayingId.value = \"\"));\r\n\r\n  return {\r\n    song,\r\n    mediaItems,\r\n    mediaPlayer,\r\n    nowPlaying,\r\n    nowPlayingId,\r\n    error,\r\n    togglePlay,\r\n    repeatMode,\r\n    toggleRepeatMode,\r\n    pause,\r\n    play,\r\n    reset,\r\n    goToTime,\r\n    playMediaItem,\r\n    playNextSong,\r\n    playPreviousSong,\r\n    status,\r\n    previewMode,\r\n    progress,\r\n    authenticatedMediaSource,\r\n    duration,\r\n    getYoutubeUrl,\r\n    determineMediaPlayer,\r\n  };\r\n});\r\n","import { defineStore } from \"pinia\";\r\n\r\nexport const useFullSongPlaybackStore = defineStore(\r\n  \"full-song-playback\",\r\n  () => {\r\n    const spotify = useSpotifyStore();\r\n    const apple = useAppleMusicStore();\r\n    const beta = useBetaStore();\r\n    const modals = useModalStore();\r\n    const debug = useDebug();\r\n    const mediaplayer = useMediaPlayerStore();\r\n    const api = useApiStore();\r\n\r\n    const integration = ref<\"apple\" | \"spotify\" | null>(null);\r\n    const nextIntegration = ref<\"apple\" | \"spotify\" | null>(null);\r\n    const integrationTerm = computed(() => {\r\n      if (!beta.features.fullSongPlayback) {\r\n        return \"\";\r\n      }\r\n      if (integration.value === \"apple\") {\r\n        return \"Apple Music\";\r\n      } else if (integration.value === \"spotify\") {\r\n        return \"Spotify\";\r\n      }\r\n      return \"\";\r\n    });\r\n\r\n    function setIntegration(newIntegration: \"apple\" | \"spotify\") {\r\n      if (!beta.features.fullSongPlayback) {\r\n        return;\r\n      }\r\n\r\n      if (integration.value === newIntegration) {\r\n        nextIntegration.value = null;\r\n      } else {\r\n        nextIntegration.value = newIntegration;\r\n      }\r\n\r\n      if (integration.value) {\r\n        modals.showModal(\"ConfirmDisconnectIntegrationModal\");\r\n      } else {\r\n        authorize(newIntegration);\r\n      }\r\n    }\r\n\r\n    function setIntegrationConfirmed() {\r\n      if (!beta.features.fullSongPlayback) {\r\n        return;\r\n      }\r\n      if (integration.value) {\r\n        unauthorize();\r\n        integration.value = null;\r\n      }\r\n\r\n      if (nextIntegration.value) {\r\n        authorize(nextIntegration.value);\r\n      }\r\n    }\r\n\r\n    function unauthorize() {\r\n      if (!beta.features.fullSongPlayback) {\r\n        return;\r\n      }\r\n      mediaplayer.pause();\r\n      if (integration.value === \"apple\") {\r\n        apple.unauthorize();\r\n      } else if (integration.value === \"spotify\") {\r\n        spotify.unauthorize();\r\n      }\r\n    }\r\n\r\n    function authorize(service: \"apple\" | \"spotify\") {\r\n      if (!beta.features.fullSongPlayback) {\r\n        return;\r\n      }\r\n      if (service === \"apple\") {\r\n        apple.authorize();\r\n      } else if (service === \"spotify\") {\r\n        spotify.authorize();\r\n      }\r\n    }\r\n\r\n    async function saveSettings(\r\n      authInfo: any,\r\n      service: \"apple\" | \"spotify\" | null,\r\n    ) {\r\n      if (service === integration.value) {\r\n        const data = {\r\n          musicPlayerPreferences: JSON.stringify({\r\n            authInfo: (authInfo && JSON.stringify(authInfo)) || null,\r\n            service,\r\n          }),\r\n        };\r\n        await api.post(\"/UpdateMusicPlayerPreferences \", data);\r\n      } else if (service !== integration.value) {\r\n        // purposely ignore this case\r\n        debug.log(\"ignoring save settings\", authInfo, service);\r\n      }\r\n    }\r\n\r\n    watch(integration, () => {\r\n      if (!integration.value) {\r\n        saveSettings(null, null);\r\n      }\r\n    });\r\n\r\n    if (beta.features.fullSongPlayback) {\r\n      watch(\r\n        () => [apple.authorized, spotify.authorized],\r\n        () => {\r\n          mediaplayer.reset();\r\n          if (apple.authorized) {\r\n            integration.value = \"apple\";\r\n          } else if (spotify.authorized) {\r\n            integration.value = \"spotify\";\r\n          } else {\r\n            integration.value = null;\r\n          }\r\n          (window as any).dataLayer.push({\r\n            event: 'dspIntegration',\r\n            dsp_integration_status: integration.value ? true : false,\r\n            dsp_integration_platform: integration.value,\r\n          })\r\n          // if (mediaplayer.nowPlaying) {\r\n          //   mediaplayer.playMediaItem(mediaplayer.nowPlaying.id, true);\r\n          // }\r\n        },\r\n      );\r\n    }\r\n\r\n    const connecting = computed(\r\n      () =>\r\n        (beta.features.fullSongPlayback &&\r\n          (apple.connecting || spotify.connecting)) ||\r\n        false,\r\n    );\r\n\r\n    return {\r\n      integration,\r\n      nextIntegration,\r\n      connecting,\r\n      integrationTerm,\r\n      setIntegration,\r\n      setIntegrationConfirmed,\r\n\r\n      saveSettings,\r\n    };\r\n  },\r\n);\r\n","import { Song } from \"@/models/Song\";\r\nimport { DataType } from \"@/models/DataType\";\r\nimport Arrangement from \"@/models/Arrangement\";\r\nimport { LoadStatus } from \"@/models/frontend-only/LoadStatus\";\r\nimport getYouTubeID from \"get-youtube-id\";\r\nimport { CustomError } from \"@/models/frontend-only/CustomError\";\r\nimport { EmailSettings } from \"@/models/frontend-only/EmailSettings\";\r\nimport { FEMediaItem } from \"@/models/frontend-only/FEMediaItem\";\r\nimport { FESong } from \"@/models/frontend-only/FESong\";\r\nimport { SongVersionItem } from \"@/models/frontend-only/SongVersion\";\r\n\r\nexport const useSongStore = defineStore(\"song\", () => {\r\n  const appStore = useAppStore();\r\n  const route = useRoute();\r\n  const api = useApiStore();\r\n  const profileStore = useProfileStore();\r\n\r\n  const fullSongStore = useFullSongPlaybackStore();\r\n  const busy = useBusyStore();\r\n  const debug = useDebug();\r\n  const { t } = useI18n();\r\n  const status = ref<LoadStatus>(LoadStatus.Loading);\r\n  const toast = useToastStore();\r\n  const showCopyButton = computed(() => !!navigator?.clipboard?.writeText);\r\n\r\n  const dataType = computed(() =>\r\n    route.path.includes(\"/arrangements/\")\r\n      ? DataType.Arrangement\r\n      : DataType.Song,\r\n  );\r\n  const arrangementType = computed(\r\n    () => dataType.value === DataType.Arrangement,\r\n  );\r\n  const title = computed(() =>\r\n    arrangementType.value\r\n      ? arrangement.value?.title || \"\"\r\n      : song.value?.title || \"\",\r\n  );\r\n\r\n  const loading = ref<boolean>(false); // To be removed altogether and replaced with 'status'\r\n  const song = ref<FESong | null>(null);\r\n  const media = ref<FEMediaItem[]>([]);\r\n  const arrangement = ref<Arrangement | null>(null);\r\n  const data = computed(() =>\r\n    arrangementType.value ? arrangement.value : song.value,\r\n  );\r\n\r\n  const bgSplashImgUrl = ref(\"\");\r\n\r\n  const defaultKey = computed(() =>\r\n    data.value?.defaultKey?.length ? data.value.defaultKey[0] : \"\",\r\n  );\r\n\r\n  const copyLyricsContent = computed(() => {\r\n    if (data.value && data.value.lyrics) {\r\n      const licenseText = profileStore.profile?.licenseNumber\r\n        ? t(\"G.CcliLicenseNumber\") + profileStore.profile?.licenseNumber\r\n        : \"\";\r\n      return [\r\n        data.value.title,\r\n        ...data.value.lyrics.map(\r\n          (l) =>\r\n            l.partLabel +\r\n            \"\\n\" +\r\n            l.lyrics\r\n              .split(\"|\")\r\n              .map((ll) => ll.trim())\r\n              .join(\"\\n\"),\r\n        ),\r\n        [\r\n          data.value.authors.map((a) => a.label).join(\", \"),\r\n          t(\"G.CcliSongNumber\") + data.value.ccliSongNumber,\r\n          data.value.copyrights\r\n            ?.replace(/(\\r\\n|\\n|\\r)/gm, \"\")\r\n            .replace(/\\s+/g, \" \"),\r\n          t(\"G.MES_SongSelectDisclaimer\"),\r\n          //t(\"G.CcliLicenseNumber\") + profileStore.profile?.licenseNumber,\r\n          licenseText,\r\n        ].join(\"\\n\"),\r\n      ].join(\"\\n\\n\");\r\n    }\r\n    return \"\";\r\n  });\r\n\r\n  async function _getSongDetails(\r\n    songNumber: string,\r\n    slug: string,\r\n    // arrangementNumber: string\r\n  ) {\r\n    songNotFound.value = false;\r\n    status.value = LoadStatus.Loading;\r\n    busy.showBusy();\r\n    song.value = null;\r\n    try {\r\n      const songResponse = (await api.get(\"/GetSongDetails\", {\r\n        songNumber,\r\n        slug,\r\n      })) as Song;\r\n\r\n      let songVersion: SongVersionItem | null = null;\r\n      if (songResponse?.media.length) {\r\n        songResponse.media.forEach((m, mIndex) => {\r\n          debug.log(\"media item\", m);\r\n\r\n          if (m.type === \"song\") {\r\n            // m.urls.forEach((url, urlIndex) => {\r\n            //   url.source = \"url\";\r\n            //   url.url = m.previewUrl || url.url;\r\n            // });\r\n          } else if (m.type === \"video\") {\r\n            m.urls.forEach((url) => {\r\n              url.source = \"youtube\";\r\n              let videoId = getYouTubeID(url.url);\r\n              if (!videoId && url.url.includes(\"embed\")) {\r\n                videoId = url.url.split(\"/\").pop() || \"\";\r\n              }\r\n              if (!videoId) {\r\n                return;\r\n              }\r\n              const thumbnail = `https://img.youtube.com/vi/${videoId}/0.jpg`;\r\n              songResponse.media[mIndex].artwork = thumbnail;\r\n            });\r\n          }\r\n        });\r\n\r\n        if (songResponse.ccliSongNumber) {\r\n          songVersion = await getSongVersions(songResponse.ccliSongNumber);\r\n          if (songVersion) {\r\n            songResponse.title = songVersion.SongTitle;\r\n            songResponse.media = [\r\n              {\r\n                applesongid: songVersion.AppleRecordingID,\r\n                isrc: songVersion.ISRC,\r\n                artwork: songVersion.AlbumArtURL,\r\n                previewUrl: songVersion.SoundSampleURL,\r\n                title: songVersion.Album,\r\n                id: \"R01\",\r\n                previewLengthSeconds: 0,\r\n                lengthSeconds: 0,\r\n                subtitle: songVersion.Artist,\r\n                type: \"song\",\r\n                arrangementNumber: null,\r\n                urls: [\r\n                  {\r\n                    source: \"iTunes\",\r\n                    url: songVersion.AlbumURL,\r\n                    id: songVersion.AppleRecordingID,\r\n                  },\r\n                ],\r\n              },\r\n              ...songResponse.media.filter((m) => m.type === \"video\"),\r\n            ];\r\n          }\r\n        }\r\n      }\r\n\r\n      bgSplashImgUrl.value =\r\n        songResponse?.media?.find((m) => m.type === \"song\")?.artwork || \"\";\r\n      song.value = Object.assign(\r\n        {\r\n          enableSongVersion: !!songVersion,\r\n          album: songVersion?.Album || null,\r\n          artist: songVersion?.Artist || null,\r\n        },\r\n        songResponse,\r\n      );\r\n\r\n      await setupMedia();\r\n      status.value = LoadStatus.Ready;\r\n    } catch (err) {\r\n      if ((err as CustomError)?.customData?.err?.response?.status === 404) {\r\n        songNotFound.value = true;\r\n      }\r\n      status.value = LoadStatus.Error;\r\n      throw err;\r\n    }\r\n    busy.hideBusy();\r\n    status.value = LoadStatus.Ready;\r\n  }\r\n  const songNotFound = ref(false);\r\n  let getSongDetailsPromise: Promise<void> | null = null;\r\n  watch(() => fullSongStore.integration, setupMedia);\r\n\r\n  async function setupMedia() {\r\n    let _media = song.value?.media || [];\r\n    if (!_media.length) {\r\n      media.value = [];\r\n      return;\r\n    }\r\n\r\n    //only get unique isrcs\r\n    const isrcs = [\r\n      ...new Set(\r\n        _media.filter((m) => m.type !== \"video\" && m.isrc).map((m) => m.isrc),\r\n      ),\r\n    ];\r\n\r\n    const theRest = _media.filter((m) => m.type === \"video\" || !m.isrc);\r\n    _media = [\r\n      ...isrcs.map((isrc) => _media.find((m) => m.isrc === isrc)!),\r\n      ...theRest,\r\n    ];\r\n\r\n    if (fullSongStore.integration === \"spotify\") {\r\n      const promises: Promise<void>[] = [];\r\n\r\n      const spotifyStore = useSpotifyStore();\r\n      _media.forEach((m, i) => {\r\n        if (m.type === \"song\" && m.isrc) {\r\n          if (\r\n            (song.value?.enableSongVersion && i === 0) ||\r\n            !song.value?.enableSongVersion\r\n          ) {\r\n            promises.push(\r\n              spotifyStore.getSongFromISRC(m.isrc).then((spotifyItem) => {\r\n                if (spotifyItem) {\r\n                  m.urls.push(spotifyItem);\r\n                  m.title = spotifyItem.title || m.title;\r\n                  m.subtitle = spotifyItem.subtitle || m.subtitle;\r\n                  m.artwork = spotifyItem.artwork || m.artwork;\r\n                }\r\n              }),\r\n            );\r\n          }\r\n        }\r\n      });\r\n      await Promise.all(promises);\r\n\r\n      _media = _media.filter(\r\n        (m) =>\r\n          m.type === \"video\" ||\r\n          (m.type === \"song\" && !!m.urls.find((u) => u.source === \"Spotify\")) ||\r\n          !!m.urls.find((u) => u.source === \"SoundSample\"),\r\n      );\r\n    }\r\n    if (fullSongStore.integration === \"apple\") {\r\n      _media = _media.filter(\r\n        (m) =>\r\n          m.type === \"video\" ||\r\n          (m.type === \"song\" && !!m.urls.find((u) => u.source === \"iTunes\")) ||\r\n          !!m.urls.find((u) => u.source === \"SoundSample\"),\r\n      );\r\n    }\r\n    media.value = _media as FEMediaItem[];\r\n    console.timeEnd(\"setup-media\");\r\n  }\r\n\r\n  async function getSongDetails(songNumber: string, slug: string) {\r\n    if (!getSongDetailsPromise) {\r\n      getSongDetailsPromise = _getSongDetails(songNumber, slug).finally(() => {\r\n        getSongDetailsPromise = null;\r\n      });\r\n    }\r\n    await getSongDetailsPromise;\r\n    return;\r\n  }\r\n\r\n  /*  async function getArrangementDetails(\r\n    songNumber: string,\r\n    slug: string,\r\n    arrangementNumber: string\r\n  ) {\r\n    status.value = LoadStatus.Loading;\r\n    busy.showBusy();\r\n    try {\r\n      arrangement.value = (await api.post(\"/GetArrangementDetails\", {\r\n        songNumber,\r\n        slug,\r\n        arrangementNumber,\r\n      })) as Arrangement;\r\n    } catch (err) {\r\n      status.value = LoadStatus.Error;\r\n      throw err;\r\n    }\r\n    busy.hideBusy();\r\n    status.value = LoadStatus.Ready;\r\n  }*/\r\n\r\n  const onLyricsActivityDebounced = useDebounceFn(onLyricsActivity, 2000);\r\n\r\n  function onLyricsActivity(\r\n    activityType: \"copied\" | \"printed\" | \"downloaded\" | \"shared\" | \"emailed\",\r\n  ) {\r\n    //no await necessary here since we don't want this to be blocking in any way\r\n    if (\r\n      !song.value ||\r\n      !song.value.lyrics ||\r\n      status.value === LoadStatus.Error ||\r\n      status.value === LoadStatus.Loading\r\n    ) {\r\n      return;\r\n    }\r\n    api.post(\"/RecordSongLyricsActivity\", {\r\n      ccliSongNumber: song.value.ccliSongNumber,\r\n      activityType,\r\n    });\r\n  }\r\n\r\n  async function copyToClipboard(content: string) {\r\n    if (navigator.clipboard && navigator.clipboard.writeText) {\r\n      navigator.clipboard.writeText(content || \"\");\r\n    } else {\r\n      toast.errorToast(t(\"SV.MES_EnableCopy\"));\r\n    }\r\n  }\r\n\r\n  function updateSongdetailsMeta() {\r\n    const hasLyrics = song.value?.products.lyrics.exists;\r\n    const hasChords = song.value?.products.chords.exists;\r\n    const authors = song.value?.authors.map((i) => i.label).join(\", \");\r\n    let metaContent = \"\";\r\n\r\n    if (song.value?.artist) {\r\n      metaContent = t(\r\n        \"S.LIT_PageDescriptionSEO_SongWithChordLyricAndSheetMusicByAuthor\",\r\n        [title.value, authors],\r\n      );\r\n    } else {\r\n      if (hasChords) {\r\n        if (hasLyrics) {\r\n          metaContent = t(\r\n            \"S.LIT_PageDescriptionSEO_SongWithChordLyricAndResources\",\r\n            [title.value, authors],\r\n          );\r\n        } else {\r\n          metaContent = t(\r\n            \"S.LIT_PageDescriptionSEO_SongWithChordAndResources\",\r\n            [title.value, authors],\r\n          );\r\n        }\r\n      } else {\r\n        if (hasLyrics) {\r\n          metaContent = t(\r\n            \"S.LIT_PageDescriptionSEO_SongWithLyricAndResources\",\r\n            [title.value, authors],\r\n          );\r\n        } else {\r\n          metaContent = t(\"S.LIT_PageDescriptionSEO_SongWithResources\", [\r\n            title.value,\r\n            authors,\r\n          ]);\r\n        }\r\n      }\r\n    }\r\n\r\n    appStore.updateDescription(metaContent);\r\n  }\r\n\r\n  const placeholderNotLoaded = computed(\r\n    () => status.value !== LoadStatus.Ready,\r\n  );\r\n  const placeholderNotAuthorized = computed(\r\n    () =>\r\n      placeholderNotLoaded.value ||\r\n      (status.value === LoadStatus.Ready &&\r\n        !song.value?.products.general.authorized),\r\n  );\r\n\r\n  const modals = useModalStore();\r\n\r\n  function showMaxSongUsage() {\r\n    modals.showModal(\"MaxSongModal\");\r\n  }\r\n\r\n  const emailSettings = ref<EmailSettings>({\r\n    product: \"\",\r\n    songKey: null,\r\n    style: null,\r\n    columns: null,\r\n    octave: null,\r\n    noteSize: null,\r\n    orientation: null,\r\n    paperSize: null,\r\n    busy: false,\r\n    renderer: null,\r\n  });\r\n\r\n  async function emailSong(settings: {\r\n    product: string;\r\n    songKey: string | null;\r\n    style: string | null;\r\n    columns: string | null;\r\n    octave: string | null;\r\n    noteSize: string | null;\r\n    orientation: string | null;\r\n    paperSize: string | null;\r\n    renderer?: string | null;\r\n    enableFontCustomization?: boolean;\r\n    css?: string;\r\n  }) {\r\n    emailSettings.value.busy = true;\r\n\r\n    emailSettings.value.product = settings.product;\r\n    emailSettings.value.songKey = settings.songKey;\r\n    emailSettings.value.style = settings.style;\r\n    emailSettings.value.columns = settings.columns;\r\n    emailSettings.value.octave = settings.octave;\r\n    emailSettings.value.noteSize = settings.noteSize;\r\n    emailSettings.value.orientation = settings.orientation;\r\n    emailSettings.value.paperSize = settings.paperSize;\r\n    emailSettings.value.renderer = settings.renderer;\r\n    emailSettings.value.enableFontCustomization =\r\n      settings.enableFontCustomization;\r\n    emailSettings.value.css = settings.css;\r\n\r\n    await profileStore.getProfile();\r\n\r\n    const emails = profileStore.profile?.availableEmails || [];\r\n\r\n    if (emails.length >= 2) {\r\n      modals.showModal(\"SelectEmailModal\");\r\n    } else if (emails.length === 1) {\r\n      await submitEmailSong(emails[0], true);\r\n    } else {\r\n      toast.errorToast(t(\"SV.MES_NoEmailsAssociated\"));\r\n    }\r\n\r\n    emailSettings.value.busy = false;\r\n  }\r\n\r\n  async function submitEmailSong(email: string, ignoreBusy = false) {\r\n    if (!ignoreBusy) {\r\n      emailSettings.value.busy = true;\r\n    }\r\n    if (!song.value) {\r\n      return;\r\n    }\r\n    const params: { [key: string]: string } = {\r\n      email,\r\n      songNumber: song.value.ccliSongNumber || \"\",\r\n      product: emailSettings.value.product,\r\n      key: emailSettings.value.songKey || \"\",\r\n      style: emailSettings.value.style || \"\",\r\n      columns: emailSettings.value.columns || \"\",\r\n      octave: emailSettings.value.octave || \"\",\r\n      noteSize: emailSettings.value.noteSize || \"\",\r\n      orientation: emailSettings.value.orientation || \"\",\r\n      paperSize: emailSettings.value.paperSize || \"\",\r\n    };\r\n\r\n    if (emailSettings.value.enableFontCustomization !== undefined) {\r\n      params[\"enableFontCustomization\"] = emailSettings.value\r\n        .enableFontCustomization\r\n        ? \"1\"\r\n        : \"0\";\r\n    }\r\n    if (emailSettings.value.enableFontCustomization) {\r\n      params[\"css\"] = emailSettings.value.css || \"\";\r\n    }\r\n\r\n    await api.post(\"/EmailSong\", params);\r\n\r\n    if (\r\n      emailSettings.value.product === \"lead\" ||\r\n      emailSettings.value.product === \"vocal\"\r\n    ) {\r\n      params[\"renderer\"] = emailSettings.value.renderer || \"legacy\";\r\n    }\r\n\r\n    if (emailSettings.value.product === \"lyrics\") {\r\n      onLyricsActivityDebounced(\"emailed\");\r\n    }\r\n    if (!ignoreBusy) {\r\n      emailSettings.value.busy = false;\r\n    }\r\n    modals.hideModal();\r\n    toast.successToast(t(\"SV.LIT_SongSentTo\", { email: email }));\r\n  }\r\n\r\n  return {\r\n    submitEmailSong,\r\n    emailSong,\r\n    emailSettings,\r\n    arrangementType,\r\n    placeholderNotLoaded,\r\n    placeholderNotAuthorized,\r\n    dataType,\r\n    status,\r\n    song,\r\n    loading,\r\n    arrangement,\r\n    data,\r\n    defaultKey,\r\n    title,\r\n    getSongDetails,\r\n    //getArrangementDetails,\r\n    copyLyricsContent,\r\n    onLyricsActivity,\r\n    getSongDetailsPromise,\r\n    showMaxSongUsage,\r\n    songNotFound,\r\n    copyToClipboard,\r\n    showCopyButton,\r\n    media,\r\n    bgSplashImgUrl,\r\n    //status,\r\n    updateSongdetailsMeta,\r\n    onLyricsActivityDebounced,\r\n  };\r\n});\r\n"],"names":["DataType","openWindow","url","queryParams","useSameWindow","queryString","fullUrl","w","h","wLeft","wTop","left","top","crypto","getRandomValues","size","random","mask","result","randomUints","i","randomIndex","generateVerifier","length","generateChallenge","code_verifier","buffer","pkceChallenge","verifier","challenge","getFullSongIntegrationTokens","debug","useDebug","profile","useProfileStore","authInfo","service","_a","_b","_c","_e","_d","clientId","AppConstants","callbackUrl","scopes","useSpotifyStore","defineStore","toastStore","useToastStore","t","useI18n","fullPlaybackStore","useFullSongPlaybackStore","authorized","ref","playState","status","MediaPlayerStatus","error","player","playerState","playerId","playerReady","pollIntervalRef","currentTime","duration","songId","SpotifySettings","saveSettings","authState","pkcePair","seekOnPlay","accessTokenExpired","now","expires","refreshAccessToken","params","response","data","setExpires","err","unauthorize","init","authorize","isMobile","openedWindow","broadcastChannel","authorizeCallback","timerRef","connecting","computed","BroadcastChannel","onError","msg","toastErrorAuth","expiresIn","event","nextTick","verifyUserHasPremium","connectToSpotify","pollForStatus","checkStatus","unpollForStatus","checkSeekTime","seek","time","minTime","getSongFromISRC","isrc","api","useApiStore","waitUntilTrue","cacheKey","countryCode","cachedItem","RaygunFunctions","items","request","debug2","track","a","resolve","script","cb","searchQuery","requestHeaders","body","responseData","clearTokensFromUserMeta","skipSaving","playSong","id","atTime","play","pause","showMsg","spotifyUserData","seekTo","useAppleMusicStore","instance","token","onProgressUpdate","onPlaybackStateChange","getStatusUpdates","getLatestToken","loadTokensFromUserMeta","loadScript","instanceAvailable","throwErrorIfNotAvailable","settings","k","saveTokensFromUserMeta","keysAndValues","MediaPlayerRepeatMode","MediaPlayerRepeatMode2","useMediaPlayerStore","store","useSongStore","toast","song","mediaItems","spotifyStore","fullSongPlaybackStore","appleStore","audioPlayer","useAltAudioPlayback","youtubeStore","useYoutubeStore","nowPlayingId","previewMode","authenticatedMediaSource","mediaPlayer","nowPlaying","determineMediaPlayer","media","u","progress","togglePlay","toggleAudioPlayback","goToTime","final","asyncWait","playNextSong","index","playMediaItem","playPreviousSong","startMediaPlayback","spotifyInfo","mediaId","dontStart","repeatMode","toggleRepeatMode","reset","getYoutubeUrl","m","emitter","spotify","apple","beta","useBetaStore","modals","useModalStore","mediaplayer","integration","nextIntegration","integrationTerm","setIntegration","newIntegration","setIntegrationConfirmed","watch","appStore","useAppStore","route","useRoute","profileStore","fullSongStore","busy","useBusyStore","LoadStatus","showCopyButton","dataType","arrangementType","title","arrangement","loading","bgSplashImgUrl","defaultKey","copyLyricsContent","licenseText","l","ll","_getSongDetails","songNumber","slug","songNotFound","songResponse","songVersion","mIndex","videoId","getYouTubeID","thumbnail","getSongVersions","setupMedia","getSongDetailsPromise","_media","isrcs","theRest","promises","spotifyItem","getSongDetails","onLyricsActivityDebounced","useDebounceFn","onLyricsActivity","activityType","copyToClipboard","content","updateSongdetailsMeta","hasLyrics","hasChords","authors","metaContent","placeholderNotLoaded","placeholderNotAuthorized","showMaxSongUsage","emailSettings","emailSong","emails","submitEmailSong","email","ignoreBusy"],"mappings":"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","x_google_ignoreList":[2]}