feat(merge-split): numbered selection instead of checkboxes, user-defined merge order

Replace checkboxes with numbered selectors (1, 2, 3...) that show the
merge order. Click order determines VOD sequence in the merged result.
Chronological auto-sort removed — user controls the order.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
xRangerDE 2026-03-20 08:55:35 +01:00
parent 674041a603
commit 0e6b219455
4 changed files with 41 additions and 20 deletions

View File

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

View File

@ -140,10 +140,11 @@ function getQueueMetaText(item: QueueItem): string {
}
function toggleQueueSelection(id: string): void {
if (selectedQueueIds.has(id)) {
selectedQueueIds.delete(id);
const index = selectedQueueIds.indexOf(id);
if (index >= 0) {
selectedQueueIds.splice(index, 1);
} else {
selectedQueueIds.add(id);
selectedQueueIds.push(id);
}
renderQueue();
updateMergeGroupButton();
@ -157,11 +158,11 @@ function updateMergeGroupButton(): void {
const validIds = new Set(
queue.filter(item => item.status === 'pending' && !item.mergeGroup).map(item => item.id)
);
selectedQueueIds = new Set([...selectedQueueIds].filter(id => validIds.has(id)));
selectedQueueIds = selectedQueueIds.filter(id => validIds.has(id));
if (selectedQueueIds.size >= 2) {
if (selectedQueueIds.length >= 2) {
btn.style.display = '';
btn.textContent = `${UI_TEXT.mergeGroup.btn} (${selectedQueueIds.size})`;
btn.textContent = `${UI_TEXT.mergeGroup.btn} (${selectedQueueIds.length})`;
btn.disabled = false;
} else {
btn.style.display = 'none';
@ -169,10 +170,10 @@ function updateMergeGroupButton(): void {
}
async function createMergeGroupFromSelection(): Promise<void> {
if (selectedQueueIds.size < 2) return;
if (selectedQueueIds.length < 2) return;
const ids = [...selectedQueueIds];
selectedQueueIds.clear();
selectedQueueIds = [];
queue = await window.api.createMergeGroup(ids);
renderQueue();
updateMergeGroupButton();
@ -213,8 +214,9 @@ function renderQueue(): void {
const progressClass = item.status === 'downloading' && !hasDeterminateProgress ? ' indeterminate' : '';
const isMergeGroup = !!item.mergeGroup;
const showCheckbox = item.status === 'pending' && !isMergeGroup;
const isChecked = selectedQueueIds.has(item.id);
const showSelector = item.status === 'pending' && !isMergeGroup;
const selectionIndex = selectedQueueIds.indexOf(item.id);
const isSelected = selectionIndex >= 0;
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> '
: '';
@ -224,8 +226,8 @@ function renderQueue(): void {
return `
<div class="queue-item${isMergeGroup ? ' merge-group' : ''}">
${showCheckbox
? `<input type="checkbox" class="queue-checkbox" ${isChecked ? 'checked' : ''} onchange="toggleQueueSelection('${item.id}')" />`
${showSelector
? `<div class="queue-selector${isSelected ? ' selected' : ''}" onclick="toggleQueueSelection('${item.id}')">${isSelected ? selectionIndex + 1 : ''}</div>`
: ''
}
<div class="status ${item.status}"></div>

View File

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

View File

@ -329,13 +329,30 @@ body {
opacity: 1;
}
.queue-checkbox {
width: 14px;
height: 14px;
margin-top: 2px;
.queue-selector {
width: 22px;
height: 22px;
border: 2px solid var(--text-secondary);
border-radius: 4px;
cursor: pointer;
accent-color: var(--accent);
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 {