How providers are structured and how to create a new one.
Each provider lives in its own folder under providers/:
providers/
myProvider/
catalog.ts
meta.ts
posts.ts
stream.ts
episodes.ts (optional)
catalog.tstitle property will be shown as the heading on the home page (e.g., “Popular Movies”).filter property is passed to the getPosts function in posts.ts.{ title: "Popular Movies", filter: "/category/popular-movies" }, then home-page heading will show “Popular Movies” and /category/popular-movies will be sent to getPosts as the filter argument. Your getPosts implementation should use this to fetch and return the relevant items (e.g., popular movies).genres: each genre object has a title (displayed as a heading) and a filter (used to fetch genre-specific items).catalog: An array of objects with title and filter fields.genres: (optional) An array for genre filters.meta.tsgetMeta({ link, providerContext }): Returns an Info object with details like title, synopsis, image, etc.posts.tsgetPosts({ filter, page, providerValue, signal, providerContext }): Returns an array of Post objects for a given filter and page.getSearchPosts({ searchQuery, page, providerValue, signal, providerContext }): (optional) Returns search results as an array of Post objects.stream.tsgetStream({ link, type, signal, providerContext }): Returns an array of Stream objects with streaming info.episodes.ts (Optional)getMeta, but others require a separate request to fetch episodes for a specific season.getMeta function cannot return all episodes at once, you can return a linkList like this:
linkList: [
{
title: "season 1",
episodesLink: "/season-1",
},
];
episodesLink value (e.g., /season-1) will be sent as the url argument to getEpisodes in episodes.ts.getEpisodes function should then fetch and return the list of episodes for that season.getEpisodes({ url, providerContext }): Returns an array of EpisodeLink objects for the given season or episode group.providerContext?providerContext is an object passed to each function, providing shared utilities and dependencies, such as:
axios: For HTTP requestscheerio: For HTML parsingcommonHeaders: Standard HTTP headersextractors: Shared extractor functionsAes: (if needed) for encryption/decryptionThis ensures all providers use the same tools and patterns, making code easier to maintain and extend.
All function signatures and return types should use the interfaces from providers/types.ts:
Post, Info, Stream, EpisodeLink, etc.posts.tsimport { Post, ProviderContext } from "../types";
export const getPosts = async function ({
filter,
page,
providerValue,
signal,
providerContext,
}: {
filter: string;
page: number;
providerValue: string;
signal: AbortSignal;
providerContext: ProviderContext;
}): Promise<Post[]> {
// ...implementation...
};
export const getSearchPosts = async function ({
searchQuery,
page,
providerValue,
signal,
providerContext,
}: {
searchQuery: string;
page: number;
providerValue: string;
signal: AbortSignal;
providerContext: ProviderContext;
}): Promise<Post[]> {
// ...implementation...
};
catalog.ts// catalog.ts
export const catalog = [
{ title: "Popular Movies", filter: "/category/popular-movies" },
{ title: "Latest TV Shows", filter: "/category/latest-tv-shows" },
];
export const genres = [
{ title: "Action", filter: "/genre/action" },
{ title: "Drama", filter: "/genre/drama" },
];
meta.ts// meta.ts
import { Info, ProviderContext } from "../types";
export const getMeta = async function ({
link,
providerContext,
}: {
link: string;
providerContext: ProviderContext;
}): Promise<Info> {
// Fetch and parse metadata for the item
// ...implementation...
return {
title: "Example Movie",
synopsis: "A sample synopsis.",
image: "https://example.com/image.jpg",
imdbId: "tt1234567",
type: "movie",
linkList: [],
};
};
stream.ts// stream.ts
import { Stream, ProviderContext } from "../types";
export const getStream = async function ({
link,
type,
signal,
providerContext,
}: {
link: string;
type: string;
signal: AbortSignal;
providerContext: ProviderContext;
}): Promise<Stream[]> {
// Fetch and return streaming sources
// ...implementation...
return [
{
server: "ExampleServer",
link: "https://example.com/stream.m3u8",
type: "m3u8",
quality: "1080",
},
];
};
episodes.ts (Optional)// episodes.ts
import { EpisodeLink, ProviderContext } from "../types";
export const getEpisodes = async function ({
url,
providerContext,
}: {
url: string;
providerContext: ProviderContext;
}): Promise<EpisodeLink[]> {
// Fetch and return episode links
// ...implementation...
return [
{ title: "Episode 1", link: "https://example.com/ep1" },
{ title: "Episode 2", link: "https://example.com/ep2" },
];
};
linkList in meta.tsThe linkList property in the object returned by getMeta is used to describe available seasons, episodes, or direct download/stream links for the item.
linkList can represent a season or anything you want; it will be shown in the dropdown.episodesLink property. When the user selects that season, the app will call getEpisodes with this value.directLinks array. Each directLinks entry should have a link, title, and type (e.g., “movie” or “series”).quality property can be used to indicate video quality (e.g., “1080”).linkList: [
{
title: "Season 2",
episodesLink: "",
directLinks: [
{
link: "https://example.com/download",
title: "Episode 1",
type: "movie",
},
// ...more episodes or links
],
quality: "1080",
},
];
directLinks, the app will send the selected link directly to getStream when needed, skipping the need for an extra episode request.episodesLink, the app will call getEpisodes to fetch the episode list for that season or group.This gives you flexibility to support both providers that need extra requests for episodes and those that can return all links up front.
Start the Dev Server
npm run auto
http://<your-local-ip>:3001).Configure the Doodle Movies App for Local Testing
src/lib/services/ExtensionManager.ts.private testMode = true;
private baseUrlTestMode = "http://<your-local-ip>:3001"; // Use the Mobile test url from the dev server
Network Requirement
Test in the App
This workflow allows you to quickly test and debug new providers before deploying them.
Follow this structure and naming convention to ensure your provider integrates smoothly with the project.