Goal: Play this video (Bick Buck Bunny) automatically:
https://www.youtube.com/watch?v=aqz-KE-bpKQ
Usage
./play-youtube-video-headless.py
Links
https://www.seleniumhq.org/
https://developers.google.com/youtube/iframe_api_reference#Playback_status
https://stackoverflow.com/questions/46753393/how-to-make-firefox-headless-programatically-in-selenium-with-python
https://stackoverflow.com/questions/29706101/youtube-selenium-python-how-to-know-when-video-ends
https://github.com/wichmannpas/youtubecontrol
https://stackoverflow.com/questions/51764056/how-to-click-on-the-play-button-of-a-youtube-video-embedded-within-smtebook-thro/51764669
https://en.wikipedia.org/wiki/Xvfb
Prerequisites
- A web browser (to parse the client-side JavaScript). For Linux, this means either Firefox or Chrome.
- A webdriver, which is either
geckodriver(for Firefox) orchromedriver(for Chrome) - Selenium (Python bindings), https://www.seleniumhq.org/, a framework to control a web browser programatically.
- Xvfb, the X virtual frambuffer (https://en.wikipedia.org/wiki/Xvfb), to be able to run a browser in "headless" mode, that is, no graphical output.
- Python bindings for Xvfb
- jQuery (single file in current directory)
- YouTube Jasvascript API (single file in current directory)
NOTE: play-youtube-video-headless.py has only been tested with Firefox, not with Chrome.
Solution 1
Use Selenium/Python to access the remote (Youtube) webpage directly.
Wait until the Youtube play button is clickable:
WebDriverWait(browser, 60).until(EC.element_to_be_clickable((By.XPATH, "//button[@class='ytp-play-button ytp-button']"))).click()
Problem/disadvantages:
The browser loads the entire YouTube webpage, not only the video, which takes a long time (additional images, ads, etc).
This makes the script hard to control, unless using very long timeouts.
Solution 2
Create a local web page with an embedded Youtube video, use Selenium/Python to access the local webpage.
The local web page uses JavaScript to communicate with the YouTube Embedded API.
Use Selenium/Python to access the local web page.
Solution 2: The web page
Complete reading:
https://tutorialzine.com/2015/08/how-to-control-youtubes-video-player-with-javascript
Resume:
The index.html is a minimalistic local web page which uses the JavaScript in script.js to communicate with the Youtube Javascript API.
The Youtube video to be played is declared in script.js:
var player,
time_update_interval = 0;
function onYouTubeIframeAPIReady() {
player = new YT.Player('video-placeholder', {
width: 600,
height: 400,
videoId: 'aqz-KE-bpKQ', // <--- THIS IS THE VIDEO ID, THAT IS, BICK BUCK BUNNY
playerVars: {
color: 'white'
},
events: {
onReady: initialize
}
});
}
The Javascript in script.js updates the following HTML tags in index.html:
current-time-secondsdurationplayer-state
Solution 2: The Python script
The Python script is very basic:
- Start the web browser in headless mode (no output from the command line)
- Load the local web page
- Wait for the embedded Youtube video to be loaded
- Parse the following values from
index.html:current-time-secondsdurationplayer-state
- When
player-stateindicates that the video has finished, quit the browser, and exit the Python script.
Note that the Python script does not start nor stop the Youtube video.
All video Play/Pause stuff is handled by the Javascript in script.js.
(It is possible to control Play/Pause from Python, if desired, though.)
Advantages:
The web page is local, simple, and contains no other external resources but the video iframe, and thus loads must faster than Solution 1.
The Python/Selenium script becomes a very simple watchguard for the video player state.
TODO
Add options to the Python script to control
- The video URL to be played
The number of seconds to play (quit video after X seconds even if its duration is Y seconds)
./play-youtube-video-headless.py [url] [play-n-seconds]