some marketing + other changes & fixes

This commit is contained in:
2024-07-21 08:21:09 +02:00
parent 221ae67ec2
commit a5e2520d28
9 changed files with 84 additions and 33 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -1,7 +1,7 @@
<!-- eslint-disable no-undef --> <!-- eslint-disable no-undef -->
<template> <template>
<div id="notifications"> <div id="notifications">
<div class="message-box" :class="[ location, size ]"> <div class="message-box" :class="[ location, size ]" :style="'z-index: ' + ( messageType === 'hide' ? '-1' : '1000' )">
<div class="message-container" :class="messageType"> <div class="message-container" :class="messageType">
<button @click="handleNotifications();" class="close-notification"><span class="material-symbols-outlined close-notification-icon">close</span></button> <button @click="handleNotifications();" class="close-notification"><span class="material-symbols-outlined close-notification-icon">close</span></button>
<span class="material-symbols-outlined types hide" v-if="messageType == 'hide'">question_mark</span> <span class="material-symbols-outlined types hide" v-if="messageType == 'hide'">question_mark</span>
@@ -150,15 +150,11 @@
notificationTimeout = setTimeout( () => { notificationTimeout = setTimeout( () => {
handleNotifications(); handleNotifications();
}, notifications.value[ currentDID.value ].showDuration * 1000 ); }, notifications.value[ currentDID.value ].showDuration * 1000 );
// eslint-disable-next-line no-undef
$( '.message-box' ).css( 'z-index', 1000 );
} else { } else {
try { try {
clearInterval( progressBar ); clearInterval( progressBar );
} catch (err) { /* empty */ } } catch (err) { /* empty */ }
messageType.value = 'hide'; messageType.value = 'hide';
// eslint-disable-next-line no-undef
$( '.message-box' ).css( 'z-index', -1 );
} }
} }
@@ -185,7 +181,7 @@
<style scoped> <style scoped>
.message-box { .message-box {
position: fixed; position: fixed;
z-index: -1; z-index: -100;
color: white; color: white;
transition: all 0.5s; transition: all 0.5s;
width: 95vw; width: 95vw;

View File

@@ -24,7 +24,7 @@
</div> </div>
</div> </div>
</div> </div>
<div :class="'controls-wrapper' + ( isShowingFullScreenPlayer ? ' full-screen' : '' )"> <div :class="'controls-wrapper' + ( isShowingFullScreenPlayer ? ' full-screen' : '' )" :style="playlist.length > 0 ? '' : 'pointer-events: none'">
<div class="main-controls"> <div class="main-controls">
<span class="material-symbols-outlined controls next-previous" @click="control( 'previous' )" id="previous" v-if="isShowingFullScreenPlayer">skip_previous</span> <span class="material-symbols-outlined controls next-previous" @click="control( 'previous' )" id="previous" v-if="isShowingFullScreenPlayer">skip_previous</span>
<span class="material-symbols-outlined controls forward-back" @click="control( 'back' )" :style="'rotate: -' + 360 * clickCountBack + 'deg;'" v-if="isShowingFullScreenPlayer">replay_10</span> <span class="material-symbols-outlined controls forward-back" @click="control( 'back' )" :style="'rotate: -' + 360 * clickCountBack + 'deg;'" v-if="isShowingFullScreenPlayer">replay_10</span>
@@ -64,7 +64,8 @@
:is-logged-into-apple-music="player.isLoggedIn" :is-logged-into-apple-music="player.isLoggedIn"
@add-new-songs-apple-music="( song ) => addNewSongFromObject( song )" @add-new-songs-apple-music="( song ) => addNewSongFromObject( song )"
@delete-song="song => removeSongFromPlaylist( song )" @delete-song="song => removeSongFromPlaylist( song )"
@clear-playlist="() => clearPlaylist()"></playlistView> @clear-playlist="() => clearPlaylist()"
@send-additional-info="() => sendAdditionalInfo()"></playlistView>
</div> </div>
<notificationsModule ref="notifications" location="bottomleft" size="bigger"></notificationsModule> <notificationsModule ref="notifications" location="bottomleft" size="bigger"></notificationsModule>
<popupModule @update="( data ) => popupReturnHandler( data )" ref="popup"></popupModule> <popupModule @update="( data ) => popupReturnHandler( data )" ref="popup"></popupModule>
@@ -225,10 +226,14 @@
notifications.value.createNotification( 'Disconnected successfully!', 5, 'ok', 'normal' ); notifications.value.createNotification( 'Disconnected successfully!', 5, 'ok', 'normal' );
} }
} else if ( action === 'show-share' ) { } else if ( action === 'show-share' ) {
alert( 'You are currently connected to share "' + roomName.value popup.value.openPopup( {
+ '". \nYou can connect to it via https://music.janishutz.com/share/' + roomName.value title: 'Details on share',
+ '. \n\nYou can connect to the fancy showcase screen using this link: https://music.janishutz.com/fancy/' + roomName.value subtitle: 'You are currently connected to share "' + roomName.value
+ '. Be aware that this one will use significantly more system AND network resources, so only use that for a screen that is front and center, not for a QR code to have all people connect to.' ); + '". \nYou can connect to it via <a href="https://music.janishutz.com/share/' + roomName.value + '" target="_blank">https://music.janishutz.com/share/' + roomName.value + '</a>'
+ '. \n\nYou can connect to the fancy showcase screen using this link: <a href="https://music.janishutz.com/fancy/' + roomName.value + '" target="_blank">https://music.janishutz.com/fancy/' + roomName.value + '</a>'
+ '. Be aware that this one will use significantly more system AND network resources, so only use that for a screen that is front and center, not for a QR code to have all people connect to.'
} );
currentlyOpenPopup = 'share-details';
} }
} }
@@ -514,6 +519,11 @@
notificationHandler.emit( 'playlist-update', playlist.value ); notificationHandler.emit( 'playlist-update', playlist.value );
} }
const sendAdditionalInfo = () => {
notifications.value.createNotification( 'Additional song info transmitted', 5, 'ok', 'normal' );
notificationHandler.emit( 'playlist-update', playlist.value );
}
emits( 'playerStateChange', isShowingFullScreenPlayer.value ? 'show' : 'hide' ); emits( 'playerStateChange', isShowingFullScreenPlayer.value ? 'show' : 'hide' );
const userStore = useUserStore(); const userStore = useUserStore();

