Skip to content

Commit 9838a33

Browse files
committed
fix: videos (LF) not updating, related to and closes #207
1 parent a0cfb42 commit 9838a33

2 files changed

Lines changed: 69 additions & 34 deletions

File tree

bun.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/utils/youtube/fetchLatestUploads.ts

Lines changed: 68 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,41 @@ import getSinglePlaylistAndReturnVideoData, {
1515
PlaylistType,
1616
} from "./getSinglePlaylistAndReturnVideoData";
1717

18+
/**
19+
* Parse an ISO 8601 duration string (e.g. "PT1H2M3S") into total seconds.
20+
*/
21+
function parseISO8601Duration(duration: string): number {
22+
const match = duration.match(/PT(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)S)?/);
23+
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;
28+
}
29+
30+
/**
31+
* Fetch the duration (in seconds) of a video using the YouTube Videos API.
32+
* Returns 0 if the duration cannot be determined.
33+
*/
34+
async function fetchVideoDuration(videoId: string): Promise<number> {
35+
const res = await fetch(
36+
`https://youtube.googleapis.com/youtube/v3/videos?part=contentDetails&id=${videoId}&key=${env.youtubeApiKey}`,
37+
);
38+
39+
if (!res.ok) {
40+
console.error(
41+
"Error fetching video duration:",
42+
res.statusText,
43+
);
44+
return 0;
45+
}
46+
47+
const data = await res.json();
48+
if (!data.items || data.items.length === 0) return 0;
49+
50+
return parseISO8601Duration(data.items[0].contentDetails.duration);
51+
}
52+
1853
export const updates = new Map<
1954
string,
2055
{
@@ -99,12 +134,29 @@ export default async function fetchLatestUploads() {
99134
"Requires update?",
100135
requiresUpdate,
101136
);
102-
const [longVideoId, shortVideoId, streamVideoId] =
103-
await Promise.all([
104-
getSinglePlaylistAndReturnVideoData(
105-
channelId,
106-
PlaylistType.Video,
107-
),
137+
// Use duration-based detection to reduce API quota usage
138+
// and avoid UULF which is currently lagging
139+
const durationSeconds = await fetchVideoDuration(videoId);
140+
const THREE_MINUTES = 180;
141+
142+
let contentType: PlaylistType | null = null;
143+
144+
if (durationSeconds >= THREE_MINUTES) {
145+
// Over 3 minutes: cannot be a short, check only if it's a stream
146+
const streamVideoId = await getSinglePlaylistAndReturnVideoData(
147+
channelId,
148+
PlaylistType.Stream,
149+
);
150+
151+
if (videoId === streamVideoId.videoId) {
152+
contentType = PlaylistType.Stream;
153+
} else {
154+
// Not a stream and over 3 min; must be a regular video
155+
contentType = PlaylistType.Video;
156+
}
157+
} else {
158+
// Under 3 minutes: could be a short or a video, check UUSH and UULV
159+
const [shortVideoId, streamVideoId] = await Promise.all([
108160
getSinglePlaylistAndReturnVideoData(
109161
channelId,
110162
PlaylistType.Short,
@@ -115,42 +167,24 @@ export default async function fetchLatestUploads() {
115167
),
116168
]);
117169

118-
if (!longVideoId && !shortVideoId && !streamVideoId) {
119-
console.error(
120-
"No video IDs found for channel in fetchLatestUploads",
121-
);
122-
continue;
123-
}
124-
125-
let contentType: PlaylistType | null = null;
126-
127-
if (videoId == longVideoId.videoId) {
128-
contentType = PlaylistType.Video;
129-
} else if (videoId == shortVideoId.videoId) {
130-
contentType = PlaylistType.Short;
131-
} else if (videoId == streamVideoId.videoId) {
132-
contentType = PlaylistType.Stream;
133-
} else {
134-
console.error(
135-
"Video ID does not match any fetched video IDs for channel",
136-
channelId,
137-
);
170+
if (videoId === shortVideoId.videoId) {
171+
contentType = PlaylistType.Short;
172+
} else if (videoId === streamVideoId.videoId) {
173+
contentType = PlaylistType.Stream;
174+
} else {
175+
// Not in shorts or streams playlist → regular video
176+
contentType = PlaylistType.Video;
177+
}
138178
}
139179

140-
const videoIdMap = {
141-
[PlaylistType.Video]: longVideoId,
142-
[PlaylistType.Short]: shortVideoId,
143-
[PlaylistType.Stream]: streamVideoId,
144-
};
145-
146-
console.log("Determined content type:", contentType);
180+
console.log("Determined content type:", contentType, `(duration: ${durationSeconds}s)`);
147181

148182
if (contentType) {
149183
console.log(
150184
`Updating ${contentType} video ID for channel`,
151185
channelId,
152186
"to",
153-
videoIdMap[contentType as keyof typeof videoIdMap],
187+
videoId,
154188
);
155189
} else {
156190
console.error(

0 commit comments

Comments
 (0)