Google Sheets - Youtube playlist
Started to play with YouTube data api, the goal was to retrieve some basic data about videos as well as managing play lists, but after a while realized that things may be achieved much easily right from Google Sheets
In my demo I have an spreadsheet with YouTube links and custom menu that will call sync function
Under the hood sync function will do its best to make things happen
Here is an sample code I have ended up with
/*
I will be called each time spread sheet is opened
Create YouTube \ Sync menu item that will trigger synchronization
Alternative approach will be to run in onEdit
Also we can schedule onSync run
This approach choose because it is not expected for list to change often
Also it will be changed manually and just to have an example of custom menu
*/
function onOpen() {
SpreadsheetApp.getUi().createMenu("YouTube").addItem("Sync", "onSync").addToUi()
}
/*
Callback for YouTube \ Sync menu item
Extracted here because of alert popup which makes it impossible to run sync from editor
*/
function onSync() {
var {items, removed, added, rearanged} = sync()
var message = "YouTube sync completed\n\n"
message += "- " + items.length + " items synced in playlist\n"
if (removed) {
message += "- " + removed + " items removed\n"
}
if (added) {
message += "- " + removed + " items added\n"
}
if (rearanged) {
message += "- " + rearanged + " items rearanged\n"
}
if (!removed && !added && !rearanged) {
message += "- " + "nothing changed"
}
SpreadsheetApp.getUi().alert(message)
}
/*
Sync videos from Google Sheet to YouTube
How it works:
1. retrieve links from spread sheet
2. retrieve items from playlist
3. remove unwanted items from playlist
4. add missing items to playlist
5. rearange items
*/
function sync() {
var removed = 0
var added = 0
var rearanged = 0
console.log("retrieving videos from youtube playlist")
var items = getVideosFromPlaylist()
console.log(items.length + " videos retrieved from youtube")
console.log("retrieving videos from spreadsheet")
var videos = getVideosFromSheet()
console.log(videos.length + " videos retrieved from spreadsheet")
// remove unwanted items
console.log("removing unwanted items")
for(var item of items) {
if(!videos.includes(item.videoId)) {
console.log("removing " + item.videoId)
YouTube.PlaylistItems.remove(item.id)
removed = removed + 1
}
}
console.log(removed + " items removed")
// add missing videos
console.log("adding missing videos")
for(var videoId of videos) {
if (!items.find(item => item.videoId == videoId)) {
console.log("inserting " + item.videoId)
YouTube.PlaylistItems.insert({
snippet: {
playlistId: getPlaylistId(),
resourceId: {
kind: "youtube#video",
videoId: videoId
}
}
}, ["snippet"])
added = added + 1
} else {
console.log("skipping insert for " + item.videoId)
}
}
console.log(added + " items added")
// reset index
console.log("retrieving videos from youtube playlist")
items = getVideosFromPlaylist()
console.log(items.length + " videos retrieved from youtube")
console.log("rearanging items")
for(var item of items) {
var position = videos.indexOf(item.videoId)
if (item.position != position) {
console.log('reset index of ' + item.videoId + ' to ' + position)
YouTube.PlaylistItems.update({
id: item.id,
snippet: {
playlistId: getPlaylistId(),
resourceId: {
kind: "youtube#video",
videoId: item.videoId,
position: position
}
}
}, ["snippet"])
rearanged = rearanged + 1
} else {
console.log("skipping reorder for " + item.videoId)
}
}
console.log(rearanged + " items rearanged")
return {items, removed, added, rearanged}
}
/*
Retrive YouTube playlist items
Nothing special here, extracted only for readability
The code little bit longer than needed only because of paginated response
*/
function getVideosFromPlaylist() {
var items = []
var nextPageToken = ''
while (nextPageToken != null) {
var response = YouTube.PlaylistItems.list(["snippet"], {
playlistId: getPlaylistId(),
maxResults: 50,
pageToken: nextPageToken
})
for(var item of response.items) {
items.push({
id: item.id,
position: item.snippet.position,
videoId: item.snippet.resourceId.videoId
})
}
nextPageToken = response.nextPageToken
}
//console.log(items)
//console.log(items.length)
return items
}
/*
Retrieve YouTube links from spreadsheet
Things to fix/consider:
- getDataRange instead of getRange - so data retrieving will be more dynamic - aka even if I will move links to sibling column it should still work
- in sample I did not bother at all but it should use regular expression matching to catch links
*/
function getVideosFromSheet() {
return SpreadsheetApp.getActive().getSheetByName("Sheet1").getRange(1,1,1000).getValues().map(x => x.shift()).filter(x => !!x).map(x => x.replace('https://www.youtube.com/watch?v=', ''))
}
/*
Nevermind
*/
function getPlaylistId() {
return "PL2jJW0z9auIfNcigq0-yVYVLiD--febPX"
}
Notes:
- for this to work app script should be attached to GCP project, otherwise Google wont authorize it
- nothing special in code, just saving it for future
- api reference is helpfull to understand which params are available
- samples have some basic examples as well