mirror of
https://github.com/janishutz/MusicPlayerV2.git
synced 2025-11-25 13:04:23 +00:00
some progress on player + playlist loading
This commit is contained in:
@@ -6,7 +6,7 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200">
|
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200">
|
||||||
<!-- TODO: Update URL -->
|
<!-- TODO: Update URL -->
|
||||||
<script src="/musickit.js"></script>
|
<script src="https://js-cdn.music.apple.com/musickit/v3/musickit.js"></script>
|
||||||
<title>MusicPlayer</title>
|
<title>MusicPlayer</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -1,10 +1,18 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<h1>Library</h1>
|
<h1>Library</h1>
|
||||||
<playlistsView></playlistsView>
|
<playlistsView :playlists="$props.playlists"></playlistsView>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import playlistsView from '@/components/playlistsView.vue';
|
import playlistsView from '@/components/playlistsView.vue';
|
||||||
|
|
||||||
|
defineProps( {
|
||||||
|
'playlists': {
|
||||||
|
'default': [],
|
||||||
|
'type': Array<any>,
|
||||||
|
'required': true,
|
||||||
|
}
|
||||||
|
} );
|
||||||
</script>
|
</script>
|
||||||
@@ -29,7 +29,7 @@
|
|||||||
|
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import playlistView from '@/components/playlistView.vue';
|
import playlistView from '@/components/playlistView.vue';
|
||||||
import MusicKitJSWrapper from '@/scripts/player';
|
import MusicKitJSWrapper from '@/scripts/music-player';
|
||||||
|
|
||||||
const isPlaying = ref( false );
|
const isPlaying = ref( false );
|
||||||
const repeatMode = ref( '' );
|
const repeatMode = ref( '' );
|
||||||
@@ -46,9 +46,9 @@
|
|||||||
isPlaying.value = !isPlaying.value;
|
isPlaying.value = !isPlaying.value;
|
||||||
// TODO: Execute function on player
|
// TODO: Execute function on player
|
||||||
if ( isPlaying.value ) {
|
if ( isPlaying.value ) {
|
||||||
player.play();
|
player.control( 'play' );
|
||||||
} else {
|
} else {
|
||||||
player.pause();
|
player.control( 'pause' );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,8 +85,28 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getPlaylists = ( cb: ( data: object ) => void ) => {
|
||||||
|
player.getUserPlaylists( cb );
|
||||||
|
}
|
||||||
|
|
||||||
|
const logIntoAppleMusic = () => {
|
||||||
|
player.logIn();
|
||||||
|
}
|
||||||
|
|
||||||
|
const getAuth = (): boolean[] => {
|
||||||
|
return player.getAuth();
|
||||||
|
}
|
||||||
|
|
||||||
|
const skipLogin = () => {
|
||||||
|
player.init();
|
||||||
|
}
|
||||||
|
|
||||||
defineExpose( {
|
defineExpose( {
|
||||||
|
logIntoAppleMusic,
|
||||||
|
getPlaylists,
|
||||||
controlUI,
|
controlUI,
|
||||||
|
getAuth,
|
||||||
|
skipLogin,
|
||||||
} );
|
} );
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,18 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<h3>Your playlists</h3>
|
<h3>Your playlists</h3>
|
||||||
|
<div v-for="pl in $props.playlists" v-bind:key="pl.id">
|
||||||
|
{{ pl.attributes.name }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
const props = defineProps( {
|
||||||
|
'playlists': {
|
||||||
|
'default': [],
|
||||||
|
'type': Array<any>,
|
||||||
|
'required': true,
|
||||||
|
}
|
||||||
|
} )
|
||||||
|
</script>
|
||||||
361
MusicPlayerV2-GUI/src/scripts/music-player.ts
Normal file
361
MusicPlayerV2-GUI/src/scripts/music-player.ts
Normal file
@@ -0,0 +1,361 @@
|
|||||||
|
type Origin = 'apple-music' | 'disk';
|
||||||
|
|
||||||
|
interface Song {
|
||||||
|
/**
|
||||||
|
* The ID. Either the apple music ID, or if from local disk, an ID starting in local_
|
||||||
|
*/
|
||||||
|
id: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Origin of the song
|
||||||
|
*/
|
||||||
|
origin: Origin;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The cover image as a URL
|
||||||
|
*/
|
||||||
|
cover: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The artist of the song
|
||||||
|
*/
|
||||||
|
artist: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the song
|
||||||
|
*/
|
||||||
|
title: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Duration of the song in milliseconds
|
||||||
|
*/
|
||||||
|
duration: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (OPTIONAL) The genres this song belongs to. Can be displayed on the showcase screen, but requires settings there
|
||||||
|
*/
|
||||||
|
genres?: string[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (OPTIONAL) This will be displayed in brackets on the showcase screens
|
||||||
|
*/
|
||||||
|
additionalInfo?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Config {
|
||||||
|
devToken: string;
|
||||||
|
userToken: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
type ControlAction = 'play' | 'pause' | 'next' | 'previous' | 'skip-10' | 'back-10';
|
||||||
|
type RepeatMode = 'off' | 'once' | 'all';
|
||||||
|
|
||||||
|
class MusicKitJSWrapper {
|
||||||
|
playingSongID: number;
|
||||||
|
playlist: Song[];
|
||||||
|
queue: number[];
|
||||||
|
config: Config;
|
||||||
|
musicKit: any;
|
||||||
|
isLoggedIn: boolean;
|
||||||
|
isPreparedToPlay: boolean;
|
||||||
|
repeatMode: RepeatMode;
|
||||||
|
isShuffleEnabled: boolean;
|
||||||
|
hasEncounteredAuthError: boolean;
|
||||||
|
|
||||||
|
constructor () {
|
||||||
|
this.playingSongID = 0;
|
||||||
|
this.playlist = [];
|
||||||
|
this.queue = [];
|
||||||
|
this.config = {
|
||||||
|
devToken: '',
|
||||||
|
userToken: '',
|
||||||
|
};
|
||||||
|
this.isShuffleEnabled = false;
|
||||||
|
this.repeatMode = 'off';
|
||||||
|
this.isPreparedToPlay = false;
|
||||||
|
this.isLoggedIn = false;
|
||||||
|
this.hasEncounteredAuthError = false;
|
||||||
|
|
||||||
|
const self = this;
|
||||||
|
|
||||||
|
if ( !window.MusicKit ) {
|
||||||
|
document.addEventListener( 'musickitloaded', () => {
|
||||||
|
self.init();
|
||||||
|
} );
|
||||||
|
} else {
|
||||||
|
this.init();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log a user into Apple Music. Will automatically initialize MusicKitJS, once user is logged in
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
logIn (): void {
|
||||||
|
if ( !this.musicKit.isAuthorized ) {
|
||||||
|
this.musicKit.authorize().then( () => {
|
||||||
|
this.isLoggedIn = true;
|
||||||
|
this.init();
|
||||||
|
} ).catch( () => {
|
||||||
|
this.hasEncounteredAuthError = true;
|
||||||
|
} );
|
||||||
|
} else {
|
||||||
|
this.musicKit.authorize().then( () => {
|
||||||
|
this.isLoggedIn = true;
|
||||||
|
this.init();
|
||||||
|
} ).catch( () => {
|
||||||
|
this.hasEncounteredAuthError = true;
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize MusicKitJS. Should not be called. Use logIn instead, which first tries to log the user in, then calls this method.
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
init (): void {
|
||||||
|
fetch( localStorage.getItem( 'url' ) + '/getAppleMusicDevToken', { credentials: 'include' } ).then( res => {
|
||||||
|
if ( res.status === 200 ) {
|
||||||
|
res.text().then( token => {
|
||||||
|
// MusicKit global is now defined
|
||||||
|
MusicKit.configure( {
|
||||||
|
developerToken: token,
|
||||||
|
app: {
|
||||||
|
name: 'MusicPlayer',
|
||||||
|
build: '3'
|
||||||
|
},
|
||||||
|
storefrontId: 'CH',
|
||||||
|
} ).then( () => {
|
||||||
|
this.config.devToken = token;
|
||||||
|
this.musicKit = MusicKit.getInstance();
|
||||||
|
if ( this.musicKit.isAuthorized ) {
|
||||||
|
this.isLoggedIn = true;
|
||||||
|
this.config.userToken = this.musicKit.musicUserToken;
|
||||||
|
}
|
||||||
|
this.musicKit.shuffleMode = MusicKit.PlayerShuffleMode.off;
|
||||||
|
} );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the authentication status of the user
|
||||||
|
* @returns {boolean[]} Returns an array, where the first element indicates login status, the second one, if an error was encountered
|
||||||
|
*/
|
||||||
|
getAuth (): boolean[] {
|
||||||
|
return [ this.isLoggedIn, this.hasEncounteredAuthError ];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request data from the Apple Music API
|
||||||
|
* @param {string} url The URL at the Apple Music API to call (including protocol and url)
|
||||||
|
* @param {( data: object ) => void} callback A callback function that takes the data and returns nothing
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
apiGetRequest ( url: string, callback: ( data: object ) => void ): void {
|
||||||
|
if ( this.config.devToken != '' && this.config.userToken != '' ) {
|
||||||
|
fetch( url, {
|
||||||
|
method: 'GET',
|
||||||
|
headers: {
|
||||||
|
'Authorization': `Bearer ${ this.config.devToken }`,
|
||||||
|
'Music-User-Token': this.config.userToken
|
||||||
|
}
|
||||||
|
} ).then( res => {
|
||||||
|
if ( res.status === 200 ) {
|
||||||
|
res.json().then( json => {
|
||||||
|
try {
|
||||||
|
callback( { 'status': 'ok', 'data': json } );
|
||||||
|
} catch( err ) { /* empty */}
|
||||||
|
} );
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
callback( { 'status': 'error', 'error': res.status } );
|
||||||
|
} catch( err ) { /* empty */}
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
} else return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the playlist to play
|
||||||
|
* @param {Song[]} playlist The playlist as an array of songs
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
setPlaylist ( playlist: Song[] ): void {
|
||||||
|
this.playlist = playlist;
|
||||||
|
this.setShuffle( this.isShuffleEnabled );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepare a specific song in the queue for playing and start playing
|
||||||
|
* @param {number} playlistID The ID of the song in the playlist to prepare to play
|
||||||
|
* @returns {boolean} Returns true, if successful, false, if playlist is missing / empty. Set that first
|
||||||
|
*/
|
||||||
|
prepare ( playlistID: number ): boolean {
|
||||||
|
if ( this.playlist.length > 0 ) {
|
||||||
|
this.playingSongID = playlistID;
|
||||||
|
this.isPreparedToPlay = true;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Control the player
|
||||||
|
* @param {ControlAction} action Action to take on the player
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
control ( action: ControlAction ): void {
|
||||||
|
switch ( action ) {
|
||||||
|
case "play":
|
||||||
|
if ( this.isPreparedToPlay ) {
|
||||||
|
if ( this.playlist[ this.playingSongID ].origin === 'apple-music' ) {
|
||||||
|
this.musicKit.play();
|
||||||
|
} else {
|
||||||
|
// TODO: Implement
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "pause":
|
||||||
|
if ( this.isPreparedToPlay ) {
|
||||||
|
if ( this.playlist[ this.playingSongID ].origin === 'apple-music' ) {
|
||||||
|
this.musicKit.pause();
|
||||||
|
} else {
|
||||||
|
// TODO: Implement
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "back-10":
|
||||||
|
if ( this.playlist[ this.playingSongID ].origin === 'apple-music' ) {
|
||||||
|
this.musicKit.seekToTime( this.musicKit.currentPlaybackTime > 10 ? this.musicKit.currentPlaybackTime - 10 : 0 );
|
||||||
|
} else {
|
||||||
|
// TODO: Implement
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "skip-10":
|
||||||
|
if ( this.playlist[ this.playingSongID ].origin === 'apple-music' ) {
|
||||||
|
if ( this.musicKit.currentPlaybackTime < ( this.playlist[ this.playingSongID ].duration - 10 ) ) {
|
||||||
|
this.musicKit.seekToTime( this.musicKit.currentPlaybackTime + 10 );
|
||||||
|
} else {
|
||||||
|
if ( this.repeatMode !== 'once' ) {
|
||||||
|
this.control( 'next' );
|
||||||
|
} else {
|
||||||
|
this.musicKit.seekToTime( 0 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// TODO: Finish
|
||||||
|
// if ( this.audioPlayer.currentTime < ( this.playlist[ this.playingSongID ].duration - 10 ) ) {
|
||||||
|
// this.audioPlayer.currentTime = this.audioPlayer.currentTime + 10;
|
||||||
|
// this.pos = this.audioPlayer.currentTime;
|
||||||
|
// this.sendUpdate( 'pos' );
|
||||||
|
// } else {
|
||||||
|
// if ( this.repeatMode !== 'one' ) {
|
||||||
|
// this.control( 'next' );
|
||||||
|
// } else {
|
||||||
|
// this.audioPlayer.currentTime = 0;
|
||||||
|
// this.pos = this.audioPlayer.currentTime;
|
||||||
|
// this.sendUpdate( 'pos' );
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "next":
|
||||||
|
//
|
||||||
|
break;
|
||||||
|
case "previous":
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setShuffle ( enabled: boolean ) {
|
||||||
|
this.isShuffleEnabled = enabled;
|
||||||
|
// TODO: Shuffle playlist
|
||||||
|
}
|
||||||
|
|
||||||
|
setRepeatMode ( mode: RepeatMode ) {
|
||||||
|
this.repeatMode = mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
goToPos ( pos: number ) {
|
||||||
|
if ( this.playlist[ this.playingSongID ].origin === 'apple-music' ) {
|
||||||
|
this.musicKit.seekToTime( pos );
|
||||||
|
} else {
|
||||||
|
// TODO: Implement
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the current position of the play heed. Will return in ms since start of the song
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
getPlaybackPos (): number {
|
||||||
|
if ( this.playlist[ this.playingSongID ].origin === 'apple-music' ) {
|
||||||
|
return this.musicKit.currentPlaybackTime;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
// TODO: Implement
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get details on the currently playing song
|
||||||
|
* @returns {Song}
|
||||||
|
*/
|
||||||
|
getPlayingSong (): Song {
|
||||||
|
return this.playlist[ this.playingSongID ];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the playlist index of the currently playing song
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
getPlayingSongID (): number {
|
||||||
|
return this.playingSongID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the full playlist, as it is set currently, not ordered by queue settings, but as passed in originally
|
||||||
|
* @returns {Song[]}
|
||||||
|
*/
|
||||||
|
getPlaylist (): Song[] {
|
||||||
|
return this.playlist;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as getPlaylist, but returns a ordered playlist, by how it will play according to the queue.
|
||||||
|
* @returns {Song[]}
|
||||||
|
*/
|
||||||
|
getQueue (): Song[] {
|
||||||
|
const data = [];
|
||||||
|
for ( const el in this.queue ) {
|
||||||
|
data.push( this.playlist[ this.queue[ el ] ] );
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all playlists the authenticated user has on Apple Music. Only available once the user has authenticated!
|
||||||
|
* @param {( data: object ) => void} cb The callback function called with the results from the API
|
||||||
|
* @returns {boolean} Returns true, if user is authenticated and request was started, false if not.
|
||||||
|
*/
|
||||||
|
getUserPlaylists ( cb: ( data: object ) => void ): boolean {
|
||||||
|
if ( this.isLoggedIn ) {
|
||||||
|
this.apiGetRequest( 'https://api.music.apple.com/v1/me/library/playlists', cb );
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// findSongOnAppleMusic ( searchTerm: string ): Song => {
|
||||||
|
// TODO: Implement
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MusicKitJSWrapper;
|
||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// IMPORTANT: Old, unfinished version that doesn't ship! See ./music-player.ts for the actual code!
|
||||||
|
|
||||||
|
|
||||||
type Origin = 'apple-music' | 'disk';
|
type Origin = 'apple-music' | 'disk';
|
||||||
|
|
||||||
interface Song {
|
interface Song {
|
||||||
|
|||||||
@@ -1,13 +1,15 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="app-view">
|
<div class="app-view">
|
||||||
<div class="home-view" v-if="isLoggedIntoAppleMusic">
|
<div class="home-view" v-if="isLoggedIntoAppleMusic">
|
||||||
<libraryView class="library-view"></libraryView>
|
<libraryView class="library-view" :playlists="playlists"></libraryView>
|
||||||
<playerView :class="'player-view' + ( isShowingFullScreenPlayer ? ' full-screen-player' : '' )" @player-state-change="( state ) => { handlePlayerStateChange( state ) }"></playerView>
|
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="login-view">
|
<div v-else class="login-view">
|
||||||
<img src="@/assets/appleMusicIcon.svg" alt="Apple Music Icon">
|
<img src="@/assets/appleMusicIcon.svg" alt="Apple Music Icon">
|
||||||
<button class="fancy-button" style="margin-top: 20px;">Log into Apple Music</button>
|
<button class="fancy-button" style="margin-top: 20px;" @click="logIntoAppleMusic()">Log into Apple Music</button>
|
||||||
|
<button class="fancy-button" title="This allows you to use local playlists only. Cover images for your songs will be fetched from the apple music api as good as possible" @click="skipLogin()">Continue without logging in</button>
|
||||||
</div>
|
</div>
|
||||||
|
<playerView :class="'player-view' + ( isLoggedIntoAppleMusic ? ( isShowingFullScreenPlayer ? ' full-screen-player' : '' ) : ' player-hidden' )" @player-state-change="( state ) => { handlePlayerStateChange( state ) }"
|
||||||
|
ref="player"></playerView>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -16,8 +18,10 @@
|
|||||||
import libraryView from '@/components/libraryView.vue';
|
import libraryView from '@/components/libraryView.vue';
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
|
|
||||||
const isLoggedIntoAppleMusic = ref( true );
|
const isLoggedIntoAppleMusic = ref( false );
|
||||||
const isShowingFullScreenPlayer = ref( false );
|
const isShowingFullScreenPlayer = ref( false );
|
||||||
|
const player = ref( playerView );
|
||||||
|
const playlists = ref( [] );
|
||||||
|
|
||||||
const handlePlayerStateChange = ( newState: string ) => {
|
const handlePlayerStateChange = ( newState: string ) => {
|
||||||
if ( newState === 'hide' ) {
|
if ( newState === 'hide' ) {
|
||||||
@@ -26,21 +30,44 @@
|
|||||||
isShowingFullScreenPlayer.value = true;
|
isShowingFullScreenPlayer.value = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let loginChecker = 0;
|
||||||
|
|
||||||
|
const logIntoAppleMusic = () => {
|
||||||
|
loginChecker = setInterval( () => {
|
||||||
|
if ( player.value.getAuth()[ 0 ] ) {
|
||||||
|
isLoggedIntoAppleMusic.value = true;
|
||||||
|
player.value.getPlaylists( ( data ) => {
|
||||||
|
console.log( data.data.data );
|
||||||
|
playlists.value = data.data.data;
|
||||||
|
} );
|
||||||
|
clearInterval( loginChecker );
|
||||||
|
} else if ( player.value.getAuth()[ 1 ] ) {
|
||||||
|
clearInterval( loginChecker );
|
||||||
|
alert( 'An error occurred when logging you in. Please try again!' );
|
||||||
|
}
|
||||||
|
}, 500 );
|
||||||
|
}
|
||||||
|
|
||||||
|
const skipLogin = () => {
|
||||||
|
isLoggedIntoAppleMusic.value = true;
|
||||||
|
player.value.skipLogin();
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.library-view {
|
.library-view {
|
||||||
height: calc( 90vh - 10px );
|
height: calc( 90vh - 10px );
|
||||||
width: 100vw;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-view {
|
.app-view {
|
||||||
height: 100vh;
|
height: 100%;
|
||||||
width: 100vw;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.home-view {
|
.home-view {
|
||||||
height: 100vh;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.login-view {
|
.login-view {
|
||||||
@@ -71,4 +98,8 @@
|
|||||||
left: 0;
|
left: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.player-hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
17
backend/dist/app.js
vendored
17
backend/dist/app.js
vendored
@@ -24,15 +24,16 @@ const run = () => {
|
|||||||
// sign dev token
|
// sign dev token
|
||||||
const privateKey = fs_1.default.readFileSync(path_1.default.join(__dirname + '/config/apple_private_key.p8')).toString();
|
const privateKey = fs_1.default.readFileSync(path_1.default.join(__dirname + '/config/apple_private_key.p8')).toString();
|
||||||
// TODO: Remove secret
|
// TODO: Remove secret
|
||||||
const config = JSON.parse('' + fs_1.default.readFileSync(path_1.default.join(__dirname + '/config/apple-music-api.config.json')));
|
const config = JSON.parse('' + fs_1.default.readFileSync(path_1.default.join(__dirname + '/config/apple-music-api.config.secret.json')));
|
||||||
const jwtToken = jsonwebtoken_1.default.sign({}, privateKey, {
|
const now = new Date().getTime();
|
||||||
|
const tomorrow = now + 24 * 3600 * 1000;
|
||||||
|
const jwtToken = jsonwebtoken_1.default.sign({
|
||||||
|
'iss': config.teamID,
|
||||||
|
'iat': Math.floor(now / 1000),
|
||||||
|
'exp': Math.floor(tomorrow / 1000),
|
||||||
|
}, privateKey, {
|
||||||
algorithm: "ES256",
|
algorithm: "ES256",
|
||||||
expiresIn: "180d",
|
keyid: config.keyID
|
||||||
issuer: config.teamID,
|
|
||||||
header: {
|
|
||||||
alg: "ES256",
|
|
||||||
kid: config.keyID
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
res.send(jwtToken);
|
res.send(jwtToken);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -26,15 +26,16 @@ const run = () => {
|
|||||||
// sign dev token
|
// sign dev token
|
||||||
const privateKey = fs.readFileSync( path.join( __dirname + '/config/apple_private_key.p8' ) ).toString();
|
const privateKey = fs.readFileSync( path.join( __dirname + '/config/apple_private_key.p8' ) ).toString();
|
||||||
// TODO: Remove secret
|
// TODO: Remove secret
|
||||||
const config = JSON.parse( '' + fs.readFileSync( path.join( __dirname + '/config/apple-music-api.config.json' ) ) );
|
const config = JSON.parse( '' + fs.readFileSync( path.join( __dirname + '/config/apple-music-api.config.secret.json' ) ) );
|
||||||
const jwtToken = jwt.sign( {}, privateKey, {
|
const now = new Date().getTime();
|
||||||
|
const tomorrow = now + 24 * 3600 * 1000;
|
||||||
|
const jwtToken = jwt.sign( {
|
||||||
|
'iss': config.teamID,
|
||||||
|
'iat': Math.floor( now / 1000 ),
|
||||||
|
'exp': Math.floor( tomorrow / 1000 ),
|
||||||
|
}, privateKey, {
|
||||||
algorithm: "ES256",
|
algorithm: "ES256",
|
||||||
expiresIn: "180d",
|
keyid: config.keyID
|
||||||
issuer: config.teamID,
|
|
||||||
header: {
|
|
||||||
alg: "ES256",
|
|
||||||
kid: config.keyID
|
|
||||||
}
|
|
||||||
} );
|
} );
|
||||||
res.send( jwtToken );
|
res.send( jwtToken );
|
||||||
} );
|
} );
|
||||||
|
|||||||
Reference in New Issue
Block a user