View File

@@ -6,9 +6,9 @@
<button @click="openSearch()" v-if="$props.isLoggedIntoAppleMusic" class="small-buttons" title="Search Apple Music for the song"><span class="material-symbols-outlined">search</span></button> <button @click="openSearch()" v-if="$props.isLoggedIntoAppleMusic" class="small-buttons" title="Search Apple Music for the song"><span class="material-symbols-outlined">search</span></button>
<button @click="clearPlaylist()" class="small-buttons" title="Clear the playlist"><span class="material-symbols-outlined">delete</span></button> <button @click="clearPlaylist()" class="small-buttons" title="Clear the playlist"><span class="material-symbols-outlined">delete</span></button>
<p v-if="!hasSelectedSongs">Please select at least one song to proceed</p> <p v-if="!hasSelectedSongs">Please select at least one song to proceed</p>
<button title="Transmit additional information" class="small-buttons" @click="sendAdditionalInfo()"><span class="material-symbols-outlined">send</span></button>
<div class="playlist-box" id="pl-box"> <div class="playlist-box" id="pl-box">
<!-- TODO: Allow editing additionalInfo. Think also how to make it persist over reloads... Export to JSON and then best-guess add them? Very easy for Apple Music 'cause ID, but how for local songs? --> <!-- TODO: Allow editing additionalInfo. Think also how to make it persist over reloads... Export to JSON and then best-guess add them? Very easy for Apple Music 'cause ID, but how for local songs? Maybe using retrieved ID from Apple Music? -->
<!-- TODO: Allow deleting songs, as well as whole playlist -> Handle on player side -->
<!-- TODO: Handle long AppleMusic Playlists, as AppleMusic doesn't automatically load all songs of a playlist --> <!-- TODO: Handle long AppleMusic Playlists, as AppleMusic doesn't automatically load all songs of a playlist -->
<div class="song" v-for="song in computedPlaylist" v-bind:key="song.id" <div class="song" v-for="song in computedPlaylist" v-bind:key="song.id"
:class="( song.id === ( $props.playlist ? $props.playlist [ $props.currentlyPlaying ?? 0 ].id : '' ) && isPlaying ? 'playing' : ' not-playing' ) :class="( song.id === ( $props.playlist ? $props.playlist [ $props.currentlyPlaying ?? 0 ].id : '' ) && isPlaying ? 'playing' : ' not-playing' )
@@ -27,7 +27,10 @@
<span class="material-symbols-outlined move-icon" @click="moveSong( song.id, 'up' )" title="Move song up" v-if="canBeMoved( 'up', song.id )">arrow_upward</span> <span class="material-symbols-outlined move-icon" @click="moveSong( song.id, 'up' )" title="Move song up" v-if="canBeMoved( 'up', song.id )">arrow_upward</span>
<span class="material-symbols-outlined move-icon" @click="moveSong( song.id, 'down' )" title="Move song down" v-if="canBeMoved( 'down', song.id )">arrow_downward</span> <span class="material-symbols-outlined move-icon" @click="moveSong( song.id, 'down' )" title="Move song down" v-if="canBeMoved( 'down', song.id )">arrow_downward</span>
<h3 class="song-title">{{ song.title }}</h3> <h3 class="song-title">{{ song.title }}</h3>
<div>
<input type="text" placeholder="Additional information for remote display" v-model="song.additionalInfo">
<p class="playing-in">{{ getTimeUntil( song ) }}</p> <p class="playing-in">{{ getTimeUntil( song ) }}</p>
</div>
<button @click="deleteSong( song.id )" class="small-buttons" title="Remove this song from the queue" v-if="canBeMoved( 'down', song.id ) || canBeMoved( 'up', song.id )"><span class="material-symbols-outlined">delete</span></button> <button @click="deleteSong( song.id )" class="small-buttons" title="Remove this song from the queue" v-if="canBeMoved( 'down', song.id ) || canBeMoved( 'up', song.id )"><span class="material-symbols-outlined">delete</span></button>
</div> </div>
</div> </div>
@@ -36,7 +39,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
// TODO: Add logout button // TODO: Add logout button
import type { AppleMusicSongData, ReadFile, Song } from '@/scripts/song'; import type { AppleMusicSongData, ReadFile, Song } from '@/scripts/song';
import { computed, ref } from 'vue'; import { computed, ref } from 'vue';
import searchView from './searchView.vue'; import searchView from './searchView.vue';
@@ -198,7 +201,11 @@
} }
} }
const emits = defineEmits( [ 'play-song', 'control', 'playlist-reorder', 'add-new-songs', 'add-new-songs-apple-music', 'delete-song', 'clear-playlist' ] ); const sendAdditionalInfo = () => {
emits( 'send-additional-info' );
}
const emits = defineEmits( [ 'play-song', 'control', 'playlist-reorder', 'add-new-songs', 'add-new-songs-apple-music', 'delete-song', 'clear-playlist', 'send-additional-info' ] );
</script> </script>
<style scoped> <style scoped>
@@ -224,11 +231,11 @@
} }
.song .song-cover { .song .song-cover {
width: 5vw; width: 6rem;
height: 5vw; height: 6rem;
object-fit: cover; object-fit: cover;
object-position: center; object-position: center;
font-size: 5vw; font-size: 6rem;
} }
.song-title { .song-title {
@@ -244,14 +251,14 @@
align-items: center; align-items: center;
flex-direction: row; flex-direction: row;
margin: 0; margin: 0;
width: 5vw; width: 6rem;
height: 5vw; height: 6rem;
background-color: rgba( 0, 0, 0, 0.6 ); background-color: rgba( 0, 0, 0, 0.6 );
} }
.playing-symbols-wrapper { .playing-symbols-wrapper {
width: 4vw; width: 5rem;
height: 5vw; height: 6rem;
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
@@ -294,11 +301,11 @@
.play-icon, .pause-icon { .play-icon, .pause-icon {
display: none; display: none;
width: 5vw; width: 6rem;
height: 5vw; height: 6rem;
object-fit: cover; object-fit: cover;
object-position: center; object-position: center;
font-size: 5vw; font-size: 6rem;
cursor: pointer; cursor: pointer;
user-select: none; user-select: none;
} }

View File

@@ -7,7 +7,7 @@
</div> </div>
<div v-else-if="!$props.isLoggedIn" class="not-logged-in"> <div v-else-if="!$props.isLoggedIn" class="not-logged-in">
<p>You are not logged into Apple Music. We therefore can't show you your playlists. <a href="" title="Refreshes the page, allowing you to log in">Change that</a></p> <p>You are not logged into Apple Music. We therefore can't show you your playlists. <a href="" title="Refreshes the page, allowing you to log in">Change that</a></p>
<p>Use the below button to load songs from your local disk</p> <p>Use the button below to load songs from your local disk</p>
<input class="pl-loader-button" type="file" multiple="true" accept="audio/*" id="pl-loader"><br> <input class="pl-loader-button" type="file" multiple="true" accept="audio/*" id="pl-loader"><br>
<button @click="loadPlaylistFromDisk()" class="pl-loader-button" id="load-button">Load</button> <button @click="loadPlaylistFromDisk()" class="pl-loader-button" id="load-button">Load</button>
<p v-if="!hasSelectedSongs">Please select at least one song to proceed!</p> <p v-if="!hasSelectedSongs">Please select at least one song to proceed!</p>

View File

@@ -1,5 +1,6 @@
<template> <template>
<div class="app-view"> <div class="app-view">
<button id="logout" @click="logout()"><span class="material-symbols-outlined">logout</span></button>
<div class="loading-view" v-if="!hasFinishedLoading"> <div class="loading-view" v-if="!hasFinishedLoading">
<h1>Loading...</h1> <h1>Loading...</h1>
</div> </div>
@@ -93,9 +94,27 @@
} }
} ); } );
const logout = () => {
location.href = 'http://localhost:8080/logout?return=http://localhost:8081';
// location.href = 'https://id.janishutz.com/logout?return=https://music.janishutz.com';
}
</script> </script>
<style scoped> <style scoped>
#logout {
border: none;
background: none;
position: fixed;
left: calc( 10px + 2rem );
top: 10px;
cursor: pointer;
}
#logout .material-symbols-outlined {
font-size: 1.5rem;
color: var( --primary-color );
}
.library-view { .library-view {
height: calc( 90vh - 10px ); height: calc( 90vh - 10px );
width: 100%; width: 100%;

View File

@@ -5,21 +5,25 @@
<h1>MusicPlayer</h1> <h1>MusicPlayer</h1>
<p><i>An Open Source, browser-based MusicPlayer with beautiful graphics</i></p> <p><i>An Open Source, browser-based MusicPlayer with beautiful graphics</i></p>
<div style="margin-top: 20px;"> <div style="margin-top: 20px;">
<a href="https://store.janishutz.com/product/com.janishutz.MusicPlayer" class="fancy-button">Subscribe</a> <a href="https://store.janishutz.com/product/com.janishutz.MusicPlayer" class="fancy-button" target="_blank">Subscribe</a>
<a href="https://github.com/simplePCBuilding/MusicPlayerV2" class="fancy-button" style="margin-left: 10px;">GitHub</a> <a href="https://github.com/simplePCBuilding/MusicPlayerV2" class="fancy-button" style="margin-left: 10px;" target="_blank">GitHub</a>
</div> </div>
</div> </div>
<div class="full-height"> <div class="full-height">
<h2>Fully featured Music Player</h2> <h2>Fully featured Music Player</h2>
<img src="https://github.com/simplePCBuilding/MusicPlayerV2/raw/master/assets/logo.png" alt="MusicPlayer Logo" class="promo-img">
</div> </div>
<div class="full-height"> <div class="full-height">
<h2>Apple Music integration</h2> <h2>Apple Music integration</h2>
<img src="https://github.com/simplePCBuilding/MusicPlayerV2/raw/master/assets/logo.png" alt="MusicPlayer Logo" class="promo-img">
</div> </div>
<div class="full-height"> <div class="full-height">
<h2>Share your playlist</h2> <h2>Share your playlist</h2>
<img src="https://github.com/simplePCBuilding/MusicPlayerV2/raw/master/assets/logo.png" alt="MusicPlayer Logo" class="promo-img">
</div> </div>
<div class="full-height"> <div class="full-height">
<h2>Fully browser based</h2> <h2>Fully browser based</h2>
<img src="https://github.com/simplePCBuilding/MusicPlayerV2/raw/master/assets/logo.png" alt="MusicPlayer Logo" class="promo-img">
</div> </div>
</div> </div>
</template> </template>
@@ -39,4 +43,17 @@
align-items: center; align-items: center;
flex-direction: column; flex-direction: column;
} }
.full-height {
height: 100vh;
width: 100vw;
display: flex;
justify-content: center;
align-items: center;
}
.promo-img {
height: 100vh;
width: 100vh;
}
</style> </style>

