{"version":3,"file":"SongStore-cGanLO0U.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.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(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 console.log(\"getSongFromISRC error\", 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((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;\r\n unauthorize: () => Promise;\r\n play: () => Promise;\r\n pause: () => Promise;\r\n stop: () => Promise;\r\n seekToTime: (time: number) => Promise;\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.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(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(\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.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.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(false); // To be removed altogether and replaced with 'status'\r\n const song = ref(null);\r\n const media = ref([]);\r\n const arrangement = ref(null);\r\n const data = computed(() =>\r\n arrangementType.value ? arrangement.value : song.value,\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 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 | 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[] = [];\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({\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 //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","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]}