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.

424 lines 22.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const cheerio_1 = require("cheerio"); const models_1 = require("../../models"); const extractors_1 = require("../../extractors"); class MultiMovies extends models_1.MovieParser { constructor(customBaseURL) { super(...arguments); this.name = 'MultiMovies'; this.baseUrl = 'https://multimovies.world'; this.logo = 'https://multimovies.life/wp-content/uploads/2024/01/cropped-CompressJPEG.online_512x512_image.png'; this.classPath = 'MOVIES.MultiMovies'; this.supportedTypes = new Set([models_1.TvType.MOVIE, models_1.TvType.TVSERIES]); /** * * @param query search query string * @param page page number (default 1) (optional) */ this.search = async (query, page = 1) => { const searchResult = { currentPage: page, hasNextPage: false, results: [], }; try { let url; if (page === 1) { url = `${this.baseUrl}/?s=${query.replace(/[\W_]+/g, '+')}`; } else { url = `${this.baseUrl}/page/${page}/?s=${query.replace(/[\W_]+/g, '+')}`; } const { data } = await this.client.get(url); const $ = (0, cheerio_1.load)(data); const navSelector = 'div.pagination'; searchResult.hasNextPage = $(navSelector).find('#nextpagination').length > 0; const articles = $('.search-page .result-item article').toArray(); await Promise.all(articles.map(async (el) => { var _a, _b, _c, _d, _e; const seasonSet = new Set(); const href = (_b = (_a = $(el) .find('.thumbnail a') .attr('href')) === null || _a === void 0 ? void 0 : _a.replace(/^https?:\/\/[^/]+\//, '').replace(/^\/|\/$/g, '')) !== null && _b !== void 0 ? _b : ''; const episodesInfo = await this.fetchMediaInfo(href); const episodes = (episodesInfo === null || episodesInfo === void 0 ? void 0 : episodesInfo.episodes) || []; for (const episode of episodes) { if (episode.season != null) { seasonSet.add(episode.season); } } searchResult.results.push({ id: href, title: $(el).find('.details .title a').text().trim(), url: (_c = $(el).find('.thumbnail a').attr('href')) !== null && _c !== void 0 ? _c : '', image: (_d = $(el).find('.thumbnail img').attr('src')) !== null && _d !== void 0 ? _d : '', rating: parseFloat($(el).find('.meta .rating').text().replace('IMDb ', '')) || 0, releaseDate: $(el).find('.meta .year').text().trim(), season: seasonSet.size, description: $(el).find('.contenido p').text().trim(), type: ((_e = $(el).find('.thumbnail a').attr('href')) === null || _e === void 0 ? void 0 : _e.includes('/movies/')) ? 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, _g, _h, _j; if (!mediaId.startsWith(this.baseUrl)) { mediaId = `${this.baseUrl}/${mediaId}`; } const movieInfo = { id: mediaId.replace(/^https?:\/\/[^/]+\//, '').replace(/^\/|\/$/g, ''), title: '', url: mediaId, }; try { const { data } = await this.client.get(mediaId); const $ = (0, cheerio_1.load)(data); const recommendationsArray = []; $('div#single_relacionados article').each((i, el) => { var _a, _b, _c, _d; recommendationsArray.push({ id: (_a = $(el) .find('a') .attr('href')) === null || _a === void 0 ? void 0 : _a.replace(/^https?:\/\/[^/]+\//, '').replace(/^\/|\/$/g, ''), title: $(el).find('a img').attr('alt'), image: (_b = $(el).find('a img').attr('data-src')) !== null && _b !== void 0 ? _b : $(el).find('a img').attr('src'), type: ((_c = $(el).find('.thumbnail a').attr('href')) === null || _c === void 0 ? void 0 : _c.includes('/movies/')) ? models_1.TvType.TVSERIES : (_d = models_1.TvType.MOVIE) !== null && _d !== void 0 ? _d : null, }); }); movieInfo.cover = (_b = (_a = $('div#info .galeria').first().find('.g-item a').attr('href')) === null || _a === void 0 ? void 0 : _a.trim()) !== null && _b !== void 0 ? _b : ''; movieInfo.title = $('.sheader > .data > h1').text(); movieInfo.image = (_c = $('.sheader > .poster > img').attr('src')) !== null && _c !== void 0 ? _c : $('.sheader > .poster > img').attr('data-src'); movieInfo.description = $('div#info div[itemprop="description"] p').text(); movieInfo.type = movieInfo.id.split('/')[0] === 'tvshows' ? models_1.TvType.TVSERIES : models_1.TvType.MOVIE; movieInfo.releaseDate = $('.sheader > .data > .extra > span.date').text().trim(); movieInfo.trailer = { id: (_f = (_e = (_d = $('div#trailer .embed iframe').attr('data-litespeed-src')) === null || _d === void 0 ? void 0 : _d.split('embed/')[1]) === null || _e === void 0 ? void 0 : _e.split('?')[0]) !== null && _f !== void 0 ? _f : (_h = (_g = $('div#trailer .embed iframe').attr('src')) === null || _g === void 0 ? void 0 : _g.split('embed/')[1]) === null || _h === void 0 ? void 0 : _h.split('?')[0], url: (_j = $('div#trailer .embed iframe').attr('data-litespeed-src')) !== null && _j !== void 0 ? _j : $('div#trailer .embed iframe').attr('src'), }; movieInfo.genres = $('.sgeneros a') .map((i, el) => $(el).text()) .get() .map(v => v.trim()); movieInfo.characters = []; $('div#cast .persons .person').each((i, el) => { var _a; const url = $(el).find('.img > a').attr('href'); const image = (_a = $(el).find('.img > a > img').attr('data-src')) !== null && _a !== void 0 ? _a : $(el).find('.img > a > img').attr('src'); const name = $(el).find('.data > .name > a').text(); const character = $(el).find('.data > .caracter').text(); movieInfo.characters.push({ url, image, name, character, }); }); movieInfo.country = $('.sheader > .data > .extra > span.country').text(); movieInfo.duration = $('.sheader > .data > .extra > span.runtime').text(); movieInfo.rating = parseFloat($('.starstruck-rating span.dt_rating_vgs[itemprop="ratingValue"]').text()); movieInfo.recommendations = recommendationsArray; if (movieInfo.type === models_1.TvType.TVSERIES) { movieInfo.episodes = []; $('#seasons .se-c').each((i, el) => { const seasonNumber = parseInt($(el).find('.se-t').text().trim()); $(el) .find('.episodios li') .each((j, ep) => { var _a, _b, _c, _d, _e, _f, _g; const episode = { id: (_a = $(ep) .find('.episodiotitle a') .attr('href')) === null || _a === void 0 ? void 0 : _a.replace(/^https?:\/\/[^/]+\//, '').replace(/^\/|\/$/g, ''), season: seasonNumber, number: parseInt($(ep).find('.numerando').text().trim().split('-')[1]), title: $(ep).find('.episodiotitle a').text().trim(), url: (_c = (_b = $(ep).find('.episodiotitle a').attr('href')) === null || _b === void 0 ? void 0 : _b.trim()) !== null && _c !== void 0 ? _c : '', releaseDate: String(new Date($(ep).find('.episodiotitle .date').text().trim()).getFullYear()), image: (_e = (_d = $(ep).find('.imagen img').attr('data-src')) === null || _d === void 0 ? void 0 : _d.trim()) !== null && _e !== void 0 ? _e : (_f = $(ep).find('.imagen img').attr('src')) === null || _f === void 0 ? void 0 : _f.trim(), }; (_g = movieInfo.episodes) === null || _g === void 0 ? void 0 : _g.push(episode); }); }); } else { movieInfo.episodes = [ { id: movieInfo.id, title: movieInfo.title, url: movieInfo.url, image: movieInfo.cover || movieInfo.image, }, ]; } return movieInfo; } catch (err) { throw new Error(err.message); } }; /** * * @param episodeId episode id * @param media media id * @param server server type (default `StreamWish`) (optional) */ this.fetchEpisodeSources = async (episodeId, mediaId, //just placeholder for compatibility with tmdb server = models_1.StreamingServers.StreamWish, fileId) => { if (episodeId.startsWith('http')) { const serverUrl = new URL(episodeId); switch (server) { case models_1.StreamingServers.MixDrop: return { headers: { Referer: serverUrl.href }, sources: await new extractors_1.MixDrop(this.proxyConfig, this.adapter).extract(serverUrl), download: fileId ? `https://gdmirrorbot.nl/file/${fileId}` : '', }; case models_1.StreamingServers.StreamWish: return { headers: { Referer: serverUrl.href }, ...(await new extractors_1.StreamWish(this.proxyConfig, this.adapter).extract(serverUrl)), download: fileId ? `https://gdmirrorbot.nl/file/${fileId}` : '', }; case models_1.StreamingServers.StreamTape: return { headers: { Referer: serverUrl.href }, sources: await new extractors_1.StreamTape(this.proxyConfig, this.adapter).extract(serverUrl), download: fileId ? `https://gdmirrorbot.nl/file/${fileId}` : '', }; case models_1.StreamingServers.VidHide: return { headers: { Referer: serverUrl.href }, sources: await new extractors_1.VidHide(this.proxyConfig, this.adapter).extract(serverUrl), download: fileId ? `https://gdmirrorbot.nl/file/${fileId}` : '', }; default: return { headers: { Referer: serverUrl.href }, ...(await new extractors_1.StreamWish(this.proxyConfig, this.adapter).extract(serverUrl)), download: fileId ? `https://gdmirrorbot.nl/file/${fileId}` : '', }; } } try { const servers = await this.fetchEpisodeServers(episodeId); const i = servers.findIndex(s => s.name.toLowerCase() === server.toLowerCase()); if (i === -1) { throw new Error(`Server ${server} not found`); } const serverUrl = new URL(servers[i].url); let fileId = ''; if (!episodeId.startsWith('http')) { const { fileId: id } = await this.getServer(`${this.baseUrl}/${episodeId}`); fileId = id !== null && id !== void 0 ? id : ''; } // fileId to be used for download link return await this.fetchEpisodeSources(serverUrl.href, mediaId, server, fileId); } catch (err) { throw new Error(err.message); } }; /** * * @param episodeId takes episode link or movie id */ this.fetchEpisodeServers = async (episodeId) => { if (!episodeId.startsWith(this.baseUrl)) { episodeId = `${this.baseUrl}/${episodeId}`; } try { const { servers } = await this.getServer(episodeId); return servers; } catch (err) { throw new Error(err.message); } }; this.fetchPopular = async (page = 1) => { const result = { currentPage: page, hasNextPage: false, results: [], }; try { const { data } = await this.client.get(`${this.baseUrl}/trending/page/${page}/`); const $ = (0, cheerio_1.load)(data); const navSelector = 'div.pagination'; result.hasNextPage = $(navSelector).find('#nextpagination').length > 0; $('.items > article') .each((i, el) => { var _a, _b, _c, _d, _e; const resultItem = { id: $(el).attr('id'), title: (_a = $(el).find('div.data > h3').text()) !== null && _a !== void 0 ? _a : '', url: $(el).find('div.poster > a').attr('href'), image: (_b = $(el).find('div.poster > img').attr('data-src')) !== null && _b !== void 0 ? _b : '', type: ((_c = $(el).find('div.poster > a').attr('href')) === null || _c === void 0 ? void 0 : _c.includes('/movies/')) ? models_1.TvType.MOVIE : models_1.TvType.TVSERIES, rating: (_d = $(el).find('div.poster > div.rating').text()) !== null && _d !== void 0 ? _d : '', releaseDate: (_e = $(el).find('div.data > span').text()) !== null && _e !== void 0 ? _e : '', }; result.results.push(resultItem); }) .get(); return result; } catch (err) { throw new Error(err.message); } }; this.fetchByGenre = async (genre, page = 1) => { const result = { currentPage: page, hasNextPage: false, results: [], }; try { const { data } = await this.client.get(`${this.baseUrl}/genre/${genre}/page/${page}`); const $ = (0, cheerio_1.load)(data); const navSelector = 'div.pagination'; result.hasNextPage = $(navSelector).find('#nextpagination').length > 0; $('.items > article') .each((i, el) => { var _a, _b, _c, _d, _e; const resultItem = { id: $(el).attr('id'), title: (_a = $(el).find('div.data > h3').text()) !== null && _a !== void 0 ? _a : '', url: $(el).find('div.poster > a').attr('href'), image: (_b = $(el).find('div.poster > img').attr('data-src')) !== null && _b !== void 0 ? _b : '', type: ((_c = $(el).find('div.poster > a').attr('href')) === null || _c === void 0 ? void 0 : _c.includes('/movies/')) ? models_1.TvType.MOVIE : models_1.TvType.TVSERIES, rating: (_d = $(el).find('div.poster > div.rating').text()) !== null && _d !== void 0 ? _d : '', releaseDate: (_e = $(el).find('div.data > span').text()) !== null && _e !== void 0 ? _e : '', }; result.results.push(resultItem); }) .get(); return result; } catch (err) { throw new Error(err.message); } }; if (customBaseURL) { if (customBaseURL.startsWith('http://') || customBaseURL.startsWith('https://')) { this.baseUrl = customBaseURL; } else { this.baseUrl = `http://${customBaseURL}`; } } else { this.baseUrl = this.baseUrl; } } async getServer(url) { var _a, _b, _c, _d, _e; try { const { data } = await this.client.get(url); const $ = (0, cheerio_1.load)(data); // Extract player config const playerConfig = { postId: $('#player-option-1').attr('data-post'), nume: $('#player-option-1').attr('data-nume'), type: $('#player-option-1').attr('data-type'), }; if (!playerConfig.postId || !playerConfig.nume || !playerConfig.type) { throw new Error('Missing player configuration'); } const formData = new FormData(); formData.append('action', 'doo_player_ajax'); formData.append('post', playerConfig.postId); formData.append('nume', playerConfig.nume); formData.append('type', playerConfig.type); const headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36', }; const playerRes = await this.client.post(`${this.baseUrl}/wp-admin/admin-ajax.php`, formData, { headers, }); const iframeUrl = ((_c = (_b = (_a = playerRes.data) === null || _a === void 0 ? void 0 : _a.embed_url) === null || _b === void 0 ? void 0 : _b.match(/<iframe[^>]+src="([^"]+)"[^>]*>/i)) === null || _c === void 0 ? void 0 : _c[1]) || ((_d = playerRes.data) === null || _d === void 0 ? void 0 : _d.embed_url); // Handle non-multimovies case if (!iframeUrl.includes('multimovies')) { let playerBaseUrl = iframeUrl.split('/').slice(0, 3).join('/'); const redirectResponse = await this.client.head(playerBaseUrl, { headers }); // Update base URL if redirect occurred if (redirectResponse) { playerBaseUrl = redirectResponse.request._redirectable._options.href.split('/').slice(0, 3).join('/') || redirectResponse.request.res.responseURL.split('/').slice(0, 3).join('/'); } const fileId = iframeUrl.split('/').pop(); if (!fileId) { throw new Error('No player ID found'); } const streamRequestData = new FormData(); streamRequestData.append('sid', fileId); const streamResponse = await this.client.post(`${playerBaseUrl}/embedhelper.php`, streamRequestData, { headers, }); if (!streamResponse.data) { throw new Error('No stream data found'); } const streamDetails = streamResponse.data; const mresultBase64 = streamDetails.mresult; const mresultDecoded = Buffer.from(mresultBase64, 'base64').toString('utf-8'); streamDetails.mresult = JSON.parse(mresultDecoded); const mresultKeys = new Set(Object.keys(streamDetails.mresult)); const siteUrlsKeys = new Set(Object.keys(streamDetails.siteUrls)); // Find common keys const commonKeys = [...mresultKeys].filter(key => siteUrlsKeys.has(key)); // Convert to a Set (if needed) const commonStreamSites = new Set(commonKeys); const servers = Array.from(commonStreamSites).map(site => { return { name: streamDetails.siteFriendlyNames[site] === 'StreamHG' ? 'StreamWish' : streamDetails.siteFriendlyNames[site], url: streamDetails.siteUrls[site] + streamDetails.mresult[site], }; }); return { servers, fileId }; } else { //@Durgesh return { servers: [{ name: 'StreamWish', url: iframeUrl }], fileId: (_e = iframeUrl.split('/').pop()) !== null && _e !== void 0 ? _e : '', }; } } catch (err) { throw new Error(err.message); } } } // (async () => { // const movie = new MultiMovies(); // const search = await movie.search('jujutsu'); // const movieInfo = await movie.fetchEpisodeSources('movies/pushpa-2-the-rule/'); // const server = await movie.fetchEpisodeServers('movies/pushpa-2-the-rule/'); // // const recentTv = await movie.fetchPopular(); // // const genre = await movie.fetchByGenre('action'); // console.log(search); // })(); exports.default = MultiMovies; //# sourceMappingURL=multimovies.js.map