Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions websites/M/Media/metadata.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"$schema": "https://schemas.premid.app/metadata/1.16",
"apiVersion": 1,
"author": {
"name": "siq",
"id": "123456789012345678"
},
"service": "Media",
"description": {
"en": "Self-hosted media tracking platform for music, books, movies, games, and more."
},
"url": "media.siqnole.dev",
"regExp": "^(?:https?[:][/][/])?(?:www[.])?(?:media[.]siqnole[.]dev|localhost:5173)[/]",
"version": "1.0.0",
"logo": "https://media.siqnole.dev/mydia.png",

Check failure

Code scanning / PMD

Makes sure all images (logo and URLs) are exactly 512x512 pixels Error

Image URL dimensions must be exactly 512x512 pixels, got 800x800 for URL: https://media.siqnole.dev/mydia.png
Comment thread
github-advanced-security[bot] marked this conversation as resolved.
Fixed
"thumbnail": "https://media.siqnole.dev/mydia.png",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thumbnail should be a landscape promotional image or screenshot

"color": "#a688e8",
"category": "socials",
"tags": [

Check failure

Code scanning / PMD

Makes sure the `tags` don't contain the service name Error

Tags must not contain the service name
Comment thread
github-advanced-security[bot] marked this conversation as resolved.
Fixed
"media",
"tracking",
"ratings"
]
}
141 changes: 141 additions & 0 deletions websites/M/Media/presence.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
import { ActivityType } from 'premid'

// NOTE: Since Discord proxies all status images, it cannot fetch local files (like localhost or media.siqnole.dev if it's local).
// Replace the URL below with a publicly hosted URL of your logo (e.g. uploaded to Imgur or Discord CDN) to resolve "No Image".
const APP_LOGO_URL = 'https://media.siqnole.dev/mydia.png'

Check failure

Code scanning / PMD

Makes sure all images (logo and URLs) are exactly 512x512 pixels Error

Image URL dimensions must be exactly 512x512 pixels, got 800x800 for URL: https://media.siqnole.dev/mydia.png
Comment thread
github-advanced-security[bot] marked this conversation as resolved.
Fixed

const presence = new Presence({
clientId: '1511807266913910855',
})

let browsingTimestamp = Math.floor(Date.now() / 1000)
let lastPath = ''

presence.on('UpdateData', async () => {
const { pathname } = document.location

// Reset timestamp when switching major pages
if (pathname !== lastPath) {
browsingTimestamp = Math.floor(Date.now() / 1000)
lastPath = pathname
}

let presenceData: PresenceData

// Identify active Now Live items and scrape their cover art URL if available
let activeMedia: { label: string, title: string, sub: string, coverUrl: string | null } | null = null

if (pathname.startsWith('/@')) {
const firstNowItem = document.querySelector('.now-grid .now-item')
if (firstNowItem) {
const label = firstNowItem.querySelector('.now-label')?.textContent?.trim().toLowerCase() || ''
const title = firstNowItem.querySelector('.now-title')?.textContent?.trim() || ''
const sub = firstNowItem.querySelector('.now-sub')?.textContent?.trim() || ''

// Scrape cover image if it exists (e.g., Spotify, Steam, or custom reading cover)
const imgEl = firstNowItem.querySelector('.now-art img') as HTMLImageElement | null
const coverUrl = (imgEl && imgEl.src) ? imgEl.src : null

if (title) {
activeMedia = { label, title, sub, coverUrl }
}
}
}

if (activeMedia) {
const { label, title, sub, coverUrl } = activeMedia
const profileUser = pathname.substring(2)
const stateText = sub ? `${title} (${sub})` : title

// Use the scraped cover art as the large image, and pin the app logo in the corner as the small image!
const largeImage = coverUrl || APP_LOGO_URL
const smallImage = coverUrl ? APP_LOGO_URL : undefined

if (label.includes('listening')) {
presenceData = {
largeImageKey: largeImage,
largeImageText: `Viewing @${profileUser}'s profile`,
smallImageKey: smallImage,
smallImageText: 'media.siqnole.dev',
startTimestamp: browsingTimestamp,
type: ActivityType.Listening,
details: `Listening to:`,
state: stateText,
}
}
else if (label.includes('watching') || label.includes('film') || label.includes('movie')) {
presenceData = {
largeImageKey: largeImage,
largeImageText: `Viewing @${profileUser}'s profile`,
smallImageKey: smallImage,
smallImageText: 'media.siqnole.dev',
startTimestamp: browsingTimestamp,
type: ActivityType.Watching,
details: `Watching:`,
state: stateText,
}
}
else {
// playing / reading - Non-media (ActivityType.Playing). No largeImageText is allowed in PreMiD.
presenceData = {
largeImageKey: largeImage,
smallImageKey: smallImage,
smallImageText: 'media.siqnole.dev',
startTimestamp: browsingTimestamp,
type: ActivityType.Playing,
details: label.includes('playing') || label.includes('steam') ? 'Playing:' : 'Reading:',
state: stateText,
}
}
}
else {
// Non-media state (browsing) - No largeImageText allowed!
let details = 'Browsing'
let state = 'Home'

if (pathname === '/') {
details = 'Browsing Landing Page'
state = 'Welcome to Media'
}
else if (pathname === '/home') {
details = 'Checking Feed'
state = 'Browsing recent activity'
}
else if (pathname === '/login') {
details = 'Logging In'
state = 'Authenticating'
}
else if (pathname === '/register') {
details = 'Creating Account'
state = 'Joining the platform'
}
else if (pathname === '/shop') {
details = 'Browsing the Shop'
state = 'Checking out cosmetics'
}
else if (pathname === '/admin') {
details = 'Managing Platform'
state = 'Admin Dashboard'
}
else if (pathname.startsWith('/@')) {
const profileUser = pathname.substring(2)
details = `Viewing @${profileUser}'s profile`
state = 'Viewing profile'
}

presenceData = {
largeImageKey: APP_LOGO_URL,
startTimestamp: browsingTimestamp,
type: ActivityType.Playing,
details,
state,
}
}

if (presenceData.details) {
presence.setActivity(presenceData)
}
else {
presence.clearActivity()
}
})
Loading