Compare commits
No commits in common. "46dc29a2265fb4cffdd61c18366092417d3b0fc3" and "674041a603de3f32c310964af87a7fea8fcba7e0" have entirely different histories.
46dc29a226
...
674041a603
4
package-lock.json
generated
4
package-lock.json
generated
@ -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",
|
||||||
|
|||||||
@ -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",
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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 {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user