Skip to content

Commit

Permalink
feat(Cineby): add activity (#9087)
Browse files Browse the repository at this point in the history
  • Loading branch information
Slowlife01 authored Jan 6, 2025
1 parent 8e252df commit 8be78e4
Show file tree
Hide file tree
Showing 3 changed files with 247 additions and 0 deletions.
111 changes: 111 additions & 0 deletions websites/C/Cineby/api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/* eslint-disable camelcase */
// Hack to resolve Deepscan
const no_op = (a: number) => a + 1;
no_op(0);

export interface Details {
poster_path?: string;
}

export interface TvDetails extends Details {
name?: string;
season_poster?: string;
episode_title?: string;
episode_number?: number;
season_number?: number;
}

export interface EpisodeDetails {
name: string;
episode_number: number;
season_number: number;
}

export interface MovieDetails extends Details {
title?: string;
release_date?: string;
runtime?: number;
}

export interface AnimeDetails {
details: {
title: string;
thumbnail: string;
episodes: {
episode: number;
title: string;
}[];
};
}

const cache: Map<string, TvDetails | MovieDetails | AnimeDetails> = new Map();

export class CinebyApi {
private static readonly BASE_URL = "https://db.cineby.app/3";
private static readonly API_KEY = "269890f657dddf4635473cf4cf456576";

private static readonly ANIME_URL = "https://api.cineby.app/hianime";

public static async getCurrent<T extends TvDetails | MovieDetails>(
pathname: string
): Promise<T> {
if (cache.has(pathname)) return cache.get(pathname) as T;

const [type, id] = pathname.split("/").slice(1),
response = await fetch(
`${this.BASE_URL}/${type}/${id}?language=en&api_key=${this.API_KEY}`
);

if (type === "tv") {
const json = await response.json(),
episode = await this.getCurrentEpisode(pathname),
returnData = {
...json,
season_poster: json.seasons[episode.season_number - 1].poster_path,
episode_title: episode.name,
episode_number: episode.episode_number,
season_number: episode.season_number,
} as T;

cache.set(pathname, returnData);

return returnData;
}

const json = await response.json();
cache.set(pathname, json);

return json;
}

private static async getCurrentEpisode(
pathname: string
): Promise<EpisodeDetails> {
const [id, season, episode] = pathname.split("/").slice(2),
response = await fetch(
`${this.BASE_URL}/tv/${id}/season/${season ?? 1}/episode/${
episode ?? 1
}?language=en&api_key=${this.API_KEY}`
);

return response.json();
}

public static async getCurrentAnime(pathname: string): Promise<AnimeDetails> {
if (cache.has(pathname)) return cache.get(pathname) as AnimeDetails;

const { search } = document.location,
id = pathname.split("/")[2],
response = await fetch(
`${
this.ANIME_URL
}/sources-with-id?providerId=${id}&dub=${new URLSearchParams(
search
).get("dub")}`
);

cache.set(pathname, await response.json());

return response.json();
}
}
43 changes: 43 additions & 0 deletions websites/C/Cineby/metadata.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
{
"$schema": "https://schemas.premid.app/metadata/1.12",
"apiVersion": 1,
"author": {
"id": "374905512661221377",
"name": "slowlife."
},
"service": "Cineby",
"description": {
"en": "Watch Free TV Shows Online, Watch Free Movies Online"
},
"url": "www.cineby.app",
"version": "1.0.0",
"logo": "https://i.imgur.com/zAKeytL.png",
"thumbnail": "https://i.imgur.com/MrvcmcK.png",
"color": "#fb0013",
"category": "videos",
"tags": [
"series",
"movies",
"anime"
],
"settings": [
{
"id": "showBrowsing",
"title": "Show Browsing",
"icon": "fad fa-search",
"value": false
},
{
"id": "useActivityName",
"title": "Show Title as Activity",
"icon": "fad fa-user-edit",
"value": true
},
{
"id": "showCover",
"title": "Show Cover",
"icon": "fas fa-images",
"value": true
}
]
}
93 changes: 93 additions & 0 deletions websites/C/Cineby/presence.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import { CinebyApi, MovieDetails, TvDetails } from "./api";

const presence = new Presence({
clientId: "1325115346696273993",
}),
startTimestamp = Math.floor(Date.now() / 1000);

presence.on("UpdateData", async () => {
const presenceData: PresenceData = {
largeImageKey: "https://i.imgur.com/zAKeytL.png",
details: "Browsing",
type: ActivityType.Watching,
startTimestamp,
},
{ pathname } = document.location,
[showBrowsing, useActivityName, showCover] = await Promise.all([
presence.getSetting<boolean>("showBrowsing"),
presence.getSetting<boolean>("useActivityName"),
presence.getSetting<boolean>("showCover"),
]);

switch (pathname.split("/")[1]) {
case "movie": {
const {
title,
poster_path: posterPath,
release_date: releaseDate,
runtime,
} = await CinebyApi.getCurrent<MovieDetails>(pathname);

if (useActivityName) presenceData.name = title;
presenceData.details = title;
presenceData.state = `${releaseDate
.split("-")
.shift()}${runtime} minutes`;

if (showCover)
presenceData.largeImageKey = `https://image.tmdb.org/t/p/original${posterPath}`;
break;
}
case "tv": {
const {
name: title,
season_poster: seasonPoster,
episode_title: episodeTitle,
season_number: seasonNumber,
episode_number: episodeNumber,
} = await CinebyApi.getCurrent<TvDetails>(pathname);

if (useActivityName) presenceData.name = title;

presenceData.details = useActivityName ? episodeTitle : title;
presenceData.state = useActivityName
? `Season ${seasonNumber}, Episode ${episodeNumber}`
: `S${seasonNumber}:E${episodeNumber} ${episodeTitle}`;

if (showCover)
presenceData.largeImageKey = `https://image.tmdb.org/t/p/original${seasonPoster}`;

break;
}
case "anime": {
const { details } = await CinebyApi.getCurrentAnime(pathname),
{ title, thumbnail, episodes } = details,
{ episode, title: episodeTitle } = episodes.find(
({ episode }) =>
episode === (parseInt(pathname.split("/").pop()) || 1)
);

if (useActivityName) presenceData.name = title;

presenceData.details = useActivityName
? episodeTitle.replace(/E[0-9]{1,}: /, "").trim()
: title;
presenceData.state = `Episode ${episode}`;

if (showCover) presenceData.largeImageKey = thumbnail;
break;
}
default:
if (!showBrowsing) return presence.clearActivity();
}

const video = document.querySelector("video");
if (video) {
if (!video.paused) {
[presenceData.startTimestamp, presenceData.endTimestamp] =
presence.getTimestampsfromMedia(video);
} else presenceData.smallImageKey = Assets.Pause;
}

presence.setActivity(presenceData);
});

0 comments on commit 8be78e4

Please sign in to comment.