Fix preview control layers and centred settings icons in YouTubeDL 1.4.6
This commit is contained in:
1 parent
5f2aad00f4
commit
a4b8a1c469
13 files changed
+102
-25
No files matched your search
+1
-1
@@ -24,7 +24,7 @@ npm run check
|
||||
python tools/build.py
|
||||
```
|
||||
|
||||
`tools/build.py` собирает небольшой `dist/YouTubeDL-1.4.5.zip` без EXE.
|
||||
`tools/build.py` собирает небольшой `dist/YouTubeDL-1.4.6.zip` без EXE.
|
||||
Для сборки расширения не требуется предварительно собирать помощник.
|
||||
|
||||
## Браузерные проверки
|
||||
|
||||
+3
-3
@@ -6,7 +6,7 @@ Firefox, macOS, Linux и Windows ARM не входят в эту сборку.
|
||||
Скачивания доступны в [релизах проекта](https://git.lonarpgproxy.space/OwnerLink/YouTubeDL/releases/latest).
|
||||
Помощник распространяется **отдельно**: внутри архива расширения EXE нет.
|
||||
|
||||
1. Скачайте **YouTubeDL-1.4.5.zip** и распакуйте его в постоянную папку. Не удаляйте и не перемещайте её после установки.
|
||||
1. Скачайте **YouTubeDL-1.4.6.zip** и распакуйте его в постоянную папку. Не удаляйте и не перемещайте её после установки.
|
||||
2. Откройте `edge://extensions` или `chrome://extensions`. Включите **Режим разработчика**, нажмите **Загрузить распакованное расширение** и выберите папку **extension** внутри распакованного архива.
|
||||
3. На странице релиза отдельно скачайте **YouTubeDL-Helper-Setup.exe**. Это автономный комплект: Python, yt-dlp, EJS, Node.js, FFmpeg и FFprobe уже внутри.
|
||||
4. Запустите EXE вручную и дождитесь окончания установки. Администратор и интернет для установки комплекта не требуются. Программы устанавливаются для текущего пользователя в `%LOCALAPPDATA%\YouTubeDL\Helper`.
|
||||
@@ -59,7 +59,7 @@ Get-FileHash -Algorithm SHA256 -LiteralPath '.\YouTubeDL-Helper-Setup.exe'
|
||||
|
||||
При разных дисках результат сначала копируется во временную папку на диске сохранения, затем публикуется под итоговым именем. Прогресс копирования виден в уведомлении; частичный файл не появляется под готовым именем. При отмене помощник завершает группу процессов данной задачи и удаляет её временные папки.
|
||||
|
||||
Для отдельной рабочей папки, подробного прогресса слияния и исправленной отмены установите помощник 1.3.2 и расширение 1.4.5. Обновление компонентов не заменяет программный код помощника; для этой версии запустите новый установщик помощника.
|
||||
Для отдельной рабочей папки, подробного прогресса слияния и исправленной отмены установите помощник 1.3.2 и расширение 1.4.6. Обновление компонентов не заменяет программный код помощника; для этой версии запустите новый установщик помощника.
|
||||
|
||||
## История и ошибки
|
||||
|
||||
@@ -69,7 +69,7 @@ Get-FileHash -Algorithm SHA256 -LiteralPath '.\YouTubeDL-Helper-Setup.exe'
|
||||
|
||||
## Совместимость версий
|
||||
|
||||
В настройках и мастере первого запуска отображаются версии расширения и помощника. Расширение 1.4.5 поддерживает помощник 1.3.2. При старом помощнике появится кнопка «Обновить помощник», при более новом помощнике или устаревшем расширении — «Обновить расширение». Пока совместимость не подтверждена, новая загрузка не запускается.
|
||||
В настройках и мастере первого запуска отображаются версии расширения и помощника. Расширение 1.4.6 поддерживает помощник 1.3.2. При старом помощнике появится кнопка «Обновить помощник», при более новом помощнике или устаревшем расширении — «Обновить расширение». Пока совместимость не подтверждена, новая загрузка не запускается.
|
||||
|
||||
После установки помощника нажмите «Проверить»: статус изменится без перезагрузки страницы. После замены файлов расширения нажмите «Обновить» на странице расширений браузера и перезагрузите вкладку YouTube. Обновление компонентов обновляет инструменты внутри комплекта и не заменяет само расширение или код помощника.
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
**[Инструкция](INSTALL.md)** · **[Обработка данных](PRIVACY.md)** ·
|
||||
**[Сообщить об ошибке](https://git.lonarpgproxy.space/OwnerLink/YouTubeDL/issues)**
|
||||
|
||||
Windows 10/11 x64 · Microsoft Edge / Google Chrome 120+ · расширение **1.4.5** · помощник **1.3.2**.
|
||||
Windows 10/11 x64 · Microsoft Edge / Google Chrome 120+ · расширение **1.4.6** · помощник **1.3.2**.
|
||||
Расширение устанавливается распакованным, через режим разработчика. В магазинах браузеров пока не опубликовано.
|
||||
|
||||
## Что умеет
|
||||
@@ -38,7 +38,7 @@ DRM-контент и гарантированный обход ограниче
|
||||
|
||||
## Установка: два отдельных скачивания
|
||||
|
||||
1. Откройте [последний релиз](https://git.lonarpgproxy.space/OwnerLink/YouTubeDL/releases/latest), скачайте **YouTubeDL-1.4.5.zip** и распакуйте в постоянную папку.
|
||||
1. Откройте [последний релиз](https://git.lonarpgproxy.space/OwnerLink/YouTubeDL/releases/latest), скачайте **YouTubeDL-1.4.6.zip** и распакуйте в постоянную папку.
|
||||
2. В `edge://extensions` или `chrome://extensions` включите **Режим разработчика**, нажмите **Загрузить распакованное расширение** и выберите папку **extension**.
|
||||
3. **Отдельно скачайте YouTubeDL-Helper-Setup.exe из того же релиза** и запустите его вручную. EXE не встроен в расширение: кнопка установки открывает страницу релизов.
|
||||
4. Обновите YouTube, откройте **⚙** и пройдите мастер. Выберите папку и параметры; зелёный статус подтверждает связь с помощником.
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
# YouTubeDL 1.4.6
|
||||
|
||||
Расширение **1.4.6** для Edge и Chrome 120+. Совместимый локальный помощник — **1.3.2**.
|
||||
|
||||
- Исправлено перекрытие: кнопки на обычных превью и Shorts больше не появляются поверх уведомлений и меню YouTube.
|
||||
- Значок настроек заменён симметричной шестерёнкой с окружностью по центру на всех кнопках, включая превью видео и Shorts.
|
||||
- Кнопки остаются доступны при замене превью Shorts проигрываемым видео.
|
||||
|
||||
## Обновление
|
||||
|
||||
1. Скачайте **YouTubeDL-1.4.6.zip** и распакуйте в постоянную папку, заменив прежнюю папку `extension`.
|
||||
2. Откройте `chrome://extensions` или `edge://extensions` и перезагрузите YouTubeDL. Если устанавливаете впервые, включите режим разработчика и выберите «Загрузить распакованное расширение» → папку `extension`.
|
||||
3. Обновите уже открытые страницы YouTube. В настройках расширения должна отображаться версия **1.4.6**.
|
||||
|
||||
Установленный помощник **1.3.2** обновлять не требуется. Для первой установки его EXE доступен отдельно в этом релизе.
|
||||
|
||||
## Проверка
|
||||
|
||||
Проверены слои кнопок, обычные и Shorts-превью, замена превью плеером, центр значка настроек, меню и совместимость помощника в Edge. Документы и служебные файлы находятся в сворачиваемом разделе загрузок.
|
||||
Vendored
+7
-4
@@ -6,8 +6,11 @@
|
||||
const previewResize = new ResizeObserver(schedulePreviewLayout);
|
||||
let watchButton = null, shortsButton = null, shortsRenderer = null;
|
||||
let menu = null, menuAnchor = null, menuSize = { width: 270, height: 142 };
|
||||
// Above hover playback, below YouTube's masthead (2020) and popups (2202).
|
||||
// Shorts controls live at the document root to survive preview replacement.
|
||||
const pageControlLayer = 2000;
|
||||
const icon = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3v12m-5-5 5 5 5-5M4 17v4h16v-4"/></svg>';
|
||||
const gear = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m9 3-.6 2.4-2.1 1.2L4 6l-2 3.5 1.8 1.7v2.4L2 15.3 4 19l2.3-.6 2.1 1.2L9 22h4l.6-2.4 2.1-1.2 2.3.6 2-3.7-1.8-1.7v-2.4L20 9.5 18 6l-2.3.6-2.1-1.2L13 3Z" transform="translate(1 -.5) scale(.95)"/><circle cx="12" cy="12" r="3"/></svg>';
|
||||
const gear = "<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.8\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><path d=\"M8.939 4.609L10.2 4.205L10.264 2.152L13.736 2.152L13.8 4.205L15.061 4.609L16.239 5.216L17.736 3.808L20.192 6.264L18.784 7.761L19.391 8.939L19.795 10.2L21.848 10.264L21.848 13.736L19.795 13.8L19.391 15.061L18.784 16.239L20.192 17.736L17.736 20.192L16.239 18.784L15.061 19.391L13.8 19.795L13.736 21.848L10.264 21.848L10.2 19.795L8.939 19.391L7.761 18.784L6.264 20.192L3.808 17.736L5.216 16.239L4.609 15.061L4.205 13.8L2.152 13.736L2.152 10.264L4.205 10.2L4.609 8.939L5.216 7.761L3.808 6.264L6.264 3.808L7.761 5.216L8.939 4.609Z\"/><circle cx=\"12\" cy=\"12\" r=\"3\"/></svg>";
|
||||
const themeStyle = ':host{font-family:Roboto,"Segoe UI",sans-serif;--bg:#fff;--fg:#0f0f0f;--muted:#606060;--button:#0000000d;--hover:#0000001a;--pressed:#00000026;--line:#0000001a}:host([dark]){--bg:#212121;--fg:#f1f1f1;--muted:#aaa;--button:#ffffff1a;--hover:#ffffff33;--pressed:#ffffff40;--line:#ffffff1a}*{box-sizing:border-box}button{font:inherit;cursor:pointer}';
|
||||
const dark = () => document.documentElement.hasAttribute('dark') || document.documentElement.dataset.theme === 'dark';
|
||||
function canonical(value) {
|
||||
@@ -73,7 +76,7 @@
|
||||
function makeControl(kind, resolveUrl) {
|
||||
const host = document.createElement('span'); host.dataset.ytdlControl = 'true'; host.dataset.kind = kind;
|
||||
const shadow = host.attachShadow({ mode: 'open' });
|
||||
shadow.innerHTML = `<style>${themeStyle}.pair{display:flex;align-items:center;gap:6px}button{display:flex;align-items:center;justify-content:center;gap:6px;height:36px;padding:0 16px;border:0;border-radius:999px;background:var(--button);color:var(--fg);font-size:14px;font-weight:500;white-space:nowrap}button:hover{background:var(--hover)}button:active{background:var(--pressed)}button:focus-visible{outline:2px solid var(--fg);outline-offset:2px}.glyph{display:grid;place-items:center}svg{width:20px;height:20px}.settings{width:36px;padding:0}:host([data-kind=thumbnail]) button{width:34px;height:34px;padding:0;background:#0f0f0fbb;color:#fff;box-shadow:0 1px 5px #0003}:host([data-kind=thumbnail]) button:hover{background:#303030}:host([data-kind=thumbnail]) .label{display:none}:host([data-kind=shorts]) .pair{flex-direction:column;gap:9px}:host([data-kind=shorts]) .download{background:transparent;height:auto;padding:0;flex-direction:column;gap:6px;color:var(--fg)}:host([data-kind=shorts]) .glyph{width:48px;height:48px;border-radius:50%;background:var(--button)}:host([data-kind=shorts]) .download:hover .glyph{background:var(--hover)}:host([data-kind=shorts]) .download:active .glyph{background:var(--pressed)}:host([data-kind=shorts]) svg{width:24px;height:24px}:host([data-kind=shorts]) .settings svg{width:19px;height:19px}:host([data-kind=shorts]) .label{font-size:12px}</style><div class="pair"><button class="download" type="button" title="Скачать по сохранённым настройкам" aria-label="Скачать по сохранённым настройкам"><span class="glyph">${icon}</span><span class="label">Скачать</span></button><button class="settings" type="button" title="Настройки скачивания" aria-label="Настройки скачивания">${gear}</button></div>`;
|
||||
shadow.innerHTML = `<style>${themeStyle}.pair{display:flex;align-items:center;gap:6px}button{display:flex;align-items:center;justify-content:center;gap:6px;height:36px;padding:0 16px;border:0;border-radius:999px;background:var(--button);color:var(--fg);font-size:14px;font-weight:500;white-space:nowrap}button:hover{background:var(--hover)}button:active{background:var(--pressed)}button:focus-visible{outline:2px solid var(--fg);outline-offset:2px}.glyph{display:grid;place-items:center}svg{display:block;flex-shrink:0;width:20px;height:20px}.settings{width:36px;padding:0}:host([data-kind=thumbnail]) button{width:34px;height:34px;padding:0;background:#0f0f0fbb;color:#fff;box-shadow:0 1px 5px #0003}:host([data-kind=thumbnail]) button:hover{background:#303030}:host([data-kind=thumbnail]) .label{display:none}:host([data-kind=shorts]) .pair{flex-direction:column;gap:9px}:host([data-kind=shorts]) .download{background:transparent;height:auto;padding:0;flex-direction:column;gap:6px;color:var(--fg)}:host([data-kind=shorts]) .glyph{width:48px;height:48px;border-radius:50%;background:var(--button)}:host([data-kind=shorts]) .download:hover .glyph{background:var(--hover)}:host([data-kind=shorts]) .download:active .glyph{background:var(--pressed)}:host([data-kind=shorts]) svg{width:24px;height:24px}:host([data-kind=shorts]) .settings svg{width:19px;height:19px}:host([data-kind=shorts]) .label{font-size:12px}</style><div class="pair"><button class="download" type="button" title="Скачать по сохранённым настройкам" aria-label="Скачать по сохранённым настройкам"><span class="glyph">${icon}</span><span class="label">Скачать</span></button><button class="settings" type="button" title="Настройки скачивания" aria-label="Настройки скачивания">${gear}</button></div>`;
|
||||
for (const button of shadow.querySelectorAll('button')) {
|
||||
button.addEventListener('pointerdown', event => { event.stopPropagation(); });
|
||||
button.addEventListener('keydown', event => { event.stopPropagation(); });
|
||||
@@ -206,7 +209,7 @@
|
||||
});
|
||||
host.className = 'ytdl-thumbnail-download';
|
||||
const key = `ytdl-preview-${++previewSequence}`; root.dataset.ytdlPreview = key; host.dataset.ytdlPreviewFor = key;
|
||||
host.style.cssText = `position:${card ? 'fixed' : 'absolute'};left:0;top:0;width:74px;height:34px;margin:0;padding:0;line-height:1;z-index:2147483644;display:inline-flex`;
|
||||
host.style.cssText = `position:${card ? 'fixed' : 'absolute'};left:0;top:0;width:74px;height:34px;margin:0;padding:0;line-height:1;z-index:${pageControlLayer};display:inline-flex`;
|
||||
if (card) document.documentElement.append(host);
|
||||
else {
|
||||
if (getComputedStyle(root).position === 'static') root.style.position = 'relative';
|
||||
@@ -233,7 +236,7 @@
|
||||
shortsButton.style.cssText = 'display:flex;justify-content:center;margin-top:16px;flex-shrink:0';
|
||||
rail.append(shortsButton);
|
||||
} else {
|
||||
shortsButton.style.cssText = 'position:fixed;right:16px;bottom:180px;z-index:2147483645;display:inline-flex';
|
||||
shortsButton.style.cssText = `position:fixed;right:16px;bottom:180px;z-index:${pageControlLayer};display:inline-flex`;
|
||||
document.documentElement.append(shortsButton);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"manifest_version": 3,
|
||||
"name": "YouTubeDL",
|
||||
"description": "Скачать видео и аудио с YouTube: качество, формат, папка, NVIDIA NVENC и AMD AMF.",
|
||||
"version": "1.4.5",
|
||||
"version": "1.4.6",
|
||||
"minimum_chrome_version": "120",
|
||||
"key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6bCUFVUmC9OqpL0+/vrQDKEesuiylybHxRWJXfMV7VfctMbDjAQzActxImzMGIviC8PJrCHT86v/erppUhIgqFrSftHVPPWmYbVJ/g6KBu1bRNIG5J1WDUnMO2E4hGNEJQe+6ezqGuGdk659qQOqP5khGbnog9wUs+1nPpolaXbXsUudn5leaxJ0SrdFT9oWjq59bAc7raEKjR1chU9pB9g9alEA8lqpcKUU8j7f/KJC9YvkOlTNEsLXhuLLzcC7Aw/eI3lgBqBLFWIcrEYrBPVFeIlNaVLdl6b8YqAD+eBaT1xdpT6VbGh/d3lf/Vq/TBzTzCplcMO2vIFGDKTNhQIDAQAB",
|
||||
"permissions": [
|
||||
|
||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "youtubedl",
|
||||
"version": "1.4.5",
|
||||
"version": "1.4.6",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "youtubedl",
|
||||
"version": "1.4.5",
|
||||
"version": "1.4.6",
|
||||
"license": "SEE LICENSE IN LICENSE",
|
||||
"devDependencies": {
|
||||
"playwright": "^1.64.0"
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "youtubedl",
|
||||
"version": "1.4.5",
|
||||
"version": "1.4.6",
|
||||
"license": "SEE LICENSE IN LICENSE",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
|
||||
+3
-3
@@ -40,7 +40,7 @@
|
||||
<div class="hero-actions"><a class="button primary" href="#install">Установить расширение <span aria-hidden="true">↓</span></a><a class="hero-link" href="#features">Посмотреть возможности <span aria-hidden="true">↗</span></a></div>
|
||||
<p class="hero-note">Бесплатно · Для Windows · Обработка на вашем компьютере</p>
|
||||
</div>
|
||||
<div class="hero-bottom"><span>ВИДЕО. ЗВУК. ВАШ ВЫБОР.</span><a href="https://git.lonarpgproxy.space/OwnerLink/YouTubeDL/releases/tag/v1.4.5">Выпуск 1.4.5 <span aria-hidden="true">↗</span></a></div>
|
||||
<div class="hero-bottom"><span>ВИДЕО. ЗВУК. ВАШ ВЫБОР.</span><a href="https://git.lonarpgproxy.space/OwnerLink/YouTubeDL/releases/tag/v1.4.6">Выпуск 1.4.6 <span aria-hidden="true">↗</span></a></div>
|
||||
</div>
|
||||
</section>
|
||||
<div class="format-strip"><div class="wrap"><p>Один ролик.<br><strong>Ваш формат.</strong></p><div class="format-list" aria-label="Форматы"><span>MP4</span><span>MKV</span><span>WebM</span><i aria-hidden="true"></i><span>MP3</span><span>M4A</span><span>Opus</span><span>FLAC</span><span>WAV</span></div></div></div>
|
||||
@@ -70,8 +70,8 @@
|
||||
<section class="install-section" id="install" aria-labelledby="install-title"><div class="wrap">
|
||||
<div class="install-heading reveal"><div><p class="overline">04 / НАЧНЁМ</p><h2 id="install-title">Два скачивания.<br><em>Один комплект.</em></h2></div><p>Windows 10/11 x64<br>Edge или Chrome 120+<br><span>Без прав администратора</span></p></div>
|
||||
<div class="download-grid reveal">
|
||||
<article class="download-card"><div class="download-card-top"><span class="package-number">1</span><span class="package-tag">БРАУЗЕР</span><span class="version">v1.4.5</span></div><h3>Расширение</h3><p>Кнопки на YouTube, настройки и уведомления. Устанавливается распакованным.</p><a class="button primary package-link" data-download="extension" href="https://git.lonarpgproxy.space/OwnerLink/YouTubeDL/releases/download/v1.4.5/YouTubeDL-1.4.5.zip">Скачать расширение <span aria-hidden="true">↓</span></a><small>ZIP · <span id="extension-size">Небольшой архив</span></small></article>
|
||||
<article class="download-card helper-card"><div class="download-card-top"><span class="package-number">2</span><span class="package-tag">КОМПЬЮТЕР</span><span class="version">v1.3.2</span></div><h3>Локальный помощник</h3><p>Скачивает, соединяет и конвертирует. Все необходимые компоненты уже внутри.</p><a class="button secondary package-link" data-download="helper" href="https://git.lonarpgproxy.space/OwnerLink/YouTubeDL/releases/download/v1.4.5/YouTubeDL-Helper-Setup.exe">Скачать помощник <span aria-hidden="true">↓</span></a><small>EXE · 124,3 МиБ · устанавливается отдельно</small></article>
|
||||
<article class="download-card"><div class="download-card-top"><span class="package-number">1</span><span class="package-tag">БРАУЗЕР</span><span class="version">v1.4.6</span></div><h3>Расширение</h3><p>Кнопки на YouTube, настройки и уведомления. Устанавливается распакованным.</p><a class="button primary package-link" data-download="extension" href="https://git.lonarpgproxy.space/OwnerLink/YouTubeDL/releases/download/v1.4.6/YouTubeDL-1.4.6.zip">Скачать расширение <span aria-hidden="true">↓</span></a><small>ZIP · <span id="extension-size">Небольшой архив</span></small></article>
|
||||
<article class="download-card helper-card"><div class="download-card-top"><span class="package-number">2</span><span class="package-tag">КОМПЬЮТЕР</span><span class="version">v1.3.2</span></div><h3>Локальный помощник</h3><p>Скачивает, соединяет и конвертирует. Все необходимые компоненты уже внутри.</p><a class="button secondary package-link" data-download="helper" href="https://git.lonarpgproxy.space/OwnerLink/YouTubeDL/releases/download/v1.4.6/YouTubeDL-Helper-Setup.exe">Скачать помощник <span aria-hidden="true">↓</span></a><small>EXE · 124,3 МиБ · устанавливается отдельно</small></article>
|
||||
</div>
|
||||
<p class="download-note">Оба файла размещены в <a href="https://git.lonarpgproxy.space/OwnerLink/YouTubeDL/releases/latest">релизах Gitea ↗</a>. Помощник не встроен в ZIP. <a href="https://git.lonarpgproxy.space/OwnerLink/YouTubeDL/src/branch/main/INSTALL.md#проверка-скачанных-файлов">Проверка SHA256 и подробности</a>.</p>
|
||||
<ol class="install-steps reveal">
|
||||
|
||||
+1
-1
@@ -35,7 +35,7 @@ try {
|
||||
assert.equal(new URL(page.url()).hash,"#install");
|
||||
assert.ok(await page.locator(".download-grid").isVisible());
|
||||
assert.equal(await page.locator('[data-download="extension"]').getAttribute("href"),`https://git.lonarpgproxy.space/OwnerLink/YouTubeDL/releases/download/v${version}/YouTubeDL-${version}.zip`);
|
||||
assert.equal(await page.locator('[data-download="helper"]').getAttribute("href"),"https://git.lonarpgproxy.space/OwnerLink/YouTubeDL/releases/download/v1.4.5/YouTubeDL-Helper-Setup.exe");
|
||||
assert.equal(await page.locator('[data-download="helper"]').getAttribute("href"),"https://git.lonarpgproxy.space/OwnerLink/YouTubeDL/releases/download/v1.4.6/YouTubeDL-Helper-Setup.exe");
|
||||
await page.locator('[data-screenshot="light"]').click();
|
||||
await page.locator("#menu-screenshot").evaluate(image => image.decode());
|
||||
assert.match(await page.locator("#menu-screenshot").getAttribute("src"), /menu-light\.png$/);
|
||||
|
||||
@@ -8,7 +8,7 @@ const root = path.dirname(path.dirname(fileURLToPath(import.meta.url)));
|
||||
const artifacts = path.join(root, "test-artifacts");
|
||||
await fs.mkdir(artifacts, { recursive: true });
|
||||
const browser = await chromium.launch({ headless: true, executablePath: "C:/Program Files (x86)/Microsoft/Edge/Application/msedge.exe" });
|
||||
const context = await browser.newContext({ viewport: { width: 1200, height: 800 }, reducedMotion: "reduce" });
|
||||
const context = await browser.newContext({ viewport: { width: 1200, height: 800 }, reducedMotion: "reduce", deviceScaleFactor: Number(process.env.YTDL_TEST_SCALE || 1) });
|
||||
await context.addInitScript({ path: path.join(root, "tests/ui-fixture.js") });
|
||||
const poster = 'data:image/svg+xml,' + encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" width="330" height="186"><defs><linearGradient id="g"><stop stop-color="#096574"/><stop offset="1" stop-color="#192636"/></linearGradient></defs><path fill="url(#g)" d="M0 0h330v186H0z"/></svg>');
|
||||
await context.route("https://www.youtube.com/**", route => route.fulfill({ contentType: "text/html", body: `<!doctype html><html dark><head><meta charset="utf-8"><style>
|
||||
@@ -42,6 +42,42 @@ try {
|
||||
for (const id of ["short-card", "legacy-card", "modern-card"]) {
|
||||
await page.locator(`#${id} [data-ytdl-preview], #${id}[data-ytdl-preview]`).waitFor(); await assertInside(id);
|
||||
}
|
||||
// YouTube's native notification/account dropdowns are fixed at z-index 2202.
|
||||
// Both the Shorts portal and regular thumbnail controls must stay beneath them.
|
||||
await page.evaluate(() => {
|
||||
const container = document.createElement('ytd-popup-container');
|
||||
container.style.cssText = 'position:absolute;inset:0 0 auto';
|
||||
container.innerHTML = '<tp-yt-iron-dropdown id="native-popup" style="position:fixed;left:12px;top:56px;width:1100px;height:300px;z-index:2202;background:#282828;color:white;border-radius:12px;padding:16px;box-sizing:border-box"><h2>Уведомления YouTube</h2><p>Новые видео и трансляции</p></tp-yt-iron-dropdown>';
|
||||
document.body.append(container);
|
||||
});
|
||||
for (const id of ['short-card', 'legacy-card', 'modern-card']) {
|
||||
const covered = await page.locator(`#${id}`).evaluate(card => {
|
||||
const owner = card.dataset.ytdlPreview || card.querySelector('[data-ytdl-preview]')?.dataset.ytdlPreview;
|
||||
const host = document.querySelector(`[data-ytdl-preview-for="${owner}"]`);
|
||||
return [...host.shadowRoot.querySelectorAll('button')].every(button => {
|
||||
const rect = button.getBoundingClientRect();
|
||||
return !!document.elementFromPoint(rect.x + rect.width / 2, rect.y + rect.height / 2)?.closest('#native-popup');
|
||||
});
|
||||
});
|
||||
assert.equal(covered, true, `Native YouTube popup must cover both controls on ${id}`);
|
||||
}
|
||||
await page.screenshot({ path: path.join(artifacts, 'thumbnail-native-popup.png'), animations: 'disabled' });
|
||||
await page.evaluate(() => document.querySelector('ytd-popup-container').remove());
|
||||
// Closing the popup must restore interaction without a page refresh.
|
||||
const legacyOwner = await page.locator('#legacy-card [data-ytdl-preview]').getAttribute('data-ytdl-preview');
|
||||
await page.locator(`[data-ytdl-preview-for="${legacyOwner}"] .download`).click();
|
||||
assert.equal(await page.evaluate(() => window.__quickRequests.at(-1)), 'https://www.youtube.com/watch?v=jNQXAC9IVRw');
|
||||
// Compare the actual rendered centres, including any SVG transforms.
|
||||
const gearCentres = await page.locator('.ytdl-thumbnail-download .settings svg').evaluateAll(svgs => svgs.map(svg => {
|
||||
const outline = svg.querySelector('path'), circle = svg.querySelector('circle'), box = outline.getBBox();
|
||||
const outer = new DOMPoint(box.x + box.width / 2, box.y + box.height / 2).matrixTransform(outline.getCTM());
|
||||
const inner = new DOMPoint(circle.cx.baseVal.value, circle.cy.baseVal.value).matrixTransform(circle.getCTM());
|
||||
const button = svg.closest('button').getBoundingClientRect(), hole = circle.getBoundingClientRect();
|
||||
return { outer: { x: outer.x, y: outer.y }, inner: { x: inner.x, y: inner.y }, button: { x: button.x + button.width / 2, y: button.y + button.height / 2 }, hole: { x: hole.x + hole.width / 2, y: hole.y + hole.height / 2 } };
|
||||
}));
|
||||
assert.equal(gearCentres.length, 3, 'Check regular, modern and Shorts thumbnail gears');
|
||||
assert.ok(gearCentres.every(gear => Math.abs(gear.outer.x - gear.inner.x) < .01 && Math.abs(gear.outer.y - gear.inner.y) < .01 && Math.abs(gear.button.x - gear.hole.x) < .01 && Math.abs(gear.button.y - gear.hole.y) < .01),
|
||||
`Settings gear must have concentric outline and hole: ${JSON.stringify(gearCentres)}`);
|
||||
// The real YouTube app is absolutely positioned: BODY has zero height, and
|
||||
// its scroll/auto overflow is propagated to the viewport, not a zero-size clip.
|
||||
await page.evaluate(() => {
|
||||
@@ -134,6 +170,25 @@ try {
|
||||
assert.equal(await shortButtons.isVisible(),true);
|
||||
await page.evaluate(() => document.querySelector('#short-card').remove());
|
||||
await shortButtons.waitFor({state:'detached'});
|
||||
// The standalone Shorts page can temporarily lack its native action rail.
|
||||
// Its fixed fallback controls must follow the same popup layering rule.
|
||||
await page.setViewportSize({width:1200,height:800});
|
||||
await page.goto('https://www.youtube.com/shorts/Mf9GCn_LsUI');
|
||||
await page.addScriptTag({ path: path.join(root, 'extension/controls.js') });
|
||||
const fallback = page.locator('#ytdl-shorts-download');
|
||||
await fallback.waitFor({state:'visible'});
|
||||
await page.evaluate(() => {
|
||||
const popup = document.createElement('tp-yt-iron-dropdown'); popup.id = 'native-popup';
|
||||
popup.style.cssText = 'position:fixed;inset:56px 0 0;z-index:2202;background:#282828';
|
||||
document.body.append(popup);
|
||||
});
|
||||
assert.equal(await fallback.evaluate(host => [...host.shadowRoot.querySelectorAll('button')].every(button => {
|
||||
const rect = button.getBoundingClientRect();
|
||||
return document.elementFromPoint(rect.x + rect.width / 2, rect.y + rect.height / 2)?.id === 'native-popup';
|
||||
})), true, 'Native popup must also cover standalone Shorts fallback controls');
|
||||
await page.evaluate(() => document.querySelector('#native-popup').remove());
|
||||
await fallback.locator('.download').click();
|
||||
assert.equal(await page.evaluate(() => window.__quickRequests.at(-1)), 'https://www.youtube.com/watch?v=Mf9GCn_LsUI');
|
||||
assert.deepEqual(errors, []);
|
||||
console.log('Thumbnail placement passed: real YouTube zero-height BODY, image bounds, title links, padding, borders, scaled layout, replaced/hidden/removed hover previews, responsive/lazy sizing, scroll, clipped shelves and recycled URLs.');
|
||||
console.log('Thumbnail placement passed: native popup occlusion, centred settings gear, real YouTube zero-height BODY, image bounds, title links, padding, borders, scaled layout, replaced/hidden/removed hover previews, responsive/lazy sizing, scroll, clipped shelves and recycled URLs.');
|
||||
} finally { await browser.close(); }
|
||||
+1
-1
@@ -31,7 +31,7 @@
|
||||
], audios: [{ id: "251", codec: "opus", extension: "webm", bitrate: 160, language: "en", note: "English", size: 5000000 }] };
|
||||
window.chrome = {
|
||||
runtime: {
|
||||
getManifest: () => ({ version: window.__extensionVersion || "1.4.5" }),
|
||||
getManifest: () => ({ version: window.__extensionVersion || "1.4.6" }),
|
||||
getURL: file => `https://ui.ytdl.test/${file}`,
|
||||
sendMessage: async message => {
|
||||
if (message.type === "QUICK_DOWNLOAD") { window.__quickRequests.push(message.url); return { ok: true, jobId: "fixture-job" }; }
|
||||
|
||||
@@ -20,8 +20,8 @@ try {
|
||||
page.on("pageerror", error => errors.push(error.message));
|
||||
await page.goto("https://ui.ytdl.test/downloader.html?theme=dark&url=https://www.youtube.com/watch?v=aircAruvnKk");
|
||||
await page.locator('#helper-panel[data-state="incompatible"]').waitFor();
|
||||
assert.match(await page.locator('#helper-message').textContent(), /1\.3\.0.*1\.4\.5/);
|
||||
assert.match(await page.locator('#helper-versions').textContent(), /Расширение 1\.4\.5.*Помощник 1\.3\.0/);
|
||||
assert.match(await page.locator('#helper-message').textContent(), /1\.3\.0.*1\.4\.6/);
|
||||
assert.match(await page.locator('#helper-versions').textContent(), /Расширение 1\.4\.6.*Помощник 1\.3\.0/);
|
||||
assert.equal(await page.locator('#helper-install').textContent(), 'Обновить помощник');
|
||||
assert.equal(await page.locator('#download').isDisabled(), true);
|
||||
assert.equal(await page.locator('#download-form').isVisible(), false);
|
||||
@@ -30,7 +30,7 @@ try {
|
||||
await page.locator('#setup-helper[data-state="incompatible"]').waitFor();
|
||||
assert.equal(await page.locator('#setup-next').isDisabled(), true);
|
||||
assert.equal(await page.locator('#setup-install').textContent(), 'Обновить помощник');
|
||||
assert.match(await page.locator('#setup-versions').textContent(), /1\.4\.5.*1\.3\.0/);
|
||||
assert.match(await page.locator('#setup-versions').textContent(), /1\.4\.6.*1\.3\.0/);
|
||||
await page.evaluate(() => { window.__helperVersion = '1.3.2'; });
|
||||
await page.locator('#setup-check').click();
|
||||
await page.locator('#setup-helper[data-state="running"]').waitFor();
|
||||
@@ -44,7 +44,7 @@ try {
|
||||
assert.equal(await page.locator('#setup-install-steps').isVisible(), false);
|
||||
await page.locator('#setup-close').click();
|
||||
assert.equal(await page.locator('#helper-install').textContent(), 'Обновить расширение');
|
||||
assert.match(await page.locator('#helper-message').textContent(), /Помощник 1\.3\.3.*расширением 1\.4\.5/);
|
||||
assert.match(await page.locator('#helper-message').textContent(), /Помощник 1\.3\.3.*расширением 1\.4\.6/);
|
||||
assert.equal(await page.locator('#download').isDisabled(), true);
|
||||
await page.evaluate(() => { window.__helperVersion = '1.3.2'; });
|
||||
await page.locator('#helper-start').click();
|
||||
|
||||
Reference in new issue
Block a user