Film Maker
Programming Snapshot – YouTube Metadata
Instead of manually editing the metadata of YouTube movies, video craftsman Mike Schilli dips into YouTube’s API spell book and lets a script automatically do the work.
If one day someone should invite me onto a TV talk show, in which I could brag about my best productivity tricks, I would say this: The most effective way forward is to be able to make quick changes at any time, which you can revert later on – just as quickly and almost without loss – if they turn out to be duds.
Software development with Git is a good example of this: Git makes it possible to boldly add new functions to programs in huge leaps or to rearrange the code on a large scale. If the whole thing turns out to be a crazy idea after a while, the developer simply reverts everything in just a second without anyone noticing what pipe dreams they were chasing in the meantime.
That's why I religiously put everything I produce under version control. My blog posts, my articles, my programs: The version control system lets me revert to yesterday's status at any time should the need arise, and for any reason.
But up to now, I have not been able to get the procedure to work for my YouTube videos. For example, if I change the title or even just one tag of one of my internationally-respected, quality movies (Figure 1), I can't simply tell YouTube later on: Today, all I've done is produce nonsense; please undo everything and make it look like yesterday.
Metadata with Version Control
Therefore, I want to entrust the metadata of my YouTube existence to a local YAML file (Listing 1) and version it with Git. A script then regularly checks the entries in the file, reads the ID of each movie from the YAML data, and checks on YouTube whether everything is set up according to the file (i.e., whether the title in the file matches the video page's metadata). In the event of differences, the script adapts the online YouTube data to the YAML data. Listing 1 [1] defines a long list of videos with their IDs and titles. It could easily be extended with tags, a thumbnail image, a release date, or other metadata.
Listing 1
videos.yaml
1 videos: 2 - id: _3i5yVoTvCs 3 title: "How to flip German pancakes" 4 - id: brPfE66FC24 5 title: "Tivo Stream Cooling Fan Replacement" 6 - id: 2qxXhW7RxsY 7 title: "Rio Portable Beach Shelter Assembly Instructions"
At the User's Service
But before the script is allowed to access or change the user data, Google has to grant the new application access to the account holder's data, because Joe Public is not allowed to mess around with my videos. Google obtains the user's consent in Listing 2 using the Google API [2] to guide the user's browser to a Google page on which the user logs in and then confirms that the application actually should have access (Figure 2).
Listing 2
youtube-sync
01 #!/usr/bin/python 02 import httplib2 03 import os 04 import sys 05 import yaml 06 07 from apiclient.discovery import build 08 from apiclient.errors import HttpError 09 from oauth2client.client import \ 10 flow_from_clientsecrets 11 from oauth2client.file import Storage 12 from oauth2client.tools import \ 13 argparser, run_flow 14 15 CLIENT_SECRETS_FILE = "client-secrets.json" 16 YOUTUBE_READ_WRITE_SCOPE = \ 17 "https://www.googleapis.com/auth/youtube" 18 YOUTUBE_API_SERVICE_NAME = "youtube" 19 YOUTUBE_API_VERSION = "v3" 20 21 def get_authenticated_service(args): 22 flow = flow_from_clientsecrets( 23 CLIENT_SECRETS_FILE, 24 scope=YOUTUBE_READ_WRITE_SCOPE) 25 26 storage = Storage("oauth2.json"); 27 credentials = storage.get() 28 29 if credentials is None or \ 30 credentials.invalid: 31 credentials = \ 32 run_flow(flow, storage, args) 33 34 return build(YOUTUBE_API_SERVICE_NAME, 35 YOUTUBE_API_VERSION, 36 http=credentials.authorize( 37 httplib2.Http())) 38 39 def video_update(youtube, id, title): 40 response = youtube.videos().list( 41 id=id, part='snippet').execute() 42 43 if not response["items"]: 44 print("Video '%s' was not found." % id) 45 sys.exit(1) 46 47 snippet = response["items"][0]["snippet"] 48 49 if snippet['title'] == title: 50 print("%s: Unchanged" % id) 51 return 52 53 snippet['title'] = title 54 55 try: 56 youtube.videos().update( 57 part='snippet', 58 body=dict( 59 snippet=snippet, id=id)).execute() 60 except HttpError, e: 61 print("HTTP error %d: %s" % \ 62 (e.resp.status, e.content)) 63 else: 64 print("Updated OK") 65 66 if __name__ == "__main__": 67 args = argparser.parse_args() 68 youtube = get_authenticated_service(args) 69 70 stream = open("videos.yaml", "r") 71 all = yaml.load(stream) 72 for video in all['videos']: 73 video_update(youtube, video['id'], 74 video['title'])
To do this, API jockeys need to create a new project on the Google Cloud Platform Console [2] (Figure 3). Then navigate to Create credentials (Figure 4) and select OAuth client ID [3] (not API key, that's for project management only). Since it is a desktop program and not a web application, you have to select Other in the selection menu for the application type. The strings then produced by Google for the Client ID and Client Secret (Figure 5) need to be entered into a JSON file as shown in Listing 3.
Listing 3
client-secrets.json
1 { 2 "installed": { 3 "client_id": "XXX", 4 "client_secret": "YYY", 5 "redirect_uris": ["http://localhost", "urn:ietf:wg:oauth:2.0:oob"], 6 "auth_uri": "https://accounts.google.com/o/oauth2/auth", 7 "token_uri": "https://accounts.google.com/o/oauth2/token" 8 } 9 }
After the script's first run, when the user has successfully granted permission in the browser, the browser branches to a page with a The authentication flow has completed message. The script drops an OAuth 2 access token into the oauth2.json
file, thus granting access to the user's data for future calls without the user having to agree again.
This works until the access token expires. The corresponding expiration date is also noted in the JSON file. The file also contains a refresh token that the script can use to request a new token after the current access token expires. This practically works infinitely – unless the user goes to the Google Console (Figure 5) and revokes access for the client, in which case Google pulls the plug.
The get_authenticated_service()
function in line 21 of Listing 2 defines YOUTUBE_READ_WRITE_SCOPE
as the access scope, thus requesting read and write access. The interaction with the browser and the underlying OAuth 2 token dance is nicely abstracted by the Google API SDK; the script only calls the flow_from_clientsecrets()
and run_flow()
functions from the two oauth2client.client
and oauth2client.tools
packages. This works equally well in the browser on both Linux and Mac OS.
Line 70 reads the YAML file with the locally stored video metadata; line 71 iterates over all movies located there. For each of them, it calls the video_update()
function defined in line 39, which first retrieves the online movie's metadata by its ID using youtube.videos().list()
. Data retrieved is limited to the snippet
area, which YouTube uses to designate the title, tags, description, and a few other fields.
Line 49 retrieves the movie title from this metadata and compares it with the local version. If the two titles do not match, line 56 triggers the update()
method in a try
block. The function expects the originally retrieved metadata along with the new, modified title as parameters. If an error occurs during transfer, line 61 prints the HTTP error message; otherwise line 64 reports Updated OK
– and the metadata on YouTube now exactly matches the metadata stored locally in the version control system.
Installation and Outlook
The SDK needed to run the script is available as a Python package from the standard repository and can be installed via pip
:
pip install --user --upgrade google-api-python-client
After the script's first run – with the browser window popping up at the beginning to obtain the user's consent – it produces the following output with the YAML file in Listing 1:
<$> ./youtube-sync _3i5yVoTvCs: Unchanged brPfE66FC24: Unchanged 2qxXhW7RxsY: Unchanged
Since all title strings in the retrieved YouTube metadata match the YAML data, the script does not make any changes. However, if a title text changes in the YAML file, the script fires it off to YouTube, which refreshes the movie's metadata. The script confirms such an action with Updated OK
.
The script can be extended as needed, so that it can also upload videos from the hard disk to YouTube if required and automatically synchronize the local status of your movie collection with the publicly accessible movies on YouTube in each run. If you version your local collection and its metadata with a version control system, you can jump back and forth in time, making changes, and reverting if an idea turns out to be less than brilliant.
Infos
- Listings for this article: ftp://ftp.linux-magazine.com/pub/listings/linux-magazine.com/209/
- Google Cloud Platform Console: https://console.cloud.google.com/apis
- "OAuth 2.0 for Mobile & Desktop Apps": https://developers.google.com/identity/protocols/OAuth2InstalledApp @IE
Buy this article as PDF
(incl. VAT)
Buy Linux Magazine
Subscribe to our Linux Newsletters
Find Linux and Open Source Jobs
Subscribe to our ADMIN Newsletters
Support Our Work
Linux Magazine content is made possible with support from readers like you. Please consider contributing when you’ve found an article to be beneficial.
News
-
Red Hat Enterprise Linux 9.5 Released
Notify your friends, loved ones, and colleagues that the latest version of RHEL is available with plenty of enhancements.
-
Linux Sees Massive Performance Increase from a Single Line of Code
With one line of code, Intel was able to increase the performance of the Linux kernel by 4,000 percent.
-
Fedora KDE Approved as an Official Spin
If you prefer the Plasma desktop environment and the Fedora distribution, you're in luck because there's now an official spin that is listed on the same level as the Fedora Workstation edition.
-
New Steam Client Ups the Ante for Linux
The latest release from Steam has some pretty cool tricks up its sleeve.
-
Gnome OS Transitioning Toward a General-Purpose Distro
If you're looking for the perfectly vanilla take on the Gnome desktop, Gnome OS might be for you.
-
Fedora 41 Released with New Features
If you're a Fedora fan or just looking for a Linux distribution to help you migrate from Windows, Fedora 41 might be just the ticket.
-
AlmaLinux OS Kitten 10 Gives Power Users a Sneak Preview
If you're looking to kick the tires of AlmaLinux's upstream version, the developers have a purrfect solution.
-
Gnome 47.1 Released with a Few Fixes
The latest release of the Gnome desktop is all about fixing a few nagging issues and not about bringing new features into the mix.
-
System76 Unveils an Ampere-Powered Thelio Desktop
If you're looking for a new desktop system for developing autonomous driving and software-defined vehicle solutions. System76 has you covered.
-
VirtualBox 7.1.4 Includes Initial Support for Linux kernel 6.12
The latest version of VirtualBox has arrived and it not only adds initial support for kernel 6.12 but another feature that will make using the virtual machine tool much easier.