miwory music player gen 1 & 2 & 3

This commit is contained in:
2025-08-31 00:36:15 +03:00
parent ecf9933a15
commit 7e7c9644c4
9 changed files with 689 additions and 0 deletions

View File

@ -0,0 +1,24 @@
<div id="widget">
<div id="player">
<div class="player_background">
<img id="background_img">
</div>
<div class="data">
<div class="source">
<svg id="logo" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 30 30">
<path fill="#fff"d="M15 0a15 15 0 1 0 0 30 15 15 0 0 0 0-30ZM7.4 20.5A18.2 18.2 0 0 1 21.3 22c.2.1.3.4.4.7l-.1 1a.8.8 0 0 1-1 .2 16.4 16.4 0 0 0-13-1.2.8.8 0 0 1-.7-.6c-.2-.4.1-1.4.5-1.5ZM6.7 15a22.7 22.7 0 0 1 16.4 1.7c.2.1.4.3.4.6v.7c-.3.5-.6 1-.9 1a1 1 0 0 1-.4-.2A20.4 20.4 0 0 0 7 17.2a1 1 0 0 1-1-.6c0-.6.3-1.5.7-1.6Zm-.1-3.6h-.3c-.5 0-1-.3-1-.8-.2-.7.2-1.4.7-1.5a28 28 0 0 1 19 2l.5.7c.1.3.1.6 0 .8-.2.4-.6.8-1 .8l-.5-.1a25 25 0 0 0-17.4-2Z" />
</svg>
<a id="source"></a>
</div>
<div class="meta">
<a id="title"></a>
<a id="artist"></a>
</div>
<div id="progressbar">
<div class="background"></div>
<div class="progress"></div>
<div class="pointer"></div>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,72 @@
let widgetNode = document.getElementById('widget');
let musicPlayerNode = document.getElementById('player');
let musicPlayerTitleNode = document.getElementById('title');
let musicPlayerArtistNode = document.getElementById('artist');
let musicPlayerBackgroundNode = document.getElementById('background_img');
let musicPlayerProgress = document.getElementById('progressbar');
let pausedAt = null;
let trackDuration = 0;
let trackProgress = 0;
let trackEnd = new Date();
window.addEventListener('message', function (event) {
let message = event.detail;
let data = message.data;
widgetNode.classList.add('active');
if (data == null) {
musicPlayerNode.classList.remove('active');
return;
};
if (!data.is_playing && !pausedAt) {
pausedAt = new Date();
};
if (data.is_playing) {
musicPlayerNode.classList.add('active');
pausedAt = null;
};
trackDuration = data.track.duration;
trackProgress = data.progress;
trackEnd = new Date().getTime() + data.track.duration - data.progress;
musicPlayerTitleNode.innerText = data.track.name;
musicPlayerArtistNode.innerText = data.track.artists.join(', ');
if (musicPlayerBackgroundNode.src != data.track.cover) {
musicPlayerBackgroundNode.src = data.track.cover;
};
});
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
};
async function update() {
if (pausedAt && pausedAt.getTime() + 10000 < new Date().getTime()) {
player.classList.remove('active');
await delay(100);
return update();
};
var progress;
if (pausedAt) {
progress = trackProgress / trackDuration * 100;
} else {
progress = (trackDuration - (trackEnd - new Date().getTime())) / trackDuration * 100;
};
if (progress >= 100) {
progress = 100;
};
musicPlayerProgress.style.setProperty('--progress', `${progress}%`);
await delay(100);
update();
};
update();

View File

