diff --git a/manifest.json b/manifest.json index a5b6030..8fd8054 100644 --- a/manifest.json +++ b/manifest.json @@ -143,6 +143,14 @@ "type": "english", "disabled": true }, + { + "display_name": "MoviezWap", + "value": "Moviezwap", + "version": "1.0", + "icon": "", + "type": "india", + "disabled": false + }, { "display_name": "ShowBox", "value": "showbox", diff --git a/providers/moviezwap/catalog.ts b/providers/moviezwap/catalog.ts new file mode 100644 index 0000000..5920fa9 --- /dev/null +++ b/providers/moviezwap/catalog.ts @@ -0,0 +1,21 @@ +export const catalog = [ + { + title: "Telugu Movies", + filter: "/category/Telugu-(2025)-Movies.html", + }, + { + title: "Tamil Movies", + filter: "/category/Tamil-(2025)-Movies.html", + }, + { + title: "Hollywood Telugu Dubbed", + filter: "/category/Telugu-Dubbed-Hollywood-Movies-Complete-Set.html", + }, + { + title: "Web Series", + filter: "/category/Telugu-Web-Series.html", + }, + ]; + + export const genres = []; + \ No newline at end of file diff --git a/providers/moviezwap/episodes.ts b/providers/moviezwap/episodes.ts new file mode 100644 index 0000000..bb04c42 --- /dev/null +++ b/providers/moviezwap/episodes.ts @@ -0,0 +1,43 @@ +import { EpisodeLink, ProviderContext } from "../types"; + +export const getEpisodes = async function ({ + url, + providerContext, +}: { + url: string; + providerContext: ProviderContext; +}): Promise { + const { axios, cheerio, getBaseUrl } = providerContext; + try { + const res = await axios.get(url); + const baseUrl = await getBaseUrl("moviezwap"); + const html = res.data; + const $ = cheerio.load(html); + + const episodeLinks: EpisodeLink[] = []; + + $('a[href*="download.php?file="], a[href*="dwload.php?file="]').each( + (i, el) => { + const downloadPage = + $(el).attr("href")?.replace("dwload.php", "download.php") || ""; + let text = $(el).text().trim(); + if (text.includes("Download page")) { + // Remove "Download" from the text + text = "Play"; + } + if (downloadPage && text) { + // Only add links with quality in text + episodeLinks.push({ + title: text, + link: baseUrl + downloadPage, + }); + } + } + ); + + return episodeLinks; + } catch (err) { + console.error(err); + return []; + } +}; diff --git a/providers/moviezwap/meta.ts b/providers/moviezwap/meta.ts new file mode 100644 index 0000000..77fed0c --- /dev/null +++ b/providers/moviezwap/meta.ts @@ -0,0 +1,105 @@ +import { Info, Link, ProviderContext } from "../types"; + +export const getMeta = async function ({ + link, + providerContext, +}: { + link: string; + providerContext: ProviderContext; +}): Promise { + try { + const { axios, cheerio, getBaseUrl } = providerContext; + const baseUrl = await getBaseUrl("moviezwap"); + const url = link.startsWith("http") ? link : `${baseUrl}${link}`; + const res = await axios.get(url); + const data = res.data; + const $ = cheerio.load(data); + + // 1. Poster image find image with width 260 + let image = $('img[width="260"]').attr("src") || ""; + if (image && !image.startsWith("http")) { + image = baseUrl + image; + } + + const tags = $("font[color='steelblue']") + .map((i, el) => $(el).text().trim()) + .get() + .slice(0, 2); + + // 2. Title + const title = $("title").text().replace(" - MoviezWap", "").trim() || ""; + + // 3. Info table + let synopsis = ""; + let imdbId = ""; + let type = "movie"; + let infoRows: string[] = []; + $("td:contains('Movie Information')") + .parent() + .nextAll("tr") + .each((i, el) => { + const tds = $(el).find("td"); + if (tds.length === 2) { + const key = tds.eq(0).text().trim(); + const value = tds.eq(1).text().trim(); + infoRows.push(`${key}: ${value}`); + if (key.toLowerCase().includes("plot")) synopsis = value; + if (key.toLowerCase().includes("imdb")) imdbId = value; + } + }); + if (!synopsis) { + // fallback: try to find a

with plot + synopsis = $("p:contains('plot')").text().trim(); + } + + // 4. Download links (multiple qualities) + const links: Link[] = []; + $('a[href*="download.php?file="], a[href*="dwload.php?file="]').each( + (i, el) => { + const downloadPage = + $(el).attr("href")?.replace("dwload.php", "download.php") || ""; + const text = $(el).text().trim(); + if (downloadPage && /\d+p/i.test(text)) { + // Only add links with quality in text + links.push({ + title: text, + directLinks: [{ title: "Movie", link: baseUrl + downloadPage }], + }); + } + } + ); + + $("img[src*='/images/play.png']").each((i, el) => { + const downloadPage = $(el).siblings("a").attr("href"); + const text = $(el).siblings("a").text().trim(); + console.log("Found link:🔥🔥", text, downloadPage); + if (downloadPage && text) { + links.push({ + title: text, + episodesLink: baseUrl + downloadPage, + }); + } + }); + + return { + title, + synopsis, + image, + imdbId, + tags, + type, + linkList: links, + //info: infoRows.join("\n"), + }; + } catch (err) { + console.error(err); + return { + title: "", + synopsis: "", + image: "", + imdbId: "", + type: "movie", + linkList: [], + }; + } +}; diff --git a/providers/moviezwap/posts.ts b/providers/moviezwap/posts.ts new file mode 100644 index 0000000..879e1c5 --- /dev/null +++ b/providers/moviezwap/posts.ts @@ -0,0 +1,70 @@ +import { Post, ProviderContext } from "../types"; + +export const getPosts = async function ({ + filter, + page, + signal, + providerContext, +}: { + filter: string; + page: number; + providerValue: string; + signal: AbortSignal; + providerContext: ProviderContext; +}): Promise { + const { getBaseUrl, cheerio } = providerContext; + const baseUrl = await getBaseUrl("moviezwap"); + const url = `${baseUrl}${filter}`; + return posts({ url, signal, cheerio }); +}; + +export const getSearchPosts = async function ({ + searchQuery, + page, + signal, + providerContext, +}: { + searchQuery: string; + page: number; + providerValue: string; + signal: AbortSignal; + providerContext: ProviderContext; +}): Promise { + const { getBaseUrl, cheerio } = providerContext; + const baseUrl = await getBaseUrl("moviezwap"); + const url = `${baseUrl}/search.php?q=${encodeURIComponent(searchQuery)}`; + return posts({ url, signal, cheerio }); +}; + +async function posts({ + url, + signal, + cheerio, +}: { + url: string; + signal: AbortSignal; + cheerio: ProviderContext["cheerio"]; +}): Promise { + try { + const res = await fetch(url, { signal }); + const data = await res.text(); + const $ = cheerio.load(data); + const catalog: Post[] = []; + $('a[href^="/movie/"]').each((i, el) => { + const title = $(el).text().trim(); + const link = $(el).attr("href"); + const image = ""; + if (title && link) { + catalog.push({ + title: title, + link: link, + image: image, + }); + } + }); + return catalog; + } catch (err) { + console.error("moviezwapGetPosts error ", err); + return []; + } +} diff --git a/providers/moviezwap/stream.ts b/providers/moviezwap/stream.ts new file mode 100644 index 0000000..2840ff9 --- /dev/null +++ b/providers/moviezwap/stream.ts @@ -0,0 +1,34 @@ +import { ProviderContext, Stream } from "../types"; + +export async function getStream({ + link, + signal, + providerContext, +}: { + link: string; + type: string; + signal: AbortSignal; + providerContext: ProviderContext; +}) { + const { axios, cheerio, commonHeaders: headers } = providerContext; + const res = await axios.get(link, { headers, signal }); + const html = res.data; + const $ = cheerio.load(html); + const Streams: Stream[] = []; + + // Find the actual .mp4 download link + let downloadLink = null; + $('a:contains("Fast Download Server")').each((i, el) => { + const href = $(el).attr("href"); + if (href && href.toLocaleLowerCase().includes(".mp4")) { + Streams.push({ + link: href, + type: "mp4", + server: "Fast Download", + headers: headers, + }); + } + }); + + return Streams; +}