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-seconds
duration
player-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-seconds
duration
player-state
- When
player-state
indicates 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]