Bug Location: /home/vercel-sandbox/twitch_alternate_player/player.js:7485
Function: м_Статистика.ПолученПреобразованныйСегмент(оСегмент)
Root Cause: HTML element ID mismatch - JavaScript references Russian element IDs that have been replaced with English IDs in the HTML
Severity: CRITICAL - Causes TypeError when processing transformed video segments, breaking statistics UI updates
Line 7485: м_Статистика.ПолученПреобразованныйСегмент(оСегмент)
↓
Line 1971: function ПолученПреобразованныйСегмент(оСегмент)
↓
Line 1995: Узел("статистика-сжатиевидео").textContent = сСжатиеВидео
↓
FAILURE: document.getElementById("статистика-сжатиевидео") returns null
↓
TypeError: Cannot set property 'textContent' of null
The error occurs when:
- A video segment is received from the Web Worker after TS→MP4 transcoding
- The segment data type is not a number (line 7484:
typeof оСегмент.пДанные != "number") - Statistics module attempts to update UI with segment metadata
- First discontinuity segment (
оСегмент.лРазрыв === true) triggers video codec info update
Web Worker (worker.js)
↓ Transcoded segment via postMessage
player.js Line 7470: switch (мДанные[0])
↓ case 1: Transformed segment received
Line 7473-7479: Create Сегмент object
Line 7485: м_Статистика.ПолученПреобразованныйСегмент(оСегмент) ← ERROR HERE
↓
Line 1971: function ПолученПреобразованныйСегмент(оСегмент)
↓
Line 1972: Check if statistics window is open
Line 1974: Check if segment has media data (мбМедиасегмент property)
Line 1975: Check if discontinuity (лРазрыв flag)
↓
Line 1976-1995: Update video codec statistics
→ Line 1995: Узел("статистика-сжатиевидео").textContent ← FAILS
оСегмент = {
чНомер: <segment number>,
лРазрыв: <boolean - discontinuity flag>,
пДанные: {
чПреобразованЗа: <transcode time in ms>,
мбМедиасегмент: <ArrayBuffer of MP4 data>,
лЕстьВидео: <boolean>,
лЕстьЗвук: <boolean>,
// Video metadata (when лЕстьВидео === true):
nProfileIndication: <H.264 profile>,
nConstraintSetFlag: <constraint flags>,
nLevelIndication: <H.264 level>,
nMaxNumberReferenceFrames: <ref frame count>,
чДиапазон: <color range: -1/0/1>,
лЧересстрочное: <boolean - interlaced>,
чЧастотаКадров: <frame rate>,
чШиринаКартинки: <width>,
чВысотаКартинки: <height>,
// Audio metadata (when лЕстьЗвук === true):
nAudioObjectType: <AAC type 1-4>,
чЧастотаДискретизации: <sample rate>,
чКоличествоКаналов: <channel count>,
// Frame statistics:
чСредняяДлительностьВидеоСемпла: <avg frame duration ms>,
чМинДлительностьВидеоСемпла: <min frame duration ms>,
чМаксДлительностьВидеоСемпла: <max frame duration ms>,
чБитрейтЗвука: <audio bitrate kbps>,
// Error flags:
лЗабраковано: <boolean - rejected>,
лПотериВидео: <boolean - video loss>,
лПотериЗвука: <boolean - audio loss>
}
}| Line | JavaScript Code | Russian ID | English ID in HTML | Status |
|---|---|---|---|---|
| 1995 | Узел("статистика-сжатиевидео") |
статистика-сжатиевидео | ❌ COMMENTED OUT | MISSING |
| 1995 | (should use) | - | statistics-videocompression | EXISTS |
| 1997 | Узел("статистика-разрешениевидео") |
статистика-разрешениевидео | ✅ EXISTS (both) | OK |
| 2000 | Узел("статистика-сжатиевидео") |
статистика-сжатиевидео | ❌ COMMENTED OUT | MISSING |
| 2001 | Узел("статистика-разрешениевидео") |
статистика-разрешениевидео | ✅ EXISTS (both) | OK |
| 2003 | Узел("статистика-частотакадров") |
статистика-частотакадров | ✅ EXISTS (both) | OK |
| 2005 | Узел("статистика-сжатиезвука") |
статистика-сжатиезвука | ✅ EXISTS (both) | OK |
| 2012 | Узел("статистика-сжатиезвука") |
статистика-сжатиезвука | ✅ EXISTS (both) | OK |
| 2014 | Узел("статистика-битрейтзвука") |
статистика-битрейтзвука | ✅ EXISTS (both) | OK |
| 2068 | ОбновитьЗначение("статистика-частотакадров") |
статистика-частотакадров | ✅ EXISTS (both) | OK |
| 2076 | Узел("статистика-битрейтзвука") |
статистика-битрейтзвука | ✅ EXISTS (both) | OK |
| 2081 | Узел("статистика-преобразованза") |
статистика-преобразованза | ✅ EXISTS (both) | OK |
| 2090 | ОбновитьЗначение("статистика-потерьвидео") |
статистика-потерьвидео | ✅ EXISTS (both) | OK |
| 2096 | ОбновитьЗначение("статистика-потерьзвука") |
статистика-потерьзвука | ✅ EXISTS (both) | OK |
| Line | Function | Element ID | Status |
|---|---|---|---|
| 1691 | РазобранСписокСегментов | статистика-количестворекламы | ✅ OK |
| 1692 | РазобранСписокСегментов | статистика-частотарекламы | ✅ OK |
| 1693 | РазобранСписокСегментов | статистика-исходных | ✅ OK |
| 1709 | НеЗагруженыСегменты | статистика-незагруженныхсегментов | ✅ OK |
| 1822 | НеЗагруженыСегменты | статистика-незагруженныхсегментов | ✅ OK |
| 1824 | НеЗагруженыСегменты | статистика-исчерпано | ✅ OK |
| 1844 | ПолучитьДанныеДляОтчета | статистика-разрешениевидео | ✅ OK |
| 1846 | ПолучитьДанныеДляОтчета | статистика-сжатиевидео | |
| 1847 | ПолучитьДанныеДляОтчета | статистика-сжатиезвука | ✅ OK |
| 1865 | РазобранСписокСегментов | статистика-сервер | ✅ OK |
| 1873 | РазобранСписокСегментов | статистика-список | ✅ OK |
| 1877 | РазобранСписокСегментов | статистика-targetduration | ✅ OK |
| 1952 | ОшибкаЗагрузки | статистика-ошибокзагрузки | ✅ OK |
| 1953 | ОшибкаЗагрузки | статистика-незагруженныхсегментов | ✅ OK |
| 1967 | пропущеныСегменты | статистика-незагруженныхсегментов | ✅ OK |
<!-- COMMENTED OUT: -->
<!-- <span id=статистика-сжатиевидео title="..."></span> -->
<!-- ACTIVE REPLACEMENT: -->
<span id=statistics-videocompression title="Video compression parameters: ..."></span>Problem: The Russian ID статистика-сжатиевидео has been commented out and replaced with the English ID statistics-videocompression, but the JavaScript still references the Russian ID.
Most other elements maintain BOTH IDs during the translation process:
<span id=статистика-разрешениевидео></span>
<!-- <span id=statistics-videoresolution></span> -->This explains why only статистика-сжатиевидео causes failures - other elements still have their Russian IDs active.
Line 1995: Узел("статистика-сжатиевидео").textContent = сСжатиеВидео
- Attempts to set textContent on null
- Throws TypeError
- Function execution halts
Line 2000: Узел("статистика-сжатиевидео").textContent = "—"
- Same element access in else branch
- Would fail if video is absent in stream
- Same TypeError
Line 1846: ПараметрыВидео: Узел("статистика-сжатиевидео").textContent
- Used in ПолучитьДанныеДляОтчета() for bug reports
- Reads textContent from same element
- Would fail when generating diagnostic reports
- Trigger: Every time a video segment completes transcoding in the Web Worker
- Frequency: Every 2-10 seconds (depends on HLS segment duration)
- Discontinuity segments: First segment of stream, quality changes, ad boundaries
Line 1972: const лОкноОткрыто = ОкноОткрыто();The function checks if the statistics overlay is open (S key) before updating DOM elements. However, the critical failure at line 1995 occurs BEFORE this check for video codec information on discontinuity segments.
Line 1974: if (оДанные.hasOwnProperty("мбМедиасегмент")) {
Line 1975: if (оСегмент.лРазрыв) { // ← DISCONTINUITY FLAG
// Update codec info (lines 1976-2015)
// LINE 1995 FAILURE OCCURS HERECritical Detail: Video codec information (H.264 profile, level, resolution) is only updated on discontinuity segments (лРазрыв === true). This means:
- First segment of the stream → FAILS
- Quality change (auto or manual) → FAILS
- Ad break transitions → FAILS
✅ статистика-разрешениевидео / statistics-videoresolution ✅ статистика-частотакадров / statistics-framerate ✅ статистика-сжатиезвука / statistics-audiocompression ✅ статистика-битрейтзвука / statistics-audiobitrate ✅ статистика-сервер / statistics-server ✅ статистика-список / statistics-list ✅ статистика-targetduration / statistics-targetduration ✅ статистика-очередь / statistics-queue ✅ статистика-преобразованза / statistics-convertedin ✅ статистика-задержкатрансляции / statistics-streamdelay ✅ статистика-длительностьпросмотра / statistics-viewingduration ✅ статистика-количестворекламы / statistics-adcount ✅ статистика-частотарекламы / statistics-adfrequency ✅ статистика-исходных / statistics-source ✅ статистика-незагруженныхсегментов / statistics-undownloadedsegments ✅ статистика-исчерпано / statistics-exhausted ✅ статистика-ошибокзагрузки / statistics-loaderrors ✅ статистика-потерьвидео / statistics-videoloss ✅ статистика-потерьзвука / statistics-audioloss ✅ статистика-забракованных / statistics-rejected ✅ статистика-пропущенныхсегментов / statistics-skippedsegments ✅ статистика-пропущено / statistics-skipped ✅ статистика-переполнено / statistics-overflowed ✅ статистика-скачано / statistics-downloaded
❌ statistics-videocompression (Russian ID commented out) ← THIS IS THE BUG
These exist in HTML as active elements but have not been translated yet:
- статистика-интервалобновления
- статистика-сегментовдобавлено
- статистика-секунддобавлено
- статистика-толщинасегмента
- статистика-толщинаканала
- статистика-ожиданиеответа
- статистика-непросмотрено
The safest fix is to restore the dual-ID pattern used everywhere else in the codebase. This prevents breaking existing functionality while supporting future translation.
File: /home/vercel-sandbox/twitch_alternate_player/player.html
Line: 67-68
Current (BROKEN):
<!-- <span id=статистика-сжатиевидео title="Параметры сжатия видео: ..."></span> -->
<span id=statistics-videocompression title="Video compression parameters: ..."></span>Fixed (SAFE):
<span id=статистика-сжатиевидео></span>
<!-- <span id=statistics-videocompression></span> -->
<span title="Video compression parameters: compression standard, profile, level, maximum number of reference frames, range, frame rate"></span>OR (Better - matches dual-ID pattern):
<span id=статистика-сжатиевидео title="Параметры сжатия видео: стандарт сжатия, профиль, уровень, максимальное количество опорных кадров, диапазон, частота кадров"></span>
<!-- <span id=statistics-videocompression title="Video compression parameters: compression standard, profile, level, maximum number of reference frames, range, frame rate"></span>File: /home/vercel-sandbox/twitch_alternate_player/player.js
After confirming dual IDs exist in HTML, update all references:
// Line 1995 - Update video codec text
- Узел("статистика-сжатиевидео").textContent = сСжатиеВидео;
+ Узел("statistics-videocompression").textContent = сСжатиеВидео;
// Line 2000 - Clear video codec on no video
- Узел("статистика-сжатиевидео").textContent = "—";
+ Узел("statistics-videocompression").textContent = "—";
// Line 1846 - Read for report generation
- Узел("статистика-сжатиевидео").textContent,
+ Узел("statistics-videocompression").textContent,Note: This change should be coordinated with the full translation effort documented in CLAUDE.md.
Enhance the Узел() helper function to provide better error messages:
File: /home/vercel-sandbox/twitch_alternate_player/common.js
Line: 216-221
Current:
function Узел(пЭлемент) {
const элЭлемент = typeof пЭлемент == 'string' ? document.getElementById(пЭлемент) : пЭлемент;
Проверить(элЭлемент.nodeType === 1);
return элЭлемент;
}Enhanced:
function Узел(пЭлемент) {
const элЭлемент = typeof пЭлемент == 'string' ? document.getElementById(пЭлемент) : пЭлемент;
if (!элЭлемент) {
console.error(`[Узел] Element not found: ${пЭлемент}`);
throw new Error(`DOM element not found: ${пЭлемент}`);
}
Проверить(элЭлемент.nodeType === 1);
return элЭлемент;
}This would provide a clearer error message instead of "Cannot read property 'nodeType' of null".
- Load extension in Chrome
- Navigate to a Twitch channel
- Wait for first video segment to load
- Expected: Statistics overlay should update without errors
- Verify: Open DevTools Console - no TypeError
- With stream playing, open settings
- Change quality (e.g., 1080p → 720p)
- Expected: Codec info updates in statistics overlay
- Verify: Press S to open stats, check video parameters
- With stream playing, attempt to generate bug report
- Expected: Report includes video codec information
- Verify: Check report data structure
After applying Fix #1, verify these elements still work:
- ✅ Video resolution display (статистика-разрешениевидео)
- ✅ Frame rate display (статистика-частотакадров)
- ✅ Audio codec display (статистика-сжатиезвука)
- ✅ Audio bitrate display (статистика-битрейтзвука)
- ✅ All other statistics overlay fields
Root Cause: The HTML translation (Russian → English IDs) was done without updating the JavaScript references simultaneously. This violates the atomic translation requirement in CLAUDE.md:
Translation commits must be atomic per file. Do not mix translation of identifiers with logic changes in the same commit.
The HTML was partially translated without a corresponding JavaScript update, creating this mismatch.
- Identify all references: Use
grep -r "element-id"across all files - Create dual IDs first: Add English IDs alongside Russian IDs in HTML
- Update JavaScript gradually: Change JS references file-by-file
- Remove Russian IDs last: Only after all JS references are updated
- Test after each step: Verify functionality throughout
Based on the HTML scan, these elements have been fully translated to English but may have JavaScript references elsewhere:
statistics-updateinterval(commented: статистика-интервалобновления)statistics-segmentsadded(commented: статистика-сегментовдобавлено)statistics-secondsadded(commented: статистика-секунддобавлено)statistics-segmentthickness(commented: статистика-толщинасегмента)statistics-channelthickness(commented: статистика-толщинаканала)statistics-responsewait(commented: статистика-ожиданиеответа)statistics-unwatched(commented: статистика-непросмотрено)
Action Item: Audit all м_Статистика module DOM accesses to find additional mismatches.
| Function Name | Lines | DOM Updates |
|---|---|---|
| РазобранСписокСегментов | 1661-1703 | 6 element updates |
| ДобавленыСегментыВОчередь | ~1800-1900 | Multiple Анализ class updates |
| ОшибкаЗагрузки | 1945-1955 | 2 element updates |
| пропущеныСегменты | 1960-1970 | 2 element updates |
| ПолученПреобразованныйСегмент | 1971-2099 | 10+ element updates ← ERROR HERE |
| обновитьЗаполненностьБуфера | 2100-2108 | 1 Анализ update |
| ИсчерпанБуферПроигрывателя | 2109-2121 | 1 element update |
Total DOM element access points in м_Статистика module: ~50+
Critical insight: Only 1 out of ~50 element accesses is broken, but it's a high-frequency, high-visibility update that occurs on every stream start and quality change.
File: /home/vercel-sandbox/twitch_alternate_player/common.js
Lines: 216-222
function Узел(пЭлемент) {
const элЭлемент = typeof пЭлемент == 'string'
? document.getElementById(пЭлемент)
: пЭлемент;
Проверить(элЭлемент.nodeType === 1);
return элЭлемент;
}File: /home/vercel-sandbox/twitch_alternate_player/player.js
Lines: 1540-1545
function ОбновитьЗначение(пЭлемент, пЗначение, лВыделить) {
const узЭлемент = Узел(пЭлемент);
узЭлемент.classList.toggle("статистика-выделить", лВыделить);
узЭлемент.textContent = пЗначение;
return узЭлемент;
}File: /home/vercel-sandbox/twitch_alternate_player/player.js
Lines: 7473-7479
const оСегмент = new Сегмент(
ОБРАБОТКА_ПРЕОБРАЗОВАН,
мДанные[1].пДанные,
мДанные[1].чДлительность,
мДанные[1].лРазрыв,
мДанные[1].чНомер
);Immediate Action: Apply Fix #1 to restore the Russian element ID статистика-сжатиевидео in player.html line 67. This is a one-line change that will resolve the critical TypeError.
Short-term: Audit the entire м_Статистика module for other potential ID mismatches with the partially-translated HTML.
Long-term: Follow the structured translation process outlined in CLAUDE.md to complete the Russian→English migration without introducing regressions.
Report Generated: 2026-07-07 Diagnostic Tool: Claude Code Agent (Sonnet 4.5) Analysis Depth: Full source code trace, DOM inspection, data flow analysis