Compare commits
42 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4ef7dda14a | ||
|
|
ee31cedae0 | ||
|
d3b0cb5e13
|
|||
|
0a79974d11
|
|||
|
4e327944a0
|
|||
|
09a437f7fb
|
|||
|
3cbe18aac0
|
|||
|
|
62418f8e95 | ||
|
bfd3760969
|
|||
|
efd89b2e64
|
|||
|
0dc1747178
|
|||
|
8577164785
|
|||
|
8af98968dd
|
|||
|
8f00cbcdd6
|
|||
|
af75551bc2
|
|||
|
3a6cc1e44f
|
|||
|
7664b5f0ff
|
|||
|
ec5d236cad
|
|||
|
d6b7a255d0
|
|||
|
22bc7324db
|
|||
|
48e8f271e7
|
|||
|
9a0ad6070b
|
|||
|
6039589f24
|
|||
|
d4cba7eb6c
|
|||
|
70cb453280
|
|||
|
7a106331e7
|
|||
|
8775e131af
|
|||
|
1f16f7cb62
|
|||
|
80b7f3cd00
|
|||
|
8b79e067bc
|
|||
|
cda0627d5a
|
|||
|
ad40dd6d6b
|
|||
|
b91d53dc6f
|
|||
|
cda4fd1f26
|
|||
|
ff2a2edaa5
|
|||
|
38d8d5d4c5
|
|||
|
f010452abf
|
|||
|
ab93f8242b
|
|||
|
1505414a1a
|
|||
|
c04d7c9a24
|
|||
|
3ee2df7faa
|
|||
|
d2c883c211
|
23
.gitea/workflows/ci.yaml
Normal file
23
.gitea/workflows/ci.yaml
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
name: CI
|
||||||
|
|
||||||
|
on: [push, pull_request]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up Python
|
||||||
|
uses: actions/setup-python@v5
|
||||||
|
with:
|
||||||
|
python-version: 3.11
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: |
|
||||||
|
pip install --upgrade pip
|
||||||
|
pip install -r requirements-dev.txt
|
||||||
|
|
||||||
|
- name: Run tests
|
||||||
|
run: pytest
|
||||||
40
.gitea/workflows/git-sync.yaml
Normal file
40
.gitea/workflows/git-sync.yaml
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
name: git-sync-with-mirror
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ master ]
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
git-sync:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: git-sync
|
||||||
|
env:
|
||||||
|
git_sync_source_repo: git@git.fridu.us:heckyel/yt-local.git
|
||||||
|
git_sync_destination_repo: ssh://git@c.fridu.us/software/yt-local.git
|
||||||
|
if: env.git_sync_source_repo && env.git_sync_destination_repo
|
||||||
|
uses: astounds/git-sync@v1
|
||||||
|
with:
|
||||||
|
source_repo: git@git.fridu.us:heckyel/yt-local.git
|
||||||
|
source_branch: "master"
|
||||||
|
destination_repo: ssh://git@c.fridu.us/software/yt-local.git
|
||||||
|
destination_branch: "master"
|
||||||
|
source_ssh_private_key: ${{ secrets.GIT_SYNC_SOURCE_SSH_PRIVATE_KEY }}
|
||||||
|
destination_ssh_private_key: ${{ secrets.GIT_SYNC_DESTINATION_SSH_PRIVATE_KEY }}
|
||||||
|
|
||||||
|
- name: git-sync-sourcehut
|
||||||
|
env:
|
||||||
|
git_sync_source_repo: git@git.fridu.us:heckyel/yt-local.git
|
||||||
|
git_sync_destination_repo: git@git.sr.ht:~heckyel/yt-local
|
||||||
|
if: env.git_sync_source_repo && env.git_sync_destination_repo
|
||||||
|
uses: astounds/git-sync@v1
|
||||||
|
with:
|
||||||
|
source_repo: git@git.fridu.us:heckyel/yt-local.git
|
||||||
|
source_branch: "master"
|
||||||
|
destination_repo: git@git.sr.ht:~heckyel/yt-local
|
||||||
|
destination_branch: "master"
|
||||||
|
source_ssh_private_key: ${{ secrets.GIT_SYNC_SOURCE_SSH_PRIVATE_KEY }}
|
||||||
|
destination_ssh_private_key: ${{ secrets.GIT_SYNC_DESTINATION_SSH_PRIVATE_KEY }}
|
||||||
|
continue-on-error: true
|
||||||
@@ -1,5 +1,3 @@
|
|||||||
[](https://drone.hgit.ga/heckyel/yt-local)
|
|
||||||
|
|
||||||
# yt-local
|
# yt-local
|
||||||
|
|
||||||
Fork of [youtube-local](https://github.com/user234683/youtube-local)
|
Fork of [youtube-local](https://github.com/user234683/youtube-local)
|
||||||
@@ -153,7 +151,7 @@ For coding guidelines and an overview of the software architecture, see the [HAC
|
|||||||
|
|
||||||
yt-local is not made to work in public mode, however there is an instance of yt-local in public mode but with less features
|
yt-local is not made to work in public mode, however there is an instance of yt-local in public mode but with less features
|
||||||
|
|
||||||
- <https://1cd1-93-95-230-133.ngrok-free.app/https://youtube.com>
|
- <https://m.fridu.us/https://youtube.com>
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
|||||||
@@ -114,10 +114,12 @@ if bitness == '32':
|
|||||||
visual_c_runtime_url = 'https://github.com/yuempek/vc-archive/raw/master/archives/vc15_(14.10.25017.0)_2017_x86.7z'
|
visual_c_runtime_url = 'https://github.com/yuempek/vc-archive/raw/master/archives/vc15_(14.10.25017.0)_2017_x86.7z'
|
||||||
visual_c_runtime_sha256 = '2549eb4d2ce4cf3a87425ea01940f74368bf1cda378ef8a8a1f1a12ed59f1547'
|
visual_c_runtime_sha256 = '2549eb4d2ce4cf3a87425ea01940f74368bf1cda378ef8a8a1f1a12ed59f1547'
|
||||||
visual_c_name = 'vc15_(14.10.25017.0)_2017_x86.7z'
|
visual_c_name = 'vc15_(14.10.25017.0)_2017_x86.7z'
|
||||||
|
visual_c_path_to_dlls = 'runtime_minimum/System'
|
||||||
else:
|
else:
|
||||||
visual_c_runtime_url = 'https://github.com/yuempek/vc-archive/raw/master/archives/vc15_(14.10.25017.0)_2017_x64.7z'
|
visual_c_runtime_url = 'https://github.com/yuempek/vc-archive/raw/master/archives/vc15_(14.10.25017.0)_2017_x64.7z'
|
||||||
visual_c_runtime_sha256 = '4f00b824c37e1017a93fccbd5775e6ee54f824b6786f5730d257a87a3d9ce921'
|
visual_c_runtime_sha256 = '4f00b824c37e1017a93fccbd5775e6ee54f824b6786f5730d257a87a3d9ce921'
|
||||||
visual_c_name = 'vc15_(14.10.25017.0)_2017_x64.7z'
|
visual_c_name = 'vc15_(14.10.25017.0)_2017_x64.7z'
|
||||||
|
visual_c_path_to_dlls = 'runtime_minimum/System64'
|
||||||
|
|
||||||
download_if_not_exists('get-pip.py', get_pip_url)
|
download_if_not_exists('get-pip.py', get_pip_url)
|
||||||
|
|
||||||
@@ -198,7 +200,7 @@ with open('./python/python3' + major_release + '._pth', 'a', encoding='utf-8') a
|
|||||||
f.write('..\n')'''
|
f.write('..\n')'''
|
||||||
|
|
||||||
log('Inserting Microsoft C Runtime')
|
log('Inserting Microsoft C Runtime')
|
||||||
check_subp(subprocess.run([r'7z', '-y', 'e', '-opython', 'vc15_(14.10.25017.0)_2017_x86.7z', 'runtime_minimum/System']))
|
check_subp(subprocess.run([r'7z', '-y', 'e', '-opython', visual_c_name, visual_c_path_to_dlls]))
|
||||||
|
|
||||||
log('Installing dependencies')
|
log('Installing dependencies')
|
||||||
wine_run(['./python/python.exe', '-I', '-m', 'pip', 'install', '--no-compile', '-r', './requirements.txt'])
|
wine_run(['./python/python.exe', '-I', '-m', 'pip', 'install', '--no-compile', '-r', './requirements.txt'])
|
||||||
|
|||||||
@@ -1,28 +1,21 @@
|
|||||||
attrs==22.1.0
|
blinker==1.7.0
|
||||||
Brotli==1.0.9
|
Brotli==1.1.0
|
||||||
cachetools==4.2.4
|
cachetools==5.3.3
|
||||||
click==8.0.4
|
click==8.1.7
|
||||||
dataclasses==0.6
|
|
||||||
defusedxml==0.7.1
|
defusedxml==0.7.1
|
||||||
Flask==2.0.1
|
Flask==3.0.2
|
||||||
gevent==22.10.2
|
gevent==24.2.1
|
||||||
greenlet==2.0.1
|
greenlet==3.0.3
|
||||||
importlib-metadata==4.6.4
|
iniconfig==2.0.0
|
||||||
iniconfig==1.1.1
|
itsdangerous==2.1.2
|
||||||
itsdangerous==2.0.1
|
Jinja2==3.1.4
|
||||||
Jinja2==3.0.3
|
MarkupSafe==2.1.5
|
||||||
MarkupSafe==2.0.1
|
packaging==24.0
|
||||||
packaging==20.9
|
pluggy==1.4.0
|
||||||
pluggy>=0.13.1
|
|
||||||
py==1.10.0
|
|
||||||
pyparsing==2.4.7
|
|
||||||
PySocks==1.7.1
|
PySocks==1.7.1
|
||||||
pytest==6.2.5
|
pytest==8.1.1
|
||||||
stem==1.8.0
|
stem==1.8.2
|
||||||
toml==0.10.2
|
urllib3==2.2.2
|
||||||
typing-extensions==3.10.0.2
|
Werkzeug==3.0.3
|
||||||
urllib3==1.26.11
|
zope.event==5.0
|
||||||
Werkzeug==2.1.1
|
zope.interface==6.2
|
||||||
zipp==3.5.1
|
|
||||||
zope.event==4.5.0
|
|
||||||
zope.interface==5.4.0
|
|
||||||
|
|||||||
@@ -1,20 +1,17 @@
|
|||||||
Brotli==1.0.9
|
blinker==1.7.0
|
||||||
cachetools==4.2.4
|
Brotli==1.1.0
|
||||||
click==8.0.4
|
cachetools==5.3.3
|
||||||
dataclasses==0.6
|
click==8.1.7
|
||||||
defusedxml==0.7.1
|
defusedxml==0.7.1
|
||||||
Flask==2.0.1
|
Flask==3.0.2
|
||||||
gevent==22.10.2
|
gevent==24.2.1
|
||||||
greenlet==2.0.1
|
greenlet==3.0.3
|
||||||
importlib-metadata==4.6.4
|
itsdangerous==2.1.2
|
||||||
itsdangerous==2.0.1
|
Jinja2==3.1.4
|
||||||
Jinja2==3.0.3
|
MarkupSafe==2.1.5
|
||||||
MarkupSafe==2.0.1
|
|
||||||
PySocks==1.7.1
|
PySocks==1.7.1
|
||||||
stem==1.8.0
|
stem==1.8.2
|
||||||
typing-extensions==3.10.0.2
|
urllib3==2.2.2
|
||||||
urllib3==1.26.11
|
Werkzeug==3.0.3
|
||||||
Werkzeug==2.1.1
|
zope.event==5.0
|
||||||
zipp==3.5.1
|
zope.interface==6.2
|
||||||
zope.event==4.5.0
|
|
||||||
zope.interface==5.4.0
|
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ def proxy_site(env, start_response, video=False):
|
|||||||
else:
|
else:
|
||||||
response, cleanup_func = util.fetch_url_response(url, send_headers)
|
response, cleanup_func = util.fetch_url_response(url, send_headers)
|
||||||
|
|
||||||
response_headers = response.getheaders()
|
response_headers = response.headers
|
||||||
if isinstance(response_headers, urllib3._collections.HTTPHeaderDict):
|
if isinstance(response_headers, urllib3._collections.HTTPHeaderDict):
|
||||||
response_headers = response_headers.items()
|
response_headers = response_headers.items()
|
||||||
if video:
|
if video:
|
||||||
|
|||||||
@@ -264,7 +264,7 @@ def get_channel_tab(channel_id, page="1", sort=3, tab='videos', view=1,
|
|||||||
'hl': 'en',
|
'hl': 'en',
|
||||||
'gl': 'US',
|
'gl': 'US',
|
||||||
'clientName': 'WEB',
|
'clientName': 'WEB',
|
||||||
'clientVersion': '2.20180830',
|
'clientVersion': '2.20240327.00.00',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'continuation': ctoken,
|
'continuation': ctoken,
|
||||||
@@ -371,7 +371,7 @@ def get_channel_search_json(channel_id, query, page):
|
|||||||
'hl': 'en',
|
'hl': 'en',
|
||||||
'gl': 'US',
|
'gl': 'US',
|
||||||
'clientName': 'WEB',
|
'clientName': 'WEB',
|
||||||
'clientVersion': '2.20180830',
|
'clientVersion': '2.20240327.00.00',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'continuation': ctoken,
|
'continuation': ctoken,
|
||||||
@@ -389,6 +389,7 @@ def post_process_channel_info(info):
|
|||||||
info['avatar'] = util.prefix_url(info['avatar'])
|
info['avatar'] = util.prefix_url(info['avatar'])
|
||||||
info['channel_url'] = util.prefix_url(info['channel_url'])
|
info['channel_url'] = util.prefix_url(info['channel_url'])
|
||||||
for item in info['items']:
|
for item in info['items']:
|
||||||
|
item['thumbnail'] = "https://i.ytimg.com/vi/{}/hqdefault.jpg".format(item['id'])
|
||||||
util.prefix_urls(item)
|
util.prefix_urls(item)
|
||||||
util.add_extra_html_info(item)
|
util.add_extra_html_info(item)
|
||||||
if info['current_tab'] == 'about':
|
if info['current_tab'] == 'about':
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ def request_comments(ctoken, replies=False):
|
|||||||
'hl': 'en',
|
'hl': 'en',
|
||||||
'gl': 'US',
|
'gl': 'US',
|
||||||
'clientName': 'MWEB',
|
'clientName': 'MWEB',
|
||||||
'clientVersion': '2.20210804.02.00',
|
'clientVersion': '2.20240328.08.00',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'continuation': ctoken.replace('=', '%3D'),
|
'continuation': ctoken.replace('=', '%3D'),
|
||||||
|
|||||||
@@ -256,7 +256,8 @@ hr {
|
|||||||
padding-top: 6px;
|
padding-top: 6px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
border: none;
|
border: 1px solid;
|
||||||
|
border-color: var(--button-border);
|
||||||
border-radius: 0.2rem;
|
border-radius: 0.2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,20 +1,22 @@
|
|||||||
:root {
|
:root {
|
||||||
--background: #212121;
|
--background: #121113;
|
||||||
--text: #FFFFFF;
|
--text: #FFFFFF;
|
||||||
--secondary-hover: #73828c;
|
--secondary-hover: #222222;
|
||||||
--secondary-focus: #303030;
|
--secondary-focus: #121113;
|
||||||
--secondary-inverse: #FFF;
|
--secondary-inverse: #FFFFFF;
|
||||||
--primary-background: #242424;
|
--primary-background: #242424;
|
||||||
--secondary-background: #424242;
|
--secondary-background: #222222;
|
||||||
--thumb-background: #757575;
|
--thumb-background: #222222;
|
||||||
--link: #00B0FF;
|
--link: #00B0FF;
|
||||||
--link-visited: #40C4FF;
|
--link-visited: #40C4FF;
|
||||||
--border-bg: #FFFFFF;
|
--border-bg: #222222;
|
||||||
--buttom: #dcdcdb;
|
--border-bg-settings: #000000;
|
||||||
--buttom-text: #415462;
|
--border-bg-license: #000000;
|
||||||
--button-border: #91918c;
|
--buttom: #121113;
|
||||||
--buttom-hover: #BBB;
|
--buttom-text: #FFFFFF;
|
||||||
--search-text: #FFF;
|
--button-border: #222222;
|
||||||
--time-background: #212121;
|
--buttom-hover: #222222;
|
||||||
--time-text: #FFF;
|
--search-text: #FFFFFF;
|
||||||
|
--time-background: #121113;
|
||||||
|
--time-text: #FFFFFF;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,19 +1,21 @@
|
|||||||
:root {
|
:root {
|
||||||
--background: #2d3743;
|
--background: #2D3743;
|
||||||
--text: #FFFFFF;
|
--text: #FFFFFF;
|
||||||
--secondary-hover: #73828c;
|
--secondary-hover: #73828C;
|
||||||
--secondary-focus: rgba(115, 130, 140, 0.125);
|
--secondary-focus: rgba(115, 130, 140, 0.125);
|
||||||
--secondary-inverse: #FFFFFF;
|
--secondary-inverse: #FFFFFF;
|
||||||
--primary-background: #2d3743;
|
--primary-background: #2D3743;
|
||||||
--secondary-background: #102027;
|
--secondary-background: #102027;
|
||||||
--thumb-background: #35404D;
|
--thumb-background: #35404D;
|
||||||
--link: #22aaff;
|
--link: #22AAFF;
|
||||||
--link-visited: #7755ff;
|
--link-visited: #7755FF;
|
||||||
--border-bg: #FFFFFF;
|
--border-bg: #FFFFFF;
|
||||||
--buttom: #DCDCDC;
|
--border-bg-settings: #FFFFFF;
|
||||||
--buttom-text: #415462;
|
--border-bg-license: #FFFFFF;
|
||||||
--button-border: #91918c;
|
--buttom: #2D3743;
|
||||||
--buttom-hover: #BBBBBB;
|
--buttom-text: #FFFFFF;
|
||||||
|
--button-border: #102027;
|
||||||
|
--buttom-hover: #102027;
|
||||||
--search-text: #FFFFFF;
|
--search-text: #FFFFFF;
|
||||||
--time-background: #212121;
|
--time-background: #212121;
|
||||||
--time-text: #FFFFFF;
|
--time-text: #FFFFFF;
|
||||||
|
|||||||
@@ -569,7 +569,8 @@ function fetchRange(url, start, end, debugInfo) {
|
|||||||
onFailure(e, 'Network error');
|
onFailure(e, 'Network error');
|
||||||
};
|
};
|
||||||
xhr.ontimeout = function (event){
|
xhr.ontimeout = function (event){
|
||||||
onFailure(null, 'Timeout (15s)', maxRetries=1);
|
xhr.timeout += 5000;
|
||||||
|
onFailure(null, 'Timeout (15s)', maxRetries=5);
|
||||||
};
|
};
|
||||||
xhr.send();
|
xhr.send();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -181,7 +181,7 @@ label[for=options-toggle-cbox] {
|
|||||||
|
|
||||||
.table td,.table th {
|
.table td,.table th {
|
||||||
padding: 10px 10px;
|
padding: 10px 10px;
|
||||||
border: 1px solid var(--secondary-background);
|
border: 1px solid var(--border-bg-license);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,9 +10,11 @@
|
|||||||
--link: #212121;
|
--link: #212121;
|
||||||
--link-visited: #808080;
|
--link-visited: #808080;
|
||||||
--border-bg: #212121;
|
--border-bg: #212121;
|
||||||
--buttom: #DCDCDC;
|
--border-bg-settings: #91918C;
|
||||||
|
--border-bg-license: #91918C;
|
||||||
|
--buttom: #FFFFFF;
|
||||||
--buttom-text: #212121;
|
--buttom-text: #212121;
|
||||||
--button-border: #91918c;
|
--button-border: #91918C;
|
||||||
--buttom-hover: #BBBBBB;
|
--buttom-hover: #BBBBBB;
|
||||||
--search-text: #212121;
|
--search-text: #212121;
|
||||||
--time-background: #212121;
|
--time-background: #212121;
|
||||||
|
|||||||
39
youtube/static/modules/plyr/custom_plyr.css
Normal file
39
youtube/static/modules/plyr/custom_plyr.css
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
/* Prevent this div from blocking right-click menu for video
|
||||||
|
e.g. Firefox playback speed options */
|
||||||
|
.plyr__poster {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* plyr fix */
|
||||||
|
.plyr:-moz-full-screen video {
|
||||||
|
max-height: initial;
|
||||||
|
}
|
||||||
|
|
||||||
|
.plyr:-webkit-full-screen video {
|
||||||
|
max-height: initial;
|
||||||
|
}
|
||||||
|
|
||||||
|
.plyr:-ms-fullscreen video {
|
||||||
|
max-height: initial;
|
||||||
|
}
|
||||||
|
|
||||||
|
.plyr:fullscreen video {
|
||||||
|
max-height: initial;
|
||||||
|
}
|
||||||
|
|
||||||
|
.plyr__preview-thumb__image-container {
|
||||||
|
width: 158px;
|
||||||
|
height: 90px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.plyr__preview-thumb {
|
||||||
|
bottom: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.plyr__menu__container [role="menu"],
|
||||||
|
.plyr__menu__container [role="menucaptions"] {
|
||||||
|
/* Set vertical scroll */
|
||||||
|
/* issue https://github.com/sampotts/plyr/issues/1420 */
|
||||||
|
max-height: 320px;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
@@ -155,7 +155,7 @@ label[for=options-toggle-cbox] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.settings-form > h2 {
|
.settings-form > h2 {
|
||||||
border-bottom: 2px solid var(--border-bg);
|
border-bottom: 2px solid var(--border-bg-settings);
|
||||||
padding-bottom: 0.5rem;
|
padding-bottom: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,20 +24,6 @@ video {
|
|||||||
max-height: calc(100vh/1.5);
|
max-height: calc(100vh/1.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* plyr fix */
|
|
||||||
.plyr:-moz-full-screen video {
|
|
||||||
max-height: initial;
|
|
||||||
}
|
|
||||||
.plyr:-webkit-full-screen video {
|
|
||||||
max-height: initial;
|
|
||||||
}
|
|
||||||
.plyr:-ms-fullscreen video {
|
|
||||||
max-height: initial;
|
|
||||||
}
|
|
||||||
.plyr:fullscreen video {
|
|
||||||
max-height: initial;
|
|
||||||
}
|
|
||||||
|
|
||||||
a:link {
|
a:link {
|
||||||
color: var(--link);
|
color: var(--link);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,14 +8,8 @@
|
|||||||
{% if settings.use_video_player == 2 %}
|
{% if settings.use_video_player == 2 %}
|
||||||
<!-- plyr -->
|
<!-- plyr -->
|
||||||
<link href="/youtube.com/static/modules/plyr/plyr.css" rel="stylesheet">
|
<link href="/youtube.com/static/modules/plyr/plyr.css" rel="stylesheet">
|
||||||
|
<link href="/youtube.com/static/modules/plyr/custom_plyr.css" rel="stylesheet">
|
||||||
<!--/ plyr -->
|
<!--/ plyr -->
|
||||||
<style>
|
|
||||||
/* Prevent this div from blocking right-click menu for video
|
|
||||||
e.g. Firefox playback speed options */
|
|
||||||
.plyr__poster {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endblock style %}
|
{% endblock style %}
|
||||||
|
|
||||||
|
|||||||
@@ -336,7 +336,7 @@ def fetch_url(url, headers=(), timeout=15, report_text=None, data=None,
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
):
|
):
|
||||||
print(response.status, response.reason, response.getheaders())
|
print(response.status, response.reason, response.headers)
|
||||||
ip = re.search(
|
ip = re.search(
|
||||||
br'IP address: ((?:[\da-f]*:)+[\da-f]+|(?:\d+\.)+\d+)',
|
br'IP address: ((?:[\da-f]*:)+[\da-f]+|(?:\d+\.)+\d+)',
|
||||||
content)
|
content)
|
||||||
@@ -395,22 +395,22 @@ def head(url, use_tor=False, report_text=None, max_redirects=10):
|
|||||||
return response
|
return response
|
||||||
|
|
||||||
|
|
||||||
mobile_user_agent = 'Mozilla/5.0 (Linux; Android 7.0; Redmi Note 4 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36'
|
mobile_user_agent = 'Mozilla/5.0 (Linux; Android 14) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.6312.80 Mobile Safari/537.36'
|
||||||
mobile_ua = (('User-Agent', mobile_user_agent),)
|
mobile_ua = (('User-Agent', mobile_user_agent),)
|
||||||
desktop_user_agent = 'Mozilla/5.0 (Windows NT 6.1; rv:52.0) Gecko/20100101 Firefox/52.0'
|
desktop_user_agent = 'Mozilla/5.0 (Windows NT 10.0; rv:124.0) Gecko/20100101 Firefox/124.0'
|
||||||
desktop_ua = (('User-Agent', desktop_user_agent),)
|
desktop_ua = (('User-Agent', desktop_user_agent),)
|
||||||
json_header = (('Content-Type', 'application/json'),)
|
json_header = (('Content-Type', 'application/json'),)
|
||||||
desktop_xhr_headers = (
|
desktop_xhr_headers = (
|
||||||
('Accept', '*/*'),
|
('Accept', '*/*'),
|
||||||
('Accept-Language', 'en-US,en;q=0.5'),
|
('Accept-Language', 'en-US,en;q=0.5'),
|
||||||
('X-YouTube-Client-Name', '1'),
|
('X-YouTube-Client-Name', '1'),
|
||||||
('X-YouTube-Client-Version', '2.20180830'),
|
('X-YouTube-Client-Version', '2.20240327.00.00'),
|
||||||
) + desktop_ua
|
) + desktop_ua
|
||||||
mobile_xhr_headers = (
|
mobile_xhr_headers = (
|
||||||
('Accept', '*/*'),
|
('Accept', '*/*'),
|
||||||
('Accept-Language', 'en-US,en;q=0.5'),
|
('Accept-Language', 'en-US,en;q=0.5'),
|
||||||
('X-YouTube-Client-Name', '2'),
|
('X-YouTube-Client-Name', '1'),
|
||||||
('X-YouTube-Client-Version', '2.20180830'),
|
('X-YouTube-Client-Version', '2.20240328.08.00'),
|
||||||
) + mobile_ua
|
) + mobile_ua
|
||||||
|
|
||||||
|
|
||||||
@@ -667,6 +667,16 @@ def to_valid_filename(name):
|
|||||||
|
|
||||||
# https://github.com/yt-dlp/yt-dlp/blob/master/yt_dlp/extractor/youtube.py#L72
|
# https://github.com/yt-dlp/yt-dlp/blob/master/yt_dlp/extractor/youtube.py#L72
|
||||||
INNERTUBE_CLIENTS = {
|
INNERTUBE_CLIENTS = {
|
||||||
|
'web_creator': {
|
||||||
|
'INNERTUBE_API_KEY': 'AIzaSyBUPetSUmoZL-OhlxA7wSac5XinrygCqMo',
|
||||||
|
'INNERTUBE_CONTEXT': {
|
||||||
|
'client': {
|
||||||
|
'clientName': 'WEB_CREATOR',
|
||||||
|
'clientVersion': '1.20240723.03.00',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'INNERTUBE_CONTEXT_CLIENT_NAME': 62,
|
||||||
|
},
|
||||||
'android': {
|
'android': {
|
||||||
'INNERTUBE_API_KEY': 'AIzaSyA8eiZmM1FaDVjRy-df2KTyQ_vz_yYM39w',
|
'INNERTUBE_API_KEY': 'AIzaSyA8eiZmM1FaDVjRy-df2KTyQ_vz_yYM39w',
|
||||||
'INNERTUBE_CONTEXT': {
|
'INNERTUBE_CONTEXT': {
|
||||||
@@ -674,21 +684,37 @@ INNERTUBE_CLIENTS = {
|
|||||||
'hl': 'en',
|
'hl': 'en',
|
||||||
'gl': 'US',
|
'gl': 'US',
|
||||||
'clientName': 'ANDROID',
|
'clientName': 'ANDROID',
|
||||||
'clientVersion': '17.31.35',
|
'clientVersion': '19.15.35',
|
||||||
'osName': 'Android',
|
'osName': 'Android',
|
||||||
'osVersion': '12',
|
'osVersion': '14',
|
||||||
'androidSdkVersion': 31,
|
'androidSdkVersion': 34,
|
||||||
'userAgent': 'com.google.android.youtube/17.31.35 (Linux; U; Android 12) gzip'
|
'platform': 'MOBILE',
|
||||||
},
|
'userAgent': 'com.google.android.youtube/19.15.35 (Linux; U; Android 14; en_US; Google Pixel 6 Pro) gzip'
|
||||||
# https://github.com/yt-dlp/yt-dlp/pull/575#issuecomment-887739287
|
}
|
||||||
#'thirdParty': {
|
|
||||||
# 'embedUrl': 'https://google.com', # Can be any valid URL
|
|
||||||
#}
|
|
||||||
},
|
},
|
||||||
'INNERTUBE_CONTEXT_CLIENT_NAME': 3,
|
'INNERTUBE_CONTEXT_CLIENT_NAME': 3,
|
||||||
'REQUIRE_JS_PLAYER': False,
|
'REQUIRE_JS_PLAYER': False,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
'ios': {
|
||||||
|
'INNERTUBE_API_KEY': 'AIzaSyB-63vPrdThhKuerbB2N_l7Kwwcxj6yUAc',
|
||||||
|
'INNERTUBE_CONTEXT': {
|
||||||
|
'client': {
|
||||||
|
'hl': 'en',
|
||||||
|
'gl': 'US',
|
||||||
|
'clientName': 'IOS',
|
||||||
|
'clientVersion': '19.29.1',
|
||||||
|
'deviceMake': 'Apple',
|
||||||
|
'deviceModel': 'iPhone16,2',
|
||||||
|
'userAgent': 'com.google.ios.youtube/19.29.1 (iPhone16,2; U; CPU iOS 17_5_1 like Mac OS X;)',
|
||||||
|
'osName': 'iPhone',
|
||||||
|
'osVersion': '17.5.1.21F90',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'INNERTUBE_CONTEXT_CLIENT_NAME': 5,
|
||||||
|
'REQUIRE_JS_PLAYER': False
|
||||||
|
},
|
||||||
|
|
||||||
# This client can access age restricted videos (unless the uploader has disabled the 'allow embedding' option)
|
# This client can access age restricted videos (unless the uploader has disabled the 'allow embedding' option)
|
||||||
# See: https://github.com/zerodytrash/YouTube-Internal-Clients
|
# See: https://github.com/zerodytrash/YouTube-Internal-Clients
|
||||||
'tv_embedded': {
|
'tv_embedded': {
|
||||||
@@ -699,6 +725,7 @@ INNERTUBE_CLIENTS = {
|
|||||||
'gl': 'US',
|
'gl': 'US',
|
||||||
'clientName': 'TVHTML5_SIMPLY_EMBEDDED_PLAYER',
|
'clientName': 'TVHTML5_SIMPLY_EMBEDDED_PLAYER',
|
||||||
'clientVersion': '2.0',
|
'clientVersion': '2.0',
|
||||||
|
'clientScreen': 'EMBED',
|
||||||
},
|
},
|
||||||
# https://github.com/yt-dlp/yt-dlp/pull/575#issuecomment-887739287
|
# https://github.com/yt-dlp/yt-dlp/pull/575#issuecomment-887739287
|
||||||
'thirdParty': {
|
'thirdParty': {
|
||||||
@@ -715,7 +742,7 @@ INNERTUBE_CLIENTS = {
|
|||||||
'INNERTUBE_CONTEXT': {
|
'INNERTUBE_CONTEXT': {
|
||||||
'client': {
|
'client': {
|
||||||
'clientName': 'WEB',
|
'clientName': 'WEB',
|
||||||
'clientVersion': '2.20220801.00.00',
|
'clientVersion': '2.20240327.00.00',
|
||||||
'userAgent': desktop_user_agent,
|
'userAgent': desktop_user_agent,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
__version__ = '0.2.7'
|
__version__ = '0.2.19'
|
||||||
|
|||||||
@@ -343,7 +343,7 @@ def _add_to_error(info, key, additional_message):
|
|||||||
def fetch_player_response(client, video_id):
|
def fetch_player_response(client, video_id):
|
||||||
return util.call_youtube_api(client, 'player', {
|
return util.call_youtube_api(client, 'player', {
|
||||||
'videoId': video_id,
|
'videoId': video_id,
|
||||||
'params': 'CgIQBg',
|
'params': 'CgIIAdgDAQ==',
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
@@ -372,17 +372,7 @@ def extract_info(video_id, use_invidious, playlist_id=None, index=None):
|
|||||||
tasks = (
|
tasks = (
|
||||||
# Get video metadata from here
|
# Get video metadata from here
|
||||||
gevent.spawn(fetch_watch_page_info, video_id, playlist_id, index),
|
gevent.spawn(fetch_watch_page_info, video_id, playlist_id, index),
|
||||||
|
gevent.spawn(fetch_player_response, 'ios', video_id)
|
||||||
# Get video URLs by spoofing as android client because its urls don't
|
|
||||||
# require decryption
|
|
||||||
# The URLs returned with WEB for videos requiring decryption
|
|
||||||
# couldn't be decrypted with the base.js from the web page for some
|
|
||||||
# reason
|
|
||||||
# https://github.com/yt-dlp/yt-dlp/issues/574#issuecomment-887171136
|
|
||||||
|
|
||||||
# Update 4/26/23, these URLs will randomly start returning 403
|
|
||||||
# mid-playback and I'm not sure why
|
|
||||||
gevent.spawn(fetch_player_response, 'android', video_id)
|
|
||||||
)
|
)
|
||||||
gevent.joinall(tasks)
|
gevent.joinall(tasks)
|
||||||
util.check_gevent_exceptions(*tasks)
|
util.check_gevent_exceptions(*tasks)
|
||||||
|
|||||||
Reference in New Issue
Block a user