diff --git a/websites/C/Cinejoy/metadata.json b/websites/C/Cinejoy/metadata.json new file mode 100644 index 000000000000..053b4ff0b637 --- /dev/null +++ b/websites/C/Cinejoy/metadata.json @@ -0,0 +1,25 @@ +{ + "$schema": "https://schemas.premid.app/metadata/1.17", + "apiVersion": 1, + "author": { + "id": "1233363061440512011", + "name": "lxzy" + }, + "service": "Cinejoy", + "description": { + "en": "Watch free movies and TV shows on Cinejoy." + }, + "url": "cinejoy.to", + "regExp": "^https?[:][/][/]([a-z0-9-]+[.])*cinejoy[.]to[/]", + "version": "1.0.0", + "logo": "https://i.imgur.com/3wpcyto.png", + "thumbnail": "https://i.imgur.com/S4XjEAo.jpeg", + "color": "#95FF50", + "category": "videos", + "tags": [ + "movie", + "tv", + "series", + "streaming" + ] +} diff --git a/websites/C/Cinejoy/presence.ts b/websites/C/Cinejoy/presence.ts new file mode 100644 index 000000000000..c0e834b0d859 --- /dev/null +++ b/websites/C/Cinejoy/presence.ts @@ -0,0 +1,95 @@ +import { Assets, getTimestampsFromMedia } from 'premid' + +const presence = new Presence({ + clientId: '1534742028368347156', +}) + +const TMDB_KEY = '8476a7ab80ad76f0936744df0430e67c' +const TMDB_IMG = 'https://image.tmdb.org/t/p/w500' + +enum ActivityAssets { + Logo = 'https://cinejoy.to/favicon.ico', +} + +function parsePath() { + const path = document.location.pathname + const parts = path.split('/').filter(Boolean) + + const type = parts.find(p => p === 'tv' || p === 'movie') + if (!type) + return null + + const typeIndex = parts.indexOf(type) + const idPart = parts[typeIndex + 1] + const idMatch = idPart?.match(/^\d+/) + const tmdbId = idMatch?.[0] + if (!tmdbId) + return null + + const seasonPart = parts[typeIndex + 2] + const episodePart = parts[typeIndex + 3] + const season = seasonPart?.match(/\d+/)?.[0] + const episode = episodePart?.match(/\d+/)?.[0] + + return { type, tmdbId, season, episode } +} + +let cache: { key: string, details: any } | null = null + +async function getTmdbDetails(type: string, tmdbId: string) { + const key = `${type}-${tmdbId}` + if (cache?.key === key) + return cache.details + + const res = await fetch( + `https://api.themoviedb.org/3/${type}/${tmdbId}?api_key=${TMDB_KEY}&language=en-US`, + ) + const data = await res.json() + cache = { key, details: data } + return data +} + +presence.on('UpdateData', async () => { + const presenceData: PresenceData = { + largeImageKey: ActivityAssets.Logo, + details: 'Browsing Cinejoy', + } + + const parsed = parsePath() + const video = document.querySelector('video') + + if (parsed) { + try { + const data = await getTmdbDetails(parsed.type, parsed.tmdbId) + const title = data.title ?? data.name ?? 'Unknown' + const posterPath = data.poster_path + + presenceData.details = title + + if (parsed.type === 'tv' && parsed.season && parsed.episode) { + presenceData.state = `S${parsed.season}:E${parsed.episode}` + } + else if (parsed.type === 'movie' && data.release_date) { + presenceData.state = data.release_date.split('-')[0] + } + + if (posterPath) { + presenceData.largeImageKey = `${TMDB_IMG}${posterPath}` + } + } + catch { + presenceData.details = 'Watching Cinejoy' + } + } + + if (video && video.readyState > 0) { + presenceData.smallImageKey = video.paused ? Assets.Pause : Assets.Play + presenceData.smallImageText = video.paused ? 'Paused' : 'Playing' + + if (!video.paused && Number.isFinite(video.duration)) { + [presenceData.startTimestamp, presenceData.endTimestamp] = getTimestampsFromMedia(video) + } + } + + presence.setActivity(presenceData) +})