diff --git a/_data/lastfmActivity.js b/_data/lastfmActivity.js new file mode 100644 index 0000000..d7dd837 --- /dev/null +++ b/_data/lastfmActivity.js @@ -0,0 +1,83 @@ +/** + * Last.fm Activity Data + * Fetches from Indiekit's endpoint-lastfm public API + */ + +import EleventyFetch from "@11ty/eleventy-fetch"; + +const INDIEKIT_URL = process.env.SITE_URL || "https://example.com"; +const LASTFM_USERNAME = process.env.LASTFM_USERNAME || ""; + +/** + * Fetch from Indiekit's public Last.fm API endpoint + */ +async function fetchFromIndiekit(endpoint) { + try { + const url = `${INDIEKIT_URL}/lastfmapi/api/${endpoint}`; + console.log(`[lastfmActivity] Fetching from Indiekit: ${url}`); + const data = await EleventyFetch(url, { + duration: "15m", + type: "json", + }); + console.log(`[lastfmActivity] Indiekit ${endpoint} success`); + return data; + } catch (error) { + console.log( + `[lastfmActivity] Indiekit API unavailable for ${endpoint}: ${error.message}` + ); + return null; + } +} + +export default async function () { + try { + console.log("[lastfmActivity] Fetching Last.fm data..."); + + // Fetch all data from Indiekit API + const [nowPlaying, scrobbles, loved, stats] = await Promise.all([ + fetchFromIndiekit("now-playing"), + fetchFromIndiekit("scrobbles"), + fetchFromIndiekit("loved"), + fetchFromIndiekit("stats"), + ]); + + // Check if we got data + const hasData = nowPlaying || scrobbles?.scrobbles?.length || stats?.summary; + + if (!hasData) { + console.log("[lastfmActivity] No data available from Indiekit"); + return { + nowPlaying: null, + scrobbles: [], + loved: [], + stats: null, + username: LASTFM_USERNAME, + profileUrl: LASTFM_USERNAME ? `https://www.last.fm/user/${LASTFM_USERNAME}` : null, + source: "unavailable", + }; + } + + console.log("[lastfmActivity] Using Indiekit API data"); + + return { + nowPlaying: nowPlaying || null, + scrobbles: scrobbles?.scrobbles || [], + loved: loved?.loved || [], + stats: stats || null, + username: LASTFM_USERNAME, + profileUrl: LASTFM_USERNAME ? `https://www.last.fm/user/${LASTFM_USERNAME}` : null, + source: "indiekit", + }; + } catch (error) { + console.error("[lastfmActivity] Error:", error.message); + return { + nowPlaying: null, + scrobbles: [], + loved: [], + stats: null, + username: LASTFM_USERNAME, + profileUrl: null, + source: "error", + }; + } +} diff --git a/listening.njk b/listening.njk new file mode 100644 index 0000000..256f267 --- /dev/null +++ b/listening.njk @@ -0,0 +1,432 @@ +--- +layout: layouts/base.njk +title: Listening Activity +permalink: /listening/ +withSidebar: true +--- +
+
+

Listening Activity

+

+ What I've been listening to on + {% if funkwhaleActivity.instanceUrl %} + Funkwhale + {% endif %} + {% if funkwhaleActivity.instanceUrl and lastfmActivity.profileUrl %} and {% endif %} + {% if lastfmActivity.profileUrl %} + Last.fm + {% endif %} +

+
+ + {# Source Filter Tabs #} +
+ + {% if funkwhaleActivity.source == 'indiekit' %} + + {% endif %} + {% if lastfmActivity.source == 'indiekit' %} + + {% endif %} +
+ + {# Now Playing Section - Combined #} + {% set fwNowPlaying = funkwhaleActivity.nowPlaying if funkwhaleActivity.nowPlaying and funkwhaleActivity.nowPlaying.status else null %} + {% set lfmNowPlaying = lastfmActivity.nowPlaying if lastfmActivity.nowPlaying and lastfmActivity.nowPlaying.status else null %} + + {% if fwNowPlaying or lfmNowPlaying %} +
+ {# Funkwhale Now Playing #} + {% if fwNowPlaying %} +
+
+
+ {% if fwNowPlaying.coverUrl %} + + {% else %} +
+ + + +
+ {% endif %} + +
+
+ Funkwhale + {% if fwNowPlaying.status == 'now-playing' %} + + + + + + + Now Playing + + {% else %} + + Recently Played + + {% endif %} +
+ +

+ {% if fwNowPlaying.trackUrl %} + {{ fwNowPlaying.track }} + {% else %} + {{ fwNowPlaying.track }} + {% endif %} +

+

{{ fwNowPlaying.artist }}

+ {% if fwNowPlaying.album %} +

{{ fwNowPlaying.album }}

+ {% endif %} +

{{ fwNowPlaying.relativeTime }}

+
+
+
+
+ {% endif %} + + {# Last.fm Now Playing #} + {% if lfmNowPlaying %} +
+
+
+ {% if lfmNowPlaying.coverUrl %} + + {% else %} +
+ + + +
+ {% endif %} + +
+
+ Last.fm + {% if lfmNowPlaying.status == 'now-playing' %} + + + + + + + Now Playing + + {% else %} + + Recently Played + + {% endif %} + {% if lfmNowPlaying.loved %} + + {% endif %} +
+ +

+ {% if lfmNowPlaying.trackUrl %} + {{ lfmNowPlaying.track }} + {% else %} + {{ lfmNowPlaying.track }} + {% endif %} +

+

{{ lfmNowPlaying.artist }}

+ {% if lfmNowPlaying.album %} +

{{ lfmNowPlaying.album }}

+ {% endif %} +

{{ lfmNowPlaying.relativeTime }}

+
+
+
+
+ {% endif %} +
+ {% endif %} + + {# Combined Stats Section #} + {% if funkwhaleActivity.stats or lastfmActivity.stats %} +
+

+ + + + Listening Statistics +

+ + {# Stats Cards Grid - Side by Side #} +
+ {# Funkwhale Stats #} + {% if funkwhaleActivity.stats %} +
+

+ + Funkwhale +

+
+
+
{{ funkwhaleActivity.stats.summary.all.totalPlays | default(0) }}
+
Plays
+
+
+
{{ funkwhaleActivity.stats.summary.all.uniqueArtists | default(0) }}
+
Artists
+
+
+
{{ funkwhaleActivity.stats.summary.all.uniqueTracks | default(0) }}
+
Tracks
+
+
+ {# Top Artists #} + {% if funkwhaleActivity.stats.topArtists.all.length %} +
+

Top Artists

+
+ {% for artist in funkwhaleActivity.stats.topArtists.all | head(5) %} +
+ {{ artist.name }} + {{ artist.playCount }} +
+ {% endfor %} +
+
+ {% endif %} +
+ {% endif %} + + {# Last.fm Stats #} + {% if lastfmActivity.stats %} +
+

+ + Last.fm +

+
+
+
{{ lastfmActivity.stats.summary.all.totalPlays | default(0) }}
+
Scrobbles
+
+
+
{{ lastfmActivity.stats.summary.all.uniqueArtists | default(0) }}
+
Artists
+
+
+
{{ lastfmActivity.stats.summary.all.lovedCount | default(0) }}
+
Loved
+
+
+ {# Top Artists from Last.fm #} + {% if lastfmActivity.stats.topArtists.all.length %} +
+

Top Artists

+
+ {% for artist in lastfmActivity.stats.topArtists.all | head(5) %} +
+ {{ artist.name }} + {{ artist.playCount }} +
+ {% endfor %} +
+
+ {% endif %} +
+ {% endif %} +
+
+ {% endif %} + + {# Recent Listens - Combined Timeline #} +
+

+ + + + Recent Listens +

+ +
+ {# Funkwhale Listenings #} + {% if funkwhaleActivity.listenings.length %} +
+ {% for listening in funkwhaleActivity.listenings | head(10) %} +
+ {% if listening.coverUrl %} + + {% else %} +
+ + + +
+ {% endif %} + +
+

+ {% if listening.trackUrl %} + {{ listening.track }} + {% else %} + {{ listening.track }} + {% endif %} +

+

{{ listening.artist }}

+
+ +
+ Funkwhale + {{ listening.relativeTime }} +
+
+ {% endfor %} +
+ {% endif %} + + {# Last.fm Scrobbles #} + {% if lastfmActivity.scrobbles.length %} +
+ {% for scrobble in lastfmActivity.scrobbles | head(10) %} +
+ {% if scrobble.coverUrl %} + + {% else %} +
+ + + +
+ {% endif %} + +
+

+ {% if scrobble.trackUrl %} + {{ scrobble.track }} + {% else %} + {{ scrobble.track }} + {% endif %} + {% if scrobble.loved %} + + {% endif %} +

+

{{ scrobble.artist }}

+
+ +
+ Last.fm + {{ scrobble.relativeTime }} +
+
+ {% endfor %} +
+ {% endif %} + + {% if not funkwhaleActivity.listenings.length and not lastfmActivity.scrobbles.length %} +

No recent listening history available.

+ {% endif %} +
+
+ + {# Loved Tracks from Last.fm #} + {% if lastfmActivity.loved.length %} +
+

+ + + + Loved Tracks + (Last.fm) +

+ +
+ {% for track in lastfmActivity.loved | head(10) %} +
+ {% if track.coverUrl %} + + {% else %} +
+ + + +
+ {% endif %} + +
+

+ {% if track.trackUrl %} + {{ track.track }} + {% else %} + {{ track.track }} + {% endif %} +

+

{{ track.artist }}

+
+ + +
+ {% endfor %} +
+
+ {% endif %} + + {# Funkwhale Favorites #} + {% if funkwhaleActivity.favorites.length %} +
+

+ + + + Favorite Tracks + (Funkwhale) +

+ +
+ {% for favorite in funkwhaleActivity.favorites | head(10) %} +
+ {% if favorite.coverUrl %} + + {% else %} +
+ + + +
+ {% endif %} + +
+

+ {% if favorite.trackUrl %} + {{ favorite.track }} + {% else %} + {{ favorite.track }} + {% endif %} +

+

{{ favorite.artist }}

+ {% if favorite.album %} +

{{ favorite.album }}

+ {% endif %} +
+
+ {% endfor %} +
+
+ {% endif %} +