This commit is contained in:
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"id": "netflix",
|
||||||
|
"name": "Netflix",
|
||||||
|
"description": "Shows the title and episode you're watching on Netflix.",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"author": "hibna",
|
||||||
|
"match": ["https://www.netflix.com/*"],
|
||||||
|
"tickInterval": 1500,
|
||||||
|
"sdkVersion": "^0.1.0"
|
||||||
|
}
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
import { ActivityType, definePresence } from "@source/presence-sdk";
|
||||||
|
|
||||||
|
function findVideo(): HTMLVideoElement | null {
|
||||||
|
return document.querySelector<HTMLVideoElement>("video");
|
||||||
|
}
|
||||||
|
|
||||||
|
function readShowTitle(): string | null {
|
||||||
|
const node =
|
||||||
|
document.querySelector<HTMLElement>("[data-uia='video-title'] h4") ??
|
||||||
|
document.querySelector<HTMLElement>(".video-title h4") ??
|
||||||
|
document.querySelector<HTMLElement>("[data-uia='player-title']");
|
||||||
|
return node?.textContent?.trim() ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function readEpisodeInfo(): string | null {
|
||||||
|
const root =
|
||||||
|
document.querySelector<HTMLElement>("[data-uia='video-title']") ??
|
||||||
|
document.querySelector<HTMLElement>(".video-title");
|
||||||
|
if (!root) return null;
|
||||||
|
const spans = Array.from(root.querySelectorAll<HTMLElement>("span"))
|
||||||
|
.map((s) => s.textContent?.trim())
|
||||||
|
.filter((t): t is string => !!t && t.length > 0);
|
||||||
|
return spans.length > 0 ? spans.join(" · ") : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isPlayerOpen(): boolean {
|
||||||
|
return location.pathname.startsWith("/watch/");
|
||||||
|
}
|
||||||
|
|
||||||
|
function browsingLabel(): string {
|
||||||
|
if (location.pathname.startsWith("/browse/genre")) return "Browsing genres";
|
||||||
|
if (location.pathname.startsWith("/latest")) return "Browsing new releases";
|
||||||
|
if (location.pathname.startsWith("/my-list")) return "Browsing my list";
|
||||||
|
if (location.pathname.startsWith("/search")) return "Searching";
|
||||||
|
if (location.pathname.startsWith("/title/")) return "Viewing title";
|
||||||
|
return "Browsing";
|
||||||
|
}
|
||||||
|
|
||||||
|
export default definePresence({
|
||||||
|
match: ["https://www.netflix.com/*"],
|
||||||
|
tickInterval: 1500,
|
||||||
|
tick(ctx) {
|
||||||
|
if (!isPlayerOpen()) {
|
||||||
|
ctx.setActivity({
|
||||||
|
type: ActivityType.WATCHING,
|
||||||
|
name: "Netflix",
|
||||||
|
details: browsingLabel(),
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const video = findVideo();
|
||||||
|
const title = readShowTitle();
|
||||||
|
|
||||||
|
if (!video || !title) {
|
||||||
|
ctx.setActivity({
|
||||||
|
type: ActivityType.WATCHING,
|
||||||
|
name: "Netflix",
|
||||||
|
details: "Loading…",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const episode = readEpisodeInfo();
|
||||||
|
const paused = video.paused;
|
||||||
|
const remainingMs =
|
||||||
|
Number.isFinite(video.duration) && video.duration > 0
|
||||||
|
? Math.floor((video.duration - video.currentTime) * 1000)
|
||||||
|
: null;
|
||||||
|
|
||||||
|
ctx.setActivity({
|
||||||
|
type: ActivityType.WATCHING,
|
||||||
|
name: "Netflix",
|
||||||
|
details: title,
|
||||||
|
state: episode
|
||||||
|
? `${paused ? "Paused" : "Watching"} · ${episode}`
|
||||||
|
: paused
|
||||||
|
? "Paused"
|
||||||
|
: "Watching",
|
||||||
|
url: location.href,
|
||||||
|
startedAt: paused ? null : Date.now() - Math.floor(video.currentTime * 1000),
|
||||||
|
endsAt: paused || remainingMs === null ? null : Date.now() + remainingMs,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user