timkoehne / Youtube-Upload-Selenium

Python Interface for uploading Youtube Videos using Selenium Webdriver
MIT License
2 stars 0 forks source link

Trying to run it on headless ubuntu #1

Open DENYHAX opened 8 months ago

DENYHAX commented 8 months ago

Hello,

I'm trying to run it on headless ubuntu. I copied my firefox profile from windows and now I have my profile.default folder on my ubuntu but when I try to run the script I get this error:

python3 example_single_video.py
The geckodriver version (0.33.0) detected in PATH at /snap/bin/geckodriver might not be compatible with the detected firefox version (121.0.1); currently, geckodriver 0.34.0 is recommended for firefox 121.*, so it is advised to delete the driver in PATH and retry
Traceback (most recent call last):
  File "/home/denyhax/code/Youtube-Upload-Selenium/example_single_video.py", line 16, in <module>
    upload_single_video(vid, firefox_profile_path)
  File "/home/denyhax/code/Youtube-Upload-Selenium/youtube_upload.py", line 31, in upload_single_video
    driver = _create_Webdriver(firefox_profile_path)
  File "/home/denyhax/code/Youtube-Upload-Selenium/youtube_upload.py", line 89, in _create_Webdriver
    driver = webdriver.Firefox(options=options)
  File "/home/denyhax/.local/lib/python3.10/site-packages/selenium/webdriver/firefox/webdriver.py", line 69, in __init__
    super().__init__(command_executor=executor, options=options)
  File "/home/denyhax/.local/lib/python3.10/site-packages/selenium/webdriver/remote/webdriver.py", line 209, in __init__
    self.start_session(capabilities)
  File "/home/denyhax/.local/lib/python3.10/site-packages/selenium/webdriver/remote/webdriver.py", line 293, in start_session
    response = self.execute(Command.NEW_SESSION, caps)["value"]
  File "/home/denyhax/.local/lib/python3.10/site-packages/selenium/webdriver/remote/webdriver.py", line 348, in execute
    self.error_handler.check_response(response)
  File "/home/denyhax/.local/lib/python3.10/site-packages/selenium/webdriver/remote/errorhandler.py", line 229, in check_response
    raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.InvalidArgumentException: Message: binary is not a Firefox executable

Any idea how to fix this?

timkoehne commented 8 months ago

Hi, I was able to replicate your issue. Apparently selenium is not able to access firefox's geckodriver and profiles when firefox is installed through snap which is the default for ubuntu. Uninstalling firefox via snap and installing the .deb from mozilla seems to fix the issue. This article explains how to do it.

I also just pushed an update to allow selenium to run headlessly.

Hope that helps!

DENYHAX commented 8 months ago

This seems to fix the geckodriver and profile issue but now when I try to run it I get this: selenium.common.exceptions.ElementClickInterceptedException: Message: Element <button id="button" class="style-scope yt-icon-button"> is not clickable at point (1211,28) because another element <tp-yt-iron-overlay-backdrop class="opened"> obscures it Thanks for your help I really appreciate it.

timkoehne commented 8 months ago

You're trying to run this without a display conntected, right? I am not sure how selenium and firefox select a resolution in this case. I think the css on youtube arranges the elements in a wierd way and they cover eachother which makes selenium unable to click on them. I just pushed an update to force selenium to run in 1920x1080, since I know that should work. Though I am not sure if this works without a display connected and i've been testing on wsl2 which utilizes my displays so I couldn't really test it yet.

DENYHAX commented 8 months ago

Yes I'm trying to run it without display. I tried your last update but I get the same error.

timkoehne commented 8 months ago

Ok, I'll set up a device with the same configuration to replicate this and continue testing. I'll get back to you.

timkoehne commented 8 months ago

It looks like there is a google popup that blocks the upload because google notices that the firefox-profile is on a different device than before. They allow you to stay logged in but as soon as you try to upload a video you need to verify your login which would then depend on your account security and 2-factor settings. Also the popup behaviour is very inconsistant, I was able recreate it once, but not again for further testing, even after trying multiple accounts on multiple devices.

That makes working around google's login-verification very cumbersome and unfortunately too time-consuming for me right now.

This is what I've been working on so far. At the bottom of the file you enter some dummy video_file_path and your firefox_profile_path aswell as your phone number including country code. Then it basically starts a video upload to try to force the popup to show up. The function verify_phone(...) should then start the verification process, input your phone number and tell google to send you a verification code. You manually enter the verification code over the commandline and it should finish the verification. After you did this once, the popup should not appear again.

Since I was only able to force popup to show up once, I wasn't able to test most of the important parts of this. There is no test to see if the popup is even there, if it's not the program will just crash after about 30 seconds. And this also assumes that phone-number verification is your default (maybe the only?) verification method.

from time import sleep
from selenium import webdriver
from selenium.webdriver.firefox.webdriver import WebDriver
from selenium.webdriver.common.by import By

def _create_Webdriver(firefox_profile_path: str) -> WebDriver:
    profile = webdriver.FirefoxProfile(firefox_profile_path)
    profile.set_preference("dom.webdriver.enabled", False)
    profile.set_preference("useAutomationExtension", False)
    profile.update_preferences()

    options = webdriver.FirefoxOptions()
    options.profile = profile
    options.add_argument("--headless")

    driver = webdriver.Firefox(options=options)
    driver.implicitly_wait(30)
    return driver

def verify_phone(driver: WebDriver, phonenumber: str):
    driver.find_element("continue-button").click()
    driver.switch_to.window(driver.window_handles[1])
    sleep(5)

    phone_input = driver.find_element(By.ID, "phoneNumberId")
    phone_input.clear()
    phone_input.send_keys(phonenumber)
    driver.find_element(By.CSS_SELECTOR, "button").click()

    # user manually enters verification code
    verification_code = input("Enter verification code: ")
    print(verification_code)

    driver.find_element(By.CSS_SELECTOR, "input").send_keys(verification_code)
    driver.find_element(By.CSS_SELECTOR, "button").click()

    driver.switch_to.window(driver.window_handles[0])

def setup_video_upload(video_file_path: str, firefox_profile_path: str) -> WebDriver:
    video_title = "phone verificaton test"
    video_description = "phone verificaton test"
    driver = _create_Webdriver(firefox_profile_path)

    driver.get("https://www.youtube.com/upload")
    sleep(2)

    # upload video file
    file_input = driver.find_element(By.CSS_SELECTOR, "input[type='file']")
    file_input.send_keys(video_file_path)
    print("selecting video file")
    sleep(2)

    # input title
    title_textarea = driver.find_element(by=By.ID, value="title-textarea")
    title_textarea = title_textarea.find_element(by=By.ID, value="textbox")
    title_textarea.clear()
    print("entering title")
    sleep(1)
    title_textarea.send_keys(video_title)

    # input description
    description_textarea = driver.find_element(by=By.ID, value="description-textarea")
    description_textarea = description_textarea.find_element(by=By.ID, value="textbox")
    description_textarea.clear()
    print("entering description")
    sleep(1)
    description_textarea.send_keys(video_description)
    sleep(5)

    return driver

driver = setup_video_upload("video_file_path", "firefox_profile_path")
sleep(5)
verify_phone(driver, "+49 0123456789")