Compare commits

..

No commits in common. "46dc29a2265fb4cffdd61c18366092417d3b0fc3" and "674041a603de3f32c310964af87a7fea8fcba7e0" have entirely different histories.

6 changed files with 23 additions and 44 deletions

4
package-lock.json generated
View File

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

View File

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

View File

@ -3870,10 +3870,8 @@ ipcMain.handle('create-merge-group', (_, itemIds: string[]) => {
return downloadQueue; return downloadQueue;
} }
// Preserve user-defined order from renderer (itemIds array order) // Sort chronologically by ISO timestamp (handles same-day different times)
const sorted = itemIds const sorted = [...selectedItems].sort((a, b) => new Date(a.date).getTime() - new Date(b.date).getTime());
.map(id => selectedItems.find(item => item.id === id))
.filter((item): item is QueueItem => item !== undefined);
// Calculate total duration // Calculate total duration
const totalDurationSec = sorted.reduce((sum, item) => sum + parseDuration(item.duration_str), 0); const totalDurationSec = sorted.reduce((sum, item) => sum + parseDuration(item.duration_str), 0);

View File

@ -140,11 +140,10 @@ function getQueueMetaText(item: QueueItem): string {
} }
function toggleQueueSelection(id: string): void { function toggleQueueSelection(id: string): void {
const index = selectedQueueIds.indexOf(id); if (selectedQueueIds.has(id)) {
if (index >= 0) { selectedQueueIds.delete(id);
selectedQueueIds.splice(index, 1);
} else { } else {
selectedQueueIds.push(id); selectedQueueIds.add(id);
} }
renderQueue(); renderQueue();
updateMergeGroupButton(); updateMergeGroupButton();
@ -158,11 +157,11 @@ function updateMergeGroupButton(): void {
const validIds = new Set( const validIds = new Set(
queue.filter(item => item.status === 'pending' && !item.mergeGroup).map(item => item.id) queue.filter(item => item.status === 'pending' && !item.mergeGroup).map(item => item.id)
); );
selectedQueueIds = selectedQueueIds.filter(id => validIds.has(id)); selectedQueueIds = new Set([...selectedQueueIds].filter(id => validIds.has(id)));
if (selectedQueueIds.length >= 2) { if (selectedQueueIds.size >= 2) {
btn.style.display = ''; btn.style.display = '';
btn.textContent = `${UI_TEXT.mergeGroup.btn} (${selectedQueueIds.length})`; btn.textContent = `${UI_TEXT.mergeGroup.btn} (${selectedQueueIds.size})`;
btn.disabled = false; btn.disabled = false;
} else { } else {
btn.style.display = 'none'; btn.style.display = 'none';
@ -170,10 +169,10 @@ function updateMergeGroupButton(): void {
} }
async function createMergeGroupFromSelection(): Promise<void> { async function createMergeGroupFromSelection(): Promise<void> {
if (selectedQueueIds.length < 2) return; if (selectedQueueIds.size < 2) return;
const ids = [...selectedQueueIds]; const ids = [...selectedQueueIds];
selectedQueueIds = []; selectedQueueIds.clear();
queue = await window.api.createMergeGroup(ids); queue = await window.api.createMergeGroup(ids);
renderQueue(); renderQueue();
updateMergeGroupButton(); updateMergeGroupButton();
@ -214,9 +213,8 @@ function renderQueue(): void {
const progressClass = item.status === 'downloading' && !hasDeterminateProgress ? ' indeterminate' : ''; const progressClass = item.status === 'downloading' && !hasDeterminateProgress ? ' indeterminate' : '';
const isMergeGroup = !!item.mergeGroup; const isMergeGroup = !!item.mergeGroup;
const showSelector = item.status === 'pending' && !isMergeGroup; const showCheckbox = item.status === 'pending' && !isMergeGroup;
const selectionIndex = selectedQueueIds.indexOf(item.id); const isChecked = selectedQueueIds.has(item.id);
const isSelected = selectionIndex >= 0;
const mergeIcon = isMergeGroup const mergeIcon = isMergeGroup
? '<svg class="merge-group-icon" viewBox="0 0 24 24" fill="currentColor" width="14" height="14"><path d="M17 20.41L18.41 19 15 15.59 13.59 17 17 20.41zM7.5 8H11v5.59L5.59 19 7 20.41l6-6V8h3.5L12 3.5 7.5 8z"/></svg> ' ? '<svg class="merge-group-icon" viewBox="0 0 24 24" fill="currentColor" width="14" height="14"><path d="M17 20.41L18.41 19 15 15.59 13.59 17 17 20.41zM7.5 8H11v5.59L5.59 19 7 20.41l6-6V8h3.5L12 3.5 7.5 8z"/></svg> '
: ''; : '';
@ -226,8 +224,8 @@ function renderQueue(): void {
return ` return `
<div class="queue-item${isMergeGroup ? ' merge-group' : ''}"> <div class="queue-item${isMergeGroup ? ' merge-group' : ''}">
${showSelector ${showCheckbox
? `<div class="queue-selector${isSelected ? ' selected' : ''}" onclick="toggleQueueSelection('${item.id}')">${isSelected ? selectionIndex + 1 : ''}</div>` ? `<input type="checkbox" class="queue-checkbox" ${isChecked ? 'checked' : ''} onchange="toggleQueueSelection('${item.id}')" />`
: '' : ''
} }
<div class="status ${item.status}"></div> <div class="status ${item.status}"></div>

View File

@ -24,7 +24,7 @@ let currentStreamer: string | null = null;
let isConnected = false; let isConnected = false;
let downloading = false; let downloading = false;
let queue: QueueItem[] = []; let queue: QueueItem[] = [];
let selectedQueueIds: string[] = []; let selectedQueueIds: Set<string> = new Set();
let cutterFile: string | null = null; let cutterFile: string | null = null;
let cutterVideoInfo: VideoInfo | null = null; let cutterVideoInfo: VideoInfo | null = null;

View File

@ -329,30 +329,13 @@ body {
opacity: 1; opacity: 1;
} }
.queue-selector { .queue-checkbox {
width: 22px; width: 14px;
height: 22px; height: 14px;
border: 2px solid var(--text-secondary); margin-top: 2px;
border-radius: 4px;
cursor: pointer; cursor: pointer;
accent-color: var(--accent);
flex-shrink: 0; flex-shrink: 0;
display: flex;
align-items: center;
justify-content: center;
font-size: 12px;
font-weight: 700;
color: var(--bg-primary);
user-select: none;
transition: all 0.15s;
}
.queue-selector.selected {
background: var(--accent);
border-color: var(--accent);
}
.queue-selector:hover {
border-color: var(--accent);
} }
.queue-item.merge-group { .queue-item.merge-group {