mirror of
https://github.com/janishutz/MusicPlayerV2.git
synced 2025-11-26 21:34:23 +00:00
technically working player
This commit is contained in:
@@ -1,13 +1,19 @@
|
||||
<template>
|
||||
<div>
|
||||
<h1>Library</h1>
|
||||
<playlistsView :playlists="$props.playlists"></playlistsView>
|
||||
<playlistsView :playlists="$props.playlists" @selected-playlist="( id ) => selectPlaylist( id )"></playlistsView>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import playlistsView from '@/components/playlistsView.vue';
|
||||
|
||||
const emits = defineEmits( [ 'selected-playlist' ] );
|
||||
|
||||
const selectPlaylist = ( id: string ) => {
|
||||
emits( 'selected-playlist', id );
|
||||
}
|
||||
|
||||
defineProps( {
|
||||
'playlists': {
|
||||
'default': [],
|
||||
|
||||
@@ -2,8 +2,10 @@
|
||||
<div>
|
||||
<div :class="'player' + ( isShowingFullScreenPlayer ? '' : ' player-hidden' )">
|
||||
<!-- TODO: Make cover art of song or otherwise MusicPlayer Logo -->
|
||||
<img src="https://github.com/simplePCBuilding/MusicPlayerV2/raw/master/assets/logo.png" alt="MusicPlayer Logo" class="logo-player" @click="controlUI( 'show' )">
|
||||
<img src="https://github.com/simplePCBuilding/MusicPlayerV2/raw/master/assets/logo.png" alt="MusicPlayer Logo" class="logo-player" @click="controlUI( 'show' )" v-if="coverArt === ''">
|
||||
<img :src="coverArt" alt="MusicPlayer Logo" class="logo-player" @click="controlUI( 'show' )" v-else>
|
||||
<p class="song-name" @click="controlUI( 'show' )">{{ currentlyPlayingSongName }}</p>
|
||||
<p>{{ nicePlaybackPos }} / {{ niceDuration }}</p>
|
||||
<div class="controls-wrapper">
|
||||
<span class="material-symbols-outlined controls next-previous" @click="control( 'previous' )" id="previous">skip_previous</span>
|
||||
<span class="material-symbols-outlined controls forward-back" @click="control( 'back' )" :style="'rotate: -' + 360 * clickCountBack + 'deg;'">replay_10</span>
|
||||
@@ -18,7 +20,7 @@
|
||||
</div>
|
||||
<div :class="'playlist-view' + ( isShowingFullScreenPlayer ? '' : ' hidden' )">
|
||||
<span class="material-symbols-outlined close-fullscreen" @click="controlUI( 'hide' )">close</span>
|
||||
<playlistView></playlistView>
|
||||
<playlistView :playlist="playlist" class="pl-wrapper"></playlistView>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -27,9 +29,10 @@
|
||||
<script setup lang="ts">
|
||||
// TODO: Handle resize, hide all non-essential controls when below 900px width
|
||||
|
||||
import { ref } from 'vue';
|
||||
import { ref, type Ref } from 'vue';
|
||||
import playlistView from '@/components/playlistView.vue';
|
||||
import MusicKitJSWrapper from '@/scripts/music-player';
|
||||
import type { Song } from '@/scripts/song';
|
||||
|
||||
const isPlaying = ref( false );
|
||||
const repeatMode = ref( '' );
|
||||
@@ -39,6 +42,11 @@
|
||||
const clickCountBack = ref( 0 );
|
||||
const isShowingFullScreenPlayer = ref( false );
|
||||
const player = new MusicKitJSWrapper();
|
||||
const playlist: Ref<Song[]> = ref( [] );
|
||||
const coverArt = ref( '' );
|
||||
const nicePlaybackPos = ref( '' );
|
||||
const niceDuration = ref( '' );
|
||||
const isShowingRemainingTime = ref( false );
|
||||
|
||||
const emits = defineEmits( [ 'playerStateChange' ] );
|
||||
|
||||
@@ -47,8 +55,10 @@
|
||||
// TODO: Execute function on player
|
||||
if ( isPlaying.value ) {
|
||||
player.control( 'play' );
|
||||
startProgressTracker();
|
||||
} else {
|
||||
player.control( 'pause' );
|
||||
stopProgressTracker();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,21 +66,44 @@
|
||||
if ( action === 'repeat' ) {
|
||||
if ( repeatMode.value === '' ) {
|
||||
repeatMode.value = '_on';
|
||||
player.setRepeatMode( 'all' );
|
||||
} else if ( repeatMode.value === '_on' ) {
|
||||
repeatMode.value = '_one_on';
|
||||
player.setRepeatMode( 'once' );
|
||||
} else {
|
||||
repeatMode.value = '';
|
||||
player.setRepeatMode( 'off' );
|
||||
}
|
||||
} else if ( action === 'shuffle' ) {
|
||||
if ( shuffleMode.value === '' ) {
|
||||
shuffleMode.value = '_on';
|
||||
player.setShuffle( true );
|
||||
} else {
|
||||
shuffleMode.value = '';
|
||||
player.setShuffle( false );
|
||||
}
|
||||
} else if ( action === 'forward' ) {
|
||||
clickCountForward.value += 1;
|
||||
player.control( 'skip-10' );
|
||||
} else if ( action === 'back' ) {
|
||||
clickCountBack.value += 1;
|
||||
player.control( 'back-10' );
|
||||
} else if ( action === 'next' ) {
|
||||
stopProgressTracker();
|
||||
player.control( 'next' );
|
||||
currentlyPlayingSongName.value = 'Loading...';
|
||||
setTimeout( () => {
|
||||
getDetails();
|
||||
startProgressTracker();
|
||||
}, 2000 );
|
||||
} else if ( action === 'previous' ) {
|
||||
stopProgressTracker();
|
||||
player.control( 'previous' );
|
||||
currentlyPlayingSongName.value = 'Loading...';
|
||||
setTimeout( () => {
|
||||
getDetails();
|
||||
startProgressTracker();
|
||||
}, 2000 );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,12 +134,87 @@
|
||||
player.init();
|
||||
}
|
||||
|
||||
const selectPlaylist = ( id: string ) => {
|
||||
currentlyPlayingSongName.value = 'Loading...';
|
||||
player.setPlaylistByID( id ).then( () => {
|
||||
isPlaying.value = true;
|
||||
setTimeout( () => {
|
||||
startProgressTracker();
|
||||
getDetails();
|
||||
}, 2000 );
|
||||
} );
|
||||
}
|
||||
|
||||
const getDetails = () => {
|
||||
const details = player.getPlayingSong();
|
||||
currentlyPlayingSongName.value = details.title;
|
||||
coverArt.value = details.cover;
|
||||
// console.log( player.getQueue() );
|
||||
playlist.value = player.getPlaylist();
|
||||
}
|
||||
|
||||
|
||||
let progressTracker = 0;
|
||||
const startProgressTracker = () => {
|
||||
const playingSong = player.getPlayingSong();
|
||||
const minuteCounts = Math.floor( ( playingSong.duration ) / 60 );
|
||||
niceDuration.value = String( minuteCounts ) + ':';
|
||||
if ( ( '' + minuteCounts ).length === 1 ) {
|
||||
niceDuration.value = '0' + minuteCounts + ':';
|
||||
}
|
||||
const secondCounts = Math.floor( ( playingSong.duration ) - minuteCounts * 60 );
|
||||
if ( ( '' + secondCounts ).length === 1 ) {
|
||||
niceDuration.value += '0' + secondCounts;
|
||||
} else {
|
||||
niceDuration.value += secondCounts;
|
||||
}
|
||||
progressTracker = setInterval( () => {
|
||||
const pos = player.getPlaybackPos();
|
||||
if ( pos > playingSong.duration - 1 ) {
|
||||
control( 'next' );
|
||||
}
|
||||
|
||||
const minuteCount = Math.floor( pos / 60 );
|
||||
nicePlaybackPos.value = minuteCount + ':';
|
||||
if ( ( '' + minuteCount ).length === 1 ) {
|
||||
nicePlaybackPos.value = '0' + minuteCount + ':';
|
||||
}
|
||||
const secondCount = Math.floor( pos - minuteCount * 60 );
|
||||
if ( ( '' + secondCount ).length === 1 ) {
|
||||
nicePlaybackPos.value += '0' + secondCount;
|
||||
} else {
|
||||
nicePlaybackPos.value += secondCount;
|
||||
}
|
||||
|
||||
if ( isShowingRemainingTime.value ) {
|
||||
const minuteCounts = Math.floor( ( playingSong.duration - pos ) / 60 );
|
||||
niceDuration.value = '-' + String( minuteCounts ) + ':';
|
||||
if ( ( '' + minuteCounts ).length === 1 ) {
|
||||
niceDuration.value = '-0' + minuteCounts + ':';
|
||||
}
|
||||
const secondCounts = Math.floor( ( playingSong.duration - pos ) - minuteCounts * 60 );
|
||||
if ( ( '' + secondCounts ).length === 1 ) {
|
||||
niceDuration.value += '0' + secondCounts;
|
||||
} else {
|
||||
niceDuration.value += secondCounts;
|
||||
}
|
||||
}
|
||||
}, 50 );
|
||||
}
|
||||
|
||||
const stopProgressTracker = () => {
|
||||
try {
|
||||
clearInterval( progressTracker );
|
||||
} catch ( _ ) { /* empty */ }
|
||||
}
|
||||
|
||||
defineExpose( {
|
||||
logIntoAppleMusic,
|
||||
getPlaylists,
|
||||
controlUI,
|
||||
getAuth,
|
||||
skipLogin,
|
||||
selectPlaylist,
|
||||
} );
|
||||
</script>
|
||||
|
||||
@@ -141,7 +249,6 @@
|
||||
}
|
||||
|
||||
.playlist-view {
|
||||
height: 15%;
|
||||
overflow: scroll;
|
||||
}
|
||||
|
||||
@@ -214,4 +321,8 @@
|
||||
.hidden .close-fullscreen {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.pl-wrapper {
|
||||
height: 80vh;
|
||||
}
|
||||
</style>
|
||||
@@ -1,5 +1,50 @@
|
||||
<template>
|
||||
<div>
|
||||
<h1>Playlist</h1>
|
||||
<div class="playlist-box">
|
||||
<div class="song" v-for="song in $props.playlist" v-bind:key="song.id">
|
||||
<img :src="song.cover" alt="Song cover" class="song-cover">
|
||||
<h3 class="song-title">{{ song.title }}</h3>
|
||||
<p class="playing-in">playing in</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { Song } from '@/scripts/song';
|
||||
|
||||
defineProps( {
|
||||
'playlist': {
|
||||
default: [],
|
||||
required: true,
|
||||
type: Array<Song>
|
||||
}
|
||||
} );
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.playlist-box {
|
||||
height: 80vh !important;
|
||||
}
|
||||
|
||||
.song {
|
||||
border: solid var( --primary-color ) 1px;
|
||||
padding: 10px;
|
||||
margin: 5px;
|
||||
width: 50%;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.song-title {
|
||||
margin-left: 10px;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.song-cover {
|
||||
height: 70px;
|
||||
}
|
||||
</style>
|
||||
@@ -1,18 +1,58 @@
|
||||
<template>
|
||||
<div>
|
||||
<h3>Your playlists</h3>
|
||||
<div v-for="pl in $props.playlists" v-bind:key="pl.id">
|
||||
{{ pl.attributes.name }}
|
||||
<div class="playlists">
|
||||
<h3 style="width: fit-content;">Your playlists</h3>
|
||||
<div v-if="$props.playlists ? $props.playlists.length < 1 : true">
|
||||
loading...
|
||||
<!-- TODO: Make prettier -->
|
||||
</div>
|
||||
<div class="playlist-wrapper">
|
||||
<div v-for="pl in $props.playlists" v-bind:key="pl.id" class="playlist" @click="selectPlaylist( pl.id )">
|
||||
{{ pl.attributes.name }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const props = defineProps( {
|
||||
defineProps( {
|
||||
'playlists': {
|
||||
'default': [],
|
||||
'type': Array<any>,
|
||||
'required': true,
|
||||
}
|
||||
} )
|
||||
</script>
|
||||
} );
|
||||
|
||||
const emits = defineEmits( [ 'selected-playlist' ] );
|
||||
|
||||
const selectPlaylist = ( id: string ) => {
|
||||
emits( 'selected-playlist', id );
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.playlists {
|
||||
width: 100%;
|
||||
height: 75vh;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.playlist-wrapper {
|
||||
width: 85%;
|
||||
overflow-y: scroll;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.playlist {
|
||||
width: 100%;
|
||||
padding: 15px;
|
||||
border: solid var( --primary-color ) 1px;
|
||||
border-radius: 5px;
|
||||
margin: 1px;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user