Create a bash script with the code below as export-yt-liked-and-disliked-videos.sh
, give it execution rights with chmod +x export-yt-liked-and-disliked-videos.sh
, and run it with your Google access token
like so:
./export-yt-liked-and-disliked-videos.sh ya29.a0Ad52N39hmTcEjI1QoL...
#!/bin/bash
ratings=("like" "dislike")
auth_token="$1"
csv_file="youtube_api_export.csv"
declare -a existingIds
read_existing_ids() {
if [ -f "$csv_file" ]; then
IFS=$'\n' read -d '' -r -a existingIds < <(tail -n +2 "$csv_file" | cut -d ',' -f 1 | tr -d '"' && printf '\0')
else
echo "CSV file does not exist, creating a new one."
echo "id,title" > "$csv_file"
fi
echo "Loaded ${#existingIds[@]} existing video IDs."
}
update_csv() {
local items=$1
item_count=$(echo "$items" | jq '.items | length')
echo "Processing $item_count new items..."
local skipped_count=0
local added_count=0
for ((i = 0; i < item_count; i++)); do
local item
item=$(echo "$items" | jq ".items[$i]")
local id
id=$(echo "$item" | jq -r '.id')
local title
title=$(echo "$item" | jq -r '.snippet.title' | sed 's/"/""/g')
local csvLine
csvLine="\"$id\",\"$title\""
if [[ " ${existingIds[*]} " =~ ${id} ]]; then
((skipped_count++))
echo "Skipping existing YouTube video ID: $id"
continue
fi
echo "$csvLine" >> "$csv_file"
((added_count++))
done
echo "Added $added_count new items, skipped $skipped_count items."
}
if [ ! -f "$csv_file" ]; then
echo "id,title" > "$csv_file"
fi
read_existing_ids
fetch_and_process_videos() {
local rating=$1
local nextPageToken=""
local url="https://www.googleapis.com/youtube/v3/videos?myRating=$rating&maxResults=50&fields=nextPageToken%2CpageInfo%2Citems(id%2Csnippet(title))&part=snippet"
while true; do
local requestUrl="${url}"
if [[ -n $nextPageToken ]]; then
requestUrl="${url}&pageToken=${nextPageToken}"
fi
response=$(curl -s --request GET \
--url "$requestUrl" \
--header "Accept: application/json" \
--header "Authorization: Bearer $auth_token" \
--header "User-Agent: insomnia/8.6.1" | jq)
update_csv "$response"
nextPageToken=$(echo "$response" | jq -r '.nextPageToken')
if [[ $nextPageToken == "null" ]] || [[ -z $nextPageToken ]]; then
echo "No more pages to fetch for rating '$rating'."
break
fi
sleep 1
done
}
for rating in "${ratings[@]}"; do
echo "Processing rating: $rating"
fetch_and_process_videos "$rating"
done
echo "CSV file '$csv_file' update complete."