Skip to content

Commit

Permalink
TEMP: Bilibili
Browse files Browse the repository at this point in the history
  • Loading branch information
Eltik committed Aug 29, 2023
1 parent dda871c commit 6ef5df4
Show file tree
Hide file tree
Showing 5 changed files with 279 additions and 29 deletions.
32 changes: 13 additions & 19 deletions anify-backend/src/mapping/impl/anime/animeflix.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,7 @@ export default class AnimeFlix extends AnimeProvider {
// /idtoinfo?ids=[]
// /episodes?id=fuufu-ijou-koibito-miman&dub=false&a=j43o4d4d3o4d1j4142474d1j4347413k414c471j4541453j46

const hash = this.generateRandomStringWithSameLength("j43o4d4d3o4d1j4142474d1j4347413k414c471j4541453j46");

const test = await this.request(`${this.api}/episodes?id=${id}&dub=false&a=${hash}`, {
headers: {
"User-Agent": this.userAgent
},
});
const hash = this.generateHash(id);

const [dataResponse, dubResponse] = await Promise.all([
this.request(`${this.api}/episodes?id=${id}&dub=false&a=${hash}`, {
Expand All @@ -78,8 +72,6 @@ export default class AnimeFlix extends AnimeProvider {

const [data, dubData] = await Promise.all([dataResponse.json(), dubResponse.json()]);

console.log("yeah baby");

const dubNumbers = new Set((dubData?.episodes ?? []).map((dub) => dub.number));

const results: Episode[] = data.episodes.map((res) => ({
Expand Down Expand Up @@ -129,16 +121,18 @@ export default class AnimeFlix extends AnimeProvider {
return await new Extractor(data.source, result).extract(server);
}

private generateRandomStringWithSameLength(source: string): string {
const characters = "abcdefghijklmnopqrstuvwxyz0123456789";
let result = "";

for (let i = 0; i < source.length; i++) {
const randomIndex = Math.floor(Math.random() * characters.length);
result += characters[randomIndex];
private generateHash(source: string): string {
const currentDate = new Date();
const averageMonthAndDate = 9 + (currentDate.getUTCDate() + currentDate.getUTCMonth()) / 2;
let result = "j4";

const inputLength = source.length;
for (let i = 0; i < inputLength; i++) {
const charCode = source.charCodeAt(i);
const encodedValue = charCode.toString(Math.floor(averageMonthAndDate));
result += encodedValue;
}

return result;
}

}
}
174 changes: 174 additions & 0 deletions anify-backend/src/mapping/impl/anime/bilibili.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
import AnimeProvider, { Episode, Source, StreamingServers, SubType } from ".";
import { Format, Formats, Result } from "../..";
import { load } from "cheerio";
import Extractor from "@/src/helper/extractor";

export default class Bilibili extends AnimeProvider {
override rateLimit = 250;
override id = "bilibili";
override url = "https://bilibili.com";

private api = "https://api.bilibili.tv/intl/gateway/web";

override formats: Format[] = [Format.MOVIE, Format.ONA, Format.OVA, Format.SPECIAL, Format.TV, Format.TV_SHORT];

override get subTypes(): SubType[] {
return [SubType.SUB];
}

override get headers(): Record<string, string> | undefined {
return { Referer: "https://kwik.cx" };
}

override async search(query: string, format?: Format, year?: number): Promise<Result[] | undefined> {
const request = await this.request(`${this.api}/v2/search?keyword=${encodeURIComponent(query)}&platform=web&pn=1&ps=20&qid=&s_locale=en_US`);
if (!request.ok) {
console.log(await request.text())
return [];
}
const data = await request.json();
const results: Result[] = [];

console.log(data)

if (!data?.data) {
return [];
}

data.data.map((item) => {
const formatString: string = item.type.toUpperCase();
const f: Format = Formats.includes(formatString as Format) ? (formatString as Format) : Format.UNKNOWN;

results.push({
id: String(item.id) ?? item.session,
title: item.title,
year: item.year,
img: item.poster,
format: f,
altTitles: [],
providerId: this.id,
});
});

return results;
}

override async fetchEpisodes(id: string): Promise<Episode[] | undefined> {
const episodes: Episode[] = [];

const req = await (await this.request(`${this.url}${id.includes("-") ? `/anime/${id}` : `/a/${id}`}`)).text();

const $ = load(req);

const tempId = $("head > meta[property='og:url']").attr("content")!.split("/").pop()!;
const { last_page, data } = await (await this.request(`${this.url}/api?m=release&id=${tempId}&sort=episode_asc&page=1`)).json();

data.map((item) => {
const updatedAt = new Date(item.created_at ?? Date.now()).getTime();

episodes.push({
id: item.id + "-" + id,
number: item.episode,
title: item.title && item.title.length > 0 ? item.title : "Episode " + item.episode,
img: item.snapshot,
isFiller: item.filler === 1,
hasDub: false,
updatedAt,
});
});

const pageNumbers = Array.from({ length: last_page - 1 }, (_, i) => i + 2);

const promises = pageNumbers.map((pageNumber) => this.request(`${this.url}/api?m=release&id=${tempId}&sort=episode_asc&page=${pageNumber}`).then((res) => res.json()));
const results = await Promise.all(promises);

results.forEach((showData) => {
for (const data of showData.data) {
if (data) {
const updatedAt = new Date(data.created_at ?? Date.now()).getTime();

episodes.push({
id: data.id + "-" + id,
number: data.episode,
title: data.title && data.title.length > 0 ? data.title : "Episode " + data.episode,
img: data.snapshot,
isFiller: data.filler === 1,
hasDub: false,
updatedAt,
});
}
}
});
(data as any[]).sort((a, b) => a.number - b.number);
return episodes;
}

override async fetchSources(id: string, subType: SubType = SubType.SUB, server: StreamingServers = StreamingServers.Kwik): Promise<Source | undefined> {
const animeId = id.split("-").pop()!;
const episodeId = id.split("-")[0];

const req = await this.request(`${this.url}${animeId.includes("-") ? `/anime/${animeId}` : `/a/${animeId}`}`);

try {
const url = req.url;
// Need session id to fetch the watch page
const sessionId = url.split("/anime/").pop()!;

const $ = load(await req.text());
const tempId = $("head > meta[property='og:url']").attr("content")!.split("/").pop()!;
const { last_page, data } = await (await this.request(`${this.url}/api?m=release&id=${tempId}&sort=episode_asc&page=1`)).json();

let episodeSession = "";

for (let i = 0; i < data.length; i++) {
if (String(data[i].id) === episodeId) {
episodeSession = data[i].session;
break;
}
}

if (episodeSession === "") {
for (let i = 1; i < last_page; i++) {
const data = await (await this.request(`${this.url}/api?m=release&id=${tempId}&sort=episode_asc&page=${i + 1}`)).json();

for (let j = 0; j < data.length; j++) {
if (String(data[j].id) === episodeId) {
episodeSession = data[j].session;
break;
}
}

if (episodeSession !== "") break;
}
}

if (episodeSession === "") return undefined;

const watchReq = await (await this.request(`${this.url}/play/${sessionId}/${episodeSession}`)).text();

const regex = /https:\/\/kwik\.cx\/e\/\w+/g;
const matches = watchReq.match(regex);

if (matches === null) return undefined;

const result: Source = {
sources: [],
subtitles: [],
intro: {
start: 0,
end: 0,
},
outro: {
start: 0,
end: 0,
},
headers: this.headers ?? {},
};

return await new Extractor(matches[0], result).extract(server);
} catch (e) {
console.error(e);
return undefined;
}
}
}
3 changes: 2 additions & 1 deletion anify-backend/src/mapping/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,9 @@ import SimklMeta from "./impl/meta/simkl";
import Simkl from "./impl/information/simkl";
import ColoredManga from "./impl/manga/coloredmanga";
import AnimeFlix from "./impl/anime/animeflix";
import Bilibili from "./impl/anime/bilibili";

const ANIME_PROVIDERS: AnimeProvider[] = [new NineAnime(), new GogoAnime(), new Zoro(), new AnimePahe()];
const ANIME_PROVIDERS: AnimeProvider[] = [new NineAnime(), new GogoAnime(), new Zoro(), new AnimePahe(), new Bilibili()];
const animeProviders: Record<string, AnimeProvider> = ANIME_PROVIDERS.reduce((acc, provider) => {
acc[provider.id] = provider;
return acc;
Expand Down
86 changes: 86 additions & 0 deletions anify-backend/src/test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import dotenv from "dotenv";
dotenv.config();

import queues from "./worker";
import emitter, { Events } from "@/src/helper/event";
import { start } from "./server/server";
import Database from "./database";
import { MediaStatus, animeProviders } from "./mapping";
import { fetchCorsProxies } from "./helper/proxies";

emitter.on(Events.COMPLETED_SEASONAL_LOAD, async (data) => {
for (let i = 0; i < data.trending.length; i++) {
if (data.trending[i].status === MediaStatus.NOT_YET_RELEASED) {
continue;
}
const existing = await Database.info(String(data.trending[i].aniListId));
if (!existing) {
queues.mappingQueue.add({ id: data.trending[i].aniListId, type: data.trending[i].type });
}
}

for (let i = 0; i < data.popular.length; i++) {
if (data.popular[i].status === MediaStatus.NOT_YET_RELEASED) {
continue;
}
const existing = await Database.info(String(data.popular[i].aniListId));
if (!existing) queues.mappingQueue.add({ id: data.popular[i].aniListId, type: data.popular[i].type });
}

for (let i = 0; i < data.top.length; i++) {
if (data.top[i].status === MediaStatus.NOT_YET_RELEASED) {
continue;
}
const existing = await Database.info(String(data.top[i].aniListId));
if (!existing) queues.mappingQueue.add({ id: data.top[i].aniListId, type: data.top[i].type });
}

for (let i = 0; i < data.seasonal.length; i++) {
if (data.seasonal[i].status === MediaStatus.NOT_YET_RELEASED) {
continue;
}
const existing = await Database.info(String(data.seasonal[i].aniListId));
if (!existing) queues.mappingQueue.add({ id: data.seasonal[i].aniListId, type: data.seasonal[i].type });
}
});

emitter.on(Events.COMPLETED_MAPPING_LOAD, async (data) => {
for (let i = 0; i < data.length; i++) {
if (await Database.info(String(data[i].aniListId))) {
continue;
}
queues.createEntry.add({ toInsert: data[i], type: data[i].type });
}
});

emitter.on(Events.COMPLETED_SEARCH_LOAD, (data) => {
if (data[0]?.aniListId) {
for (let i = 0; i < data.length; i++) {
if (data[i].status === MediaStatus.NOT_YET_RELEASED) {
continue;
}
queues.mappingQueue.add({ id: data[i].aniListId, type: data[i].type });
}
}
});

// Todo: For inserting all skip times, merge the episodescrape repo so that it adds a bunch of events lol
emitter.on(Events.COMPLETED_SKIPTIMES_LOAD, (data) => {
// Do something
});

emitter.on(Events.COMPLETED_PAGE_UPLOAD, (data) => {
// Do something
});

queues.seasonQueue.start();
queues.mappingQueue.start();
queues.createEntry.start();
queues.searchQueue.start();
queues.skipTimes.start();
queues.uploadPages.start();

fetchCorsProxies().then(async () => {
await Database.initializeDatabase();
await animeProviders.bilibili.search("Mushoku Tensei").then(console.log)
});
13 changes: 4 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,11 @@
"description": "The best Japanese media web application.",
"private": true,
"scripts": {
"test": "cd anify-backend && npm run test",
"start": "cd anify-manager && npm run dev",
"install": "cd anify-manager && npm i && cd ../anify-frontend && npm i && cd ../anify-backend && npm i",
"lint": "cd anify-frontend && npx next lint && cd ../anify-backend && npm run lint",
"install": "cd anify-manager && npm i && cd ../anify-frontend && npm i && cd ../anify-backend && npm i && cd ../anify-auth && npm i",
"lint": "cd anify-frontend && npx next lint && cd ../anify-backend && npm run lint && cd ../anify-auth && npm run lint",
"build": "npm run install && npm run build:ts && npm run build:db",
"build:ts": "cd anify-manager && npm run build:ts && cd ../anify-backend && npm run build:ts && cd ../anify-frontend && npm run build",
"build:db": "cd anify-frontend && npm run db:generate && npm run db:push && npm run db:validate && npm run build && cd ../anify-backend && npm run db:generate && npm run db:push && npm run db:validate",
"redis:flush": "redis-cli flushall",
"db:generate": "npx prisma generate",
"db:push": "npx prisma db push",
"db:validate": "npx prisma validate"
"build:ts": "cd anify-manager && npm run build:ts && cd ../anify-backend && npm run build:ts && cd ../anify-frontend && npm run build && cd ../anify-auth && npm run build",
"build:db": "cd anify-frontend && npm run build:db && cd ../anify-backend && npm run build:db && cd ../anify-auth && npm run build:db"
}
}

0 comments on commit 6ef5df4

Please sign in to comment.