@ -0,0 +1,139 @@
@import url(https://fonts.googleapis.com/css2?family=Nunito:ital,wght@0,900;1,900&display=swap);
#widget {
display: flex;
align-items: center;
justify-content: center;
visibility: hidden
}
#widget.active {
visibility: visible
}
#player {
position: relative;
width: 800px;
height: 320px;
overflow: hidden;
border-radius: 30px;
margin-inline: 30px;
color: #fff;
font-family: "Nunito", sans-serif;
font-weight: 900;
opacity: 0;
box-shadow: 0 0 20px 5px rgba(0, 0, 0, .5);
transition: opacity 350ms ease-in-out
}
#player.active {
opacity: 1
}
#player .player_background {
position: absolute;
inset: 0
}
#player #background_img {
position: absolute;
width: 100%;
height: 100%;
object-fit: cover;
opacity: .35
}
#player .player_background::before {
position: absolute;
content: "";
inset: 0;
background-color: #1e1e1e
}
#player .data {
position: relative;
width: calc(100% - 150px);
height: calc(100% - 60px);
display: flex;
flex-direction: column;
gap: 15px;
padding: 30px 75px;
z-index: 99
}
#player .source {
display: flex;
opacity: .6;
gap: 10px
}
#player .source #logo {
width: 30px
}
#player .data .meta {
display: flex;
flex-direction: column
}
#player .data .meta #artist,
#player .data .meta #title {
word-break: keep-all;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap
}
#player .data #source {
font-size: 28px
}
#player .data #title {
font-size: 42px
}
#player .data #artist {
font-size: 32px;
opacity: .6
}
#player #progressbar {
position: relative;
width: 100%;
height: 30px;
border-radius: 25px;
margin-top: 20px;
--progress: 0%
}
#player #progressbar .background {
position: absolute;
inset: 0;
border-radius: inherit;
background-color: #d9d9d9;
opacity: .25
}
#player #progressbar .progress {
position: absolute;
inset: 0;
border-radius: inherit;
background-color: #c6d3e6;
width: 100%;
max-width: var(--progress);
transition: max-width 200ms ease-in-out
}
#player #progressbar .pointer {
position: absolute;
top: 50%;
width: 50px;
aspect-ratio: 1;
background-color: #dceaff;
border: 1px solid #737373;
border-radius: 100%;
margin-left: var(--progress);
transform: translate(-50%, -50%);
transition: margin-left 200ms ease-in-out;
z-index: 99
}

View File

@ -0,0 +1,44 @@
<div id="widget">
<div id="player">
<div class="main">
<div class="player_background">
<img id="background_img">
</div>
<div class="data">
<div class="info">
<a id="title"></a>
<a id="artist"></a>
</div>
<div class="time">
<div id="now"></div>
<div class="bars">
<div class="bar"></div>
<div class="bar"></div>
<div class="bar"></div>
<div class="bar"></div>
<div class="bar"></div>
<div class="bar"></div>
<div class="bar"></div>
<div class="bar"></div>
<div class="bar"></div>
<div class="bar"></div>
<div class="bar"></div>
<div class="bar"></div>
<div class="bar"></div>
<div class="bar"></div>
<div class="bar"></div>
<div class="bar"></div>
<div class="bar"></div>
<div class="bar"></div>
<div class="bar"></div>
<div class="bar"></div>
</div>
<div id="duration"></div>
</div>
</div>
</div>
<div id="progressbar">
<div class="background"></div>
</div>
</div>
</div>

View File

@ -0,0 +1,83 @@
let widgetNode = document.getElementById('widget');
let musicPlayerNode = document.getElementById('player');
let musicPlayerTitleNode = document.getElementById('title');
let musicPlayerArtistNode = document.getElementById('artist');
let musicPlayerNowNode = document.getElementById('now');
let musicPlayerDurationNode = document.getElementById('duration');
let musicPlayerBackgroundNode = document.getElementById('background_img');
let musicPlayerProgress = document.getElementById('progressbar');
let pausedAt = null;
let trackDuration = 0;
let trackProgress = 0;
let trackEnd = new Date();
window.addEventListener('message', function (event) {
let message = event.detail;
let data = message.data;
widgetNode.classList.add('active');
if (data == null) {
musicPlayerNode.classList.remove('active');
return;
};
if (!data.is_playing && !pausedAt) {
pausedAt = new Date();
};
if (data.is_playing) {
musicPlayerNode.classList.add('active');
pausedAt = null;
};
trackDuration = data.track.duration;
trackProgress = data.progress;
trackEnd = new Date().getTime() + data.track.duration - data.progress;
musicPlayerTitleNode.innerText = data.track.name;
musicPlayerArtistNode.innerText = data.track.artists.join(', ');
musicPlayerDurationNode.innerText = formatTime(trackDuration);
if (musicPlayerBackgroundNode.src != data.track.cover) {
musicPlayerBackgroundNode.src = data.track.cover;
};
});
function formatTime(milliseconds) {
let seconds = milliseconds / 1000;
let minutes = Math.floor(seconds / 60);
let secondsFormatted = (seconds % 60).toFixed(0).padStart(2, '0');
return `${minutes}:${secondsFormatted}`;
};
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
};
async function update() {
if (pausedAt && pausedAt.getTime() + 10000 < new Date().getTime()) {
player.classList.remove('active');
await delay(100);
return update();
};
var progress;
if (pausedAt) {
progress = trackProgress / trackDuration * 100;
} else {
progress = (trackDuration - (trackEnd - new Date().getTime())) / trackDuration * 100;
musicPlayerNowNode.innerText = formatTime((trackDuration - (trackEnd - new Date().getTime())));
};
if (progress >= 100) {
progress = 100;
};
musicPlayerProgress.style.setProperty('--progress', `${progress}%`);
await delay(100);
update();
};
update();

