Created
February 19, 2020 21:27
-
-
Save iKlotho/00a3a8b16b1ba7bd72b7fd54a0d379cc to your computer and use it in GitHub Desktop.
Youtube Python Upload
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
Upload a video to youtube | |
""" | |
import os | |
import time | |
import cookielib | |
import json | |
import requests | |
import mechanize | |
from BeautifulSoup import BeautifulSoup | |
class YoutubeUpload: | |
def __init__( | |
self, | |
email, | |
passwd, | |
file="", | |
video_name="default", | |
description="", | |
privacy="public", | |
tags="", | |
): | |
self.rupio_formdata = { | |
"protocolVersion": "0.8", | |
"createSessionRequest": { | |
"fields": [ | |
{ | |
"external": { | |
"name": "file", | |
"filename": "videoname", | |
"put": {}, | |
"size": 0, | |
} | |
}, | |
{ | |
"inlined": { | |
"name": "return_address", | |
"content": "www.youtube.com", | |
"contentType": "text/plain", | |
} | |
}, | |
{ | |
"inlined": { | |
"name": "user_token", | |
"content": "aBSi_UqNbqLNey9asEQZrl3awgh8MTQ0MzIxMjM3MEAxNDQyNjA3NTcw", | |
"contentType": "text/plain", | |
} | |
}, | |
{ | |
"inlined": { | |
"name": "authuser", | |
"content": "0", | |
"contentType": "text/plain", | |
} | |
}, | |
{ | |
"inlined": { | |
"name": "uploader_type", | |
"content": "Web_XHR", | |
"contentType": "text/plain", | |
} | |
}, | |
{ | |
"inlined": { | |
"name": "frontend_id", | |
"content": "web_upload:b7ef7a96-a27f-48dd-9ff1-8f311b0d11ac:0", | |
"contentType": "text/plain", | |
} | |
}, | |
{ | |
"inlined": { | |
"name": "use_drishti_thumbnailer", | |
"content": "1", | |
"contentType": "text/plain", | |
} | |
}, | |
{ | |
"inlined": { | |
"name": "use_drishti_thumbnailer_for_high_priority", | |
"content": "1", | |
"contentType": "text/plain", | |
} | |
}, | |
{ | |
"inlined": { | |
"name": "use_venom_processing", | |
"content": "true", | |
"contentType": "text/plain", | |
} | |
}, | |
{ | |
"inlined": { | |
"name": "field_privacy", | |
"content": "private", | |
"contentType": "text/plain", | |
} | |
}, | |
{ | |
"inlined": { | |
"name": "field_myvideo_title", | |
"content": "videosxlilyseditzxokay issa", | |
"contentType": "text/plain", | |
} | |
}, | |
{ | |
"inlined": { | |
"name": "field_myvideo_descr", | |
"content": "", | |
"contentType": "text/plain", | |
} | |
}, | |
{ | |
"inlined": { | |
"name": "field_myvideo_keywords", | |
"content": "", | |
"contentType": "text/plain", | |
} | |
}, | |
{ | |
"inlined": { | |
"name": "field_myvideo_categories", | |
"content": "23", | |
"contentType": "text/plain", | |
} | |
}, | |
{ | |
"inlined": { | |
"name": "allow_public_stats", | |
"content": "yes", | |
"contentType": "text/plain", | |
} | |
}, | |
{ | |
"inlined": { | |
"name": "allow_comments", | |
"content": "yes", | |
"contentType": "text/plain", | |
} | |
}, | |
{ | |
"inlined": { | |
"name": "allow_comments_detail", | |
"content": "all", | |
"contentType": "text/plain", | |
} | |
}, | |
{ | |
"inlined": { | |
"name": "allow_ratings", | |
"content": "yes", | |
"contentType": "text/plain", | |
} | |
}, | |
{ | |
"inlined": { | |
"name": "privacy_draft", | |
"content": "public", | |
"contentType": "text/plain", | |
} | |
}, | |
{ | |
"inlined": { | |
"name": "session_token", | |
"content": "QUFFLUhqbnVUZW9NckNVbWE0OHJaTVFHVzdaZkwyZW1WZ3xBQ3Jtc0tsZFBGajRVNWhxQnp0VWF1MlZfb3BRSkUzRjVnZU51S3hWWWhuYlAxTGRhMzgyZkpKekJJNXJNekdkSHVaOWt1V3RkNkx3d1pLQkc5blJSMW9TWjdKeEZTc2NxVjhrQmw5Wk1TUVpZRERreTh2djczZHBIbVRfMVZfcmpmSElXWjlndnFveWc0Z1BZbTFibXlBVEtPLUE5cTZLV0E=", | |
"contentType": "text/plain", | |
} | |
}, | |
{ | |
"inlined": { | |
"name": "experiment_ids", | |
"content": "9415398,9416475,9417481,9419979,9420289,9422596,9423555,9428398,9428632,9429954,9431012,9431681,9432939,9433221,9433839,9433870,9434046,9434289,9434949,9435354,9435521,9438309,9439451,9439580,9439877,9440054,9441194,9441513,9441929,9442387,9442393,9442426,9442746,9444189,9445634,9445860,9446054,9446062,9446142,9446364,9446877,9447232,9447774,9448302,9449034,9449074,9449243,9449256,9450059,9450402,9450544,9450641,9451164,9451343,9451345,9451494,9451783,9451814,9451827,9451873,9451929,9451937,9452119,9452146,9452448,9452833,9452850,9453098,9453167,9453553,9453682,9454366,9454383,9454394,9454653,9454793,9455031,9455068,9455072,9455655,9455983,9456026,9456133,9456249,9456443,9456445,9456516,9456628,9456631,9456640,9456760,9456930,9457141,9457146,9457169,9457492,9457494,9457591,9457595,9457598,9457623,9457968,9458027,9458029,9458054,9458240,9458265,9458386,9458668,9458670,9458881,9459035,9459067,9459073,9459075,9459187,9459429,9459444,9459605,9459762,9459768,9459793,9459798,9460103,9460349,9460431,9460434,9460599,9460727,9460830,9461013,9461125,9461208,9461327,9461498", | |
"contentType": "text/plain", | |
} | |
}, | |
] | |
}, | |
} | |
self.json_data_check = False | |
self.user = email | |
self.passwd = passwd | |
self.rupio_url = "https://upload.youtube.com/upload/rupio" | |
self.csa_url = "https://www.youtube.com/creator_suggestions_ajax" | |
self.yummyajax_url = "https://www.youtube.com/yummy_ajax" | |
self.setvideoparams_url = "https://www.youtube.com/api/tag_suggest" | |
self.list_payload = {} | |
self.video_id = None | |
self.upload_id = None | |
self.ssn_token = None | |
self.user_token = None | |
self.frontend_upload_id = None | |
self.video_name = video_name | |
self.description = description | |
self.privacy = privacy | |
self.file_name = file | |
self.tag = tags | |
self.br = mechanize.Browser() | |
self.cj = cookielib.LWPCookieJar() | |
self.br.set_cookiejar(self.cj) | |
self.br.set_handle_equiv(True) | |
self.br.set_handle_gzip(False) | |
self.br.set_handle_redirect(True) | |
self.br.set_handle_referer(True) | |
self.br.set_handle_robots(False) | |
self.br.set_handle_refresh(mechanize._http.HTTPRefreshProcessor(), max_time=1) | |
self.br.addheaders = [ | |
( | |
"User-agent", | |
"Mozilla/5.0 (Windows NT 10.0; WOW64; rv:51.0) Gecko/20100101 Firefox/51.0", | |
) | |
] | |
self.br.addheaders = [("Accept-Language", "en-US;q=0.5,en;q=0.3")] | |
# call functions | |
self.access_1() | |
time.sleep(1) | |
self.access_2() | |
time.sleep((1)) | |
self.getSessionToken() | |
self.getFrontendUploadIdBase() | |
self.getUserToken() | |
self.find_youtube_web_uploads() | |
self.setRupioData(self.file_name) | |
self.post_creator_suggestions_ajax() | |
time.sleep(0.5) | |
self.post_rupio() | |
time.sleep(0.5) | |
self.post_yummyAjax() | |
time.sleep(0.5) | |
self.doOptions() | |
time.sleep(0.5) | |
self.setVideoParamaters() | |
def access_1(self): | |
# pylint: disable=line-too-long | |
self.br.open( | |
"https://accounts.google.com/ServiceLogin?passive=true&continue=https%3A%2F%2Fwww.youtube.com%2Fsignin%3Faction_handle_signin%3Dtrue%26app%3Ddesktop%26feature%3Dsign_in_button%26hl%3Dtr%26next%3D%252F&uilel=3&hl=tr&service=youtube#identifier" | |
) | |
self.br.select_form(nr=0) | |
self.br.form.set_all_readonly(False) | |
self.br.form["Email"] = self.user | |
self.br.submit() | |
def access_2(self): | |
self.br.select_form(nr=0) | |
self.br.form.set_all_readonly(False) | |
self.br.form["Passwd"] = self.passwd | |
self.br.submit() | |
self.session = requests.Session() | |
self.session.cookies = self.cj | |
self.session.headers[ | |
"User-Agent" | |
] = "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:51.0) Gecko/20100101 Firefox/51.0" | |
self.session.headers["Accept-Language"] = "en-US;q=0.5,en;q=0.3" | |
def getSessionToken(self): | |
token_req = self.session.get("https://www.youtube.com/upload") | |
self.soup = BeautifulSoup(token_req.content) | |
script = self.soup.findAll("script") | |
# TODO find with regex | |
script_id = self.find_word_fr_script(script, "session_token") | |
loc = script[script_id].text.find("var session_token") | |
if loc: | |
self.ssn_token = script[script_id].text[loc + 21 : loc + 313] | |
def find_word_fr_script(self, scripts, word): | |
count = 0 | |
for j in scripts: | |
if j.text.find(word) > 0: | |
break | |
count += 1 | |
return count | |
def getUserToken(self): | |
script = self.soup.findAll("script") | |
script_id = self.find_word_fr_script(script, "userToken") | |
loc = script[script_id].text.find("userToken") | |
if loc: | |
self.user_token = script[script_id].text[loc + 12 : loc + 68] | |
def getFrontendUploadIdBase(self): | |
script = self.soup.findAll("script") | |
script_id = self.find_word_fr_script(script, "frontend_upload_idBase") | |
loc = script[script_id].text.find("frontend_upload_idBase") | |
if loc: | |
self.frontend_upload_id = script[script_id].text[loc + 23 : loc + 59] | |
def get_userId(self): | |
get_user_id_req = self.session.get("https://www.youtube.com/account_advanced") | |
soup = BeautifulSoup(get_user_id_req.content) | |
div = soup.findAll("div", "account-subsection") | |
return div[0].findAll("p")[2].text[25 + 2 :] | |
def get_videoId(self): | |
self.list_payload = { | |
"client": { | |
"name": "youtube_web_uploads", | |
"version": str(self.version), | |
"token": str(self.token), | |
}, | |
"queries": [ | |
{ | |
"id": {"frontendKey": self.frontend_upload_id}, | |
"choice": { | |
"editorSuggestions": True, | |
"videoId": True, | |
"videoInfo2": True, | |
"videoIssues": True, | |
"processingProgress": True, | |
"youtubeStatus": True, | |
"thumbnailsDone": True, | |
}, | |
} | |
], | |
} | |
check = True | |
while check: | |
videoid_req = self.session.post( | |
"https://www.googleapis.com/videofeedback/v1/feedback/list", | |
data=json.dumps(self.list_payload), | |
headers={"Content-Type": "application/json"}, | |
) | |
id_json = videoid_req.json() | |
if videoid_req.status_code == 200: | |
if id_json.has_key("items"): | |
if id_json["items"][0]["feedback"]: | |
check = False | |
time.sleep(2) | |
self.video_id = id_json["items"][0]["feedback"]["videoId"]["youtubeId"] | |
if ( | |
id_json["items"][0]["feedback"]["videoId"]["registrationStatus"] | |
== "STATUS_SUCCESS" | |
): | |
print("Video posting status success") | |
self.post_yummyAjaxWithVideoId() | |
def find_youtube_web_uploads(self): | |
script = self.soup.findAll("script") | |
script_id = self.find_word_fr_script(script, "youtube_web_uploads") | |
loc = script[script_id].text.find("youtube_web_uploads") | |
if loc: | |
keep = script[script_id].text[loc + 20 : loc + 38] | |
keep = keep.split(":") | |
if len(keep) >= 2: | |
self.version = keep[0] | |
self.token = keep[1] | |
else: | |
print("version and token not found try again!") | |
self.logout() | |
def setRupioData(self, file_name): | |
self.filename = file_name | |
self.rupio_formdata["createSessionRequest"]["fields"][2]["inlined"][ | |
"content" | |
] = str(self.user_token) | |
self.rupio_formdata["createSessionRequest"]["fields"][19]["inlined"][ | |
"content" | |
] = str(self.ssn_token) | |
self.frontend_upload_id = "web_upload:" + str(self.frontend_upload_id) + ":0" | |
self.rupio_formdata["createSessionRequest"]["fields"][5]["inlined"][ | |
"content" | |
] = self.frontend_upload_id | |
self.rupio_formdata["createSessionRequest"]["fields"][0]["external"][ | |
"filename" | |
] = file_name | |
self.rupio_formdata["createSessionRequest"]["fields"][0]["external"][ | |
"size" | |
] = int(os.stat(file_name).st_size) | |
self.rupio_formdata["createSessionRequest"]["fields"][10]["inlined"][ | |
"content" | |
] = self.video_name | |
self.rupio_formdata["createSessionRequest"]["fields"][18]["inlined"][ | |
"content" | |
] = self.privacy | |
self.rupio_formdata["createSessionRequest"]["fields"][11]["inlined"][ | |
"content" | |
] = self.description | |
self.rupio_formdata["createSessionRequest"]["fields"][12]["inlined"][ | |
"content" | |
] = self.tag | |
def post_rupio(self): | |
req = self.session.post( | |
self.rupio_url, | |
data=json.dumps(self.rupio_formdata), | |
params={"authuser": "0"}, | |
) | |
search = req.json() | |
self.upload_id = search["sessionStatus"]["upload_id"] | |
print("upload_id -> ", self.upload_id) | |
def post_creator_suggestions_ajax(self): | |
print("posting creator sugg ajax") | |
req = self.session.post( | |
self.csa_url, | |
params={"action_video_rules": "1", "location": "LOCATION_UPLOAD"}, | |
data={"session_token": self.ssn_token}, | |
) | |
print("creator sugg ajax code -> ", req.status_code) | |
def post_yummyAjax(self): | |
print("posting yummy_ajax") | |
yummyajax_req = self.session.post( | |
self.yummyajax_url, | |
data={ | |
"action_report": "1", | |
"event_type": "UPLOAD_INTENT_DRAG_AND_DROP", | |
"frontend_id": self.frontend_upload_id, | |
"version": "1", | |
"filename": self.filename, | |
"session_token": str(self.ssn_token), | |
}, | |
) | |
print("yummy return ->", yummyajax_req.content) | |
def post_yummyAjaxWithVideoId(self): | |
yummywith_req = self.session.post( | |
self.yummyajax_url, | |
data={ | |
"action_report": "1", | |
"event_type": "REGISTRATION_INFO_RECEIVED", | |
"frontend_id": self.frontend_upload_id, | |
"version": "1", | |
"video_id": str(self.video_id), | |
"session_token": str(self.ssn_token), | |
}, | |
) | |
print("yummy ajax result -> ", yummywith_req.json()) | |
self.doLastYummyPost() | |
def doLastListPostYoutubeStat(self): | |
find_feedback = True | |
while find_feedback: | |
last_req = self.session.post( | |
"https://www.googleapis.com/videofeedback/v1/feedback/list", | |
data=json.dumps(self.list_payload), | |
headers={"Content-Type": "application/json"}, | |
) | |
last_json = last_req.json() | |
if last_json["items"][0].has_key("feedback"): | |
if last_json["items"][0]["feedback"].has_key("youtubeStatus"): | |
find_feedback = False | |
print( | |
"Youtube status -> video status : ", | |
last_json["items"][0]["feedback"]["youtubeStatus"]["videoStatus"], | |
) | |
def doListPostWhileFeedBack(self): | |
find_feedback = True | |
while find_feedback: | |
last_req = self.session.post( | |
"https://www.googleapis.com/videofeedback/v1/feedback/list", | |
data=json.dumps(self.list_payload), | |
headers={"Content-Type": "application/json"}, | |
) | |
last_json = last_req.json() | |
if last_json.has_key("items"): | |
if last_json["items"][0].has_key("feedback"): | |
find_feedback = False | |
time.sleep(2) | |
self.doLastYummyPost() | |
def doLastYummyPost(self): | |
yummy_with_req = self.session.post( | |
self.yummyajax_url, | |
data={ | |
"action_report": "1", | |
"event_type": "UPLOAD_MESSAGE", | |
"frontend_id": self.frontend_upload_id, | |
"version": "1", | |
"upload_message_key": "HINT_NON_STREAMABLE_MOV", | |
"transfer_id": "scotty:" + str(self.upload_id), | |
"video_id": str(self.video_id), | |
"filename": self.video_name, | |
"session_token": str(self.ssn_token), | |
}, | |
) | |
print("Return ->", yummy_with_req.json()["code"]) | |
self.doLastListPostYoutubeStat() | |
def doOptions(self): | |
self.session.options( | |
"https://www.googleapis.com/videofeedback/v1/feedback/list" | |
) | |
time.sleep(0.5) | |
self.session.options( | |
"https://upload.youtube.com/", | |
params={ | |
"authuser": "0", | |
"upload_id": str(self.upload_id), | |
"origin": "CidodHRwczovL3VwbG9hZC55b3V0dWJlLmNvbS91cGxvYWQvcnVwaW8SDXZpZGVvLXVwbG9hZHM", | |
}, | |
) | |
self.session.post("https://www.googleapis.com/videofeedback/v1/feedback/list") | |
def postVideo(self): | |
print("Posting video...") | |
files = open(self.file_name, "rb") | |
check_req = self.session.post( | |
"https://upload.youtube.com", | |
data=files, | |
headers={"Content-Type": "application/octet-stream"}, | |
params={ | |
"authuser": "0", | |
"upload_id": str(self.upload_id), | |
"origin": "CidodHRwczovL3VwbG9hZC55b3V0dWJlLmNvbS91cGxvYWQvcnVwaW8SDXZpZGVvLXVwbG9hZHM", | |
}, | |
) | |
if check_req.json().has_key("sessionStatus"): | |
print( | |
"Video posting status ->", | |
check_req.json()["sessionStatus"]["externalFieldTransfers"][0][ | |
"status" | |
], | |
) | |
print( | |
"Transfered byte ->", | |
check_req.json()["sessionStatus"]["externalFieldTransfers"][0][ | |
"bytesTransferred" | |
], | |
) | |
else: | |
print("Video posting status -> REJECTED") | |
self.logout() | |
self.get_videoId() | |
def setVideoParamaters(self): | |
print("Sending video parameter") | |
self.session.get( | |
self.setvideoparams_url, | |
params={ | |
"title": self.video_name, | |
"description": self.description, | |
"language": "tr", | |
"privacy": self.privacy, | |
"tags": self.tag, | |
"exp_bucket": "747", | |
"youtube_category": 20, | |
"want_content_tags": "true", | |
"user_id": self.get_userId(), | |
}, | |
) | |
def setVideoMetaData( | |
self, | |
title="video", | |
description="", | |
keywords="", | |
privacy="public", | |
privacy_draft="none", | |
still_id="2", | |
thumbnail_preview_version="", | |
allow_comments="yes", | |
allow_comments_detail="all", | |
allow_rating="yes", | |
reuse="all_right_reserved", | |
captions_certificate_reason="", | |
allow_embedding="yes", | |
creator_share_feeds="yes", | |
category="20", | |
location_longitude="", | |
location_latitude="", | |
location_altitude="", | |
audio_language="", | |
recorded_date="", | |
allow_public_stats="yes", | |
creator_share_gplus="yes", | |
creator_share_twitter="no", | |
self_racy="no", | |
modified_fields="privacy_draft", | |
): | |
if self.tag != "": | |
self.modified_fields = "keywords" | |
self.session.post( | |
"https://www.youtube.com/metadata_ajax", | |
params={"action_edit_video": "1"}, | |
data={ | |
"title": self.video_name, | |
"description": self.description, | |
"keywords": self.tag, | |
"privacy": self.privacy, | |
"privacy_draft": privacy_draft, | |
"still_id": still_id, | |
"thumbnail_preview_version": thumbnail_preview_version, | |
"allow_comments": allow_comments, | |
"allow_comments_detail": allow_comments_detail, | |
"allow_rating": allow_rating, | |
"reuse": reuse, | |
"captions_certificate_reason": captions_certificate_reason, | |
"allow_embedding": allow_embedding, | |
"creator_share_feeds": creator_share_feeds, | |
"category": category, | |
"location_longitude": location_longitude, | |
"location_latitude": location_latitude, | |
"location_altitude": location_altitude, | |
"audio_language": audio_language, | |
"recorded_date": recorded_date, | |
"allow_public_stats": allow_public_stats, | |
"creator_share_gplus": creator_share_gplus, | |
"creator_share_twitter": creator_share_twitter, | |
"self_racy": self_racy, | |
"modified_fields": modified_fields, | |
"video_id": str(self.video_id), | |
"session_token": str(self.getSessionToken()), | |
}, | |
) | |
def publishVideo(self): | |
share_req = self.session.post( | |
"https://www.youtube.com/video_ajax", | |
params={"action_publish": "1", "o": "U"}, | |
data={"video_id": str(self.video_id), "session_token": str(self.ssn_token)}, | |
) | |
print("Video is publishing...") | |
if share_req.json()["success"] is True: | |
print("Video publishing status -> ", share_req.json()["messages"][0]) | |
else: | |
print("Video is not published") | |
def logout(self): | |
self.session.post( | |
"https://www.youtube.com/logout", | |
params={"action_logout": "1", "session_token": str(self.ssn_token)}, | |
) | |
print("Logout") | |
y = YoutubeUpload( | |
"[email protected]", | |
"xxx", | |
"video.mp4", | |
"pythonVideo Upload", | |
"video", | |
"private", | |
"test", | |
) | |
y.postVideo() | |
y.setVideoMetaData() | |
y.publishVideo() | |
time.sleep(1) | |
y.logout() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment