Compare commits

..

No commits in common. "a82a8f97f7751173c3d1fe3128031f3e873f67d1" and "6086cd51c1fabe554ab74f39af37917b0b11e6f4" have entirely different histories.

4 changed files with 20 additions and 65 deletions

4
package-lock.json generated
View File

@ -1,12 +1,12 @@
{
"name": "twitch-vod-manager",
"version": "4.6.51",
"version": "4.6.50",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "twitch-vod-manager",
"version": "4.6.51",
"version": "4.6.50",
"license": "MIT",
"dependencies": {
"axios": "^1.6.0",

View File

@ -1,6 +1,6 @@
{
"name": "twitch-vod-manager",
"version": "4.6.51",
"version": "4.6.50",
"description": "Twitch VOD Manager - Download Twitch VODs easily",
"main": "dist/main.js",
"author": "xRangerDE",

View File

@ -482,72 +482,45 @@ function renderStreamers(): void {
nameSpan.className = 'streamer-name' + (isLive ? ' is-live' : '');
nameSpan.textContent = streamer;
// Three streamer-row action chips (AUTO toggle / VOD toggle / REC
// one-shot). All share the same accessibility wiring:
// role="button", tabindex="0", aria-pressed for the toggles +
// aria-label for screen readers, plus Enter/Space keydown
// activation. wireChipButton centralises that so each chip only
// declares its own visual class + label + handler.
const wireChipButton = (el: HTMLElement, opts: {
handler: () => void;
ariaLabel: string;
pressed?: boolean;
}): void => {
el.setAttribute('role', 'button');
el.setAttribute('tabindex', '0');
el.setAttribute('aria-label', opts.ariaLabel);
if (opts.pressed !== undefined) el.setAttribute('aria-pressed', String(opts.pressed));
el.addEventListener('click', (e) => {
e.stopPropagation();
opts.handler();
});
el.addEventListener('keydown', (e) => {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
e.stopPropagation();
opts.handler();
}
});
};
// AUTO toggle — when enabled, the main-process auto-record poller
// watches this channel for offline->live transitions and queues a
// live recording automatically.
// live recording automatically. Off by default, click to toggle.
const autoList = (config.auto_record_streamers as string[] | undefined) || [];
const isAutoOn = autoList.includes(streamer);
const autoBtn = document.createElement('span');
autoBtn.className = 'streamer-auto' + (isAutoOn ? ' active' : '');
autoBtn.textContent = 'AUTO';
autoBtn.title = UI_TEXT.streamers?.autoRecordTitle || 'Auto-record when this streamer goes live';
wireChipButton(autoBtn, {
handler: () => { void toggleAutoRecord(streamer); },
ariaLabel: UI_TEXT.streamers?.autoRecordTitle || 'Auto-record',
pressed: isAutoOn
autoBtn.addEventListener('click', (e) => {
e.stopPropagation();
void toggleAutoRecord(streamer);
});
// VOD-auto-download toggle — periodic scan of this streamer's
// VOD list, auto-queues anything new within the age window.
// VOD-auto-download toggle — when enabled, the main-process auto-VOD
// poller scans this streamer's VOD list periodically and queues new
// VODs published in the rolling window automatically. Complements
// AUTO (live capture): VOD covers downtime + transcoded archive,
// AUTO covers a stream as it happens. Useful for both.
const vodList = (config.auto_vod_download_streamers as string[] | undefined) || [];
const isVodOn = vodList.includes(streamer);
const vodBtn = document.createElement('span');
vodBtn.className = 'streamer-vod' + (isVodOn ? ' active' : '');
vodBtn.textContent = 'VOD';
vodBtn.title = UI_TEXT.streamers?.autoVodTitle || 'Auto-download new VODs';
wireChipButton(vodBtn, {
handler: () => { void toggleAutoVodDownload(streamer); },
ariaLabel: UI_TEXT.streamers?.autoVodTitle || 'Auto-download new VODs',
pressed: isVodOn
vodBtn.addEventListener('click', (e) => {
e.stopPropagation();
void toggleAutoVodDownload(streamer);
});
// Live-record one-shot — triggers a recording immediately (server
// verifies the streamer is online before honoring the request).
// Live-record button — small red dot, only triggers a live capture
// when the streamer is currently online (server checks via Helix).
const recBtn = document.createElement('span');
recBtn.className = 'streamer-rec';
recBtn.textContent = 'REC';
recBtn.title = UI_TEXT.streamers?.recordLiveTitle || 'Record live now';
wireChipButton(recBtn, {
handler: () => { void triggerLiveRecording(streamer); },
ariaLabel: UI_TEXT.streamers?.recordLiveTitle || 'Record live now'
recBtn.addEventListener('click', (e) => {
e.stopPropagation();
void triggerLiveRecording(streamer);
});
const removeSpan = document.createElement('span');
removeSpan.className = 'remove';

View File

@ -455,24 +455,6 @@ body {
border-radius: 3px;
}
/* Keyboard focus rings for the AUTO / VOD / REC chip buttons.
Each picks up its own accent: AUTO + VOD use semantic green/blue
tints matching their active state, REC the red of the live dot. */
.streamer-auto:focus-visible {
outline: none;
box-shadow: 0 0 0 2px rgba(0, 200, 83, 0.55);
}
.streamer-vod:focus-visible {
outline: none;
box-shadow: 0 0 0 2px rgba(33, 150, 243, 0.55);
}
.streamer-rec:focus-visible {
outline: none;
box-shadow: 0 0 0 2px rgba(255, 68, 68, 0.55);
}
/* Live-dot red pulsing indicator shown next to a streamer's name in
the sidebar when they are currently broadcasting on Twitch. */
.streamer-live-dot {