Skip to content

adding diziyou (turkish)#51

Open
lechixy wants to merge 6 commits intop-stream:productionfrom
lechixy:diziyou
Open

adding diziyou (turkish)#51
lechixy wants to merge 6 commits intop-stream:productionfrom
lechixy:diziyou

Conversation

@lechixy
Copy link

@lechixy lechixy commented Feb 7, 2026

This pull request adds a new provider for the Turkish streaming site Diziyou, enabling the application to scrape and stream Turkish-dubbed popular TV shows from that source.

@qodo-code-review
Copy link

Review Summary by Qodo

Add Diziyou Turkish streaming provider

✨ Enhancement

Grey Divider

Walkthroughs

Description
• Adds Diziyou Turkish streaming provider for scraping shows
• Implements show scraping with season/episode extraction
• Extracts HLS streams with Turkish dubbing support
• Parses and includes subtitle tracks from media pages
Diagram
flowchart LR
  A["Diziyou Provider"] --> B["Show Page Lookup"]
  B --> C["Episode Page Fetch"]
  C --> D["Turkish Dub Check"]
  D --> E["Extract Player URL"]
  E --> F["Parse HLS Stream"]
  F --> G["Extract Captions"]
  G --> H["Return Stream Output"]
Loading

Grey Divider

File Changes

1. src/providers/all.ts ✨ Enhancement +2/-0

Register Diziyou scraper in provider registry

• Imports new diziyouScraper from diziyou provider module
• Registers diziyouScraper in gatherAllSources() function
• Maintains alphabetical ordering of provider imports

src/providers/all.ts


2. src/providers/sources/diziyou/index.ts ✨ Enhancement +108/-0

Implement Diziyou show scraper with HLS extraction

• Implements scrapeShow() function for Turkish show scraping
• Constructs show/episode URLs using title and season/episode numbers
• Validates Turkish dubbing availability before processing
• Extracts HLS playlist URL from player iframe
• Parses subtitle tracks with language and format detection
• Returns HLS stream with CORS headers and extracted captions

src/providers/sources/diziyou/index.ts


3. src/providers/sources/diziyou/helpers.ts ✨ Enhancement +3/-0

Add title URL conversion helper function

• Adds urlifyTitle() utility function for URL-safe title conversion
• Converts titles to lowercase and replaces spaces with hyphens

src/providers/sources/diziyou/helpers.ts


Grey Divider

Qodo Logo

@qodo-code-review
Copy link

qodo-code-review bot commented Feb 7, 2026

Code Review by Qodo

🐞 Bugs (3) 📘 Rule violations (3) 📎 Requirement gaps (0)

Grey Divider


Action required

✅ 1. playlistUrl not validated 📘 Rule violation ⛯ Reliability
Description
playlistUrl is derived via a brittle split(...)[1]? extraction and can become undefined when
the upstream HTML changes or the expected `` tag is missing. • The code then returns a stream object
with playlist: playlistUrl, which can cause downstream failures (e.g., player initialization
errors) without a clear, contextual error. • Add an explicit presence check and raise a contextual
NotFoundError (or equivalent) when the playlist URL cannot be extracted.
Code

src/providers/sources/diziyou/index.ts[R68-96]

