(WIP) changes to playlist/album pages, added <artwork-material>

This commit is contained in:
booploops 2022-01-17 23:49:34 -08:00
parent fcaa891648
commit cd48e25acc
7 changed files with 269 additions and 158 deletions

View file

@ -85,6 +85,8 @@ export class Win {
this.options.height = windowState.height; this.options.height = windowState.height;
// Start the webserver for the browser window to load // Start the webserver for the browser window to load
const ws = new wsapi()
ws.InitWebSockets()
this.startWebServer(); this.startWebServer();
this.win = new electron.BrowserWindow(this.options); this.win = new electron.BrowserWindow(this.options);
@ -191,8 +193,6 @@ export class Win {
* TODO: Broadcast the remote so that /web-remote/ can connect * TODO: Broadcast the remote so that /web-remote/ can connect
* https://github.com/ciderapp/Apple-Music-Electron/blob/818ed18940ff600d76eb59d22016723a75885cd5/resources/functions/handler.js#L1173 * https://github.com/ciderapp/Apple-Music-Electron/blob/818ed18940ff600d76eb59d22016723a75885cd5/resources/functions/handler.js#L1173
*/ */
const ws = new wsapi()
ws.InitWebSockets()
const remote = express(); const remote = express();
remote.use(express.static(path.join(this.paths.srcPath, "./web-remote/"))) remote.use(express.static(path.join(this.paths.srcPath, "./web-remote/")))
remote.listen(this.remotePort, () => { remote.listen(this.remotePort, () => {

View file

@ -18,13 +18,6 @@ private class standardResponse {
} }
export class wsapi { export class wsapi {
private standa2rdResponse (status, data, message, type: string = "generic") {
this.status = status;
this.message = message;
this.data = data;
this.type = type;
}
port: any = 26369 port: any = 26369
wss: any = null wss: any = null
clients: [] clients: []

View file

@ -254,6 +254,32 @@ input[type="text"], input[type="number"] {
} }
} }
.artworkMaterial {
position: relative;
height:100%;
width:100%;
overflow: hidden;
pointer-events: none;
>img {
position: absolute;
width: 200%;
opacity: 0.5;
filter: brightness(200%) blur(180px) saturate(280%) contrast(2);
}
>img:first-child {
top:0;
left:0;
}
>img:last-child {
bottom:0;
right: 0;
transform: rotate(180deg);
}
}
[artwork-hidden] { [artwork-hidden] {
transition: opacity .25s var(--appleEase); transition: opacity .25s var(--appleEase);
@ -2345,7 +2371,7 @@ input[type="range"].web-slider.display--small::-webkit-slider-thumb {
.playlist-page { .playlist-page {
--bgColor: transparent; --bgColor: transparent;
padding: 0px; padding: 0px;
background: linear-gradient(180deg, var(--bgColor) 32px, var(--bgColor) 59px, transparent 60px, transparent 100%); //background: linear-gradient(180deg, var(--bgColor) 32px, var(--bgColor) 18px, transparent 60px, transparent 100%);
top: 0; top: 0;
padding-top: var(--navigationBarHeight); padding-top: var(--navigationBarHeight);
@ -2356,104 +2382,149 @@ input[type="range"].web-slider.display--small::-webkit-slider-thumb {
.playlist-display { .playlist-display {
padding: var(--contentInnerPadding); padding: var(--contentInnerPadding);
min-height: 300px; min-height: 300px;
position: relative;
.playlist-info { .artworkContainer {
flex-shrink: unset; position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
margin: 0;
padding: 0;
-webkit-mask-image: radial-gradient(at top left, black, transparent 70%), radial-gradient(at top right, black, transparent 70%), linear-gradient(180deg, rgb(200 200 200), transparent 98%);
opacity: .7;
.artworkMaterial>img {
filter: brightness(100%) blur(80px) saturate(100%) contrast(1);
object-position: center;
object-fit: cover;
width: 100%;
height: 100%;
transform: unset;
}
.artworkMaterial>img:last-child {
display: none;
}
}
.playlistInfo {
z-index: 1;
position: absolute;
bottom: 0;
left: 0;
right: 0;
top: 0;
display: flex; display: flex;
flex-flow: column; justify-content: center;
justify-content: flex-end; align-items: center;
width: 100%;
height: 100%;
.playlist-name { >.row {
font-weight: 700; width: calc(100% - 32px);
font-size: 1.6rem;
margin-bottom: 6px;
margin-right: 6px;
flex-shrink: unset;
} }
.nameEdit { .playlist-info {
font-weight: 700;
font-size: 1.6rem;
margin-bottom: 6px;
margin-right: 6px;
flex-shrink: unset; flex-shrink: unset;
background: transparent; display: flex;
border: 0px; flex-flow: column;
color: inherit; justify-content: flex-end;
font-family: inherit;
}
.playlist-artist { .playlist-name {
font-size: 20px; font-weight: 700;
margin-bottom: 6px; font-size: 1.6rem;
margin-right: 6px; margin-bottom: 6px;
flex-shrink: unset; margin-right: 6px;
} flex-shrink: unset;
.playlist-desc {
box-sizing: border-box;
font-size: 14px;
flex-shrink: unset;
margin-right: 5px;
max-height: 100px;
position: relative;
.content {
height: 100px;
-webkit-mask-image: -webkit-gradient(linear, left 50%, left 90%, from(rgba(0, 0, 0, 1)), to(rgba(0, 0, 0, 0)));
} }
.more-btn { .nameEdit {
appearance: none; font-weight: 700;
position: absolute; font-size: 1.6rem;
right: 0; margin-bottom: 6px;
bottom: 0; margin-right: 6px;
padding: 0 5px; flex-shrink: unset;
font-size: 14px; background: transparent;
color: var(--keyColor);
background-color: transparent;
border: 0px; border: 0px;
cursor: pointer; color: inherit;
width: 100%;
height: 100%;
overflow: hidden;
display: flex;
justify-content: flex-end;
align-items: flex-end;
font-weight: 600;
font-family: inherit; font-family: inherit;
text-transform: uppercase;
} }
}
.playlist-desc-expanded { .playlist-artist {
box-sizing: border-box; font-size: 20px;
font-size: 14px; margin-bottom: 6px;
position: relative; margin-right: 6px;
flex-shrink: unset;
}
.more-btn { .playlist-desc {
appearance: none; box-sizing: border-box;
position: absolute;
right: 0;
bottom: 0;
padding: 0 5px;
font-size: 14px; font-size: 14px;
color: var(--keyColor); flex-shrink: unset;
background-color: transparent; margin-right: 5px;
border: 0px; max-height: 100px;
cursor: pointer; position: relative;
width: 100%;
height: 100%; .content {
overflow: hidden; height: 100px;
display: flex; -webkit-mask-image: -webkit-gradient(linear, left 50%, left 90%, from(rgba(0, 0, 0, 1)), to(rgba(0, 0, 0, 0)));
justify-content: flex-end; }
align-items: flex-end;
font-weight: 600; .more-btn {
font-family: inherit; appearance: none;
text-transform: uppercase; position: absolute;
right: 0;
bottom: 0;
padding: 0 5px;
font-size: 14px;
color: var(--keyColor);
background-color: transparent;
border: 0px;
cursor: pointer;
width: 100%;
height: 100%;
overflow: hidden;
display: flex;
justify-content: flex-end;
align-items: flex-end;
font-weight: 600;
font-family: inherit;
text-transform: uppercase;
}
}
.playlist-desc-expanded {
box-sizing: border-box;
font-size: 14px;
position: relative;
.more-btn {
appearance: none;
position: absolute;
right: 0;
bottom: 0;
padding: 0 5px;
font-size: 14px;
color: var(--keyColor);
background-color: transparent;
border: 0px;
cursor: pointer;
width: 100%;
height: 100%;
overflow: hidden;
display: flex;
justify-content: flex-end;
align-items: flex-end;
font-weight: 600;
font-family: inherit;
text-transform: uppercase;
}
} }
} }
} }
} }
.friends-info { .friends-info {

View file

@ -0,0 +1,33 @@
<script type="text/x-template" id="artwork-material">
<div class="artworkMaterial">
<img :src="src"/>
<img :src="src"/>
</div>
</script>
<script>
Vue.component('artwork-material', {
template: '#artwork-material',
data: function () {
return {
src: ""
}
},
mounted() {
this.src = app.getMediaItemArtwork(this.url, this.size)
},
props: {
url: {
type: String,
required: true
},
size: {
type: [String, Number],
required: false,
default: '32'
}
},
methods: {
}
});
</script>

View file

@ -659,6 +659,8 @@
</button> </button>
</script> </script>
<!-- Artwork Material -->
<%- include('components/artwork-material') %>
<!-- Menu Panel --> <!-- Menu Panel -->
<%- include('components/menu-panel') %> <%- include('components/menu-panel') %>
<!-- Playlist Listing --> <!-- Playlist Listing -->

View file

@ -7,84 +7,93 @@
</div> </div>
</template> </template>
<template v-if="app.playlists.loadingState == 1"> <template v-if="app.playlists.loadingState == 1">
<div class="playlist-display row" <div class="playlist-display"
:style="{ :style="{
background: (data.attributes.artwork != null && data.attributes.artwork['bgColor'] != null) ? ('#' + data.attributes.artwork.bgColor) : '', '--bgColor': (data.attributes.artwork != null && data.attributes.artwork['bgColor'] != null) ? ('#' + data.attributes.artwork.bgColor) : '',
color: (data.attributes.artwork != null && data.attributes.artwork['textColor1'] != null) ? ('#' + data.attributes.artwork.textColor1) : '' '--textColor': (data.attributes.artwork != null && data.attributes.artwork['textColor1'] != null) ? ('#' + data.attributes.artwork.textColor1) : ''
}"> }">
<div class="col-auto flex-center"> <div class="playlistInfo">
<div style="width: 260px;height:260px;"> <div class="row">
<mediaitem-artwork <div class="col-auto flex-center">
:video-priority="true" <div style="width: 260px;height:260px;">
:url="(data.attributes != null && data.attributes.artwork != null) ? data.attributes.artwork.url : ((data.relationships != null && data.relationships.tracks.data.length > 0 && data.relationships.tracks.data[0].attributes != null) ? ((data.relationships.tracks.data[0].attributes.artwork != null)? data.relationships.tracks.data[0].attributes.artwork.url : ''):'')" <mediaitem-artwork
:video="(data.attributes != null && data.attributes.editorialVideo != null) ? (data.attributes.editorialVideo.motionDetailSquare ? data.attributes.editorialVideo.motionDetailSquare.video : (data.attributes.editorialVideo.motionSquareVideo1x1 ? data.attributes.editorialVideo.motionSquareVideo1x1.video : '')) : '' " shadow="large"
size="260" :video-priority="true"
></mediaitem-artwork> :url="(data.attributes != null && data.attributes.artwork != null) ? data.attributes.artwork.url : ((data.relationships != null && data.relationships.tracks.data.length > 0 && data.relationships.tracks.data[0].attributes != null) ? ((data.relationships.tracks.data[0].attributes.artwork != null)? data.relationships.tracks.data[0].attributes.artwork.url : ''):'')"
</div> :video="(data.attributes != null && data.attributes.editorialVideo != null) ? (data.attributes.editorialVideo.motionDetailSquare ? data.attributes.editorialVideo.motionDetailSquare.video : (data.attributes.editorialVideo.motionSquareVideo1x1 ? data.attributes.editorialVideo.motionSquareVideo1x1.video : '')) : '' "
</div> size="260"
<div class="col playlist-info"> ></mediaitem-artwork>
<template v-if="!editorialNotesExpanded">
<div>
<div class="playlist-name" @click="editPlaylistName()" v-show="!nameEditing">
{{data.attributes ? (data.attributes.name ??
(data.attributes.title ?? '') ?? '') : ''}}
</div> </div>
<div class="playlist-name" v-show="nameEditing"><input type="text" spellcheck="false" </div>
class="nameEdit" <div class="col playlist-info">
v-model="data.attributes.name" <template v-if="!editorialNotesExpanded">
@blur="editPlaylist" <div>
@change="editPlaylist" <div class="playlist-name" @click="editPlaylistName()" v-show="!nameEditing">
@keydown.enter="editPlaylist"/></div> {{data.attributes ? (data.attributes.name ??
<div class="playlist-artist item-navigate" (data.attributes.title ?? '') ?? '') : ''}}
v-if="getArtistName(data) != ''" </div>
@click="data.attributes && data.attributes.artistName ? app.searchAndNavigate(data,'artist') : ''"> <div class="playlist-name" v-show="nameEditing"><input type="text" spellcheck="false"
{{getArtistName(data)}} class="nameEdit"
</div> v-model="data.attributes.name"
<div class="playlist-desc" v-if="data.attributes.description && (data.attributes.description.standard || data.attributes.description.short)"> @blur="editPlaylist"
<div v-if="data.attributes.description.short" class="content" v-html="data.attributes.description.short"></div> @change="editPlaylist"
<div v-else-if="data.attributes.description.standard" class="content" v-html="data.attributes.description.standard"></div> @keydown.enter="editPlaylist"/></div>
<button v-if="data.attributes.description.short" class="more-btn" <div class="playlist-artist item-navigate"
@click="editorialNotesExpanded = !editorialNotesExpanded"> v-if="getArtistName(data) != ''"
More @click="data.attributes && data.attributes.artistName ? app.searchAndNavigate(data,'artist') : ''">
{{getArtistName(data)}}
</div>
<div class="playlist-desc" v-if="data.attributes.description && (data.attributes.description.standard || data.attributes.description.short)">
<div v-if="data.attributes.description.short" class="content" v-html="data.attributes.description.short"></div>
<div v-else-if="data.attributes.description.standard" class="content" v-html="data.attributes.description.standard"></div>
<button v-if="data.attributes.description.short" class="more-btn"
@click="editorialNotesExpanded = !editorialNotesExpanded">
More
</button>
</div>
</div>
</template>
<template v-if="editorialNotesExpanded">
<div class="playlist-desc-expanded">
<div class="content"
v-html="((data.attributes.editorialNotes) ? (data.attributes.editorialNotes.standard ?? (data.attributes.editorialNotes.short ?? '') ) : (data.attributes.description ? (data.attributes.description.standard ?? (data.attributes.description.short ?? '')) : ''))"></div>
<button class="more-btn" @click="editorialNotesExpanded = !editorialNotesExpanded">Less
</button>
</div>
</template>
<div class="playlist-controls">
<button class="md-btn" style="min-width: 120px;"
@click="app.mk.shuffleMode = 0; play()">
Play
</button> </button>
</div> <button class="md-btn" style="min-width: 120px;"
</div> @click="app.mk.shuffleMode = 1;play()">
</template> Shuffle
<template v-if="editorialNotesExpanded"> </button>
<div class="playlist-desc-expanded"> <button class="md-btn" style="min-width: 120px;" v-if="inLibrary!=null && confirm!=true"
<div class="content" @click="confirmButton()">
v-html="((data.attributes.editorialNotes) ? (data.attributes.editorialNotes.standard ?? (data.attributes.editorialNotes.short ?? '') ) : (data.attributes.description ? (data.attributes.description.standard ?? (data.attributes.description.short ?? '')) : ''))"></div> {{ (!inLibrary) ? "Add to Library" : "Remove from Library" }}
<button class="more-btn" @click="editorialNotesExpanded = !editorialNotesExpanded">Less </button>
</button> <button class="md-btn" style="min-width: 120px;" v-if="confirm==true"
</div> @click="(!inLibrary) ? addToLibrary(data.attributes.playParams.id.toString()) : removeFromLibrary(data.attributes.playParams.id.toString()) ">
</template> Confirm?
<div class="playlist-controls"> </button>
<button class="md-btn" style="min-width: 120px;" <button class="playlist-more" @click="menu">
@click="app.mk.shuffleMode = 0; play()"> <div style=" margin-top: -1px;
Play
</button>
<button class="md-btn" style="min-width: 120px;"
@click="app.mk.shuffleMode = 1;play()">
Shuffle
</button>
<button class="md-btn" style="min-width: 120px;" v-if="inLibrary!=null && confirm!=true"
@click="confirmButton()">
{{ (!inLibrary) ? "Add to Library" : "Remove from Library" }}
</button>
<button class="md-btn" style="min-width: 120px;" v-if="confirm==true"
@click="(!inLibrary) ? addToLibrary(data.attributes.playParams.id.toString()) : removeFromLibrary(data.attributes.playParams.id.toString()) ">
Confirm?
</button>
<button class="playlist-more" @click="menu">
<div style=" margin-top: -1px;
margin-left: -5px; margin-left: -5px;
width: 36px; width: 36px;
height: 36px;"> height: 36px;">
<%- include("../svg/more.svg") %> <%- include("../svg/more.svg") %>
</div>
</button>
</div> </div>
</button> </div>
</div> </div>
</div> </div>
<div class="artworkContainer" v-if="data.attributes.artwork != null">
<artwork-material :url="data.attributes.artwork.url" size="260"></artwork-material>
</div>
</div> </div>
<div class="playlist-body"> <div class="playlist-body">
<div class="well"> <div class="well">

View file

@ -5,5 +5,8 @@
{{ $store.state.test }} {{ $store.state.test }}
<div class="spinner"></div> <div class="spinner"></div>
<button class="md-btn">Cider Button</button> <button class="md-btn">Cider Button</button>
<div style="position: relative;width: 300px;height: 300px;">
<artwork-material url="https://is3-ssl.mzstatic.com/image/thumb/Music126/v4/13/41/13/1341133b-560f-1aee-461f-c4b32ec049b4/cover.jpg/{w}x{h}bb.jpg"></artwork-material>
</div>
</div> </div>
</template> </template>