UNPKG

contentapi.ts

Version:

Nodejs library that provides high-level APIs for obtaining information on various entertainment media such as books, movies, comic books, anime, manga, and so on.

244 lines 12.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const cheerio_1 = require("cheerio"); const utils_1 = require("../../utils/utils"); const models_1 = require("../../models"); const extractors_1 = require("../../extractors"); class Fmovies extends models_1.MovieParser { constructor(fmoviesResolver, proxyConfig, apiKey, adapter) { super(proxyConfig && proxyConfig.url ? proxyConfig : undefined, adapter); this.name = 'Fmovies'; this.baseUrl = 'https://ww4.fmovies.co'; this.logo = 'https://s1.bunnycdn.ru/assets/sites/fmovies/logo2.png'; this.classPath = 'MOVIES.Fmovies'; this.supportedTypes = new Set([models_1.TvType.MOVIE, models_1.TvType.TVSERIES]); this.fmoviesResolver = ''; this.apiKey = ''; /** * * @param query search query string * @param page page number (default 1) (optional) */ this.search = async (query, page = 1) => { var _a; const searchResult = { currentPage: page, hasNextPage: false, results: [], }; try { query = query.replace(/[\W_]+/g, '+'); const vrf = await this.ev(query); const { data } = await this.client.get(`${this.baseUrl}/search?keyword=${query}&vrf=${vrf}&page=${page}`); const $ = (0, cheerio_1.load)(data); searchResult.hasNextPage = (_a = $('.pagination')) === null || _a === void 0 ? void 0 : _a.find('.active').next().hasClass('disabled'); $('.filmlist > div.item').each((i, el) => { const releaseDate = $(el).find('.meta').text(); searchResult.results.push({ id: $(el).find('a.title').attr('href').slice(1), title: $(el).find('a.title').text(), url: `${this.baseUrl}/${$(el).find('a.title').attr('href').slice(1)}`, image: $(el).find('img').attr('src'), releaseDate: isNaN(parseInt(releaseDate)) ? undefined : parseInt(releaseDate).toString(), seasons: releaseDate.includes('SS') ? parseInt(releaseDate.split('SS')[1]) : undefined, type: $(el).find('i.type').text() === 'Movie' ? models_1.TvType.MOVIE : models_1.TvType.TVSERIES, }); }); return searchResult; } catch (err) { throw new Error(err.message); } }; /** * * @param mediaId media link or id */ this.fetchMediaInfo = async (mediaId) => { var _a, _b, _c, _d, _e, _f; if (!mediaId.startsWith(this.baseUrl)) { mediaId = `${this.baseUrl}/${mediaId}`; } const movieInfo = { id: mediaId.split('to/').pop(), title: '', url: mediaId, }; try { const { data } = await this.client.get(mediaId); const $ = (0, cheerio_1.load)(data); const uid = $('#watch').attr('data-id'); // TODO // const recommendationsArray: IMovieResult[] = []; // $( // 'div.movie_information > div.container > div.m_i-related > div.film-related > section.block_area > div.block_area-content > div.film_list-wrap > div.flw-item' // ).each((i, el) => { // recommendationsArray.push({ // id: $(el).find('div.film-poster > a').attr('href')?.slice(1)!, // title: $(el).find('div.film-detail > h3.film-name > a').text(), // image: $(el).find('div.film-poster > img').attr('data-src'), // duration: // $(el).find('div.film-detail > div.fd-infor > span.fdi-duration').text().replace('m', '') ?? null, // type: // $(el).find('div.film-detail > div.fd-infor > span.fdi-type').text().toLowerCase() === 'tv' // ? TvType.TVSERIES // : TvType.MOVIE ?? null, // }); // }); const container = $('.watch-extra'); movieInfo.cover = (0, utils_1.substringBeforeLast)((0, utils_1.substringAfter)((_b = (_a = $('#watch').find('.play')) === null || _a === void 0 ? void 0 : _a.attr('style')) !== null && _b !== void 0 ? _b : '', 'url('), ')'); movieInfo.title = container.find(`h1[itemprop="name"]`).text(); movieInfo.image = container.find(`img[itemprop="image"]`).attr('src'); movieInfo.description = (_d = (_c = container.find('div[itemprop="description"]')) === null || _c === void 0 ? void 0 : _c.text()) === null || _d === void 0 ? void 0 : _d.trim(); movieInfo.type = movieInfo.id.split('/')[0] === 'series' ? models_1.TvType.TVSERIES : models_1.TvType.MOVIE; movieInfo.releaseDate = (_f = (_e = container.find('span[itemprop="dateCreated"]')) === null || _e === void 0 ? void 0 : _e.text()) === null || _f === void 0 ? void 0 : _f.trim(); // TODO // movieInfo.genres = $('div.row-line:nth-child(2) > a') // .map((i, el) => $(el).text().split('&')) // .get() // .map(v => v.trim()); // movieInfo.casts = $('div.row-line:nth-child(5) > a') // .map((i, el) => $(el).text()) // .get(); // movieInfo.tags = $('div.row-line:nth-child(6) > h2') // .map((i, el) => $(el).text()) // .get(); // movieInfo.production = $('div.row-line:nth-child(4) > a:nth-child(2)').text(); // movieInfo.country = $('div.row-line:nth-child(1) > a:nth-child(2)').text(); // movieInfo.duration = $('span.item:nth-child(3)').text(); // movieInfo.rating = parseFloat($('span.item:nth-child(2)').text()); // movieInfo.recommendations = recommendationsArray as any; const ajaxData = (await this.client.get(await this.ajaxReqUrl(uid))).data; const $$ = (0, cheerio_1.load)(ajaxData.html); movieInfo.episodes = []; $$('.episode').each((i, el) => { var _a, _b, _c, _d, _e; const episode = { id: $(el).find('a').attr('data-kname'), title: (_b = (_a = $(el).find('a')) === null || _a === void 0 ? void 0 : _a.attr('title')) !== null && _b !== void 0 ? _b : '', }; if (movieInfo.type === models_1.TvType.TVSERIES) { episode.number = parseInt((_c = $(el).find('a')) === null || _c === void 0 ? void 0 : _c.attr('data-kname').split('-')[1]); episode.season = parseInt((_d = $(el).find('a')) === null || _d === void 0 ? void 0 : _d.attr('data-kname').split('-')[0]); } (_e = movieInfo.episodes) === null || _e === void 0 ? void 0 : _e.push(episode); }); return movieInfo; } catch (err) { throw new Error(err.message); } }; /** * * @param episodeId episode id * @param mediaId media id * @param server server type (default `Vizcloud`) (optional) */ this.fetchEpisodeSources = async (episodeId, mediaId, server = models_1.StreamingServers.VizCloud) => { if (episodeId.startsWith('http')) { const serverUrl = new URL(episodeId); switch (server) { case models_1.StreamingServers.StreamTape: return { headers: { Referer: serverUrl.href }, sources: await new extractors_1.StreamTape().extract(serverUrl), }; default: return { headers: { Referer: serverUrl.href }, sources: await new extractors_1.VizCloud().extract(serverUrl, this.fmoviesResolver, this.apiKey), }; } } try { const servers = await this.fetchEpisodeServers(episodeId, mediaId); const selectedServer = servers.find(s => s.name === server); if (!selectedServer) { throw new Error(`Server ${server} not found`); } const { data } = await this.client.get(`${this.baseUrl}/ajax/episode/info?id=${selectedServer.url}`); const serverUrl = new URL(await this.decrypt(data.url)); return await this.fetchEpisodeSources(serverUrl.href, mediaId, server); } catch (err) { throw new Error(err.message); } }; /** * * @param episodeId takes episode link or movie id * @param mediaId takes movie link or id (found on movie info object) */ this.fetchEpisodeServers = async (episodeId, mediaId) => { if (!mediaId.startsWith(this.baseUrl)) { mediaId = `${this.baseUrl}/${mediaId}`; } try { const { data } = await this.client.get(mediaId); const $ = (0, cheerio_1.load)(data); const uid = $('#watch').attr('data-id'); const epsiodeServers = []; const ajaxData = (await this.client.get(await this.ajaxReqUrl(uid))).data; const $$ = (0, cheerio_1.load)(ajaxData.html); const servers = {}; $$('.server').each((i, el) => { const serverId = $(el).attr('data-id'); let serverName = $(el).text().toLowerCase().split('server')[1].trim(); if (serverName == 'vidstream') { serverName = 'vizcloud'; } servers[serverId] = serverName; }); const el = $$(`a[data-kname="${episodeId}"]`); try { const serverString = JSON.parse(el.attr('data-ep')); for (const serverId in serverString) { epsiodeServers.push({ name: servers[serverId], url: serverString[serverId], }); } return epsiodeServers; } catch (err) { console.log(err); throw new Error('Episode not found'); } } catch (err) { throw new Error('Episode not found'); } }; this.fmoviesResolver = fmoviesResolver !== null && fmoviesResolver !== void 0 ? fmoviesResolver : this.fmoviesResolver; this.apiKey = apiKey !== null && apiKey !== void 0 ? apiKey : this.apiKey; } async ev(query) { const { data } = await this.client.get(`${this.fmoviesResolver}/fmovies-vrf?query=${encodeURIComponent(query)}&apikey=${this.apiKey}`); return encodeURIComponent(data.url); } async decrypt(query) { const { data } = await this.client.get(`${this.fmoviesResolver}/fmovies-decrypt?query=${encodeURIComponent(query)}&apikey=${this.apiKey}`); return data.url; } async ajaxReqUrl(id) { const vrf = await this.ev(id); return `${this.baseUrl}/ajax/film/servers?id=${id}&vrf=${vrf}&token=`; } } // (async () => { // const movie = new Fmovies("https://9anime.enimax.xyz", {url: "https://proxy.vnxservers.com/"}, "848624aaffec43808c86f5e47e3fa5b0"); // const search = await movie.search('friends'); // // const search = await movie.fetchMediaInfo('series/friends-3rvj9'); // // const search = await movie.fetchMediaInfo('movie/chimes-at-midnight-1qvnw'); // // const search = await movie.fetchEpisodeSources('1-full','movie/chimes-at-midnight-1qvnw'); // // const search = await movie.fetchMediaInfo('series/friends-3rvj9'); // // console.log(JSON.stringify(movieInfo)); // console.log( // search // ); // // const recentTv = await movie.fetchTrendingTvShows(); // // console.log(search); // })(); exports.default = Fmovies; //# sourceMappingURL=fmovies.js.map