YouTube API: Playlists

  1. Authentication and initialization
  2. Get your own playlists
  3. Get playlist items
  4. Create playlist
  5. Delete playlist
  6. Add playlist item
  7. Delete playlist item
  8. Controls
  9. The HTML

Authentication and initialization

This is essentially the same as in part 1.

/* To get your own keys, create a project at https://console.developers.google.com
and navigate to APIs & auth > Credentials */
var OAUTH2_CLIENT_ID = "_YOUR_CLIENT_ID_",
		OAUTH2_SCOPES = ["https://www.googleapis.com/auth/youtube"];

function googleApiClientReady() {
	"use strict";

	gapi.client.load("youtube", "v3");

	gapi.auth.init(function() {
		window.setTimeout(checkAuth, 1);
	});
}

function checkAuth(immediate) {
	"use strict";

	gapi.auth.authorize({
		client_id: OAUTH2_CLIENT_ID,
		scope: OAUTH2_SCOPES,
		immediate: (immediate !== false ? true : false),
	}, handleAuthResult);
}

function handleAuthResult(authResult) {
	"use strict";

	var el;

	if (authResult && !authResult.error) {
		document.getElementById("loginButton").setAttribute("disabled", "disabled");

		document.getElementById("playlistResults").addEventListener("click", playlistControls, false);
		document.getElementById("editPlaylist").addEventListener("click", playlistControls, false);
		getPlaylists();

		el = document.getElementById("insertPlaylist");
		el.addEventListener("submit", insertPlaylist, false);
		el.querySelector("input[type=submit]").removeAttribute("disabled");
	}
	else {
		document.getElementById("loginButton").onclick = function() {
			checkAuth(false);
		};
	}
}

Get your own playlists

function getPlaylists(params) {
	"use strict";

	var container = document.getElementById("playlistResults"),
			items,
			item,
			i,
			obj;

	params = params || {
		part: "snippet",
		mine: true
	};

	container.innerHTML = "";

	gapi.client.youtube.playlists.list(params).execute(function(response) {
		if (response.error) {
			alert("Error: " + response.error.message);
		}
		else if (response.pageInfo.totalResults === 0) {
			container.appendChild(document.createTextNode("No results."));
		}
		else if (response.items) {
			container.appendChild(document.importNode(document.getElementById("items").content, true));
			items = container.querySelector(".items");

			if (response.nextPageToken) {
				params.pageToken = response.nextPageToken;
				container.querySelector(".more").removeAttribute("disabled");
				container.querySelector(".more").addEventListener("click", function click(e) {
					e.target.removeEventListener("click", click, false);
					getPlaylists(params);
				}, false);
			}

			for (i = 0; i < response.items.length; i += 1) {
				obj = response.items[i];
				item = document.importNode(document.getElementById("playlist").content, true);
				item.querySelector(".item").setAttribute("data-id", obj.id);
				item.querySelector("img").setAttribute("src", obj.snippet.thumbnails["default"].url);
				item.querySelector(".title").appendChild(document.createTextNode(obj.snippet.title));
				items.appendChild(item);
			}
		}
	});
}

Get playlist items

function getPlaylistItems(params) {
	"use strict";

	var container = document.getElementById("editPlaylist"),
			items,
			item,
			i,
			obj;

	container.innerHTML = "";

	gapi.client.youtube.playlistItems.list(params).execute(function(response) {
		if (response.error) {
			alert("Error: " + response.error.message);

			return;
		}

		container.appendChild(document.importNode(document.getElementById("addToPlaylist").content, true));
		container.appendChild(document.importNode(document.getElementById("items").content, true));
		items = container.querySelector(".items");
		items.setAttribute("data-id", params.playlistId);

		if (response.nextPageToken) {
			params.pageToken = response.nextPageToken;
			container.querySelector(".more").removeAttribute("disabled");
			container.querySelector(".more").addEventListener("click", function click(e) {
				e.target.removeEventListener("click", click, false);
				getPlaylistItems(params);
			}, false);
		}

		for (i = 0; i < response.items.length; i += 1) {
			obj = response.items[i];
			item = document.importNode(document.getElementById("playlistItem").content, true);
			item.querySelector(".item").setAttribute("data-id", obj.id);
			item.querySelector("img").setAttribute("src", obj.snippet.thumbnails["default"].url);
			item.querySelector(".title").appendChild(document.createTextNode(obj.snippet.title));
			items.appendChild(item);
		}
	});
}

Create playlist