View File

@ -0,0 +1,177 @@
@import url('https://fonts.googleapis.com/css2?family=Nunito:ital,wght@0,200..1000;1,200..1000&display=swap');
#widget {
display: flex;
align-items: center;
justify-content: center;
visibility: hidden;
}
#widget.active {
visibility: visible
}
#player {
display: flex;
flex-direction: column;
gap: 10px;
font-family: "Nunito", sans-serif;
opacity: 0;
margin: 5px 30px;
transition: opacity 350ms ease-in-out;
--text-color: white;
--background-color: #52363A;
--second-color: #5475af;
}
#player.active {
opacity: 1;
}
.main {
display: flex;
gap: 10px;
}
.player_background {
position: relative;
width: 200px;
height: 200px;
border-radius: 15px;
}
.player_background::before {
position: absolute;
content: '';
inset: 0;
border-radius: inherit;
left: -15px;
background-color: var(--background-color);
z-index: -1;
}
#background_img {
width: 100%;
height: 100%;
border-radius: 0 15px 15px 0;
}
.data {
display: flex;
flex-direction: column;
justify-content: space-between;
gap: 10px;
width: 500px;
}
.info {
display: flex;
flex-direction: column;
justify-content: space-evenly;
color: var(--text-color);
background-color: var(--background-color);
border-radius: 10px;
flex: 1 1 0;
padding: 15px;
}
.info a {
word-break: keep-all;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
#title {
font-size: 28px;
font-weight: 1000;
}
#artist {
font-size: 22px;
font-weight: 400;
}
.time {
box-sizing: border-box;
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
height: 50px;
padding-inline: 15px;
border-radius: 10px;
font-weight: 800;
color: var(--text-color);
background-color: var(--background-color);
}
.bars {
display: flex;
box-sizing: border-box;
height: 100%;
padding-block: 12px;
gap: 7.5px;
}
.bar {
width: 7px;
height: 100%;
border-radius: 5px;
background: var(--second-color);
animation: bounce 1s ease-in-out infinite;
transform-origin: center;
}
.bar:nth-child(1) { animation-duration: 1.6s; animation-delay: 0s; }
.bar:nth-child(2) { animation-duration: 1.8s; animation-delay: 0.1s; }
.bar:nth-child(3) { animation-duration: 2.2s; animation-delay: 0.2s; }
.bar:nth-child(4) { animation-duration: 1.4s; animation-delay: 0.3s; }
.bar:nth-child(5) { animation-duration: 2.4s; animation-delay: 0.4s; }
.bar:nth-child(6) { animation-duration: 1.7s; animation-delay: 0.5s; }
.bar:nth-child(7) { animation-duration: 1.9s; animation-delay: 0.6s; }
.bar:nth-child(8) { animation-duration: 2.3s; animation-delay: 0.7s; }
.bar:nth-child(9) { animation-duration: 1.5s; animation-delay: 0.8s; }
.bar:nth-child(10) { animation-duration: 2.1s; animation-delay: 0.9s; }
.bar:nth-child(11) { animation-duration: 1.8s; animation-delay: 1s; }
.bar:nth-child(12) { animation-duration: 2.0s; animation-delay: 1.1s; }
.bar:nth-child(13) { animation-duration: 1.6s; animation-delay: 1.2s; }
.bar:nth-child(14) { animation-duration: 2.2s; animation-delay: 1.3s; }
.bar:nth-child(15) { animation-duration: 1.9s; animation-delay: 1.4s; }
.bar:nth-child(16) { animation-duration: 1.7s; animation-delay: 1.5s; }
.bar:nth-child(17) { animation-duration: 2.4s; animation-delay: 1.6s; }
.bar:nth-child(18) { animation-duration: 1.4s; animation-delay: 1.7s; }
.bar:nth-child(19) { animation-duration: 2.0s; animation-delay: 1.8s; }
.bar:nth-child(20) { animation-duration: 1.8s; animation-delay: 1.9s; }
#progressbar {
position: relative;
width: calc(100% + 15px);
height: 20px;
margin-left: -15px;
border-radius: 10px;
background-color: var(--background-color);
overflow: hidden;
}
#progressbar::after {
position: absolute;
content: '';
inset: 0;
border-radius: inherit;
width: 100%;
max-width: var(--progress);
background-color: var(--second-color);
transition: max-width 350ms ease-in-out;
}
@keyframes bounce {
0%, 100% {
transform: scaleY(0.3);
}
50% {
transform: scaleY(1);
}
}

