mirror of
https://github.com/movie-web/providers.git
synced 2025-09-13 11:33:25 +00:00
Add kissasian scraper
This commit is contained in:
@@ -18,7 +18,7 @@ providers need to be ported to the new provider repo:
|
|||||||
* [ ] superstream
|
* [ ] superstream
|
||||||
* [x] flixhq
|
* [x] flixhq
|
||||||
* [ ] gomovies
|
* [ ] gomovies
|
||||||
* [ ] kissasian
|
* [x] kissasian
|
||||||
* [x] remotestream
|
* [x] remotestream
|
||||||
|
|
||||||
embeds:
|
embeds:
|
||||||
|
@@ -3,11 +3,12 @@ import { mp4uploadScraper } from '@/providers/embeds/mp4upload';
|
|||||||
import { streamsbScraper } from '@/providers/embeds/streamsb';
|
import { streamsbScraper } from '@/providers/embeds/streamsb';
|
||||||
import { upcloudScraper } from '@/providers/embeds/upcloud';
|
import { upcloudScraper } from '@/providers/embeds/upcloud';
|
||||||
import { flixhqScraper } from '@/providers/sources/flixhq/index';
|
import { flixhqScraper } from '@/providers/sources/flixhq/index';
|
||||||
|
import { kissAsianScraper } from '@/providers/sources/kissasian/index';
|
||||||
import { remotestreamScraper } from '@/providers/sources/remotestream';
|
import { remotestreamScraper } from '@/providers/sources/remotestream';
|
||||||
|
|
||||||
export function gatherAllSources(): Array<Sourcerer> {
|
export function gatherAllSources(): Array<Sourcerer> {
|
||||||
// all sources are gathered here
|
// all sources are gathered here
|
||||||
return [flixhqScraper, remotestreamScraper];
|
return [flixhqScraper, remotestreamScraper, kissAsianScraper];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function gatherAllEmbeds(): Array<Embed> {
|
export function gatherAllEmbeds(): Array<Embed> {
|
||||||
|
15
src/providers/sources/kissasian/common.ts
Normal file
15
src/providers/sources/kissasian/common.ts
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import { mp4uploadScraper } from '@/providers/embeds/mp4upload';
|
||||||
|
import { streamsbScraper } from '@/providers/embeds/streamsb';
|
||||||
|
|
||||||
|
export const kissasianBase = 'https://kissasian.li';
|
||||||
|
|
||||||
|
export const embedProviders = [
|
||||||
|
{
|
||||||
|
type: mp4uploadScraper.id,
|
||||||
|
id: 'mp',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: streamsbScraper.id,
|
||||||
|
id: 'sb',
|
||||||
|
},
|
||||||
|
];
|
34
src/providers/sources/kissasian/getEmbeds.ts
Normal file
34
src/providers/sources/kissasian/getEmbeds.ts
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
import { load } from 'cheerio';
|
||||||
|
|
||||||
|
import { ScrapeContext } from '@/utils/context';
|
||||||
|
|
||||||
|
import { embedProviders, kissasianBase } from './common';
|
||||||
|
|
||||||
|
export async function getEmbeds(
|
||||||
|
ctx: ScrapeContext,
|
||||||
|
targetEpisode: {
|
||||||
|
number: string;
|
||||||
|
url?: string;
|
||||||
|
},
|
||||||
|
) {
|
||||||
|
let embeds = await Promise.all(
|
||||||
|
embedProviders.map(async (provider) => {
|
||||||
|
const watch = await ctx.fetcher<any>(`${kissasianBase}/${targetEpisode.url}&s=${provider.id}`);
|
||||||
|
|
||||||
|
const watchPage = load(watch);
|
||||||
|
|
||||||
|
const embedUrl = watchPage('iframe[id=my_video_1]').attr('src');
|
||||||
|
|
||||||
|
if (!embedUrl) throw new Error('Embed not found');
|
||||||
|
|
||||||
|
return {
|
||||||
|
embedId: provider.id,
|
||||||
|
url: embedUrl,
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
embeds = embeds.filter((e) => !!e.url);
|
||||||
|
|
||||||
|
return embeds;
|
||||||
|
}
|
14
src/providers/sources/kissasian/getEpisodes.ts
Normal file
14
src/providers/sources/kissasian/getEpisodes.ts
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import { CheerioAPI } from 'cheerio';
|
||||||
|
|
||||||
|
export async function getEpisodes(dramaPage: CheerioAPI) {
|
||||||
|
const episodesEl = dramaPage('tbody tr:not(:first-child)');
|
||||||
|
|
||||||
|
return episodesEl
|
||||||
|
.toArray()
|
||||||
|
.map((ep) => {
|
||||||
|
const number = dramaPage(ep).find('td.episodeSub a').text().split('Episode')[1]?.trim();
|
||||||
|
const url = dramaPage(ep).find('td.episodeSub a').attr('href');
|
||||||
|
return { number, url };
|
||||||
|
})
|
||||||
|
.filter((e) => !!e.url);
|
||||||
|
}
|
70
src/providers/sources/kissasian/index.ts
Normal file
70
src/providers/sources/kissasian/index.ts
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
import { load } from 'cheerio';
|
||||||
|
|
||||||
|
import { flags } from '@/main/targets';
|
||||||
|
import { makeSourcerer } from '@/providers/base';
|
||||||
|
import { NotFoundError } from '@/utils/errors';
|
||||||
|
|
||||||
|
import { getEmbeds } from './getEmbeds';
|
||||||
|
import { getEpisodes } from './getEpisodes';
|
||||||
|
import { search } from './search';
|
||||||
|
|
||||||
|
export const kissAsianScraper = makeSourcerer({
|
||||||
|
id: 'kissasian',
|
||||||
|
name: 'KissAsian',
|
||||||
|
rank: 130,
|
||||||
|
flags: [flags.NO_CORS],
|
||||||
|
|
||||||
|
async scrapeShow(ctx) {
|
||||||
|
const seasonNumber = ctx.media.season.number;
|
||||||
|
const episodeNumber = ctx.media.episode.number;
|
||||||
|
|
||||||
|
const dramas = await search(ctx, ctx.media.title, seasonNumber);
|
||||||
|
|
||||||
|
const targetDrama = dramas.find((d) => d.name?.toLowerCase() === ctx.media.title.toLowerCase()) ?? dramas[0];
|
||||||
|
if (!targetDrama) throw new Error('Drama not found');
|
||||||
|
|
||||||
|
ctx.progress(30);
|
||||||
|
|
||||||
|
const drama = await ctx.fetcher<any>(targetDrama.url);
|
||||||
|
|
||||||
|
const dramaPage = load(drama);
|
||||||
|
|
||||||
|
const episodes = await getEpisodes(dramaPage);
|
||||||
|
|
||||||
|
const targetEpisode = episodes.find((e) => e.number === `${episodeNumber}`);
|
||||||
|
if (!targetEpisode?.url) throw new NotFoundError('Episode not found');
|
||||||
|
|
||||||
|
ctx.progress(70);
|
||||||
|
|
||||||
|
const embeds = await getEmbeds(ctx, targetEpisode);
|
||||||
|
|
||||||
|
return {
|
||||||
|
embeds,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
async scrapeMovie(ctx) {
|
||||||
|
const dramas = await search(ctx, ctx.media.title, undefined);
|
||||||
|
|
||||||
|
const targetDrama = dramas.find((d) => d.name?.toLowerCase() === ctx.media.title.toLowerCase()) ?? dramas[0];
|
||||||
|
if (!targetDrama) throw new Error('Drama not found');
|
||||||
|
|
||||||
|
ctx.progress(30);
|
||||||
|
|
||||||
|
const drama = await ctx.fetcher<any>(targetDrama.url);
|
||||||
|
|
||||||
|
const dramaPage = load(drama);
|
||||||
|
|
||||||
|
const episodes = await getEpisodes(dramaPage);
|
||||||
|
|
||||||
|
const targetEpisode = episodes[0];
|
||||||
|
if (!targetEpisode?.url) throw new NotFoundError('Episode not found');
|
||||||
|
|
||||||
|
ctx.progress(70);
|
||||||
|
|
||||||
|
const embeds = await getEmbeds(ctx, targetEpisode);
|
||||||
|
|
||||||
|
return {
|
||||||
|
embeds,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
27
src/providers/sources/kissasian/search.ts
Normal file
27
src/providers/sources/kissasian/search.ts
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import { load } from 'cheerio';
|
||||||
|
import FormData from 'form-data';
|
||||||
|
|
||||||
|
import { ScrapeContext } from '@/utils/context';
|
||||||
|
|
||||||
|
import { kissasianBase } from './common';
|
||||||
|
|
||||||
|
export async function search(ctx: ScrapeContext, title: string, seasonNumber?: number) {
|
||||||
|
const searchForm = new FormData();
|
||||||
|
searchForm.append('keyword', `${title} ${seasonNumber ?? ''}`.trim());
|
||||||
|
searchForm.append('type', 'Drama');
|
||||||
|
|
||||||
|
const searchResults = await ctx.fetcher<any>('/Search/SearchSuggest', {
|
||||||
|
baseUrl: kissasianBase,
|
||||||
|
method: 'POST',
|
||||||
|
body: searchForm,
|
||||||
|
});
|
||||||
|
|
||||||
|
const searchPage = load(searchResults);
|
||||||
|
|
||||||
|
return Array.from(searchPage('a')).map((drama) => {
|
||||||
|
return {
|
||||||
|
name: searchPage(drama).text(),
|
||||||
|
url: drama.attribs.href,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
Reference in New Issue
Block a user