Skip to content

Commit ac70bfa

Browse files
committed
apply suggestions from review
1 parent 9838a33 commit ac70bfa

File tree

1 file changed

+30
-11
lines changed

1 file changed

+30
-11
lines changed

src/utils/youtube/fetchLatestUploads.ts

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,21 @@ import getSinglePlaylistAndReturnVideoData, {
1616
} from "./getSinglePlaylistAndReturnVideoData";
1717

1818
/**
19-
* Parse an ISO 8601 duration string (e.g. "PT1H2M3S") into total seconds.
19+
* Parse a full ISO 8601 duration string into total seconds.
20+
* Supports formats like "PT1H2M3S", "P1DT2H3M4S", "PT30S", etc.
21+
* Note: YouTube typically returns PT-prefixed durations, but very long
22+
* streams/videos could include a day component (P1DT...).
2023
*/
2124
function parseISO8601Duration(duration: string): number {
22-
const match = duration.match(/PT(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)S)?/);
25+
const match = duration.match(
26+
/^P(?:(\d+)D)?(?:T(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)S)?)?$/,
27+
);
2328
if (!match) return 0;
24-
const hours = parseInt(match[1] || "0", 10);
25-
const minutes = parseInt(match[2] || "0", 10);
26-
const seconds = parseInt(match[3] || "0", 10);
27-
return hours * 3600 + minutes * 60 + seconds;
29+
const days = parseInt(match[1] || "0", 10);
30+
const hours = parseInt(match[2] || "0", 10);
31+
const minutes = parseInt(match[3] || "0", 10);
32+
const seconds = parseInt(match[4] || "0", 10);
33+
return days * 86400 + hours * 3600 + minutes * 60 + seconds;
2834
}
2935

3036
/**
@@ -44,10 +50,20 @@ async function fetchVideoDuration(videoId: string): Promise<number> {
4450
return 0;
4551
}
4652

53+
// TODO: Type the response from YouTube API for better type safety
4754
const data = await res.json();
4855
if (!data.items || data.items.length === 0) return 0;
4956

50-
return parseISO8601Duration(data.items[0].contentDetails.duration);
57+
const durationFirstItem = data.items[0];
58+
if (!durationFirstItem.contentDetails || !durationFirstItem.contentDetails.duration) {
59+
console.error("Duration not found in video details for video ID:", videoId,);
60+
return 0;
61+
}
62+
63+
const duration = durationFirstItem?.contentDetails?.duration;
64+
if (typeof duration !== "string") return 0;
65+
66+
return parseISO8601Duration(duration);
5167
}
5268

5369
export const updates = new Map<
@@ -135,14 +151,17 @@ export default async function fetchLatestUploads() {
135151
requiresUpdate,
136152
);
137153
// Use duration-based detection to reduce API quota usage
138-
// and avoid UULF which is currently lagging
154+
// and avoid UULF which is currently lagging.
155+
// YouTube Shorts are currently limited to 3 minutes (180s).
156+
// Videos at exactly 180s could still be shorts, so we use
157+
// a strict greater-than check.
139158
const durationSeconds = await fetchVideoDuration(videoId);
140-
const THREE_MINUTES = 180;
159+
const SHORTS_DURATION = 180;
141160

142161
let contentType: PlaylistType | null = null;
143162

144-
if (durationSeconds >= THREE_MINUTES) {
145-
// Over 3 minutes: cannot be a short, check only if it's a stream
163+
if (durationSeconds > SHORTS_DURATION) {
164+
// Over the shorts limit: cannot be a short, check only if it's a stream
146165
const streamVideoId = await getSinglePlaylistAndReturnVideoData(
147166
channelId,
148167
PlaylistType.Stream,

0 commit comments

Comments
 (0)