Skip to content

fix: videos (LF) not updating, related to and closes #207#210

Merged
GalvinPython merged 2 commits intomainfrom
207-only-check-for-content-type-playlist-based-on-duration
Feb 12, 2026
Merged

fix: videos (LF) not updating, related to and closes #207#210
GalvinPython merged 2 commits intomainfrom
207-only-check-for-content-type-playlist-based-on-duration

Conversation

@GalvinPython
Copy link
Owner

No description provided.

@GalvinPython GalvinPython added this to the 2.0.1 milestone Feb 12, 2026
@GalvinPython GalvinPython added the bug Something isn't working label Feb 12, 2026
Copilot AI review requested due to automatic review settings February 12, 2026 11:37
@GalvinPython GalvinPython added the enhancement New feature or request label Feb 12, 2026
@GalvinPython GalvinPython linked an issue Feb 12, 2026 that may be closed by this pull request
@GalvinPython GalvinPython added the platform:youtube Anything related to YouTube label Feb 12, 2026
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adjusts YouTube latest-upload processing to address cases where “videos (LF)” are not updating (related to/closing #207) by changing how the content type (video/short/stream) is determined.

Changes:

  • Adds helpers to fetch and parse a video’s ISO-8601 duration via the YouTube Videos API.
  • Replaces the previous 3-playlist comparison (Video/Short/Stream) with duration-gated classification logic to avoid relying on UULF.
  • Updates bun.lock metadata (configVersion).

Reviewed changes

Copilot reviewed 1 out of 2 changed files in this pull request and generated 3 comments.

File Description
src/utils/youtube/fetchLatestUploads.ts Introduces duration-based classification and reduces reliance on the lagging UULF playlist.
bun.lock Lockfile metadata update (configVersion).
Comments suppressed due to low confidence (1)

src/utils/youtube/fetchLatestUploads.ts:166

  • This change adds an extra videos.list request (fetchVideoDuration) per update, and for uploads under 3 minutes it still does two playlist lookups (so 3 calls total—same as before). If the goal is to reduce quota and avoid UULF lag, you can likely drop the duration request entirely and classify by checking only UUSH (shorts) and UULV (streams); if the latest UU upload isn’t in either, treat it as a regular video.
                // Use duration-based detection to reduce API quota usage
                // and avoid UULF which is currently lagging
                const durationSeconds = await fetchVideoDuration(videoId);
                const THREE_MINUTES = 180;

                let contentType: PlaylistType | null = null;

                if (durationSeconds >= THREE_MINUTES) {
                    // Over 3 minutes: cannot be a short, check only if it's a stream
                    const streamVideoId = await getSinglePlaylistAndReturnVideoData(
                        channelId,
                        PlaylistType.Stream,
                    );

                    if (videoId === streamVideoId.videoId) {
                        contentType = PlaylistType.Stream;
                    } else {
                        // Not a stream and over 3 min; must be a regular video
                        contentType = PlaylistType.Video;
                    }
                } else {
                    // Under 3 minutes: could be a short or a video, check UUSH and UULV
                    const [shortVideoId, streamVideoId] = await Promise.all([
                        getSinglePlaylistAndReturnVideoData(
                            channelId,
                            PlaylistType.Short,
                        ),
                        getSinglePlaylistAndReturnVideoData(
                            channelId,
                            PlaylistType.Stream,

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 19 to 27
* Parse an ISO 8601 duration string (e.g. "PT1H2M3S") into total seconds.
*/
function parseISO8601Duration(duration: string): number {
const match = duration.match(/PT(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)S)?/);
if (!match) return 0;
const hours = parseInt(match[1] || "0", 10);
const minutes = parseInt(match[2] || "0", 10);
const seconds = parseInt(match[3] || "0", 10);
return hours * 3600 + minutes * 60 + seconds;
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

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

parseISO8601Duration only matches PT... and will ignore the day component if YouTube ever returns durations like P1DT2H3M (regex will match from the PT... substring and undercount). Consider parsing the full ISO-8601 duration (e.g., support an optional P(\d+)D part and anchor the regex) so duration-based classification stays correct for very long videos/streams.

Suggested change
* Parse an ISO 8601 duration string (e.g. "PT1H2M3S") into total seconds.
*/
function parseISO8601Duration(duration: string): number {
const match = duration.match(/PT(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)S)?/);
if (!match) return 0;
const hours = parseInt(match[1] || "0", 10);
const minutes = parseInt(match[2] || "0", 10);
const seconds = parseInt(match[3] || "0", 10);
return hours * 3600 + minutes * 60 + seconds;
* Parse an ISO 8601 duration string (e.g. "PT1H2M3S" or "P1DT1H2M3S") into total seconds.
*/
function parseISO8601Duration(duration: string): number {
// Support an optional day component and require the full string to match.
const match = duration.match(
/^P(?:(\d+)D)?T(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)S)?$/,
);
if (!match) return 0;
const days = parseInt(match[1] || "0", 10);
const hours = parseInt(match[2] || "0", 10);
const minutes = parseInt(match[3] || "0", 10);
const seconds = parseInt(match[4] || "0", 10);
return days * 86400 + hours * 3600 + minutes * 60 + seconds;

Copilot uses AI. Check for mistakes.
const data = await res.json();
if (!data.items || data.items.length === 0) return 0;

return parseISO8601Duration(data.items[0].contentDetails.duration);
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

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

fetchVideoDuration assumes data.items[0].contentDetails.duration is always present. If the Videos API returns an item without contentDetails (or duration), this will throw at runtime. Add shape checks/optional chaining and fall back to 0 (or treat as “unknown”) when duration isn’t available.

Suggested change
return parseISO8601Duration(data.items[0].contentDetails.duration);
const firstItem = data.items[0];
const durationStr = firstItem?.contentDetails?.duration;
if (typeof durationStr !== "string") {
return 0;
}
return parseISO8601Duration(durationStr);

Copilot uses AI. Check for mistakes.
Comment on lines 140 to 156
const THREE_MINUTES = 180;

let contentType: PlaylistType | null = null;

if (durationSeconds >= THREE_MINUTES) {
// Over 3 minutes: cannot be a short, check only if it's a stream
const streamVideoId = await getSinglePlaylistAndReturnVideoData(
channelId,
PlaylistType.Stream,
);

if (videoId === streamVideoId.videoId) {
contentType = PlaylistType.Stream;
} else {
// Not a stream and over 3 min; must be a regular video
contentType = PlaylistType.Video;
}
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

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

The duration threshold hard-codes 180 seconds and treats >= 180 as “cannot be a short”. If that assumption is ever wrong (e.g., policy changes or edge cases at exactly 180s), shorts could be misclassified as regular videos and routed to the wrong subscription flags. Consider avoiding duration-based gating for Shorts classification (or at minimum make the threshold configurable and document the assumption).

Copilot uses AI. Check for mistakes.
@GalvinPython GalvinPython merged commit fae2820 into main Feb 12, 2026
3 checks passed
@github-project-automation github-project-automation bot moved this to Done in Feedr Feb 12, 2026
@GalvinPython GalvinPython deleted the 207-only-check-for-content-type-playlist-based-on-duration branch February 12, 2026 12:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working component: bot enhancement New feature or request platform:youtube Anything related to YouTube

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

Only check for content type (playlist) based on duration

1 participant