Skip to content

v7x8 stability update#331

Merged
n-ce merged 28 commits into
mainfrom
v7x8
Jul 31, 2025
Merged

v7x8 stability update#331
n-ce merged 28 commits into
mainfrom
v7x8

Conversation

@n-ce
Copy link
Copy Markdown
Owner

@n-ce n-ce commented Jul 29, 2025

Summary by CodeRabbit

  • New Features

    • Added a health status link and visual indicator in the search section.
    • Introduced JioSaavn music playback support.
    • Added support for fetching video data from a local server.
  • Improvements

    • Enhanced subtitle and caption handling for video playback.
    • Improved API instance and proxy management, including dynamic status and health indicators.
    • Updated queue and collection items to track the last updated timestamp.
    • Upgraded several dependencies for better stability and performance.
  • Bug Fixes

    • Fixed handling of " - Topic" suffix for music uploads in search and related streams.
    • Corrected video codec detection and subtitle rendering logic.
  • Style

    • Updated cursor behavior in header dropdown menus for better user experience.
  • Chores

    • Cleaned up and removed unused settings and properties from the UI and internal state.
    • Refactored and streamlined player logic, removing deprecated code.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jul 29, 2025

Walkthrough

This update introduces a range of changes, including dependency upgrades, the removal of the enforcePiped flag and related logic, enhancements to subtitle and proxy handling, the addition of JioSaavn playback support, timestamp management for collection items, and improvements to API instance initialization and health status display. Several internal types and interfaces are updated to reflect new data structures.

Changes

Cohort / File(s) Change Summary
Dependency Upgrades
package.json
Bumped versions of hls.js, @netlify/blobs, @netlify/edge-functions, @types/node, vite, and vite-plugin-pwa.
Type and Interface Updates
src/index.d.ts
Updated types: added lastUpdated to CollectionItem, removed duplicate uploader in Piped, added subtitles to Piped, changed captions in Invidious, removed Captions alias.
Removal of enforcePiped Logic
src/lib/store.ts, src/components/Settings/playback.ts, src/modules/audioErrorHandler.ts, src/lib/utils.ts, src/modules/start.ts, src/lib/player.ts
Removed enforcePiped property and related logic from state, store, UI, error handler, and player; updated proxy and status handling.
Proxy and API Enhancements
src/lib/store.ts, src/lib/utils.ts, src/modules/start.ts
Added proxy and status to API store, updated proxy enforcement logic, initialized proxies from remote data, and improved health status indicator.
JioSaavn Playback Integration
src/modules/jioSaavn.ts, src/lib/player.ts
Added new module for JioSaavn playback, refactored player logic to support dynamic JioSaavn usage, removed old saavnPlayer function.
Subtitle and Caption Handling
src/modules/getStreamData.ts, src/modules/localExtraction.ts, src/components/WatchVideo.ts, netlify/edge-functions/fallback.ts
Standardized subtitle/caption properties, updated stream and subtitle mapping, and removed unused captions logic.
Collection and Queue Timestamping
src/lib/libraryUtils.ts, src/components/StreamItem.ts, src/scripts/list.ts, src/scripts/queue.ts, src/modules/listUtils.ts
Added and propagated lastUpdated timestamps for collection and queue items, updated components and scripts to handle new property.
Music Topic Suffix Logic
src/components/ItemsLoader.ts, src/modules/fetchList.ts, src/modules/fetchSearchResults.ts
Adjusted logic for appending " - Topic" to author/uploader names based on context and search filters.
Playlist/Artist Fetch Improvements
src/modules/fetchList.ts
Enhanced playlist ID resolution with retries over multiple endpoints.
UI and Locale Tweaks
index.html, src/locales/en.json, src/stylesheets/header.css
Added health status link and indicator, updated locale string, and adjusted header cursor styles.
Build Metadata
vite.config.ts
Switched build version string to use dynamic date formatting.

Sequence Diagram(s)

JioSaavn Playback Flow

sequenceDiagram
    participant User
    participant Player
    participant JioSaavnModule
    participant JioSaavnAPI
    participant UI

    User->>Player: Play music request
    Player->>JioSaavnModule: If JioSaavn enabled, delegate playback
    JioSaavnModule->>UI: Update title (fetching)
    JioSaavnModule->>JioSaavnAPI: Search for track (title + author)
    JioSaavnAPI-->>JioSaavnModule: Return search results
    JioSaavnModule->>JioSaavnModule: Find matching track
    alt Track found
        JioSaavnModule->>Player: Set audio source to selected quality URL
        JioSaavnModule->>UI: Update quality and history
    else Track not found / error
        JioSaavnModule->>UI: Show error, disable JioSaavn
        JioSaavnModule->>Player: Fallback to generic playback
    end
Loading

Proxy and API Status Handling

sequenceDiagram
    participant App
    participant Store
    participant RemoteAPI

    App->>RemoteAPI: Fetch instance data
    RemoteAPI-->>App: Return instance config (proxy, health, status)
    App->>Store: Update store.api.proxy, store.api.status, etc.
    App->>UI: Update health indicator based on status
    App->>Utils: Use proxyHandler to determine URL based on enforceProxy or status
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~40 minutes

Possibly related PRs

Poem

In the warren where code bunnies play,
We nibbled away old flags today.
With timestamps fresh on every hop,
And JioSaavn tunes that never stop,
Subtitles now dance in a tidy array—
Health checks blink, the proxy finds its way.
🐇✨ Hoppy coding, come what may!