View File

@ -0,0 +1,10 @@
<div id="widget">
<div id="player">
<img id="background_img">
<div class="meta">
<a id="album"></a>
<a id="title"></a>
<a id="artist"></a>
</div>
</div>
</div>

View File

@ -0,0 +1,74 @@
let widgetNode = document.getElementById('widget');
let musicPlayerNode = document.getElementById('player');
let musicPlayerTitleNode = document.getElementById('title');
let musicPlayerArtistNode = document.getElementById('artist');
let musicPlayerAlbumNode = document.getElementById('album');
let musicPlayerBackgroundNode = document.getElementById('background_img');
let musicPlayerProgress = document.getElementById('progressbar');
let pausedAt = null;
let trackDuration = 0;
let trackProgress = 0;
let trackEnd = new Date();
window.addEventListener('message', function (event) {
let message = event.detail;
let data = message.data;
widgetNode.classList.add('active');
if (data == null) {
musicPlayerNode.classList.remove('active');
return;
};
if (!data.is_playing && !pausedAt) {
pausedAt = new Date();
};
if (data.is_playing) {
musicPlayerNode.classList.add('active');
pausedAt = null;
};
trackDuration = data.track.duration;
trackProgress = data.progress;
trackEnd = new Date().getTime() + data.track.duration - data.progress;
musicPlayerTitleNode.innerText = data.track.name;
musicPlayerArtistNode.innerText = data.track.artists.join(', ');
musicPlayerAlbumNode.innerText = `album: ${data.track.album}`;
if (musicPlayerBackgroundNode.src != data.track.cover) {
musicPlayerBackgroundNode.src = data.track.cover;
};
});
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
};
async function update() {
if (pausedAt && pausedAt.getTime() + 10000 < new Date().getTime()) {
player.classList.remove('active');
await delay(100);
return update();
};
var progress;
if (pausedAt) {
progress = trackProgress / trackDuration * 100;
} else {
progress = (trackDuration - (trackEnd - new Date().getTime())) / trackDuration * 100;
};
if (progress >= 100) {
progress = 100;
};
musicPlayerProgress.style.setProperty('--progress', `${progress}%`);
await delay(100);
update();
};
update();

View File

@ -0,0 +1,66 @@
@import url('https://fonts.googleapis.com/css2?family=Nunito:ital,wght@0,200..1000;1,200..1000&display=swap');
#widget {
display: flex;
align-items: center;
justify-content: center;
visibility: hidden
}
#widget.active {
visibility: visible
}
#player {
position: relative;
display: inline-flex;
width: 800px;
height: 320px;
overflow: hidden;
border-radius: 30px;
margin-inline: 30px;
color: #fff;
font-family: "Nunito", sans-serif;
opacity: 0;
background-color: #242424;
transition: opacity 350ms ease-in-out
}
#player.active {
opacity: 1
}
#player #background_img {
height: 100%;
border-radius: 30px;
}
#player .meta {
display: flex;
flex-direction: column;
width: 450px;
margin: auto;
margin-left: 30px;
}
#player .meta a {
word-break: keep-all;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
#player #album {
font-size: 32px;
color: #E47D7D;
}
#player #title {
font-size: 42px;
font-weight: 900;
}
#player #artist {
font-size: 40px;
opacity: .6;
}