update now-playing widget to use listenbrainz

This commit is contained in:
Penelope Gwen 2025-11-09 14:00:32 -08:00
parent 8eee6a1529
commit 6460a513d7
5 changed files with 140 additions and 23 deletions

View file

@ -5,7 +5,7 @@
<title>Penelope Gwen</title> <title>Penelope Gwen</title>
<meta name="viewport" content="width=device-width,initial-scale=1"> <meta name="viewport" content="width=device-width,initial-scale=1">
<link rel="stylesheet" href="/style/css/style.css"> <link rel="stylesheet" href="/style/css/style.css">
<script src="/style/js/lastfm-nowplaying.js"></script> <!-- <script src="/style/js/lastfm-nowplaying.js"></script>-->
</head> </head>
<body> <body>
<h1>Penelope Gwen</h1> <h1>Penelope Gwen</h1>
@ -24,7 +24,17 @@
<div id='random-buttons'> <div id='random-buttons'>
</div> </div>
</div> </div>
<div id="nowplaying-placeholder"></div> <div id="now-playing" hidden="true">
<a class="flexrow now-playing" href="https://listenbrainz.org/user/pogmommy/">
<img id="np-cover" src="" hidden="true">
<div class="np-metadata sidebar-caption">
<span id="np-heading">Now Playing</span>
<span id="np-timestamp" hidden="true"></span>
<span id="np-title" class="np-title">Title</span>
<span id="np-artist">Artist</span>
</div>
</a>
</div>
<div> <div>
<h3 class="sidebar-caption">Check out my friends!</h3> <h3 class="sidebar-caption">Check out my friends!</h3>
<a href="https://cassiecandles.net/"> <a href="https://cassiecandles.net/">
@ -73,7 +83,7 @@
<script type="module" src="https://esm.sh/emfed@1"></script> <script type="module" src="https://esm.sh/emfed@1"></script>
<script> <script>
document.getElementById("emfed-placeholder").innerHTML = ""; document.getElementById("emfed-placeholder").innerHTML = "";
getNowPlaying(); // getNowPlaying();
</script> </script>
<div class="pagecontent"> <div class="pagecontent">
<div class="bubble"> <div class="bubble">
@ -116,5 +126,6 @@
<!-- <div id="footer"><p>Click <a href="https://pogmom.me/links.html">here</a> or enable javascript to view my social links</p></div> <!-- <div id="footer"><p>Click <a href="https://pogmom.me/links.html">here</a> or enable javascript to view my social links</p></div>
<script src="/style/js/views.js"></script>--> <script src="/style/js/views.js"></script>-->
<script src="/style/js/buttons.js"></script> <script src="/style/js/buttons.js"></script>
<script src="/style/js/listenbrainz-nowplaying.js"></script>
</body> </body>
</html> </html>

View file