Note

⚡️ Unit Test Generation is now available in beta!

Learn more here, or try it out under "Finishing Touches" below.


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 27ee5bd and 3d22f5a.

📒 Files selected for processing (2)
  • src/components/WatchVideo.ts (2 hunks)
  • src/lib/utils.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/components/WatchVideo.ts
  • src/lib/utils.ts
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch v7x8

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🧹 Nitpick comments (4)
package.json (1)

15-17: Double-check Netlify & Node type bumps for CI/CD compatibility

Minor bumps for @netlify/* and @types/node are low-risk, yet:

• Netlify edge functions occasionally add new required config keys—verify the production build still deploys without warnings.
@types/node@24.1.x bumps lib dom globals; if you target an older Node runtime in Netlify, mismatch warnings can appear. Consider adding an "engines" field (e.g. "node": ">=18") to lock expectations.

src/stylesheets/header.css (1)

65-69: Consider using 'default' instead of 'none' for better UX.

Setting cursor: none completely hides the cursor, which can be confusing for users. Consider using cursor: default on the li element instead, which provides a clearer visual hierarchy while maintaining the pointer cursor on the clickable anchor.

         &:has(a) {
-          cursor: none;
+          cursor: default;

           a {
             cursor: pointer;
           }
         }
src/modules/localExtraction.ts (2)

27-36: Improve type safety and resolution handling.

  const videoStreams = streamingData.adaptiveFormats
    ? streamingData.adaptiveFormats
-      .filter((f: any) => f.mimeType?.startsWith('video'))
-      .map((f: any) => ({
+      .filter((f: AdaptiveFormat) => f.mimeType?.startsWith('video'))
+      .map((f: AdaptiveFormat) => ({
        url: f.url,
        quality: f.qualityLabel || f.quality,
-        resolution: `${f.width || ''}x${f.height || ''}`.replace(/^x|x$/, ''),
+        resolution: f.width && f.height ? `${f.width}x${f.height}` : '',
        type: f.mimeType,
      }))
    : [];

38-47: Consider adding type definitions for caption tracks.

+interface CaptionTrack {
+  baseUrl: string;
+  name?: { runs?: Array<{ text: string }> };
+  vssId: string;
+  languageCode: string;
+  kind: string;
+  isTranslatable: boolean;
+}
+
  const captionTracks = captions?.playerCaptionsTracklistRenderer?.captionTracks
-    ? captions.playerCaptionsTracklistRenderer.captionTracks.map((track: any) => ({
+    ? captions.playerCaptionsTracklistRenderer.captionTracks.map((track: CaptionTrack) => ({
      baseUrl: track.baseUrl,
      name: track.name?.runs?.[0]?.text || 'Unknown',
      vssId: track.vssId,
      languageCode: track.languageCode,
      kind: track.kind,
      isTranslatable: track.isTranslatable,
    }))
    : [];
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between adb9de7 and 5c366a2.

📒 Files selected for processing (18)
  • package.json (1 hunks)
  • src/components/ItemsLoader.ts (1 hunks)
  • src/components/StreamItem.ts (2 hunks)
  • src/components/UpdatePrompt.ts (1 hunks)
  • src/index.d.ts (1 hunks)
  • src/lib/libraryUtils.ts (2 hunks)
  • src/lib/player.ts (2 hunks)
  • src/lib/store.ts (2 hunks)
  • src/lib/utils.ts (1 hunks)
  • src/locales/en.json (1 hunks)
  • src/modules/audioErrorHandler.ts (1 hunks)
  • src/modules/fetchList.ts (2 hunks)
  • src/modules/fetchSearchResults.ts (2 hunks)
  • src/modules/getStreamData.ts (1 hunks)
  • src/modules/jioSaavn.ts (1 hunks)
  • src/modules/listUtils.ts (1 hunks)
  • src/modules/localExtraction.ts (1 hunks)
  • src/stylesheets/header.css (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (5)
src/modules/getStreamData.ts (1)
src/lib/store.ts (1)
  • state (4-49)
src/modules/fetchSearchResults.ts (1)
src/lib/dom.ts (1)
  • searchFilters (15-15)
src/modules/audioErrorHandler.ts (1)
src/lib/store.ts (1)
  • state (4-49)
src/modules/jioSaavn.ts (4)
src/lib/dom.ts (4)
  • title (3-3)
  • author (5-5)
  • audio (19-19)
  • qualityView (42-42)
src/lib/store.ts (3)
  • store (66-160)
  • state (4-49)
  • params (2-2)
src/modules/setMetadata.ts (1)
  • setMetaData (11-68)
src/lib/player.ts (1)
  • player (8-108)
src/lib/player.ts (2)
src/lib/store.ts (2)
  • state (4-49)
  • store (66-160)
src/lib/dom.ts (2)
  • title (3-3)
  • playButton (17-17)
🔇 Additional comments (28)
package.json (2)

10-10: Confirm hls.js 1.6.7 doesn’t introduce subtle playback regressions

Patch releases are usually safe, but hls.js sometimes tweaks stream-handling heuristics that can surface edge-case buffering or DRM issues. Please run the existing player e2e tests (especially Safari/iOS) and glance at their changelog for 1.6.7 to ensure nothing breaks silently.


22-23: Build failure: missing TypeScript compiler

The compatibility check (npm run build && npm run preview) aborted with sh: 1: tsc: not found. Please ensure you have TypeScript installed (e.g. add typescript to your devDependencies and run npm install), or alternatively run the Vite‐only commands:

npx vite build && npx vite preview

Then confirm no deprecation warnings from vite-plugin-pwa.

src/components/UpdatePrompt.ts (1)

7-8: v7x8 branch verification successful

No further changes required.

src/lib/store.ts (2)

77-78: LGTM! Clean integration of JioSaavn state management.

The addition of useSaavn to the player store object provides a centralized way to track JioSaavn playback preference, properly initialized from the existing state.jiosaavn configuration.


118-118: Good initialization pattern.

Properly initializes the useSaavn flag from the existing state configuration, maintaining consistency with user preferences.

src/locales/en.json (1)

117-117: LGTM! Reflects JioSaavn feature stabilization.

Removing the "(Beta)" suffix indicates the JioSaavn integration has matured from beta to stable status, which aligns with the codebase refactoring mentioned in the PR.

src/modules/listUtils.ts (1)

53-54: No naming inconsistency detected—conversion from snake_case to camelCase is consistent

All incoming *_last_updated fields are uniformly mapped to internal lastUpdated properties, and the codebase consistently uses camelCase for its TypeScript definitions and assignments. No further changes needed.

• src/index.d.ts: defines lastUpdated?: string
• src/modules/listUtils.ts: maps sender.last_updated'lastUpdated'
• src/lib/utils.ts & src/lib/libraryUtils.ts: apply the same snake_case → camelCase mapping
• src/components/StreamItem.ts: uses data.lastUpdated internally

src/components/StreamItem.ts (2)

16-17: LGTM! Clean addition of optional lastUpdated property.

The optional lastUpdated property is properly typed and maintains backward compatibility.


64-64: Good fallback implementation for lastUpdated timestamp.

The data attribute correctly uses the provided lastUpdated value or falls back to the current timestamp, ensuring consistent timestamp tracking across the application.

src/components/ItemsLoader.ts (1)

33-33: Good refactoring - moving data processing upstream.

Removing the conditional " - Topic" suffix here and handling it in the data fetching modules is a better separation of concerns. The UI component should focus on presentation, not data transformation.

src/index.d.ts (1)

44-44: Correct type definition for lastUpdated property.

The optional lastUpdated string property aligns with the timestamp tracking feature implemented across the application.

src/modules/audioErrorHandler.ts (2)

11-11: LGTM! Removal of enforcePiped from destructuring.

This aligns with the broader refactoring to reduce enforcePiped usage across the codebase.


13-13: Confirm piped‐stream error handling behavior

Removing enforcePiped from the early return in src/modules/audioErrorHandler.ts means that when users have piped audio enabled (but neither HLS nor a custom instance), any load errors will now fall through into the proxy-switching and fallback logic rather than immediately notifying and stopping playback. We didn’t find any other enforcePiped checks in this module, so please verify that this change is intentional.

• File: src/modules/audioErrorHandler.ts
• Line: 13 (if (HLS || customInstance))

If piped streams should still short-circuit on error (like HLS/custom), re-add || enforcePiped to that condition; otherwise confirm that running through the full fallback flow is desired.

src/modules/getStreamData.ts (2)

95-95: Good implementation of conditional local extraction.

The dynamic import approach is appropriate for optional functionality. The async/await syntax is correct.


98-98: Local extraction module verified

  • Found src/modules/localExtraction.ts
  • Confirms it exports
    export async function fetchDataFromLocal(id: string): Promise<Piped & { captions: []; videoStreams: [] }> {  }

No further changes needed.

src/lib/libraryUtils.ts (2)

44-44: LGTM! Proper timestamp tracking implementation.

The addition of lastUpdated timestamp when saving collection items provides consistent tracking of when items were last modified. Using ISO string format is appropriate for localStorage serialization.


100-100: LGTM! Consistent timestamp propagation to UI components.

The fallback to current timestamp ensures StreamItem always receives a valid lastUpdated value, maintaining consistency in the rendering pipeline.

src/lib/utils.ts (1)

213-213: LGTM! Proper timestamp extraction from DOM dataset.

The addition correctly extracts the lastUpdated timestamp from the DOM element's dataset and provides a sensible fallback to the current timestamp, maintaining consistency with the actions menu state management.

src/modules/fetchList.ts (2)

63-70: LGTM! Consistent uploader name transformation for Hyperpipe content.

The conditional logic properly appends " - Topic" suffix to uploader names when using Hyperpipe, with appropriate checks to prevent duplicate suffixes. The implementation is clean and idempotent.


121-128: LGTM! Consistent suffix handling for paginated results.

The same transformation logic is properly applied to paginated data, ensuring consistent uploader name formatting across both initial loads and subsequent pages.

src/modules/fetchSearchResults.ts (1)

114-116: LGTM! Proper suffix handling in paginated results.

The conditional suffix addition is correctly implemented within the pagination loop, maintaining the existing filtering logic while consistently transforming uploader names for music content.

src/modules/jioSaavn.ts (1)

45-49: LGTM! Comprehensive error handling with graceful fallback.

The error handling properly manages failures by updating the UI, disabling the JioSaavn feature, and falling back to the regular player. This ensures a good user experience even when JioSaavn integration fails.

src/lib/player.ts (3)

1-1: LGTM!

Good cleanup removing the unnecessary aliasing of title as ptitle.


25-30: Verify the JioSaavn activation logic.

The current logic only imports the JioSaavn module when store.player.useSaavn is already true AND the author ends with 'Topic'. This means on the first call when useSaavn is false, it will be set to true but the JioSaavn module won't be imported even if the author ends with 'Topic'. Is this the intended behavior?

Consider this alternative structure if you want to import JioSaavn on the first call:

  if (state.jiosaavn) {
-    if (!store.player.useSaavn)
-      store.player.useSaavn = true;
-    else if (store.stream.author.endsWith('Topic'))
-      return import('../modules/jioSaavn').then(mod => mod.default());
+    store.player.useSaavn = true;
+    if (store.stream.author.endsWith('Topic'))
+      return import('../modules/jioSaavn').then(mod => mod.default());
  }

32-32: LGTM!

UI text updates are consistent with the import statement changes.

Also applies to: 40-40

src/modules/localExtraction.ts (3)

4-7: LGTM!

Good error handling with appropriate fallback when JSON parsing fails.


9-12: LGTM!

Appropriate validation of required fields while treating captions as optional.


49-62: LGTM!

The return structure properly maps local data to the expected Piped interface format.

Comment thread src/modules/fetchSearchResults.ts Outdated
Comment thread src/modules/jioSaavn.ts Outdated
export default function() {
title.textContent = 'Fetching Data via JioSaavn...';
const { author, id } = store.stream;
const query = encodeURIComponent(`${store.stream.title.replace(/\(.*?\)/g, '')} ${author.slice(0, -8)}`);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Make author suffix removal more robust.

The hardcoded author.slice(0, -8) assumes the author always ends with " - Topic" (8 characters). This could incorrectly truncate author names that don't have this suffix, leading to poor search matches.

Apply this diff for more robust author processing:

-  const query = encodeURIComponent(`${store.stream.title.replace(/\(.*?\)/g, '')} ${author.slice(0, -8)}`);
+  const authorName = author.endsWith(' - Topic') ? author.slice(0, -8) : author;
+  const query = encodeURIComponent(`${store.stream.title.replace(/\(.*?\)/g, '')} ${authorName}`);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const query = encodeURIComponent(`${store.stream.title.replace(/\(.*?\)/g, '')} ${author.slice(0, -8)}`);
const authorName = author.endsWith(' - Topic') ? author.slice(0, -8) : author;
const query = encodeURIComponent(`${store.stream.title.replace(/\(.*?\)/g, '')} ${authorName}`);
🤖 Prompt for AI Agents
In src/modules/jioSaavn.ts at line 9, the current code uses a hardcoded slice to
remove the last 8 characters from the author string, assuming it always ends
with " - Topic". To fix this, replace the slice with a check that removes the
suffix only if it actually exists at the end of the author string. Use a
conditional or regex to detect and remove " - Topic" suffix safely, ensuring
author names without this suffix remain unchanged.

Comment thread src/modules/jioSaavn.ts
Comment on lines +16 to +22
const matchingTrack = res.data.results.find((track: {
name: string,
artists: { primary: { name: string }[] }
}) =>
store.stream.title.startsWith(track.name) && author.startsWith(track.artists.primary[0].name)

);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Improve track matching robustness and consistency.

Several concerns with the current matching logic:

  1. Inconsistent author processing: The query uses processed author name, but matching uses the original author variable
  2. Loose matching criteria: Using startsWith for both title and author could lead to false positives
  3. Potential runtime error: No safety check for empty track.artists.primary array

Apply this diff to improve matching:

+      const authorName = author.endsWith(' - Topic') ? author.slice(0, -8) : author;
       const matchingTrack = res.data.results.find((track: {
         name: string,
         artists: { primary: { name: string }[] }
       }) =>
-        store.stream.title.startsWith(track.name) && author.startsWith(track.artists.primary[0].name)
+        track.name.toLowerCase() === store.stream.title.toLowerCase() && 
+        track.artists.primary.length > 0 &&
+        track.artists.primary[0].name.toLowerCase() === authorName.toLowerCase()
       );
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const matchingTrack = res.data.results.find((track: {
name: string,
artists: { primary: { name: string }[] }
}) =>
store.stream.title.startsWith(track.name) && author.startsWith(track.artists.primary[0].name)
);
const authorName = author.endsWith(' - Topic') ? author.slice(0, -8) : author;
const matchingTrack = res.data.results.find((track: {
name: string,
artists: { primary: { name: string }[] }
}) =>
track.name.toLowerCase() === store.stream.title.toLowerCase() &&
track.artists.primary.length > 0 &&
track.artists.primary[0].name.toLowerCase() === authorName.toLowerCase()
);
🤖 Prompt for AI Agents
In src/modules/jioSaavn.ts around lines 16 to 22, improve the track matching
logic by ensuring consistent use of the processed author variable instead of the
original author, replace the loose startsWith checks with stricter equality or
more precise matching methods for both title and author to reduce false
positives, and add a safety check to confirm that track.artists.primary is not
empty before accessing its first element to prevent runtime errors.

Comment thread src/modules/jioSaavn.ts
Comment on lines +32 to +39
const { url, quality } = downloadUrl[{
low: 1,
medium: downloadUrl.length - 2,
high: downloadUrl.length - 1
}[state.quality]];

audio.src = url.replace('http:', 'https:');
qualityView.textContent = quality + ' AAC';
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add safety checks for quality selection.

The quality selection logic assumes specific array structure and length without validation. This could cause runtime errors if the downloadUrl array doesn't match expectations.

Apply this diff to add safety checks:

-      const { url, quality } = downloadUrl[{
-        low: 1,
-        medium: downloadUrl.length - 2,
-        high: downloadUrl.length - 1
-      }[state.quality]];
+      const qualityIndex = {
+        low: Math.min(1, downloadUrl.length - 1),
+        medium: Math.max(0, downloadUrl.length - 2),
+        high: downloadUrl.length - 1
+      }[state.quality];
+      
+      if (!downloadUrl[qualityIndex]) {
+        throw new Error('No audio stream available for selected quality');
+      }
+      
+      const { url, quality } = downloadUrl[qualityIndex];
       
-      audio.src = url.replace('http:', 'https:');
+      audio.src = url.startsWith('http:') ? url.replace('http:', 'https:') : url;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const { url, quality } = downloadUrl[{
low: 1,
medium: downloadUrl.length - 2,
high: downloadUrl.length - 1
}[state.quality]];
audio.src = url.replace('http:', 'https:');
qualityView.textContent = quality + ' AAC';
const qualityIndex = {
low: Math.min(1, downloadUrl.length - 1),
medium: Math.max(0, downloadUrl.length - 2),
high: downloadUrl.length - 1
}[state.quality];
if (!downloadUrl[qualityIndex]) {
throw new Error('No audio stream available for selected quality');
}
const { url, quality } = downloadUrl[qualityIndex];
audio.src = url.startsWith('http:') ? url.replace('http:', 'https:') : url;
qualityView.textContent = quality + ' AAC';
🤖 Prompt for AI Agents
In src/modules/jioSaavn.ts around lines 32 to 39, the code assumes the
downloadUrl array has a specific length and structure when selecting quality,
which can cause runtime errors if the array is shorter or differently
structured. Add safety checks to verify that the indices used for low, medium,
and high quality exist in the downloadUrl array before accessing them. If the
expected index is out of bounds, provide a fallback to a valid index or handle
the error gracefully to prevent crashes.

Comment thread src/modules/localExtraction.ts Outdated
Comment on lines +1 to +2
export async function fetchDataFromLocal(id: string): Promise<Piped & { captions: [], videoStreams: [] }> {
const res = await fetch('http://localhost:9999/streams/' + id);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix return type declaration and consider making the URL configurable.

The return type { captions: [], videoStreams: [] } indicates empty arrays, but the function returns populated arrays. Also, the hardcoded localhost URL limits flexibility.

-export async function fetchDataFromLocal(id: string): Promise<Piped & { captions: [], videoStreams: [] }> {
-  const res = await fetch('http://localhost:9999/streams/' + id);
+export async function fetchDataFromLocal(id: string): Promise<Piped & { captions: any[], videoStreams: any[] }> {
+  const localUrl = process.env.LOCAL_EXTRACTOR_URL || 'http://localhost:9999';
+  const res = await fetch(`${localUrl}/streams/${id}`);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export async function fetchDataFromLocal(id: string): Promise<Piped & { captions: [], videoStreams: [] }> {
const res = await fetch('http://localhost:9999/streams/' + id);
export async function fetchDataFromLocal(id: string): Promise<Piped & { captions: any[], videoStreams: any[] }> {
const localUrl = process.env.LOCAL_EXTRACTOR_URL || 'http://localhost:9999';
const res = await fetch(`${localUrl}/streams/${id}`);
🤖 Prompt for AI Agents
In src/modules/localExtraction.ts at lines 1 to 2, update the return type to
reflect that captions and videoStreams are arrays with elements, not empty
arrays. Replace the empty array types with appropriate array types indicating
the expected content. Additionally, refactor the fetch URL to be configurable,
for example by using an environment variable or a function parameter, instead of
hardcoding 'http://localhost:9999'.

Comment on lines +14 to +25
const audioStreams = streamingData.adaptiveFormats
? streamingData.adaptiveFormats
.filter((f: any) => f.mimeType?.startsWith('audio'))
.map((f: any) => ({
url: f.url,
bitrate: parseInt(f.bitrate),
codec: f.mimeType.includes('opus') ? 'opus' : (f.mimeType.includes('aac') ? 'aac' : 'unknown'),
contentLength: parseInt(f.contentLength || '0'),
quality: f.audioQuality || `${Math.floor(parseInt(f.bitrate) / 1024)} kbps`,
mimeType: f.mimeType,
}))
: [];
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Improve type safety and codec detection.

The code uses any type and has limited codec detection. Also, the bitrate division by 1024 should be 1000 for kbps.

+interface AdaptiveFormat {
+  url: string;
+  mimeType: string;
+  bitrate: string;
+  contentLength?: string;
+  audioQuality?: string;
+  qualityLabel?: string;
+  quality?: string;
+  width?: number;
+  height?: number;
+}
+
  const audioStreams = streamingData.adaptiveFormats
    ? streamingData.adaptiveFormats
-      .filter((f: any) => f.mimeType?.startsWith('audio'))
-      .map((f: any) => ({
+      .filter((f: AdaptiveFormat) => f.mimeType?.startsWith('audio'))
+      .map((f: AdaptiveFormat) => ({
        url: f.url,
        bitrate: parseInt(f.bitrate),
-        codec: f.mimeType.includes('opus') ? 'opus' : (f.mimeType.includes('aac') ? 'aac' : 'unknown'),
+        codec: f.mimeType.match(/codecs="([^"]+)"/)?.[1] || f.mimeType.split('/')[1] || 'unknown',
        contentLength: parseInt(f.contentLength || '0'),
-        quality: f.audioQuality || `${Math.floor(parseInt(f.bitrate) / 1024)} kbps`,
+        quality: f.audioQuality || `${Math.floor(parseInt(f.bitrate) / 1000)} kbps`,
        mimeType: f.mimeType,
      }))
    : [];
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const audioStreams = streamingData.adaptiveFormats
? streamingData.adaptiveFormats
.filter((f: any) => f.mimeType?.startsWith('audio'))
.map((f: any) => ({
url: f.url,
bitrate: parseInt(f.bitrate),
codec: f.mimeType.includes('opus') ? 'opus' : (f.mimeType.includes('aac') ? 'aac' : 'unknown'),
contentLength: parseInt(f.contentLength || '0'),
quality: f.audioQuality || `${Math.floor(parseInt(f.bitrate) / 1024)} kbps`,
mimeType: f.mimeType,
}))
: [];
interface AdaptiveFormat {
url: string;
mimeType: string;
bitrate: string;
contentLength?: string;
audioQuality?: string;
qualityLabel?: string;
quality?: string;
width?: number;
height?: number;
}
const audioStreams = streamingData.adaptiveFormats
? streamingData.adaptiveFormats
.filter((f: AdaptiveFormat) => f.mimeType?.startsWith('audio'))
.map((f: AdaptiveFormat) => ({
url: f.url,
bitrate: parseInt(f.bitrate),
codec: f.mimeType.match(/codecs="([^"]+)"/)?.[1] || f.mimeType.split('/')[1] || 'unknown',
contentLength: parseInt(f.contentLength || '0'),
quality: f.audioQuality || `${Math.floor(parseInt(f.bitrate) / 1000)} kbps`,
mimeType: f.mimeType,
}))
: [];
🤖 Prompt for AI Agents
In src/modules/localExtraction.ts around lines 14 to 25, improve type safety by
replacing the use of 'any' with a proper interface or type for the
streamingData.adaptiveFormats elements. Enhance codec detection by expanding the
conditions to recognize more codecs beyond just 'opus' and 'aac'. Also, correct
the bitrate conversion by dividing by 1000 instead of 1024 when calculating kbps
in the quality field. Update the parsing of bitrate and contentLength to ensure
they are numbers and handle missing or malformed values gracefully.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ec23098 and 7e0326c.

📒 Files selected for processing (2)
  • src/scripts/list.ts (1 hunks)
  • src/scripts/queue.ts (2 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
src/scripts/queue.ts (1)
src/lib/store.ts (1)
  • store (66-160)
🔇 Additional comments (2)
src/scripts/list.ts (1)

33-34: LGTM! Dataset property normalization looks good.

The explicit copying of snake_case dataset properties to camelCase versions ensures consistent property naming before appending to the queue. This aligns with the broader effort to standardize the lastUpdated property propagation across the application.

src/scripts/queue.ts (1)

177-177: LGTM! Proper propagation of lastUpdated property.

The addition of the lastUpdated property to the StreamItem component aligns well with the broader effort to maintain consistent timestamp tracking across the application.

Comment thread src/scripts/queue.ts Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
vite.config.ts (1)

12-12: Consider simplifying the date formatting logic for better readability.

The dynamic build version generation is a good improvement over the static string. However, the current implementation using an IIFE with default parameter assignment is quite complex and hard to read.

Consider extracting the date formatting logic for better readability:

-    Build: JSON.stringify(((d = new Date()) => `v7x8 ${d.getFullYear().toString().slice(-2)}.${(d.getMonth() + 1).toString().padStart(2, '0')}.${d.getDate().toString().padStart(2, '0')}`)())
+    Build: JSON.stringify((() => {
+      const now = new Date();
+      const year = now.getFullYear().toString().slice(-2);
+      const month = (now.getMonth() + 1).toString().padStart(2, '0');
+      const day = now.getDate().toString().padStart(2, '0');
+      return `v7x8 ${year}.${month}.${day}`;
+    })())

Alternatively, use a more concise approach:

-    Build: JSON.stringify(((d = new Date()) => `v7x8 ${d.getFullYear().toString().slice(-2)}.${(d.getMonth() + 1).toString().padStart(2, '0')}.${d.getDate().toString().padStart(2, '0')}`)())
+    Build: JSON.stringify(`v7x8 ${new Date().toLocaleDateString('en-CA').slice(2).replace(/-/g, '.')}`)

Note: The current implementation uses local timezone, which means builds on different machines/timezones might produce different version strings on the same UTC date.

src/modules/getStreamData.ts (1)

98-98: Consider refactoring complex return logic for better readability.

The nested ternary operators make this logic difficult to read and maintain. Consider refactoring to use if-else statements or a switch statement for better clarity.

-  return (location.port === '9999') ? useLocal() : state.HLS ? useHls() : status === 'I' ? useInvidious() : status === 'N' ? fetchDataFromPiped(fallback) : usePiped(status === 'U' ? piped : proxy);
+  if (location.port === '9999') {
+    return useLocal();
+  }
+  
+  if (state.HLS) {
+    return useHls();
+  }
+  
+  switch (status) {
+    case 'I':
+      return useInvidious();
+    case 'N':
+      return fetchDataFromPiped(fallback);
+    case 'U':
+      return usePiped(piped);
+    default:
+      return usePiped(proxy);
+  }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bcda05d and 07e7e8a.

📒 Files selected for processing (11)
  • index.html (1 hunks)
  • package.json (1 hunks)
  • src/components/Settings/playback.ts (0 hunks)
  • src/components/UpdatePrompt.ts (1 hunks)
  • src/lib/store.ts (4 hunks)
  • src/lib/utils.ts (2 hunks)
  • src/modules/fetchList.ts (5 hunks)
  • src/modules/getStreamData.ts (3 hunks)
  • src/modules/start.ts (1 hunks)
  • src/scripts/queue.ts (1 hunks)
  • vite.config.ts (1 hunks)
💤 Files with no reviewable changes (1)
  • src/components/Settings/playback.ts
✅ Files skipped from review due to trivial changes (2)
  • src/components/UpdatePrompt.ts
  • index.html
🚧 Files skipped from review as they are similar to previous changes (5)
  • src/lib/utils.ts
  • src/lib/store.ts
  • package.json
  • src/scripts/queue.ts
  • src/modules/fetchList.ts
🧰 Additional context used
🧬 Code Graph Analysis (2)
src/modules/getStreamData.ts (1)
src/lib/store.ts (2)
  • store (65-163)
  • state (4-48)
src/modules/start.ts (1)
src/lib/store.ts (1)
  • store (65-163)
🔇 Additional comments (5)
src/modules/getStreamData.ts (3)

8-8: LGTM: Destructuring updated correctly.

The addition of proxy and status properties aligns with the updated store structure and supports the enhanced API routing logic introduced later in the function.


73-78: Well-implemented function enhancement.

The addition of the optional src parameter with a default value maintains backward compatibility while enabling the function to work with different API source arrays (piped or proxy). The recursive logic is correctly updated to pass the src parameter through.


95-95: Dynamic import implemented correctly.

The use of dynamic import for local extraction functionality is appropriate for conditional loading and keeps the main bundle size smaller.

src/modules/start.ts (2)

18-22: Custom instance initialization updated correctly.

The changes properly implement the new proxy/status-based API management:

  • Setting both proxy[0] and piped[0] ensures consistency
  • Conditional invidious setup with status assignment aligns with the new routing logic
  • Removal of deprecated enforcePiped flag is consistent with the broader refactoring

32-32: LGTM: Proxy initialization added correctly.

The addition of proxy array initialization from dynamic data is consistent with the existing pattern and necessary for the new proxy API support.

Comment thread src/modules/start.ts
Comment on lines +27 to +29
document.querySelector('samp')!.textContent = {
U: "⬛⬛⬛⬛", P: "⬛⬛⬛⬜", I: "🟧⬛⬛⬜⬜", N: "⬛⬜⬜⬜"
}[data.health as 'U'];
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Improve type safety for health status mapping.

The health status UI update is a good addition, but the type assertion as 'U' is unsafe and could cause runtime errors if data.health has an unexpected value.

-      document.querySelector('samp')!.textContent = {
-        U: "⬛⬛⬛⬛", P: "⬛⬛⬛⬜", I: "🟧⬛⬛⬜⬜", N: "⬛⬜⬜⬜"
-      }[data.health as 'U'];
+      const healthSymbols = {
+        U: "⬛⬛⬛⬛", P: "⬛⬛⬛⬜", I: "🟧⬛⬛⬜⬜", N: "⬛⬜⬜⬜"
+      } as const;
+      const healthSymbol = healthSymbols[data.health as keyof typeof healthSymbols] || "❓❓❓❓";
+      document.querySelector('samp')!.textContent = healthSymbol;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
document.querySelector('samp')!.textContent = {
U: "⬛⬛⬛⬛", P: "⬛⬛⬛⬜", I: "🟧⬛⬛⬜⬜", N: "⬛⬜⬜⬜"
}[data.health as 'U'];
const healthSymbols = {
U: "⬛⬛⬛⬛", P: "⬛⬛⬛⬜", I: "🟧⬛⬛⬜⬜", N: "⬛⬜⬜⬜"
} as const;
const healthSymbol = healthSymbols[data.health as keyof typeof healthSymbols] || "❓❓❓❓";
document.querySelector('samp')!.textContent = healthSymbol;
🤖 Prompt for AI Agents
In src/modules/start.ts around lines 27 to 29, the code uses an unsafe type
assertion 'as U' when accessing the health status mapping, which risks runtime
errors if data.health has unexpected values. To fix this, replace the assertion
with a type-safe check by validating that data.health is one of the expected
keys ('U', 'P', 'I', 'N') before accessing the mapping, and provide a fallback
value for unknown statuses to ensure safe assignment to textContent.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🔭 Outside diff range comments (1)
src/components/WatchVideo.ts (1)

128-138: Guard against empty Invidious proxy array in subtitle URLs

While store.api.invidious is initialized in src/modules/start.ts, there’s no guarantee its first element exists—if the array is empty, store.api.invidious[0] will be undefined, leading to src becoming "undefined<subtitle-path>".

• File: src/components/WatchVideo.ts
• Lines: 128–138

Consider guarding or providing a fallback when the proxy list is empty:

- src=${(store.api.status === 'P' ? '' : store.api.invidious[0]) + v.url}
+ src=${(
+   store.api.status === 'P' || store.api.invidious.length === 0
+     ? ''
+     : store.api.invidious[0]
+ ) + v.url}

Or using the nullish coalescing operator:

- src=${(store.api.status === 'P' ? '' : store.api.invidious[0]) + v.url}
+ src=${(
+   store.api.status === 'P'
+     ? ''
+     : store.api.invidious[0] ?? ''
+ ) + v.url}

This ensures src always starts with a string, preventing "undefined" prefixes at runtime.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 07e7e8a and dbab3b2.

📒 Files selected for processing (5)
  • netlify/edge-functions/fallback.ts (1 hunks)
  • src/components/WatchVideo.ts (3 hunks)
  • src/index.d.ts (3 hunks)
  • src/modules/getStreamData.ts (5 hunks)
  • src/modules/localExtraction.ts (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • netlify/edge-functions/fallback.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/index.d.ts
  • src/modules/localExtraction.ts
🧰 Additional context used
🧬 Code Graph Analysis (2)
src/components/WatchVideo.ts (1)
src/lib/store.ts (1)
  • store (65-163)
src/modules/getStreamData.ts (1)
src/lib/store.ts (2)
  • store (65-163)
  • state (4-48)
🔇 Additional comments (6)
src/components/WatchVideo.ts (2)

35-40: Type definition updated correctly for codec field.

The change from type to codec in the videoStreams type definition is consistent with the updated data structure. The codec detection logic on lines 38-39 properly uses the new codec field.


47-56: Codec field references updated consistently.

All references to f.type have been correctly updated to f.codec throughout the video stream filtering logic. The codec preference hierarchy (AV1 → VP9 → AVC) is maintained properly.

src/modules/getStreamData.ts (4)

8-9: API destructuring expanded appropriately.

The addition of proxy and status to the destructuring aligns with the expanded store.api structure and supports the new conditional API selection logic.


36-39: Captions to subtitles transformation implemented correctly.

The property rename and field mapping (c.labelname, c.urlurl) correctly transforms the Invidious captions structure to match the expected subtitles format used in the video component.


52-52: Field mapping for codec implemented correctly.

The assignment codec: v.type correctly maps the Invidious type field to the expected codec field, maintaining compatibility with the video component's updated structure.


76-81: usePiped function refactored effectively for flexibility.

The addition of the optional src parameter with a default value maintains backward compatibility while enabling the function to work with both piped and proxy arrays. The recursive logic correctly propagates the source parameter.

Comment on lines +98 to +101
const useLocal = async () => await import('./localExtraction.ts').then(mod => mod.fetchDataFromLocal(id));


return state.HLS ? useHls() : state.enforcePiped ? usePiped() : useInvidious();
return (location.port === '9999') ? useLocal() : state.HLS ? useHls() : status === 'I' ? useInvidious() : status === 'N' ? fetchDataFromPiped(fallback) : usePiped(status === 'U' ? piped : proxy);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Complex API selection logic needs refactoring for maintainability.

The comprehensive API selection strategy covers all scenarios well, but the single-line conditional on line 101 is difficult to read and maintain. Consider refactoring for clarity:

-  return (location.port === '9999') ? useLocal() : state.HLS ? useHls() : status === 'I' ? useInvidious() : status === 'N' ? fetchDataFromPiped(fallback) : usePiped(status === 'U' ? piped : proxy);
+  // Development mode with local extraction
+  if (location.port === '9999') {
+    return useLocal();
+  }
+  
+  // HLS mode
+  if (state.HLS) {
+    return useHls();
+  }
+  
+  // API selection based on status
+  switch (status) {
+    case 'I': return useInvidious();
+    case 'N': return fetchDataFromPiped(fallback);
+    default: return usePiped(status === 'U' ? piped : proxy);
+  }

Additionally, consider adding error handling for the dynamic import in useLocal():

-  const useLocal = async () => await import('./localExtraction.ts').then(mod => mod.fetchDataFromLocal(id));
+  const useLocal = async () => {
+    try {
+      const mod = await import('./localExtraction.ts');
+      return mod.fetchDataFromLocal(id);
+    } catch (error) {
+      console.warn('Local extraction failed, falling back to remote APIs:', error);
+      return state.HLS ? useHls() : usePiped();
+    }
+  };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const useLocal = async () => await import('./localExtraction.ts').then(mod => mod.fetchDataFromLocal(id));
return state.HLS ? useHls() : state.enforcePiped ? usePiped() : useInvidious();
return (location.port === '9999') ? useLocal() : state.HLS ? useHls() : status === 'I' ? useInvidious() : status === 'N' ? fetchDataFromPiped(fallback) : usePiped(status === 'U' ? piped : proxy);
const useLocal = async () => {
try {
const mod = await import('./localExtraction.ts');
return mod.fetchDataFromLocal(id);
} catch (error) {
console.warn('Local extraction failed, falling back to remote APIs:', error);
return state.HLS ? useHls() : usePiped(status === 'U' ? piped : proxy);
}
};
// Development mode with local extraction
if (location.port === '9999') {
return useLocal();
}
// HLS mode
if (state.HLS) {
return useHls();
}
// API selection based on status
switch (status) {
case 'I':
return useInvidious();
case 'N':
return fetchDataFromPiped(fallback);
default:
return usePiped(status === 'U' ? piped : proxy);
}
🤖 Prompt for AI Agents
In src/modules/getStreamData.ts around lines 98 to 101, the complex single-line
conditional for API selection is hard to read and maintain. Refactor this logic
into a clearer multi-branch if-else or switch statement to improve readability.
Also, add error handling to the dynamic import in useLocal() by wrapping the
import call in a try-catch block and handling import failures gracefully.

@n-ce
Copy link
Copy Markdown
Owner Author

n-ce commented Jul 31, 2025

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jul 31, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@n-ce n-ce merged commit 5423f6a into main Jul 31, 2025
2 checks passed
@n-ce n-ce deleted the v7x8 branch July 31, 2025 16:11
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