+  const playlistUrl = playerResponse.split('<source id="diziyouSource" src="')[1]?.split('"')[0];
+
+  const captions: Caption[] = [];
+  const regex = /<track\s+src="([^"]+)"[^>]*srclang="([^"]+)"[^>]*label="([^"]+)"/g;
+  const captionMatches = playerResponse.matchAll(regex);
+
+  for (const match of captionMatches) {
+    const decideType = match[1].endsWith('.vtt') ? 'vtt' : 'srt';
+
+    captions.push({
+      url: match[1],
+      language: match[2],
+      hasCorsRestrictions: false,
+      id: `diziyou-${ctx.media.tmdbId}-caption-${match[2]}`,
+      type: decideType,
+    });
+  }
+
+  return {
+    embeds: [],
+    stream: [
+      {
+        id: 'primary',
+        type: 'hls',
+        playlist: playlistUrl,
+        headers,
+        flags: [flags.CORS_ALLOWED],
+        captions,
+      },
Evidence
Compliance requires handling edge cases and failure points with meaningful context. Here, the
playlist URL extraction can fail silently (becoming undefined) and is still returned as part of
the stream output, violating robust error/edge-case handling expectations.

Rule 3: Generic: Robust Error Handling and Edge Case Management
src/providers/sources/diziyou/index.ts[68-96]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`playlistUrl` can be `undefined` when the expected `&amp;amp;amp;amp;amp;lt;source&amp;amp;amp;amp;amp;gt;` tag is missing/changed, but the code still returns it as the stream playlist. This creates a hidden failure mode and makes debugging harder.
## Issue Context
This scraper parses third-party HTML which is inherently brittle; missing/changed tags should be treated as an explicit edge case with a clear, contextual error.
## Fix Focus Areas
- src/providers/sources/diziyou/index.ts[68-96]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. urlifyTitle() insufficient sanitization 📘 Rule violation ⛨ Security
Description
urlifyTitle() only lowercases and replaces a single space, but does not properly
normalize/encode titles with multiple spaces, punctuation, diacritics, or path-sensitive characters
(e.g., /, ?, #). • The resulting urlTitle is used directly in a request path, so malformed
or unexpected input can cause incorrect requests and increases the risk of path manipulation within
the target domain. • Use robust slugification (replace all whitespace, strip/normalize unsafe chars)
and encode the path segment before building request URLs.
Code

src/providers/sources/diziyou/helpers.ts[R1-2]

+export function urlifyTitle(title: string) {
+  return title.toLowerCase().replace(' ', '-');
Evidence
The compliance checklist requires validation and sanitization of external inputs. Here, the media
title is transformed in a minimal way and then used directly as part of a URL path without proper
sanitization/encoding.

Rule 6: Generic: Security-First Input Validation and Data Handling
src/providers/sources/diziyou/helpers.ts[1-2]
src/providers/sources/diziyou/index.ts[23-27]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`urlifyTitle()` does not adequately sanitize/encode `ctx.media.title` before using it in request paths. This can produce malformed URLs and allows path-sensitive characters to affect the outgoing request.
## Issue Context
`ctx.media.title` is effectively an external input (metadata) and should be treated as untrusted when constructing URL paths.
## Fix Focus Areas
- src/providers/sources/diziyou/helpers.ts[1-2]
- src/providers/sources/diziyou/index.ts[23-36]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

3. Unused imdbId gate 🐞 Bug ⛯ Reliability
Description
• The scraper throws NotFoundError when ctx.media.imdbId is missing, but the IMDb id is not used
anywhere in the Diziyou logic. • Since imdbId is optional in the media model, this unnecessarily
disables the source for valid shows that lack IMDb ids upstream.
Code

src/providers/sources/diziyou/index.ts[R18-23]

+async function scrapeShow(ctx: ShowScrapeContext): Promise<SourcererOutput> {
+  if (!ctx.media.imdbId) {
+    throw new NotFoundError('IMDb id not provided');
+  }
+
+  const urlTitle = urlifyTitle(ctx.media.title);
Evidence
imdbId is optional (imdbId?: string), and after the initial guard the scraper only uses title,
season.number, and episode.number. Therefore the guard can cause false NotFound errors unrelated
to actual availability on Diziyou.

src/providers/sources/diziyou/index.ts[18-24]
src/entrypoint/utils/media.ts[1-6]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The Diziyou scraper requires `ctx.media.imdbId` but never uses it, causing unnecessary NotFound failures.
### Issue Context
`imdbId` is optional in the shared media model.
### Fix Focus Areas
- src/providers/sources/diziyou/index.ts[18-23]
- src/entrypoint/utils/media.ts[1-6]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


4. Non-absolute iframe URL risk 🐞 Bug ⛯ Reliability
Description
iframeUrl is extracted from HTML and fetched without normalization; if the site returns a
relative (/x) or protocol-relative (//x) URL, the fetcher URL builder can throw due to missing
http(s) scheme. • This makes the scraper brittle to small markup changes and can cause hard
failures even when content exists.
Code

src/providers/sources/diziyou/index.ts[R46-65]

+  let iframeUrl = mediaPage.split('<iframe id="diziyouPlayer" src="')[1]?.split('"')[0];
+  if (!iframeUrl) throw new NotFoundError('No source found');
+  iframeUrl = iframeUrl.replace('.html', '_tr.html');
+
+  ctx.progress(60);
+
+  const playerResponse = await ctx.proxiedFetcher<string>(iframeUrl, {
+    headers: {
+      Accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
+      Referer: baseUrl,
+      'Sec-Fetch-Dest': 'iframe',
+      'Sec-Fetch-Mode': 'navigate',
+      'Sec-Fetch-Site': 'cross-site',
+      'Sec-Fetch-User': '?1',
+      'Sec-GPC': '1',
+      'Upgrade-Insecure-Requests': '1',
+      'User-Agent':
+        'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
+    },
+  });
Evidence
iframeUrl is consumed as-is by ctx.proxiedFetcher. The standard fetcher path uses makeFullUrl,
which throws if the URL does not start with http:// or https:// and no suitable baseUrl is
provided.

src/providers/sources/diziyou/index.ts[46-65]
src/fetchers/standardFetch.ts[19-22]
src/fetchers/common.ts[22-23]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`iframeUrl` is fetched without ensuring it’s an absolute `http(s)` URL; relative/protocol-relative iframe src values can cause fetch failures.
### Issue Context
Fetcher URL building enforces an `http(s)` scheme.
### Fix Focus Areas
- src/providers/sources/diziyou/index.ts[46-65]
- src/fetchers/common.ts[22-23]
- src/fetchers/standardFetch.ts[19-22]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


5. Brittle 404 detection 🐞 Bug ⛯ Reliability
Description
• The scraper detects missing pages by searching for the literal substring '404 Not Found' in
HTML. • Since proxiedFetcher() returns only the response body (not status code), this check is
unreliable; many 404 pages won’t contain that exact string, leading to misleading downstream parsing
errors.
Code

src/providers/sources/diziyou/index.ts[R23-32]

+  const urlTitle = urlifyTitle(ctx.media.title);
+  const showPage = await ctx.proxiedFetcher<string>(`/${urlTitle}/`, {
+    baseUrl,
+    headers,
+  });
+
+  ctx.progress(30);
+  if (showPage.includes('404 Not Found')) {
+    throw new NotFoundError('Media not found');
+  }
Evidence
The code relies on an HTML substring, but the codebase provides proxiedFetcher.full() for
accessing statusCode. Using .full() would allow robust detection of HTTP 404 regardless of
response body content.

src/providers/sources/diziyou/index.ts[23-32]
src/fetchers/types.ts[38-41]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
404 detection is done via brittle HTML substring matching; the fetcher supports checking HTTP status codes directly.
### Issue Context
`proxiedFetcher()` returns only `body`, but `proxiedFetcher.full()` returns `{ statusCode, body, finalUrl, ... }`.
### Fix Focus Areas
- src/providers/sources/diziyou/index.ts[23-32]
- src/fetchers/types.ts[38-41]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Advisory comments

✅ 6. decideType unclear variable 📘 Rule violation ✓ Correctness
Description
• The variable name decideType does not clearly describe what it represents (it is actually the
caption file type derived from the track URL). • This reduces readability and makes the
caption-construction logic less self-documenting. • Rename it to a descriptive name like
captionType or subtitleFormat.
Code

src/providers/sources/diziyou/index.ts[R74-83]

+  for (const match of captionMatches) {
+    const decideType = match[1].endsWith('.vtt') ? 'vtt' : 'srt';
+
+    captions.push({
+      url: match[1],
+      language: match[2],
+      hasCorsRestrictions: false,
+      id: `diziyou-${ctx.media.tmdbId}-caption-${match[2]}`,
+      type: decideType,
+    });
Evidence
The checklist requires identifiers to clearly express intent. decideType is ambiguous and does not
accurately communicate that it stores the derived caption/subtitle type.

Rule 2: Generic: Meaningful Naming and Self-Documenting Code
src/providers/sources/diziyou/index.ts[74-83]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`decideType` is not a meaningful, self-documenting name for the derived subtitle/caption format.
## Issue Context
Clear naming improves maintainability and reduces the need for additional comments.
## Fix Focus Areas
- src/providers/sources/diziyou/index.ts[74-83]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant