Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Youtube + Selenium ChromeDriver (Python) - How to know when a video ends?

[Edit: solved, see mid-way in text of question]

Quick question on understanding the contents of a Youtube page with a video playing in it:

In summary

I use Selenium to play videos on Youtube, as part of a browser-based GUI.

I need to know when the video has finished playing, for the GUI to do something else (e.g. feed local HTML into the browser).

Code snippet and question

import os, time
from selenium import webdriver

# [...]
chromedriver = 'path_to_chromedriver_binary'  # substitute as appropriate
driver = webdriver.Chrome(chromedriver)
youtube_link = 'https://www.youtube.com/watch?v=somevideo'
driver.get(youtube_link)

At this point, I could time.wait() for the length of the video.

However, I wonder if I could query the YouTube page via the Selenium driver and gauge the time remaining for the play-through in a while loop (I am not familiar with how to extract this info from a youtube page)

Thanks!

[Edits with solution]

Selenium Solution

Thanks to Stanjer, and to this answer and this other answer, you can get the movie_player status through this method:

player_status = driver.execute_script("return document.getElementById('movie_player').getPlayerState()")

(don't forget to add "return" at the beginning of the script)

Selenium Alternative Solution

Less elegant but worth pointing out: driver.text returns a string representing the video timer in this string format '1:00 / 2:00'. Therefore you can check if the video has played through by something along these lines:

video_is_playing = True
while video_is_playing:
    time.sleep(1)
    video_is_playing = not(driver.text[:4] == driver.text[-4:])

[edit] As per Jose's comment, this info can also be accessed by:

driver.find_element_by_class_name("ytp-time-current").text

Complication and next question

I need to open up the video in maximised format, and with autoplay.

This means I call the following url:

youtube.com/v/<video_code>?rel=0&autoplay=1

However this returns a very short html which only contains an embed code, as per example here:

<HTML><HEAD></HEAD>
    <BODY leftMargin=0 scroll=no topMargin=0>
        <EMBED height="100%" 
        type=application/x-shockwave-flash 
        width="100%" 
        src=https://www.youtube.com/v/Fsc-oT9PsSQ?rel=0&amp;autoplay=1
        fullscreen="yes">
    </BODY>
</HTML> 

So I have no movie_player element here.

Approach 1 - can I extract the timer from the application/x-shockwave-flash?

Approach 2 - If I launch the youtube video in a classic Youtube page, how can I tell the movie_player to maximise itself?

(note: this answer and this answer probably contain info to solve approach 2, will post if I get this to work with Selenium)

like image 521
Pythonic Avatar asked Apr 17 '15 17:04

Pythonic


3 Answers

You can execute javascript API in context of youtube video page:

youtubePlayer = document.getElementById("movie_player");
youtubePlayer.getPlayerState();

So according to https://developers.google.com/youtube/js_api_reference?csw=1

state == 0 is when a video has ended

You can add an executor in a loop checking the state every N seconds.

You can also use the 'onStateChange' function of the Youtube iFrame API to print whenever the state changes.

function onPlayerStateChange(event) {
      console.log(player.getPlayerState());     // 1 = Playing || 2 = Paused || 3 = <<- O ->> || 0 = Finished.
  }
like image 114
Stan E Avatar answered Nov 23 '22 08:11

Stan E


You can get the length of video and current playing time as text and then convert them into seconds. Also, as a loop you can wait until the current time reaches the length of the video.

length_str = driver.find_element_by_class_name("ytp-time-duration").text
current_time_str = driver.find_element_by_class_name("ytp-time-current").text

import re
length = re.findall(r'\d+', length_str) # convert ['2:24'] to ['2', '24']
current_time = re.findall(r'\d+', current_time_str)

length_sec = 60 * int(length[0]) + int(length[1])
current_time_sec = (60 * int(current_time[0]) + int(current_time[1]))
remaining_time = length_sec - current_time_sec
like image 29
Jose Avatar answered Nov 23 '22 08:11

Jose


driver.find_element_by_class_name("ytp-time-current").text

it only works while the time and title are shown on the screen. Once a couple of seconds past, the titles disappears and the returned value is "".

like image 20
SomeOneMore Avatar answered Nov 23 '22 09:11

SomeOneMore