function insertPlaylist(e) {
	"use strict";

	e.preventDefault();

	gapi.client.youtube.playlists.insert({
		part: "snippet, status",
		resource: {
			snippet: {
				title: e.target[0].value,
				description: e.target[1].value
			},
			status: {
				privacyStatus: e.target[2].checked ? "private" : "public"
			}
		}
	}).execute(function(response) {
		if (response.error) {
			alert("Error: " + response.error.message);
		}
		else {
			e.target.reset();
			getPlaylists();
		}
	});
}

Delete playlist

function deletePlaylist(el) {
	"use strict";

	if (!confirm("Permanently delete " + el.querySelector(".title").textContent)) {
		return;
	}

	// This causes an error "element is null" even though the playlist is deleted
	gapi.client.youtube.playlists.delete({
		id: el.getAttribute("data-id")
	}).execute(function(response) {
		if (response.error) {
			alert("Error: " + response.error.message);
		}
		else {
			el.parentNode.removeChild(el);
		}
	});
}

Add playlist item

function insertPlaylistItem() {
	"use strict";

	var videoId = prompt("Enter video ID"),
			playlistId = document.querySelector("#editPlaylist .items").getAttribute("data-id");

	if (!videoId) {
		return;
	}

	gapi.client.youtube.playlistItems.insert({
		part: "snippet",
		resource: {
			snippet: {
				playlistId: playlistId,
				resourceId: {
					videoId: videoId,
					kind: "youtube#video"
				}
			}
		}
	}).execute(function(response) {
		if (response.error) {
			alert("Error: " + response.error.message);
		}
		else {
			getPlaylistItems({
				playlistId: playlistId,
				part: "snippet",
				maxResults: 50
			});
		}
	});
}

Delete playlist item

function deletePlaylistItem(el) {
	"use strict";

	if (!confirm("Permanently remove " + el.querySelector(".title").textContent + " from playlist?")) {
		return;
	}

	// This too causes an error "element is null" even though the item is deleted
	gapi.client.youtube.playlistItems.delete({
		id: el.getAttribute("data-id")
	}).execute(function(response) {
		if (response.error) {
			alert("Error: " + response.error.message);
		}
		else {
			el.parentNode.removeChild(el);
		}
	});
}

Controls

function playlistControls(e) {
	"use strict";

	var el;

	if (e.target.nodeName !== "BUTTON") {
		return;
	}

	el = e.target;

	while (el && el.id !== "editPlaylist" && !el.getAttribute("data-id")) {
		el = el.parentNode;
	}

	switch (e.target.className) {
		case "viewItems":
			getPlaylistItems({
				playlistId: el.getAttribute("data-id"),
				part: "snippet",
				maxResults: 50
			});
			break;

		case "deletePlaylist":
			deletePlaylist(el);
			break;

		case "insertItem":
			insertPlaylistItem();
			break;

		case "deleteItem":
			deletePlaylistItem(el);
			break;
	}
}

The HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>YouTube API Demo</title>
<style>
	hidden {display:none}
	hr {margin:1em 0; border-width:1px 0px 0px 0px; border-style:dashed; border-color:black}
	iframe {display:block; background-color:#ddd; border:none}
	img {max-width:150px}
	h1 {font-size:100%}
</style>
<script src="youtube-playlists.js"></script>
<script src="https://apis.google.com/js/client.js?onload=googleApiClientReady"></script>
</head>
<body>

<button id="loginButton" type="button">Sign in</button>

<hr>

<h1>New playlist</h1>
<form id="insertPlaylist" action="" method="post" accept-charset="utf-8">
	<input type="text" name="title" placeholder="Title" aria-label="Title">
	<input type="text" name="description" placeholder="Description" aria-label="Description">
	<label><input type="checkbox" name="private" checked> Private</label>
	<input type="submit" value="Create playlist" disabled>
</form>

<hr>

<h1>My playlists</h1>
<div id="playlistResults"></div>

<hr>

<h1>Edit playlist</h1>
<div id="editPlaylist"></div>

<template id="items" hidden>
	<ul class="items"></ul>
	<button class="more" type="button" disabled>More results</button>
</template>

<template id="playlist" hidden>
	<li class="item" data-kind="playlist">
		<img>
		<span class="title"></span>
		<button class="viewItems" type="button">Edit items</button>
		<button class="deletePlaylist" type="button">Delete</button>
	</li>
</template>

<template id="playlistItem" hidden>
	<li class="item" data-kind="playlistitem">
		<img>
		<span class="title"></span>
		<button class="deleteItem" type="button">Delete</button>
	</li>
</template>

<template id="addToPlaylist" hidden>
	<button class="insertItem" type="button">Add to playlist...</button>
</template>

</body>
</html>
Using
  • YouTube Data API v3
  • Javascript client library

Comments