✨ (spotify) add spotify player
This commit is contained in:
@@ -1,7 +1,12 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="chilled-music">
|
<div class="chilled-music">
|
||||||
<transition name="fade">
|
<transition name="fade">
|
||||||
<img v-show="!ready" src="@/assets/loader.svg" :alt="$t('loading')" />
|
<img
|
||||||
|
v-show="!ready"
|
||||||
|
class="loader"
|
||||||
|
src="@/assets/loader.svg"
|
||||||
|
:alt="$t('music.loading')"
|
||||||
|
/>
|
||||||
</transition>
|
</transition>
|
||||||
<section v-show="false">
|
<section v-show="false">
|
||||||
<div
|
<div
|
||||||
@@ -99,29 +104,3 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
@keyframes rotating {
|
|
||||||
from {
|
|
||||||
transform: rotate(0deg);
|
|
||||||
}
|
|
||||||
to {
|
|
||||||
transform: rotate(360deg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
img {
|
|
||||||
animation: rotating 4s linear infinite;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<i18n>
|
|
||||||
{
|
|
||||||
"en": {
|
|
||||||
"loading": "loading..."
|
|
||||||
},
|
|
||||||
"fr": {
|
|
||||||
"loading": "chargement..."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</i18n>
|
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from '@vue/composition-api'
|
import { defineComponent } from '@vue/composition-api'
|
||||||
import { useInterval } from '../hooks/useInterval'
|
import { useInterval } from '@/hooks/useInterval'
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'IntervalInput',
|
name: 'IntervalInput',
|
||||||
|
|||||||
36
src/components/SpotifyMusic.vue
Normal file
36
src/components/SpotifyMusic.vue
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
<template>
|
||||||
|
<div class="spotify-music">
|
||||||
|
<transition name="fade">
|
||||||
|
<img
|
||||||
|
v-show="!ready"
|
||||||
|
class="loader"
|
||||||
|
src="@/assets/loader.svg"
|
||||||
|
:alt="$t('music.loading')"
|
||||||
|
/>
|
||||||
|
</transition>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent, watchEffect } from '@vue/composition-api'
|
||||||
|
import { useSpotify } from '@/hooks/useSpotify'
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'SpotifyMusic',
|
||||||
|
props: {
|
||||||
|
play: {
|
||||||
|
type: Boolean,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setup(props) {
|
||||||
|
const { ready, play, pause } = useSpotify()
|
||||||
|
|
||||||
|
watchEffect(() => {
|
||||||
|
props.play ? play() : pause()
|
||||||
|
})
|
||||||
|
|
||||||
|
return { ready, play, pause }
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
@@ -20,16 +20,25 @@
|
|||||||
:class="{ selected: hasMusic, disabled: !hasMusic }"
|
:class="{ selected: hasMusic, disabled: !hasMusic }"
|
||||||
>
|
>
|
||||||
<span v-t="'chill'"></span>
|
<span v-t="'chill'"></span>
|
||||||
|
<SpotifyMusic
|
||||||
|
v-if="hasSpotify"
|
||||||
|
:play="play"
|
||||||
|
@play="onPlay"
|
||||||
|
@pause="onPause"
|
||||||
|
/>
|
||||||
<ChilledMusic
|
<ChilledMusic
|
||||||
class="chilled-music"
|
class="chilled-music"
|
||||||
v-if="hasMusic"
|
v-else-if="hasMusic"
|
||||||
:play="play"
|
:play="play"
|
||||||
@play="play"
|
@play="onPlay"
|
||||||
@pause="pause"
|
@pause="onPause"
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
<p v-if="!hasSpotify">
|
||||||
|
connect with <a href="#" @click.prevent="setHasSpotify(true)">Spotify</a>
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -40,7 +49,8 @@ import { useMusic } from '@/hooks/useMusic'
|
|||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'ZoneMusic',
|
name: 'ZoneMusic',
|
||||||
components: {
|
components: {
|
||||||
ChilledMusic: () => import('@/components/ChilledMusic.vue')
|
ChilledMusic: () => import('@/components/ChilledMusic.vue'),
|
||||||
|
SpotifyMusic: () => import('@/components/SpotifyMusic.vue')
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
play: {
|
play: {
|
||||||
@@ -49,17 +59,31 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
setup(_, { emit }) {
|
setup(_, { emit }) {
|
||||||
const { isMusicAvailable, hasMusic, setHasMusic } = useMusic()
|
const {
|
||||||
|
isMusicAvailable,
|
||||||
|
hasSpotify,
|
||||||
|
setHasSpotify,
|
||||||
|
hasMusic,
|
||||||
|
setHasMusic
|
||||||
|
} = useMusic()
|
||||||
|
|
||||||
const play = () => {
|
const onPlay = () => {
|
||||||
emit('play')
|
emit('play')
|
||||||
}
|
}
|
||||||
|
|
||||||
const pause = () => {
|
const onPause = () => {
|
||||||
emit('pause')
|
emit('pause')
|
||||||
}
|
}
|
||||||
|
|
||||||
return { isMusicAvailable, hasMusic, setHasMusic, play, pause }
|
return {
|
||||||
|
isMusicAvailable,
|
||||||
|
hasSpotify,
|
||||||
|
setHasSpotify,
|
||||||
|
hasMusic,
|
||||||
|
setHasMusic,
|
||||||
|
onPlay,
|
||||||
|
onPause
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
@@ -110,6 +134,10 @@ label[data-pm-holder] {
|
|||||||
.disabled {
|
.disabled {
|
||||||
color: desaturate($color, 70%);
|
color: desaturate($color, 70%);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
font-family: $serif-font-family;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<i18n>
|
<i18n>
|
||||||
|
|||||||
@@ -5,12 +5,20 @@ import { State, RootActions } from '@/store'
|
|||||||
export const useMusic = () => {
|
export const useMusic = () => {
|
||||||
const isIOS =
|
const isIOS =
|
||||||
navigator.platform && /iPad|iPhone|iPod/.test(navigator.platform)
|
navigator.platform && /iPad|iPhone|iPod/.test(navigator.platform)
|
||||||
const { hasMusic } = useGetters<GetterTree<State, State>>(['hasMusic'])
|
const { hasMusic, hasSpotify } = useGetters<GetterTree<State, State>>([
|
||||||
const { setHasMusic } = useActions<RootActions>(['setHasMusic'])
|
'hasMusic',
|
||||||
|
'hasSpotify'
|
||||||
|
])
|
||||||
|
const { setHasMusic, setHasSpotify } = useActions<RootActions>([
|
||||||
|
'setHasMusic',
|
||||||
|
'setHasSpotify'
|
||||||
|
])
|
||||||
|
|
||||||
return {
|
return {
|
||||||
isMusicAvailable: !isIOS,
|
isMusicAvailable: !isIOS,
|
||||||
hasMusic,
|
hasMusic,
|
||||||
setHasMusic
|
setHasMusic,
|
||||||
|
hasSpotify,
|
||||||
|
setHasSpotify
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
89
src/hooks/useSpotify.ts
Normal file
89
src/hooks/useSpotify.ts
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
/* eslint-disable */
|
||||||
|
// @ts-ignore
|
||||||
|
// @ts-nocheck
|
||||||
|
import '@/lib/spotify-player'
|
||||||
|
import { useGetters, useActions } from 'vuex-composition-helpers'
|
||||||
|
import { GetterTree } from 'vuex'
|
||||||
|
import { State, RootActions } from '@/store'
|
||||||
|
import {
|
||||||
|
redirectToSpotifyConnect,
|
||||||
|
playOnSpotify,
|
||||||
|
pauseOnSpotify
|
||||||
|
} from '@/utils/spotify'
|
||||||
|
import { ref, reactive } from '@vue/composition-api'
|
||||||
|
|
||||||
|
export const useSpotify = () => {
|
||||||
|
const ready = ref(false)
|
||||||
|
const deviceId = ref<string | null>(null)
|
||||||
|
const spotify = reactive({
|
||||||
|
player: null
|
||||||
|
})
|
||||||
|
const { accessToken, hasValidAccessToken } = useGetters<
|
||||||
|
GetterTree<State, State>
|
||||||
|
>(['accessToken', 'hasValidAccessToken'])
|
||||||
|
|
||||||
|
window.onSpotifyWebPlaybackSDKReady = async () => {
|
||||||
|
if (!hasValidAccessToken.value) {
|
||||||
|
redirectToSpotifyConnect()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
spotify.player = new Spotify.Player({
|
||||||
|
name: 'binome',
|
||||||
|
getOAuthToken: (callback) => callback(accessToken.value)
|
||||||
|
})
|
||||||
|
spotify.player.addListener('ready', ({ device_id }) => {
|
||||||
|
deviceId.value = device_id
|
||||||
|
ready.value = true
|
||||||
|
})
|
||||||
|
await spotify.player.connect()
|
||||||
|
}
|
||||||
|
|
||||||
|
const play = async () => {
|
||||||
|
try {
|
||||||
|
if (spotify.player && ready.value) {
|
||||||
|
const playerState = await spotify.player.getCurrentState()
|
||||||
|
console.log(playerState)
|
||||||
|
|
||||||
|
if (!playerState) {
|
||||||
|
playOnSpotify(accessToken.value, deviceId.value)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
await spotify.player.resume()
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.warn(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const pause = () => {
|
||||||
|
if (ready.value) {
|
||||||
|
pauseOnSpotify(accessToken.value, deviceId.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
ready,
|
||||||
|
play,
|
||||||
|
pause
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useSpotifyConnect = (hash: string) => {
|
||||||
|
window.onSpotifyWebPlaybackSDKReady = () => {}
|
||||||
|
const { setAccessToken, setTokenExpire } = useActions<RootActions>([
|
||||||
|
'setAccessToken',
|
||||||
|
'setTokenExpire'
|
||||||
|
])
|
||||||
|
hash = hash.replace('#', '')
|
||||||
|
const connection = [...hash.split('&').values()]
|
||||||
|
.map((entry) => entry.split('='))
|
||||||
|
.reduce((acc, entry) => {
|
||||||
|
acc[entry[0]] = entry[1]
|
||||||
|
return acc
|
||||||
|
}, {})
|
||||||
|
|
||||||
|
setAccessToken(connection['access_token'])
|
||||||
|
const now = new Date()
|
||||||
|
setTokenExpire(now.setTime(now.getTime() + connection['expires_in'] * 1000))
|
||||||
|
}
|
||||||
571
src/lib/spotify-player.js
Normal file
571
src/lib/spotify-player.js
Normal file
@@ -0,0 +1,571 @@
|
|||||||
|
/* eslint-disable */
|
||||||
|
/* Spotify JS-SDK - v1.7.1-d2b664d */
|
||||||
|
!(function(e) {
|
||||||
|
function t(r) {
|
||||||
|
if (n[r]) return n[r].exports
|
||||||
|
var s = (n[r] = { i: r, l: !1, exports: {} })
|
||||||
|
return e[r].call(s.exports, s, s.exports, t), (s.l = !0), s.exports
|
||||||
|
}
|
||||||
|
var n = {}
|
||||||
|
;(t.m = e),
|
||||||
|
(t.c = n),
|
||||||
|
(t.d = function(e, n, r) {
|
||||||
|
t.o(e, n) ||
|
||||||
|
Object.defineProperty(e, n, {
|
||||||
|
configurable: !1,
|
||||||
|
enumerable: !0,
|
||||||
|
get: r
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
(t.n = function(e) {
|
||||||
|
var n =
|
||||||
|
e && e.__esModule
|
||||||
|
? function() {
|
||||||
|
return e.default
|
||||||
|
}
|
||||||
|
: function() {
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
return t.d(n, 'a', n), n
|
||||||
|
}),
|
||||||
|
(t.o = function(e, t) {
|
||||||
|
return Object.prototype.hasOwnProperty.call(e, t)
|
||||||
|
}),
|
||||||
|
(t.p = ''),
|
||||||
|
t((t.s = 2))
|
||||||
|
})([
|
||||||
|
function(e, t, n) {
|
||||||
|
'use strict'
|
||||||
|
var r = {
|
||||||
|
SPOTIFY_MESSAGE: 'SP_MESSAGE',
|
||||||
|
ACCOUNT_ERROR: 'ACCOUNT_ERROR',
|
||||||
|
AUTH_ERROR: 'AUTH_ERROR',
|
||||||
|
CONNECT: 'CONNECT',
|
||||||
|
CONNECTED: 'CONNECTED',
|
||||||
|
CURRENT_STATE: 'CURRENT_STATE',
|
||||||
|
DISCONNECT: 'DISCONNECT',
|
||||||
|
EVENT: 'EVENT',
|
||||||
|
GET_CURRENT_STATE: 'GET_CURRENT_STATE',
|
||||||
|
GET_TOKEN: 'GET_TOKEN',
|
||||||
|
GET_VOLUME: 'GET_VOLUME',
|
||||||
|
INIT: 'INIT',
|
||||||
|
LOADED: 'LOADED',
|
||||||
|
NEXT_TRACK: 'NEXT_TRACK',
|
||||||
|
PAUSE: 'PAUSE',
|
||||||
|
PLAYBACK_ERROR: 'PLAYBACK_ERROR',
|
||||||
|
PLAYER_INIT_ERROR: 'PLAYER_INIT_ERROR',
|
||||||
|
PLAYER_READY: 'PLAYER_READY',
|
||||||
|
PLAYER_NOT_READY: 'PLAYER_NOT_READY',
|
||||||
|
PLAYER_STATE_CHANGED: 'PLAYER_STATE_CHANGED',
|
||||||
|
PREV_TRACK: 'PREV_TRACK',
|
||||||
|
RESUME: 'RESUME',
|
||||||
|
SEEK: 'SEEK',
|
||||||
|
SET_NAME: 'SET_NAME',
|
||||||
|
SET_VOLUME: 'SET_VOLUME',
|
||||||
|
TOGGLE_PLAY: 'TOGGLE_PLAY',
|
||||||
|
TOKEN: 'TOKEN',
|
||||||
|
VOLUME: 'VOLUME',
|
||||||
|
accountError: function(e) {
|
||||||
|
return this._createEventMessage(r.ACCOUNT_ERROR, { message: e })
|
||||||
|
},
|
||||||
|
authError: function(e) {
|
||||||
|
return this._createEventMessage(r.AUTH_ERROR, e)
|
||||||
|
},
|
||||||
|
playbackError: function(e) {
|
||||||
|
return this._createEventMessage(r.PLAYBACK_ERROR, e)
|
||||||
|
},
|
||||||
|
playerReady: function(e) {
|
||||||
|
return this._createEventMessage(r.PLAYER_READY, e)
|
||||||
|
},
|
||||||
|
playerNotReady: function(e) {
|
||||||
|
return this._createEventMessage(r.PLAYER_NOT_READY, e)
|
||||||
|
},
|
||||||
|
connect: function() {
|
||||||
|
return this._createMessage(r.CONNECT)
|
||||||
|
},
|
||||||
|
connected: function(e, t) {
|
||||||
|
return this._createMessage(r.CONNECTED, { connected: e, ref: t })
|
||||||
|
},
|
||||||
|
disconnect: function() {
|
||||||
|
return this._createMessage(r.DISCONNECT)
|
||||||
|
},
|
||||||
|
init: function(e) {
|
||||||
|
return this._createMessage(r.INIT, e)
|
||||||
|
},
|
||||||
|
playerInitError: function(e) {
|
||||||
|
return this._createEventMessage(r.PLAYER_INIT_ERROR, e)
|
||||||
|
},
|
||||||
|
getToken: function() {
|
||||||
|
return this._createMessage(r.GET_TOKEN)
|
||||||
|
},
|
||||||
|
token: function(e, t) {
|
||||||
|
return this._createMessage(r.TOKEN, { token: e, ref: t })
|
||||||
|
},
|
||||||
|
pause: function() {
|
||||||
|
return this._createMessage(r.PAUSE)
|
||||||
|
},
|
||||||
|
resume: function() {
|
||||||
|
return this._createMessage(r.RESUME)
|
||||||
|
},
|
||||||
|
togglePlay: function() {
|
||||||
|
return this._createMessage(r.TOGGLE_PLAY)
|
||||||
|
},
|
||||||
|
seek: function(e) {
|
||||||
|
return this._createMessage(r.SEEK, e)
|
||||||
|
},
|
||||||
|
nextTrack: function(e) {
|
||||||
|
return this._createMessage(r.NEXT_TRACK, e)
|
||||||
|
},
|
||||||
|
previousTrack: function(e) {
|
||||||
|
return this._createMessage(r.PREV_TRACK, e)
|
||||||
|
},
|
||||||
|
getCurrentState: function() {
|
||||||
|
return this._createMessage(r.GET_CURRENT_STATE)
|
||||||
|
},
|
||||||
|
currentState: function(e, t) {
|
||||||
|
return this._createMessage(r.CURRENT_STATE, { state: e, ref: t })
|
||||||
|
},
|
||||||
|
playerStateChanged: function(e) {
|
||||||
|
return this._createEventMessage(r.PLAYER_STATE_CHANGED, e)
|
||||||
|
},
|
||||||
|
getVolume: function() {
|
||||||
|
return this._createMessage(r.GET_VOLUME)
|
||||||
|
},
|
||||||
|
volume: function(e, t) {
|
||||||
|
return this._createMessage(r.VOLUME, { volume: e, ref: t })
|
||||||
|
},
|
||||||
|
setVolume: function(e) {
|
||||||
|
return this._createMessage(r.SET_VOLUME, e)
|
||||||
|
},
|
||||||
|
setName: function(e) {
|
||||||
|
return this._createMessage(r.SET_NAME, e)
|
||||||
|
},
|
||||||
|
embeddedLoaded: function() {
|
||||||
|
return this._createMessage(r.LOADED)
|
||||||
|
},
|
||||||
|
_createEventMessage: function(e, t) {
|
||||||
|
return this._createMessage(r.EVENT, { name: e, eventData: t })
|
||||||
|
},
|
||||||
|
_createMessage: function(e, t) {
|
||||||
|
return {
|
||||||
|
type: r.SPOTIFY_MESSAGE,
|
||||||
|
body: { topic: e, data: t ? JSON.parse(JSON.stringify(t)) : null }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
e.exports = r
|
||||||
|
},
|
||||||
|
function(e, t) {
|
||||||
|
var n
|
||||||
|
n = (function() {
|
||||||
|
return this
|
||||||
|
})()
|
||||||
|
try {
|
||||||
|
n = n || Function('return this')() || (0, eval)('this')
|
||||||
|
} catch (e) {
|
||||||
|
'object' == typeof window && (n = window)
|
||||||
|
}
|
||||||
|
e.exports = n
|
||||||
|
},
|
||||||
|
function(e, t, n) {
|
||||||
|
'use strict'
|
||||||
|
function r() {
|
||||||
|
var e = n(3)
|
||||||
|
if (!document.body) throw new Error("Document doesn't have a body")
|
||||||
|
if (
|
||||||
|
((window.Spotify = { Player: e.setupPlayerEnv(window) }),
|
||||||
|
window.onSpotifyWebPlaybackSDKReady)
|
||||||
|
)
|
||||||
|
window.onSpotifyWebPlaybackSDKReady()
|
||||||
|
else {
|
||||||
|
if (!window.onSpotifyPlayerAPIReady)
|
||||||
|
throw new Error('onSpotifyWebPlaybackSDKReady is not defined')
|
||||||
|
window.onSpotifyPlayerAPIReady()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'complete' === document.readyState
|
||||||
|
? r()
|
||||||
|
: window.addEventListener('load', r)
|
||||||
|
},
|
||||||
|
function(e, t, n) {
|
||||||
|
'use strict'
|
||||||
|
var r = n(4),
|
||||||
|
s = n(5),
|
||||||
|
o = n(0),
|
||||||
|
i = n(6),
|
||||||
|
a = function(e, t) {
|
||||||
|
var n,
|
||||||
|
a = 'https://sdk.scdn.co/embedded/index.html',
|
||||||
|
u = s.defer(),
|
||||||
|
c = new r(),
|
||||||
|
_ =
|
||||||
|
t ||
|
||||||
|
function(t) {
|
||||||
|
var n = e.document.createElement('iframe')
|
||||||
|
return (
|
||||||
|
(n.src = t),
|
||||||
|
n.setAttribute('alt', 'Audio Playback Container'),
|
||||||
|
n.setAttribute('tabIndex', '-1'),
|
||||||
|
n.style.setProperty('position', 'absolute', 'important'),
|
||||||
|
n.style.setProperty('left', '-1px', 'important'),
|
||||||
|
n.style.setProperty('width', '0', 'important'),
|
||||||
|
n.style.setProperty('height', '0', 'important'),
|
||||||
|
n.style.setProperty('border', 'none', 'important'),
|
||||||
|
n.style.setProperty('outline', 'none', 'important'),
|
||||||
|
(n.allow = 'encrypted-media; autoplay'),
|
||||||
|
e.document.body.appendChild(n),
|
||||||
|
n.contentWindow
|
||||||
|
)
|
||||||
|
},
|
||||||
|
h = function(t) {
|
||||||
|
t === o.LOADED && (c.stopListening(e, h), u.resolve())
|
||||||
|
}
|
||||||
|
c.listen(e, h), (n = _(a))
|
||||||
|
var f = function(t) {
|
||||||
|
;(this._options = this._sanitizeOptions(t)),
|
||||||
|
(this._handleMessages = this._handleMessages.bind(this)),
|
||||||
|
(this._messageHandlers = {}),
|
||||||
|
(this._eventListeners = {}),
|
||||||
|
this._setupMessageHandlers(),
|
||||||
|
(this._connectionRequests = {}),
|
||||||
|
(this._getCurrentStateRequests = {}),
|
||||||
|
(this._getVolumeRequests = {}),
|
||||||
|
(this.isLoaded = u.promise.then(
|
||||||
|
function() {
|
||||||
|
c.listen(e, this._handleMessages),
|
||||||
|
this._sendMessage(o.init(this._options))
|
||||||
|
}.bind(this)
|
||||||
|
))
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
(f.prototype._sanitizeOptions = function(t) {
|
||||||
|
var n = (e && e.location && e.location.hostname) || ''
|
||||||
|
return {
|
||||||
|
name: t.name || n,
|
||||||
|
id: i.get(),
|
||||||
|
getOAuthToken: t.getOAuthToken || t.getOauthToken,
|
||||||
|
volume: t.volume || 1
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
(f.prototype._setupMessageHandlers = function() {
|
||||||
|
;(this._messageHandlers[o.GET_TOKEN] = this._onGetToken.bind(this)),
|
||||||
|
(this._messageHandlers[o.EVENT] = this._onEvent.bind(this)),
|
||||||
|
(this._messageHandlers[o.CONNECTED] = this._onConnected.bind(
|
||||||
|
this
|
||||||
|
)),
|
||||||
|
(this._messageHandlers[
|
||||||
|
o.CURRENT_STATE
|
||||||
|
] = this._onCurrentState.bind(this)),
|
||||||
|
(this._messageHandlers[o.VOLUME] = this._onVolume.bind(this))
|
||||||
|
}),
|
||||||
|
(f.prototype.connect = function() {
|
||||||
|
return this.isLoaded.then(
|
||||||
|
function() {
|
||||||
|
var e = this._sendMessage(o.connect())
|
||||||
|
return (
|
||||||
|
(this._connectionRequests[e] = s.defer()),
|
||||||
|
this._connectionRequests[e].promise
|
||||||
|
)
|
||||||
|
}.bind(this)
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
(f.prototype.on = function(e, t) {
|
||||||
|
if (!e) throw new TypeError('Argument `eventName` is required.')
|
||||||
|
if ('function' != typeof t)
|
||||||
|
throw new TypeError('Argument `listener` must be a function.')
|
||||||
|
return (
|
||||||
|
(this._eventListeners[e] = this._eventListeners[e] || []),
|
||||||
|
-1 === this._eventListeners[e].indexOf(t) &&
|
||||||
|
(this._eventListeners[e].push(t), !0)
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
(f.prototype.addListener = function(e, t) {
|
||||||
|
return this.on(e, t)
|
||||||
|
}),
|
||||||
|
(f.prototype.removeListener = function(e, t) {
|
||||||
|
if (!e) throw new TypeError('Argument `eventName` is required.')
|
||||||
|
if (1 === arguments.length)
|
||||||
|
return (this._eventListeners[e] = []), !0
|
||||||
|
if ('function' != typeof t)
|
||||||
|
throw new TypeError('Argument `listener` must be a function.')
|
||||||
|
var n = this._eventListeners[e]
|
||||||
|
return (
|
||||||
|
!(!n || !n.length) &&
|
||||||
|
((this._eventListeners[e] = n.filter(function(e) {
|
||||||
|
return e !== t
|
||||||
|
})),
|
||||||
|
!0)
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
(f.prototype.getCurrentState = function() {
|
||||||
|
return this.isLoaded.then(
|
||||||
|
function() {
|
||||||
|
var e = this._sendMessage(o.getCurrentState())
|
||||||
|
return (
|
||||||
|
(this._getCurrentStateRequests[e] = s.defer()),
|
||||||
|
this._getCurrentStateRequests[e].promise
|
||||||
|
)
|
||||||
|
}.bind(this)
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
(f.prototype.getVolume = function() {
|
||||||
|
return this.isLoaded.then(
|
||||||
|
function() {
|
||||||
|
var e = this._sendMessage(o.getVolume())
|
||||||
|
return (
|
||||||
|
(this._getVolumeRequests[e] = s.defer()),
|
||||||
|
this._getVolumeRequests[e].promise
|
||||||
|
)
|
||||||
|
}.bind(this)
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
(f.prototype.setName = function(e) {
|
||||||
|
return this._sendMessageWhenLoaded(o.setName(e))
|
||||||
|
}),
|
||||||
|
(f.prototype.setVolume = function(e) {
|
||||||
|
return this._sendMessageWhenLoaded(o.setVolume(e))
|
||||||
|
}),
|
||||||
|
(f.prototype.pause = function() {
|
||||||
|
return this._sendMessageWhenLoaded(o.pause())
|
||||||
|
}),
|
||||||
|
(f.prototype.resume = function() {
|
||||||
|
return this._sendMessageWhenLoaded(o.resume())
|
||||||
|
}),
|
||||||
|
(f.prototype.togglePlay = function() {
|
||||||
|
return this._sendMessageWhenLoaded(o.togglePlay())
|
||||||
|
}),
|
||||||
|
(f.prototype.seek = function(e) {
|
||||||
|
return this._sendMessageWhenLoaded(o.seek(e))
|
||||||
|
}),
|
||||||
|
(f.prototype.previousTrack = function(e) {
|
||||||
|
return this._sendMessageWhenLoaded(o.previousTrack(e))
|
||||||
|
}),
|
||||||
|
(f.prototype.nextTrack = function(e) {
|
||||||
|
return this._sendMessageWhenLoaded(o.nextTrack(e))
|
||||||
|
}),
|
||||||
|
(f.prototype.disconnect = function() {
|
||||||
|
return this._sendMessageWhenLoaded(o.disconnect())
|
||||||
|
}),
|
||||||
|
(f.prototype._getListeners = (function() {
|
||||||
|
var e = {}
|
||||||
|
return (
|
||||||
|
(e[o.ACCOUNT_ERROR] = 'account_error'),
|
||||||
|
(e[o.AUTH_ERROR] = 'authentication_error'),
|
||||||
|
(e[o.PLAYBACK_ERROR] = 'playback_error'),
|
||||||
|
(e[o.PLAYER_INIT_ERROR] = 'initialization_error'),
|
||||||
|
(e[o.PLAYER_READY] = 'ready'),
|
||||||
|
(e[o.PLAYER_NOT_READY] = 'not_ready'),
|
||||||
|
(e[o.PLAYER_STATE_CHANGED] = 'player_state_changed'),
|
||||||
|
function(t) {
|
||||||
|
return this._eventListeners[e[t]] || []
|
||||||
|
}
|
||||||
|
)
|
||||||
|
})()),
|
||||||
|
(f.prototype._onEvent = function(e) {
|
||||||
|
this._getListeners(e.name).forEach(function(t) {
|
||||||
|
t(e.eventData)
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
(f.prototype._onGetToken = function(e, t) {
|
||||||
|
var n = this._options.getOAuthToken
|
||||||
|
if ('function' != typeof n) {
|
||||||
|
var r = 'getOAuthToken is not a function'
|
||||||
|
if (this._getListeners(o.PLAYER_INIT_ERROR).length)
|
||||||
|
return void this._onEvent({
|
||||||
|
name: o.PLAYER_INIT_ERROR,
|
||||||
|
eventData: { message: r }
|
||||||
|
})
|
||||||
|
throw new Error(r)
|
||||||
|
}
|
||||||
|
new s(n).then(
|
||||||
|
function(e) {
|
||||||
|
this._sendMessage(o.token(e, t))
|
||||||
|
}.bind(this)
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
(f.prototype._onConnected = function(e) {
|
||||||
|
e.ref in this._connectionRequests &&
|
||||||
|
(this._connectionRequests[e.ref].resolve(e.connected),
|
||||||
|
delete this._connectionRequests[e.ref])
|
||||||
|
}),
|
||||||
|
(f.prototype._onCurrentState = function(e) {
|
||||||
|
e.ref in this._getCurrentStateRequests &&
|
||||||
|
(this._getCurrentStateRequests[e.ref].resolve(e.state),
|
||||||
|
delete this._getCurrentStateRequests[e.ref])
|
||||||
|
}),
|
||||||
|
(f.prototype._onVolume = function(e) {
|
||||||
|
e.ref in this._getVolumeRequests &&
|
||||||
|
(this._getVolumeRequests[e.ref].resolve(e.volume),
|
||||||
|
delete this._getVolumeRequests[e.ref])
|
||||||
|
}),
|
||||||
|
(f.prototype._handleMessages = function(e, t, n) {
|
||||||
|
e in this._messageHandlers && this._messageHandlers[e](t, n)
|
||||||
|
}),
|
||||||
|
(f.prototype._sendMessage = function(e) {
|
||||||
|
return c.send(n, e, a)
|
||||||
|
}),
|
||||||
|
(f.prototype._sendMessageWhenLoaded = function(e) {
|
||||||
|
return this.isLoaded.then(this._sendMessage.bind(this, e))
|
||||||
|
}),
|
||||||
|
f
|
||||||
|
)
|
||||||
|
}
|
||||||
|
e.exports.setupPlayerEnv = a
|
||||||
|
},
|
||||||
|
function(e, t, n) {
|
||||||
|
'use strict'
|
||||||
|
var r = n(0),
|
||||||
|
s = function() {
|
||||||
|
;(this._onMessageCallback = function() {}),
|
||||||
|
(this._receiveMessage = this._receiveMessage.bind(this)),
|
||||||
|
(this._messageId = 0)
|
||||||
|
}
|
||||||
|
;(s.prototype.listen = function(e, t) {
|
||||||
|
;(this._onMessageCallback = t),
|
||||||
|
e.addEventListener('message', this._receiveMessage)
|
||||||
|
}),
|
||||||
|
(s.prototype.stopListening = function(e) {
|
||||||
|
e.removeEventListener('message', this._receiveMessage)
|
||||||
|
}),
|
||||||
|
(s.prototype.send = function(e, t, n) {
|
||||||
|
return e.postMessage(this._addMessageId(t), n || '*'), t.seq
|
||||||
|
}),
|
||||||
|
(s.prototype._addMessageId = function(e) {
|
||||||
|
return (e.seq = this._messageId++), e
|
||||||
|
}),
|
||||||
|
(s.prototype._receiveMessage = function(e) {
|
||||||
|
var t = e.data
|
||||||
|
t.type === r.SPOTIFY_MESSAGE &&
|
||||||
|
t.body &&
|
||||||
|
t.body.topic &&
|
||||||
|
this._onMessageCallback(t.body.topic, t.body.data, t.seq)
|
||||||
|
}),
|
||||||
|
(e.exports = s)
|
||||||
|
},
|
||||||
|
function(e, t, n) {
|
||||||
|
'use strict'
|
||||||
|
;(function(t) {
|
||||||
|
var n = t.Promise
|
||||||
|
if (!n) throw new Error('Fatal: no Promise implementation available.')
|
||||||
|
var r
|
||||||
|
;(r = Object.defineProperty
|
||||||
|
? function(e, t, n) {
|
||||||
|
return e[t]
|
||||||
|
? e
|
||||||
|
: (Object.defineProperty(e, t, {
|
||||||
|
value: n,
|
||||||
|
configurable: !0,
|
||||||
|
writable: !0
|
||||||
|
}),
|
||||||
|
e)
|
||||||
|
}
|
||||||
|
: function(e, t, n) {
|
||||||
|
return e[t] ? e : ((e[t] = n), e)
|
||||||
|
}),
|
||||||
|
r(n, 'defer', function() {
|
||||||
|
var e = {}
|
||||||
|
return (
|
||||||
|
(e.promise = new n(function(t, n) {
|
||||||
|
;(e.resolve = t), (e.reject = n)
|
||||||
|
})),
|
||||||
|
e
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
r(n.prototype, 'spread', function(e, t) {
|
||||||
|
return this.then(function(e) {
|
||||||
|
return n.all(e)
|
||||||
|
}).then(function(t) {
|
||||||
|
return 1 === t.length ? e(t[0]) : e.apply(this, t)
|
||||||
|
}, t)
|
||||||
|
}),
|
||||||
|
(e.exports = n)
|
||||||
|
}.call(t, n(1)))
|
||||||
|
},
|
||||||
|
function(e, t, n) {
|
||||||
|
'use strict'
|
||||||
|
;(function(t) {
|
||||||
|
function r() {
|
||||||
|
var e = new t.Uint8Array(16)
|
||||||
|
return t.crypto.getRandomValues(e), i.toHex(e.join(''), 40).slice(0, 40)
|
||||||
|
}
|
||||||
|
function s() {
|
||||||
|
for (var e = new Array(27), t = e.length; t--; )
|
||||||
|
e[t] = Math.floor(8 * Math.random())
|
||||||
|
return i.toHex(e.join(''), 40)
|
||||||
|
}
|
||||||
|
function o(e, n) {
|
||||||
|
if (e && 'string' == typeof e) return e
|
||||||
|
if (n) return u()
|
||||||
|
var r = t.localStorage.getItem(c)
|
||||||
|
return r || ((r = u()), t.localStorage.setItem(c, r)), r
|
||||||
|
}
|
||||||
|
var i = n(7),
|
||||||
|
a =
|
||||||
|
'function' == typeof t.Uint8Array &&
|
||||||
|
void 0 !== t.crypto &&
|
||||||
|
'function' == typeof t.crypto.getRandomValues,
|
||||||
|
u = a ? r : s,
|
||||||
|
c = '_spharmony_device_id'
|
||||||
|
e.exports = {
|
||||||
|
get: o,
|
||||||
|
generate: u,
|
||||||
|
generateWithCrypto: r,
|
||||||
|
generateWithRandom: s
|
||||||
|
}
|
||||||
|
}.call(t, n(1)))
|
||||||
|
},
|
||||||
|
function(e, t, n) {
|
||||||
|
'use strict'
|
||||||
|
function r(e, t, n) {
|
||||||
|
for (var r = 0, s = 0; s < e.length; ++s) {
|
||||||
|
var o = e[s] * t + r
|
||||||
|
;(e[s] = o % n), (r = ~~(o / n))
|
||||||
|
}
|
||||||
|
for (; r; ) e.push(r % n), (r = ~~(r / n))
|
||||||
|
}
|
||||||
|
function s(e, t, n, r) {
|
||||||
|
var s,
|
||||||
|
o,
|
||||||
|
i = 0
|
||||||
|
for (o = 0; o < t.length; ++o)
|
||||||
|
(s = ~~e[o] + t[o] * n + i), (e[o] = s % r), (i = ~~(s / r))
|
||||||
|
for (; i; ) (s = ~~e[o] + i), (e[o] = s % r), (i = ~~(s / r)), ++o
|
||||||
|
}
|
||||||
|
function o(e, t, n) {
|
||||||
|
for (var o = [0], i = [1], a = 0; a < e.length; ++a)
|
||||||
|
s(o, i, e[a], n), r(i, t, n)
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
function i(e, t) {
|
||||||
|
for (var n = [], r = 0; r < e.length; ++r) n.push(t[e[r]])
|
||||||
|
return n.reverse()
|
||||||
|
}
|
||||||
|
function a(e, t) {
|
||||||
|
for (; e.length < t; ) e.push(0)
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
var u = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',
|
||||||
|
c = {},
|
||||||
|
_ = {}
|
||||||
|
!(function() {
|
||||||
|
var e, t
|
||||||
|
for (e = 0, t = u.length; e < t; ++e) _[u[e]] = e
|
||||||
|
for (e = 0; e < 16; ++e) c['0123456789abcdef'[e]] = e
|
||||||
|
for (e = 0; e < 16; ++e) c['0123456789ABCDEF'[e]] = e
|
||||||
|
})(),
|
||||||
|
(e.exports = {
|
||||||
|
fromBytes: function(e, t) {
|
||||||
|
return i(a(o(e.slice(0).reverse(), 256, 62), t), u).join('')
|
||||||
|
},
|
||||||
|
toBytes: function(e, t) {
|
||||||
|
return a(o(i(e, _), 62, 256), t).reverse()
|
||||||
|
},
|
||||||
|
toHex: function(e, t) {
|
||||||
|
return i(a(o(i(e, _), 62, 16), t), u).join('')
|
||||||
|
},
|
||||||
|
fromHex: function(e, t) {
|
||||||
|
return i(a(o(i(e, c), 16, 62), t), u).join('')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
])
|
||||||
@@ -8,5 +8,8 @@
|
|||||||
"title": "Change!",
|
"title": "Change!",
|
||||||
"body": "{dev}, your turn"
|
"body": "{dev}, your turn"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"music": {
|
||||||
|
"loading": "loading..."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,5 +8,8 @@
|
|||||||
"title": "Changement !",
|
"title": "Changement !",
|
||||||
"body": "À votre tour {dev}."
|
"body": "À votre tour {dev}."
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"music": {
|
||||||
|
"loading": "loading..."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,11 @@ const routes: RouteConfig[] = [
|
|||||||
path: '/Privacy',
|
path: '/Privacy',
|
||||||
name: 'Privacy',
|
name: 'Privacy',
|
||||||
component: () => import('@/views/Privacy.vue')
|
component: () => import('@/views/Privacy.vue')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/spotify',
|
||||||
|
name: 'Spotify',
|
||||||
|
component: () => import('@/views/SpotifyCallback.vue')
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -7,8 +7,11 @@ Vue.use(Vuex)
|
|||||||
export interface State {
|
export interface State {
|
||||||
interval: number
|
interval: number
|
||||||
hasMusic: boolean
|
hasMusic: boolean
|
||||||
|
hasSpotify: boolean
|
||||||
dev1: string | null
|
dev1: string | null
|
||||||
dev2: string | null
|
dev2: string | null
|
||||||
|
accessToken: string | null
|
||||||
|
tokenExpire: Date | null
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RootActions extends ActionTree<State, State> {
|
export interface RootActions extends ActionTree<State, State> {
|
||||||
@@ -16,6 +19,8 @@ export interface RootActions extends ActionTree<State, State> {
|
|||||||
setHasMusic: (ctx: ActionContext<State, State>, payload: boolean) => void
|
setHasMusic: (ctx: ActionContext<State, State>, payload: boolean) => void
|
||||||
setDev1: (ctx: ActionContext<State, State>, payload: string) => void
|
setDev1: (ctx: ActionContext<State, State>, payload: string) => void
|
||||||
setDev2: (ctx: ActionContext<State, State>, payload: string) => void
|
setDev2: (ctx: ActionContext<State, State>, payload: string) => void
|
||||||
|
setAccessToken: (ctx: ActionContext<State, State>, payload: string) => void
|
||||||
|
setTokenExpire: (ctx: ActionContext<State, State>, payload: Date) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
const vuexLocal = new VuexPersistence<State>({
|
const vuexLocal = new VuexPersistence<State>({
|
||||||
@@ -25,21 +30,35 @@ const vuexLocal = new VuexPersistence<State>({
|
|||||||
|
|
||||||
const SET_INTERVAL = 'SET_INTERVAL'
|
const SET_INTERVAL = 'SET_INTERVAL'
|
||||||
const WITH_MUSIC = 'WITH_MUSIC'
|
const WITH_MUSIC = 'WITH_MUSIC'
|
||||||
|
const WITH_SPOTIFY = 'WITH_SPOTIFY'
|
||||||
const SET_DEV_1 = 'SET_DEV_1'
|
const SET_DEV_1 = 'SET_DEV_1'
|
||||||
const SET_DEV_2 = 'SET_DEV_2'
|
const SET_DEV_2 = 'SET_DEV_2'
|
||||||
|
const SET_ACCESS_TOKEN = 'SET_ACCESS_TOKEN'
|
||||||
|
const SET_TOKEN_EXPIRE = 'SET_TOKEN_EXPIRE'
|
||||||
|
|
||||||
const store = new Vuex.Store<State>({
|
const store = new Vuex.Store<State>({
|
||||||
state: {
|
state: {
|
||||||
interval: 5,
|
interval: 5,
|
||||||
hasMusic: false,
|
hasMusic: false,
|
||||||
|
hasSpotify: false,
|
||||||
dev1: null,
|
dev1: null,
|
||||||
dev2: null
|
dev2: null,
|
||||||
|
accessToken: null,
|
||||||
|
tokenExpire: null
|
||||||
},
|
},
|
||||||
getters: {
|
getters: {
|
||||||
interval: ({ interval }) => interval,
|
interval: ({ interval }) => interval,
|
||||||
hasMusic: ({ hasMusic }) => hasMusic,
|
hasMusic: ({ hasMusic }) => hasMusic,
|
||||||
|
hasSpotify: ({ hasSpotify }) => hasSpotify,
|
||||||
dev1: ({ dev1 }) => dev1,
|
dev1: ({ dev1 }) => dev1,
|
||||||
dev2: ({ dev2 }) => dev2
|
dev2: ({ dev2 }) => dev2,
|
||||||
|
accessToken: ({ accessToken }) => accessToken,
|
||||||
|
hasValidAccessToken: ({ accessToken, tokenExpire }) => {
|
||||||
|
if (!accessToken || !tokenExpire) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return new Date() < tokenExpire
|
||||||
|
}
|
||||||
},
|
},
|
||||||
mutations: {
|
mutations: {
|
||||||
[SET_INTERVAL](state, interval: number) {
|
[SET_INTERVAL](state, interval: number) {
|
||||||
@@ -48,11 +67,20 @@ const store = new Vuex.Store<State>({
|
|||||||
[WITH_MUSIC](state, hasMusic: boolean) {
|
[WITH_MUSIC](state, hasMusic: boolean) {
|
||||||
state.hasMusic = hasMusic
|
state.hasMusic = hasMusic
|
||||||
},
|
},
|
||||||
|
[WITH_SPOTIFY](state, hasSpotify: boolean) {
|
||||||
|
state.hasSpotify = hasSpotify
|
||||||
|
},
|
||||||
[SET_DEV_1](state, dev1: string) {
|
[SET_DEV_1](state, dev1: string) {
|
||||||
state.dev1 = dev1
|
state.dev1 = dev1
|
||||||
},
|
},
|
||||||
[SET_DEV_2](state, dev2: string) {
|
[SET_DEV_2](state, dev2: string) {
|
||||||
state.dev2 = dev2
|
state.dev2 = dev2
|
||||||
|
},
|
||||||
|
[SET_ACCESS_TOKEN](state, accessToken: string) {
|
||||||
|
state.accessToken = accessToken
|
||||||
|
},
|
||||||
|
[SET_TOKEN_EXPIRE](state, tokenExpire: Date) {
|
||||||
|
state.tokenExpire = tokenExpire
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
@@ -64,11 +92,20 @@ const store = new Vuex.Store<State>({
|
|||||||
setHasMusic({ commit }, hasMusic: boolean) {
|
setHasMusic({ commit }, hasMusic: boolean) {
|
||||||
commit(WITH_MUSIC, hasMusic)
|
commit(WITH_MUSIC, hasMusic)
|
||||||
},
|
},
|
||||||
|
setHasSpotify({ commit }, hasSpotify: boolean) {
|
||||||
|
commit(WITH_SPOTIFY, hasSpotify)
|
||||||
|
},
|
||||||
setDev1({ commit }, dev1: string) {
|
setDev1({ commit }, dev1: string) {
|
||||||
commit(SET_DEV_1, dev1)
|
commit(SET_DEV_1, dev1)
|
||||||
},
|
},
|
||||||
setDev2({ commit }, dev2: string) {
|
setDev2({ commit }, dev2: string) {
|
||||||
commit(SET_DEV_2, dev2)
|
commit(SET_DEV_2, dev2)
|
||||||
|
},
|
||||||
|
setAccessToken({ commit }, accessToken: string) {
|
||||||
|
commit(SET_ACCESS_TOKEN, accessToken)
|
||||||
|
},
|
||||||
|
setTokenExpire({ commit }, tokenExpire: Date) {
|
||||||
|
commit(SET_TOKEN_EXPIRE, tokenExpire)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
plugins: [vuexLocal.plugin]
|
plugins: [vuexLocal.plugin]
|
||||||
|
|||||||
@@ -60,3 +60,16 @@ a {
|
|||||||
.fade-leave-to {
|
.fade-leave-to {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@keyframes rotating {
|
||||||
|
from {
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
img.loader {
|
||||||
|
animation: rotating 4s linear infinite;
|
||||||
|
}
|
||||||
|
|||||||
16
src/views/SpotifyCallback.vue
Normal file
16
src/views/SpotifyCallback.vue
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<template>
|
||||||
|
<div class="spotify-callback"></div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent } from '@vue/composition-api'
|
||||||
|
import { useSpotifyConnect } from '../hooks/useSpotify'
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'SpotifyCallback',
|
||||||
|
setup(_, { root }) {
|
||||||
|
useSpotifyConnect(root.$router.currentRoute.hash)
|
||||||
|
root.$router.replace({ name: 'Home' })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
Reference in New Issue
Block a user