mirror of
https://github.com/ThatGuySam/doesitarm.git
synced 2026-05-18 06:44:46 -07:00
Replace all in-scope axios callsites with a new helpers/http.js wrapper over native fetch, including JSON/text GET, JSON POST, HEAD checks, and transient 5xx retry behavior; update all browser, build, script, and proxy API clients to use it; add focused unit tests; and remove axios from package dependencies. Constraint: Preserve API/build and deployment behavior while lowering transport surface area. Rejected: inline fetch replacements at each callsite | rejected to avoid inconsistent error/retry semantics. Confidence: high Scope-risk: moderate Directive: Keep helper in place as the transport boundary and update tests when changing request semantics. Tested: pnpm run -s typecheck, pnpm -s run test-prebuild, pnpm -s run test, pnpm -s run test:browser, pnpm -s run netlify-build, smoke GETs on /apple-silicon-app-test and /apple-silicon-app-test/?version=2 Not-tested: branch/netlify deployment health in CI pipeline after merge
176 lines
5.4 KiB
JavaScript
176 lines
5.4 KiB
JavaScript
import fs from 'fs-extra'
|
|
import { google } from 'googleapis'
|
|
|
|
import { playlists, benchmarksPlaylistId } from './playlists.js'
|
|
import { getJson } from '~/helpers/http.js'
|
|
|
|
|
|
export const youtubeVideoPath = './static/api/youtube-videos.json'
|
|
|
|
|
|
async function getPlaylistsItems ( { playlistId } = {} ) {
|
|
const perPage = 50
|
|
|
|
// Setup Youtube API V3 Service instance
|
|
const service = google.youtube('v3')
|
|
|
|
// Fetch data from the Youtube API
|
|
const { errors = null, data = null } = await service.playlistItems.list({
|
|
key: process.env.GOOGLE_API_KEY,
|
|
part: 'snippet,contentDetails',
|
|
playlistId,
|
|
maxResults: perPage
|
|
}).catch(({ errors }) => {
|
|
|
|
console.log('Error fetching playlist', errors)
|
|
|
|
return {
|
|
errors
|
|
}
|
|
})
|
|
|
|
// Send an error response if something went wrong
|
|
if (errors !== null) {
|
|
throw new Error(errors)
|
|
|
|
return
|
|
}
|
|
|
|
const items = data.items
|
|
|
|
// If there are more results then push them to our playlist
|
|
if (data.nextPageToken !== null) {
|
|
|
|
// Store the token for page #2 into our variable
|
|
let pageToken = data.nextPageToken
|
|
|
|
while (pageToken !== null) {
|
|
// Fetch data from the Youtube API
|
|
const youtubePageResponse = await service.playlistItems.list({
|
|
key: process.env.GOOGLE_API_KEY,
|
|
part: 'snippet,contentDetails',
|
|
playlistId,
|
|
maxResults: perPage,
|
|
pageToken: pageToken
|
|
})
|
|
|
|
// Add the videos from this page on to our total items list
|
|
youtubePageResponse.data.items.forEach(item => items.push(item))
|
|
|
|
// Now that we're done set up the next page token or empty out the pageToken variable so our loop will stop
|
|
pageToken = ('nextPageToken' in youtubePageResponse.data) ? youtubePageResponse.data.nextPageToken : null
|
|
}
|
|
}
|
|
|
|
console.log(`Fetched ${items.length} videos from https://www.youtube.com/playlist?list=${ playlistId }`)
|
|
|
|
return items
|
|
}
|
|
|
|
async function getYouTubeVideos ( options = {} ) {
|
|
|
|
const {
|
|
// requestsDelay = 3600,
|
|
} = options
|
|
|
|
// Fetch all videos from playlists
|
|
const playlistSets = []
|
|
|
|
for ( const playlistToFetch of playlists ) {
|
|
|
|
// console.log('playlistJsonUrl', playlistJsonUrl)
|
|
|
|
const playlistItems = await getPlaylistsItems({
|
|
playlistId: playlistToFetch.id
|
|
})
|
|
// console.log('playlistItems', playlistItems.length)
|
|
|
|
playlistSets.push( playlistItems )
|
|
}
|
|
|
|
// Pull benchmarksPlaylist out of playlist sets
|
|
// benchmarksPlaylistId
|
|
const benchmarksVideoIds = playlistSets.find( playlist => {
|
|
// Skip empty playlists
|
|
if (playlist.length === 0) return false
|
|
|
|
// Get this playlist's ID from first video
|
|
// and check against benchmarksPlaylistId
|
|
return playlist[0].snippet.playlistId === benchmarksPlaylistId
|
|
}).map( video => video.contentDetails.videoId)
|
|
|
|
// Creat an object to store playlist items
|
|
const playlistItems = {}
|
|
|
|
|
|
// Loop through the sets and store all the videos into a single array
|
|
for (const playlistSet of playlistSets) {
|
|
for (const playlistItem of playlistSet) {
|
|
// If we've already stored this video
|
|
// then skip
|
|
if (playlistItems.hasOwnProperty(playlistItem.contentDetails.videoId)) continue
|
|
|
|
const tags = []
|
|
|
|
// If this video is in the benchmarks playlist
|
|
// then add the benchmark tag
|
|
if (benchmarksVideoIds.includes(playlistItem.contentDetails.videoId)) {
|
|
tags.push('benchmark')
|
|
}
|
|
|
|
// Store newly found video
|
|
playlistItems[playlistItem.contentDetails.videoId] = {
|
|
title: playlistItem.snippet.title,
|
|
description: playlistItem.snippet.description,
|
|
timestamps: [],
|
|
rawData: playlistItem,
|
|
tags
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Loop through playlist items and store timestamp data
|
|
for (const videoId in playlistItems) {
|
|
// console.log('playlistItem', playlistItem)
|
|
// If the description is empty
|
|
// then skip
|
|
if (playlistItems[videoId].description.trim().length === 0) continue
|
|
|
|
// Break up the description by line breaks
|
|
const descriptionLines = playlistItems[videoId].description.split(/\r?\n/)
|
|
|
|
// console.log('descriptionLines', descriptionLines)
|
|
|
|
for (const line of descriptionLines) {
|
|
// https://stackoverflow.com/a/11067610/1397641
|
|
const matches = line.match(/(?:([0-5]?[0-9]):)?([0-5]?[0-9]):([0-5][0-9])/)
|
|
|
|
// If there are no timestamps on this line
|
|
// then skip
|
|
if (matches === null) continue
|
|
|
|
playlistItems[videoId].timestamps.push({
|
|
time: matches[0],
|
|
fullText: line
|
|
})
|
|
}
|
|
}
|
|
|
|
return playlistItems
|
|
}
|
|
|
|
|
|
export async function saveYouTubeVideos () {
|
|
// We'll need to lean up this function to work with 10k API Requests
|
|
// before we can use it again
|
|
// const youtubeVideos = await getYouTubeVideos()
|
|
|
|
// Locked previously sucessful YouTube API data for now
|
|
const youtubeVideos = await getJson( process.env.VIDEO_SOURCE )
|
|
|
|
|
|
// Save to JSON
|
|
await fs.outputJson( youtubeVideoPath, youtubeVideos )
|
|
|
|
}
|