@ -98,12 +98,13 @@ p {
.button { .button {
margin: 1vh 1vw; margin: 1vh 1vw;
transition: 0.5s; transition: 0.5s;
background-color: rgba(from var(--secondary-bg-color) r g b / 0.2);
display:block; display:block;
& > p { & > p {
margin: 1vh 0vw; margin: 1vh 0vw;
} }
&:hover{ &:hover{
box-shadow: 0px 0px 30px rgba(from var(--main-fg-color) r g b / 0.8); box-shadow: 0px 0px 30px rgba(from var(--secondary-bg-color) r g b / 0.6);
transition: 0.25s; transition: 0.25s;
} }
} }
@ -197,23 +198,21 @@ p {
font-family: 'Overpass'; font-family: 'Overpass';
font-style: normal; font-style: normal;
font-weight: 400; font-weight: 400;
src: url(/style/fonts/overpass/latin-ext.woff2) format('woff2'); src: url(/style/fonts/overpass/OverpassNerdFont-Regular.otf) format('opentype');
unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; /*unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;*/
} }
@font-face { /*@font-face {
font-family: 'Overpass'; font-family: 'Overpass';
font-style: normal; font-style: normal;
font-weight: 400; font-weight: 400;
src: url(/style/fonts/overpass/latin.woff2) format('woff2'); src: url(/style/fonts/overpass/latin.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
} }*/
/*LASTFM NOWPLAYING*/ /*LISTENBRAINZ NOWPLAYING*/
a.now-playing { a.now-playing {
opacity: 1;
text-decoration: none; text-decoration: none;
} }
.now-playing .np-metadata > span { .now-playing .np-metadata > span {
@ -224,18 +223,24 @@ a.now-playing {
.now-playing .np-metadata { .now-playing .np-metadata {
margin: auto 1vw auto; margin: auto 1vw auto;
height: fit-content; height: fit-content;
opacity: 0;
transition: opacity 0.4s ease-out; transition: opacity 0.4s ease-out;
transition-delay: 0.5s; transition-delay: 0.5s;
} }
.now-playing.loaded .np-metadata,.now-playing.loaded img { .now-playing.loaded .np-metadata,.now-playing.loaded img {
opacity: 1; opacity: 1;
} }
.np-title {
font-weight: bold;
}
.now-playing img { .now-playing img {
border-radius: 8px; border-radius: 8px;
color: transparent;
background-color: rgba(from var(--secondary-bg-color) r g b / 0.1);
font-size: 0px;
aspect-ratio: 1;
width: 25%; width: 25%;
} }
.now-playing .np-metadata .np-heading { #np-heading, #np-timestamp {
font-size: 11px; font-size: 11px;
font-weight: 900; font-weight: 900;
opacity: 0.5; opacity: 0.5;
@ -243,15 +248,16 @@ a.now-playing {
letter-spacing: 0.11em; letter-spacing: 0.11em;
} }
.now-playing .np-metadata .breather { .now-playing .np-metadata .breather {
margin-right: 8px; margin-right: 4px;
display: inline-block; display: inline-block;
animation: pulsate 5s linear 0s infinite; animation: pulsate 5s linear 0s infinite;
} }
@keyframes pulsate { @keyframes pulsate {
0% { transform: scale(0.2, 0.2) rotate(0deg); opacity: 0.0; } 0% { transform: scale(0.1, 0.1); opacity: 0.0; }
50% { transform: scale(1, 1) rotate(50deg); opacity: 1; } 50% { transform: scale(1, 1); opacity: 1; }
80% { transform: scale(1.8, 1.8) rotate(80deg); opacity: 0.2; } 80% { transform: scale(1.5, 1.5); opacity: 0.2; }
100% { transform: scale(4, 4) rotate(100deg); opacity: 0; } 90% { transform: scale(2, 2); opacity: 0; }
100% { transform: scale(2, 2); opacity: 0; }
} }
/*EMFED*/ /*EMFED*/

Binary file not shown.

View file

@ -0,0 +1,105 @@
// Set the Listenbrainz username
const username = "pogmommy";
// Set displayElement to the now-playing widget text from the now_playing.html file
const displayTitle = document.getElementById("np-title");
//displayTitle.href = ""
const displayArtist = document.getElementById("np-artist");
const displayCover = document.getElementById("np-cover");
const displayStatus = document.getElementById("np-heading");
const displayTimestamp = document.getElementById("np-timestamp");
const widget = document.getElementById("now-playing");
// Update the widget attributes for the username set above
//displayTitle.href = `https://listenbrainz.org/user/${username}/`;
//displayElement.dataset.username = username;
// Define endpoints from Listenbrainz API
const endpoints = {
nowPlaying: `https://api.listenbrainz.org/1/user/${username}/playing-now`,
recentTrack: `https://api.listenbrainz.org/1/user/${username}/listens?count=1`,
};
// Function to check the API response and fail gracefully if it doesn't work
async function fetchJson(url) {
const response = await fetch(url);
if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
return response.json();
}
// Function to get the artwork via API response and fail gracefully if it doesn't work
async function fetchArtwork(url) {
const response = await fetch(url);
if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
return response.json();
}
// Function to set the artist and track title returned from Listenbrainz (or set it to Unknown if nothing is found)
function renderTrack(nowPlaying, track, cover, timestamp) {
const artist = track?.artist_name || "Unknown Artist";
const title = track?.track_name || "Unknown Track";
displayTitle.textContent = `${title}`;
displayArtist.textContent = `${artist}`;
if (nowPlaying) {
displayStatus.innerHTML = "<span class=\"breather\"></span>Now Playing";
displayTimestamp.hidden = true;
} else {
displayStatus.innerHTML = "Last Played"
displayTimestamp.textContent = `${timestamp}`;
displayTimestamp.hidden = false;
}
if (cover) {
const coverUrl = cover.images?.[0]?.thumbnails?.[500] || "";
displayCover.setAttribute("alt", `Album artwork for ${title} by ${artist}`);
displayCover.setAttribute("src", coverUrl);
displayCover.hidden = false;
} else {
displayCover.hidden = true;
}
widget.hidden = false;
}
// Function to update the widget
async function updateNowPlayingWidget() {
try {
// Fetch and parse data from the nowPlaying endpoint
const nowPlayingData = await fetchJson(endpoints.nowPlaying);
const playingNow = nowPlayingData?.payload?.playing_now;
const currentTrack = nowPlayingData?.payload?.listens?.[0]?.track_metadata;
// If something is currently playing, update the widget with Now Playing: currentTrack
if (playingNow && currentTrack) {
const coverData = await fetchJson(`https://coverartarchive.org/release/${currentTrack?.additional_info.release_mbid}`);
renderTrack(true, currentTrack, coverData, "");
return;
}
// Fetch and parse data from the recentTrack endpoint
const recentData = await fetchJson(endpoints.recentTrack);
const recentTrack = recentData?.payload?.listens?.[0]?.track_metadata;
const listenTimestamp = new Date(recentData?.payload?.listens?.[0]?.listened_at * 1000);
const timestampFormatted = `(${listenTimestamp.getUTCFullYear()}-${listenTimestamp.getMonth() + 1}-${listenTimestamp.getUTCDate()})`;
// If nothing is currently playing, update the widget with Last Played: recentTrack
if (recentTrack) {
const coverData = await fetchJson(`https://coverartarchive.org/release/${recentTrack?.additional_info.release_mbid}`);
renderTrack(false, recentTrack, coverData, timestampFormatted);
}
// If there is no recent track, update the widget to say This user has no listens yet
else {
displayStatus.textContent = "🎧 This user has no listens yet";
}
}
// If the script can't fetch the data, update the widget to say Error loading track info.
// Also give more details in the console
catch (error) {
console.error("Failed to update Now Playing widget:", error);
displayStatus.textContent = "🎧 Error loading track info";
}
}
// Update the widget when the page loads, and then every minute after
updateNowPlayingWidget();
setInterval(updateNowPlayingWidget, 60000);

View file

@ -1,5 +0,0 @@
fetch('/assets/views/footer.html')
.then(response => response.text())
.then( resultText => document.getElementById('footer').innerHTML = resultText );
getNowPlaying();