View File

@@ -6,13 +6,15 @@
>{{ isTryingToSignIn ? 'Signing you in...' : 'Login / Sign up' }}</button> >{{ isTryingToSignIn ? 'Signing you in...' : 'Login / Sign up' }}</button>
<p v-else>We are sorry, but we were unable to initialize the login services. Please reload the page if you wish to retry!</p> <p v-else>We are sorry, but we were unable to initialize the login services. Please reload the page if you wish to retry!</p>
<p style="width: 80%;">MusicPlayer is a browser based Music Player, that allows you to connect other devices, simply with another web-browser, where you can see the current playlist with sleek animations. You can log in using your Apple Music account or load a playlist from your local disk, simply by selecting the songs using a file picker.</p> <p style="width: 80%;">MusicPlayer is a browser based Music Player, that allows you to connect other devices, simply with another web-browser, where you can see the current playlist with sleek animations. You can log in using your Apple Music account or load a playlist from your local disk, simply by selecting the songs using a file picker.</p>
<p>Head to my store to subscribe</p> <router-link to="/get" class="fancy-button">More information</router-link>
<notificationsModule ref="notifications" location="bottomleft" size="bigger"></notificationsModule> <notificationsModule ref="notifications" location="bottomleft" size="bigger"></notificationsModule>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
// TODO: Make possible to install and use without account, if using FOSS version
import router from '@/router'; import router from '@/router';
import { RouterLink } from 'vue-router';
import { useUserStore } from '@/stores/userStore'; import { useUserStore } from '@/stores/userStore';
import notificationsModule from '@/components/notificationsModule.vue'; import notificationsModule from '@/components/notificationsModule.vue';
import { ref } from 'vue'; import { ref } from 'vue';

View File

@@ -29,7 +29,7 @@
<div v-else-if="!hasLoaded && !showCouldNotFindRoom"> <div v-else-if="!hasLoaded && !showCouldNotFindRoom">
<h1>Loading...</h1> <h1>Loading...</h1>
</div> </div>
<div v-else> <div v-else style="max-width: 80%;">
<span class="material-symbols-outlined" style="font-size: 4rem;">wifi_off</span> <span class="material-symbols-outlined" style="font-size: 4rem;">wifi_off</span>
<h1>Couldn't connect!</h1> <h1>Couldn't connect!</h1>
<p>There does not appear to be a share with the specified name, or an error occurred when connecting.</p> <p>There does not appear to be a share with the specified name, or an error occurred when connecting.</p>