Skip to content

Commit

Permalink
Adds authentication when searching for videos, thx coletdjnz
Browse files Browse the repository at this point in the history
This should prevent potential blocking when extracting video links.
So far no one has complained because it happens while downloading many links, but I have a feeling that it could be a problem in the future.
Also prevents variable stealing from YouTubeApi class in YouTubeMain.
  • Loading branch information
Taapat committed Jun 10, 2024
1 parent e0c62e5 commit 18d97e3
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 17 deletions.
18 changes: 14 additions & 4 deletions src/OAuth.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,13 +94,23 @@ def get_new_token(self): # pragma: no cover
return data['refresh_token'], 1
return None, self.retry_interval + 2

def get_access_token(self, refresh_token):
url = 'https://accounts.google.com/o/oauth2/token'
def get_token(self, url, refresh_token):
data = {'client_id': CLIENT_ID,
'client_secret': CLIENT_SECRET,
'refresh_token': refresh_token,
'grant_type': 'refresh_token'}
data = self.get_oauth_response(url, data)
return self.get_oauth_response(url, data)

def get_access_token(self, refresh_token):
url = 'https://accounts.google.com/o/oauth2/token'
data = self.get_token(url, refresh_token)
if 'access_token' in data:
return data['access_token']
url = 'https://www.youtube.com/o/oauth2/token'
yt_data = self.get_token(url, refresh_token)
if 'token_type' in yt_data and 'access_token' in yt_data:
yt_auth = '%s %s' % (yt_data['token_type'], yt_data['access_token'])
else:
yt_auth = None
return data['access_token'], yt_auth
print('[OAuth] Error in get access token')
return None, None
9 changes: 8 additions & 1 deletion src/YouTubeApi.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,21 @@ def __init__(self, refresh_token):
self.renew_access_token()
else:
self.access_token = None
self.yt_auth = None
self.key = '&key=%s' % API_KEY

def renew_access_token(self):
self.key = '&key=%s' % API_KEY
self.access_token = OAuth().get_access_token(self.refresh_token)
self.access_token, self.yt_auth = OAuth().get_access_token(self.refresh_token)
if self.access_token:
self.key += '&access_token=%s' % self.access_token

def is_auth(self):
return bool(self.access_token)

def get_yt_auth(self):
return self.yt_auth

def try_response(self, url_or_request, renew=True):
response = {}
status_code = 'Unknown'
Expand Down
7 changes: 2 additions & 5 deletions src/YouTubeUi.py
Original file line number Diff line number Diff line change
Expand Up @@ -717,7 +717,7 @@ def useVideoUrl(self):
if not video_url: # Get and remember video url
er = 'Video url not found!'
try:
video_url = self.ytdl.extract(video_id)
video_url = self.ytdl.extract(video_id, self.ytapi.get_yt_auth())
except Exception as e:
er = e
print('[YouTube] Error in extract info:', er)
Expand Down Expand Up @@ -803,10 +803,7 @@ def createAuth(self):
config.plugins.YouTube.login.value):
from .YouTubeApi import YouTubeApi
self.ytapi = YouTubeApi(refresh_token)
if self.ytapi.access_token:
self.is_auth = True
else:
self.is_auth = False
self.is_auth = self.ytapi.is_auth()

def mySubscriptions(self):
videos = []
Expand Down
16 changes: 9 additions & 7 deletions src/YouTubeVideoUrl.py
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,7 @@ def _extract_web_response(self, video_id):
print('[YouTubeVideoUrl] Failed to parse web JSON')
return None, None

def _extract_player_response(self, video_id, client):
def _extract_player_response(self, video_id, yt_auth, client):
player_id = None
url = 'https://www.youtube.com/youtubei/v1/player?prettyPrint=false'
data = {
Expand All @@ -308,6 +308,8 @@ def _extract_player_response(self, video_id, client):
'Origin': 'https://www.youtube.com',
'X-YouTube-Client-Name': client
}
if yt_auth:
headers['Authorization'] = yt_auth
if client == 5:
VERSION = '19.09.3'
USER_AGENT = 'com.google.ios.youtube/%s (iPhone14,3; U; CPU iOS 15_6 like Mac OS X)' % VERSION
Expand Down Expand Up @@ -367,7 +369,7 @@ def _extract_player_response(self, video_id, client):
print('[YouTubeVideoUrl] Failed to parse JSON')
return None, None

def _real_extract(self, video_id):
def _real_extract(self, video_id, yt_auth):
IGNORE_VIDEO_FORMAT = (
'43', '44', '45', '46', # webm
'82', '83', '84', '85', # 3D
Expand All @@ -394,7 +396,7 @@ def _real_extract(self, video_id):
print('[YouTubeVideoUrl] skip DASH MP4 format')
self.use_dash_mp4 = DASHMP4_FORMAT

player_response, player_id = self._extract_player_response(video_id, 30)
player_response, player_id = self._extract_player_response(video_id, yt_auth, 30)
if not player_response:
raise RuntimeError('Player response not found!')

Expand All @@ -404,14 +406,14 @@ def _real_extract(self, video_id):
player_response, player_id = self._extract_web_response(video_id)
else:
print('[YouTubeVideoUrl] Got wrong player response, try ios client')
player_response, player_id = self._extract_player_response(video_id, 5)
player_response, player_id = self._extract_player_response(video_id, yt_auth, 5)

is_live = self.try_get(player_response, lambda x: x['videoDetails']['isLive'])
playability_status = player_response.get('playabilityStatus', {})

if not is_live and playability_status.get('status') == 'LOGIN_REQUIRED':
print('[YouTubeVideoUrl] Age gate content')
player_response, player_id = self._extract_player_response(video_id, 85)
player_response, player_id = self._extract_player_response(video_id, yt_auth, 85)
if not player_response:
raise RuntimeError('Age gate content player response not found!')

Expand Down Expand Up @@ -482,11 +484,11 @@ def _real_extract(self, video_id):

return str(url)

def extract(self, video_id):
def extract(self, video_id, yt_auth=None):
error_message = None
for _ in range(3):
try:
return self._real_extract(video_id)
return self._real_extract(video_id, yt_auth)
except Exception as ex:
if ex is None:
print('No supported formats found, trying again!')
Expand Down

0 comments on commit 18d97e3

Please sign in to comment.