Compare commits
5 Commits
Author | SHA1 | Date | |
---|---|---|---|
ed4b05d9b6 | |||
6f88b1cec6 | |||
03451fb8ae | |||
e45c3fd48b | |||
1153ac8f24 |
@ -53,7 +53,7 @@ def request_comments(ctoken, replies=False):
|
||||
'hl': 'en',
|
||||
'gl': 'US',
|
||||
'clientName': 'MWEB',
|
||||
'clientVersion': '2.20240328.08.00',
|
||||
'clientVersion': '2.20210804.02.00',
|
||||
},
|
||||
},
|
||||
'continuation': ctoken.replace('=', '%3D'),
|
||||
@ -78,7 +78,7 @@ def single_comment_ctoken(video_id, comment_id):
|
||||
|
||||
def post_process_comments_info(comments_info):
|
||||
for comment in comments_info['comments']:
|
||||
comment['author'] = strip_non_ascii(comment['author'])
|
||||
comment['author'] = strip_non_ascii(comment['author']) if comment.get('author') else ""
|
||||
comment['author_url'] = concat_or_none(
|
||||
'/', comment['author_url'])
|
||||
comment['author_avatar'] = concat_or_none(
|
||||
@ -189,10 +189,10 @@ def video_comments(video_id, sort=0, offset=0, lc='', secret_key=''):
|
||||
comments_info['error'] += '\n\n' + e.error_message
|
||||
comments_info['error'] += '\n\nExit node IP address: %s' % e.ip
|
||||
else:
|
||||
comments_info['error'] = 'YouTube blocked the request. IP address: %s' % e.ip
|
||||
comments_info['error'] = 'YouTube blocked the request. Error: %s' % str(e)
|
||||
|
||||
except Exception as e:
|
||||
comments_info['error'] = 'YouTube blocked the request. IP address: %s' % e.ip
|
||||
comments_info['error'] = 'YouTube blocked the request. Error: %s' % str(e)
|
||||
|
||||
if comments_info.get('error'):
|
||||
print('Error retrieving comments for ' + str(video_id) + ':\n' +
|
||||
|
@ -5,8 +5,9 @@ function changeQuality(selection) {
|
||||
let videoPaused = video.paused;
|
||||
let videoSpeed = video.playbackRate;
|
||||
let srcInfo;
|
||||
if (avMerge)
|
||||
if (avMerge && typeof avMerge.close === 'function') {
|
||||
avMerge.close();
|
||||
}
|
||||
if (selection.type == 'uni'){
|
||||
srcInfo = data['uni_sources'][selection.index];
|
||||
video.src = srcInfo.url;
|
||||
|
@ -128,6 +128,29 @@ header {
|
||||
background-color: var(--buttom-hover);
|
||||
}
|
||||
|
||||
.live-url-choices {
|
||||
background-color: var(--thumb-background);
|
||||
margin: 1rem 0;
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.playability-error {
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
height: 30vh;
|
||||
margin: 1rem 0;
|
||||
}
|
||||
|
||||
.playability-error > span {
|
||||
display: flex;
|
||||
background-color: var(--thumb-background);
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.playlist {
|
||||
display: grid;
|
||||
grid-gap: 4px;
|
||||
@ -622,6 +645,9 @@ figure.sc-video {
|
||||
max-height: 80vh;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
.playability-error {
|
||||
height: 60vh;
|
||||
}
|
||||
.playlist {
|
||||
display: grid;
|
||||
grid-gap: 1px;
|
||||
|
@ -840,6 +840,8 @@ def call_youtube_api(client, api, data):
|
||||
|
||||
def strip_non_ascii(string):
|
||||
''' Returns the string without non ASCII characters'''
|
||||
if string is None:
|
||||
return ""
|
||||
stripped = (c for c in string if 0 < ord(c) < 127)
|
||||
return ''.join(stripped)
|
||||
|
||||
|
@ -1,3 +1,3 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
__version__ = 'v0.3.1'
|
||||
__version__ = 'v0.3.2'
|
||||
|
@ -367,32 +367,42 @@ def fetch_watch_page_info(video_id, playlist_id, index):
|
||||
watch_page = watch_page.decode('utf-8')
|
||||
return yt_data_extract.extract_watch_info_from_html(watch_page)
|
||||
|
||||
|
||||
def extract_info(video_id, use_invidious, playlist_id=None, index=None):
|
||||
primary_client = 'android_vr'
|
||||
fallback_client = 'ios'
|
||||
last_resort_client = 'tv_embedded'
|
||||
|
||||
tasks = (
|
||||
# Get video metadata from here
|
||||
gevent.spawn(fetch_watch_page_info, video_id, playlist_id, index),
|
||||
gevent.spawn(fetch_player_response, 'android_vr', video_id)
|
||||
gevent.spawn(fetch_player_response, primary_client, video_id)
|
||||
)
|
||||
gevent.joinall(tasks)
|
||||
util.check_gevent_exceptions(*tasks)
|
||||
info, player_response = tasks[0].value, tasks[1].value
|
||||
|
||||
info = tasks[0].value or {}
|
||||
player_response = tasks[1].value or {}
|
||||
|
||||
yt_data_extract.update_with_new_urls(info, player_response)
|
||||
|
||||
# Age restricted video, retry
|
||||
if info['age_restricted'] or info['player_urls_missing']:
|
||||
if info['age_restricted']:
|
||||
print('Age restricted video, retrying')
|
||||
else:
|
||||
print('Player urls missing, retrying')
|
||||
player_response = fetch_player_response('tv_embedded', video_id)
|
||||
# Fallback to 'ios' if no valid URLs are found
|
||||
if not info.get('formats') or info.get('player_urls_missing'):
|
||||
print(f"No URLs found in '{primary_client}', attempting with '{fallback_client}'.")
|
||||
player_response = fetch_player_response(fallback_client, video_id) or {}
|
||||
yt_data_extract.update_with_new_urls(info, player_response)
|
||||
|
||||
# Final attempt with 'tv_embedded' if there are still no URLs
|
||||
if not info.get('formats') or info.get('player_urls_missing'):
|
||||
print(f"No URLs found in '{fallback_client}', attempting with '{last_resort_client}'")
|
||||
player_response = fetch_player_response(last_resort_client, video_id) or {}
|
||||
yt_data_extract.update_with_new_urls(info, player_response)
|
||||
|
||||
# signature decryption
|
||||
if info.get('formats'):
|
||||
decryption_error = decrypt_signatures(info, video_id)
|
||||
if decryption_error:
|
||||
decryption_error = 'Error decrypting url signatures: ' + decryption_error
|
||||
info['playability_error'] = decryption_error
|
||||
info['playability_error'] = 'Error decrypting url signatures: ' + decryption_error
|
||||
|
||||
# check if urls ready (non-live format) in former livestream
|
||||
# urls not ready if all of them have no filesize
|
||||
@ -406,20 +416,20 @@ def extract_info(video_id, use_invidious, playlist_id=None, index=None):
|
||||
|
||||
# livestream urls
|
||||
# sometimes only the livestream urls work soon after the livestream is over
|
||||
if (info['hls_manifest_url']
|
||||
and (info['live'] or not info['formats'] or not info['urls_ready'])
|
||||
):
|
||||
info['hls_formats'] = []
|
||||
if info.get('hls_manifest_url') and (info.get('live') or not info.get('formats') or not info['urls_ready']):
|
||||
try:
|
||||
manifest = util.fetch_url(info['hls_manifest_url'],
|
||||
debug_name='hls_manifest.m3u8',
|
||||
report_text='Fetched hls manifest'
|
||||
).decode('utf-8')
|
||||
|
||||
info['hls_formats'], err = yt_data_extract.extract_hls_formats(manifest)
|
||||
if not err:
|
||||
info['playability_error'] = None
|
||||
for fmt in info['hls_formats']:
|
||||
fmt['video_quality'] = video_quality_string(fmt)
|
||||
else:
|
||||
except Exception as e:
|
||||
print(f"Error obteniendo HLS manifest: {e}")
|
||||
info['hls_formats'] = []
|
||||
|
||||
# check for 403. Unnecessary for tor video routing b/c ip address is same
|
||||
|
Loading…
x
Reference in New Issue
Block a user