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:
parent
674041a603
commit
0e6b219455
@ -3870,8 +3870,10 @@ ipcMain.handle('create-merge-group', (_, itemIds: string[]) => {
|
|||||||
return downloadQueue;
|
return downloadQueue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort chronologically by ISO timestamp (handles same-day different times)
|
// Preserve user-defined order from renderer (itemIds array order)
|
||||||
const sorted = [...selectedItems].sort((a, b) => new Date(a.date).getTime() - new Date(b.date).getTime());
|
const sorted = itemIds
|
||||||
|
.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);
|
||||||
|
|||||||
@ -140,10 +140,11 @@ function getQueueMetaText(item: QueueItem): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function toggleQueueSelection(id: string): void {
|
function toggleQueueSelection(id: string): void {
|
||||||
if (selectedQueueIds.has(id)) {
|
const index = selectedQueueIds.indexOf(id);
|
||||||
selectedQueueIds.delete(id);
|
if (index >= 0) {
|
||||||
|
selectedQueueIds.splice(index, 1);
|
||||||
} else {
|
} else {
|
||||||
selectedQueueIds.add(id);
|
selectedQueueIds.push(id);
|
||||||
}
|
}
|
||||||
renderQueue();
|
renderQueue();
|
||||||
updateMergeGroupButton();
|
updateMergeGroupButton();
|
||||||
@ -157,11 +158,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 = 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.style.display = '';
|
||||||
btn.textContent = `${UI_TEXT.mergeGroup.btn} (${selectedQueueIds.size})`;
|
btn.textContent = `${UI_TEXT.mergeGroup.btn} (${selectedQueueIds.length})`;
|
||||||
btn.disabled = false;
|
btn.disabled = false;
|
||||||
} else {
|
} else {
|
||||||
btn.style.display = 'none';
|
btn.style.display = 'none';
|
||||||
@ -169,10 +170,10 @@ function updateMergeGroupButton(): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function createMergeGroupFromSelection(): Promise<void> {
|
async function createMergeGroupFromSelection(): Promise<void> {
|
||||||
if (selectedQueueIds.size < 2) return;
|
if (selectedQueueIds.length < 2) return;
|
||||||
|
|
||||||
const ids = [...selectedQueueIds];
|
const ids = [...selectedQueueIds];
|
||||||
selectedQueueIds.clear();
|
selectedQueueIds = [];
|
||||||
queue = await window.api.createMergeGroup(ids);
|
queue = await window.api.createMergeGroup(ids);
|
||||||
renderQueue();
|
renderQueue();
|
||||||
updateMergeGroupButton();
|
updateMergeGroupButton();
|
||||||
@ -213,8 +214,9 @@ 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 showCheckbox = item.status === 'pending' && !isMergeGroup;
|
const showSelector = item.status === 'pending' && !isMergeGroup;
|
||||||
const isChecked = selectedQueueIds.has(item.id);
|
const selectionIndex = selectedQueueIds.indexOf(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> '
|
||||||
: '';
|
: '';
|
||||||
@ -224,8 +226,8 @@ function renderQueue(): void {
|
|||||||
|
|
||||||
return `
|
return `
|
||||||
<div class="queue-item${isMergeGroup ? ' merge-group' : ''}">
|
<div class="queue-item${isMergeGroup ? ' merge-group' : ''}">
|
||||||
${showCheckbox
|
${showSelector
|
||||||
? `<input type="checkbox" class="queue-checkbox" ${isChecked ? 'checked' : ''} onchange="toggleQueueSelection('${item.id}')" />`
|
? `<div class="queue-selector${isSelected ? ' selected' : ''}" onclick="toggleQueueSelection('${item.id}')">${isSelected ? selectionIndex + 1 : ''}</div>`
|
||||||
: ''
|
: ''
|
||||||
}
|
}
|
||||||
<div class="status ${item.status}"></div>
|
<div class="status ${item.status}"></div>
|
||||||
|
|||||||
@ -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: Set<string> = new Set();
|
let selectedQueueIds: string[] = [];
|
||||||
|
|
||||||
let cutterFile: string | null = null;
|
let cutterFile: string | null = null;
|
||||||
let cutterVideoInfo: VideoInfo | null = null;
|
let cutterVideoInfo: VideoInfo | null = null;
|
||||||
|
|||||||
@ -329,13 +329,30 @@ body {
|
|||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.queue-checkbox {
|
.queue-selector {
|
||||||
width: 14px;
|
width: 22px;
|
||||||
height: 14px;
|
height: 22px;
|
||||||
margin-top: 2px;
|
border: 2px solid var(--text-secondary);
|
||||||
|
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 {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user