| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190 |
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <title>GrabZilla 2.1</title>
- <script src="https://cdn.tailwindcss.com"></script>
- <link rel="stylesheet" href="styles/main.css">
- <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap" rel="stylesheet">
- </head>
- <body class="bg-[#1d293d] text-white min-h-screen flex flex-col font-['Inter']">
- <!-- Header - macOS Title Bar Style -->
- <header class="bg-[#0f172b] h-[41px] flex items-center justify-center border-b border-[#314158] shrink-0 relative"
- role="banner" aria-label="GrabZilla application header" style="-webkit-app-region: drag;">
- <!-- Centered Title -->
- <div class="flex items-center gap-2" style="-webkit-app-region: no-drag;">
- <div class="bg-[#155dfc] w-6 h-6 rounded flex items-center justify-center">
- <img src="assets/icons/logo.svg" alt="GrabZilla Logo" width="16" height="16">
- </div>
- <h1 class="font-medium text-base text-white tracking-[-0.3125px] leading-6">GrabZilla 2.1</h1>
- </div>
- <!-- Settings Button (Right side) -->
- <button id="settingsBtn" class="absolute right-4 text-[#cad5e2] hover:text-white transition-colors p-1" style="-webkit-app-region: no-drag;" aria-label="Open settings" title="Settings (Ctrl+,)">
- <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
- <circle cx="12" cy="12" r="3"/>
- <path d="M12 1v6m0 6v6m8.66-10l-5.2 3M8.54 14l-5.2 3m15.52 0l-5.2-3M8.54 10l-5.2-3"/>
- </svg>
- </button>
- </header>
- <!-- Input Section - Exact Figma: 161px height -->
- <section class="h-[161px] border-b border-[#314158] px-4 py-4 shrink-0 flex flex-col gap-4" role="region"
- aria-label="Video URL input and configuration" aria-describedby="input-section-help">
- <div id="input-section-help" class="sr-only">
- Enter YouTube or Vimeo URLs to add videos to the download queue. Configure default quality and format
- settings.
- </div>
- <!-- URL Input Row -->
- <div class="flex gap-2 h-20">
- <!-- Textarea -->
- <textarea id="urlInput"
- class="flex-1 bg-[#314158] border border-[#45556c] rounded-lg p-3 text-sm resize-none text-[#90a1b9] placeholder-[#90a1b9] tracking-[-0.1504px]"
- placeholder="Paste YouTube/Vimeo URLs here (one per line)..." aria-label="YouTube and Vimeo URLs input"
- aria-describedby="url-help"></textarea>
- <div id="url-help" class="sr-only">Enter one URL per line. Supports YouTube and Vimeo links.</div>
- <!-- Action Buttons -->
- <div class="flex flex-col gap-2 w-[140px]">
- <button id="addVideoBtn"
- class="bg-[#155dfc] text-white px-4 py-2 rounded-lg text-sm font-medium flex items-center gap-2 h-9 tracking-[-0.1504px]">
- <img src="assets/icons/add.svg" alt="Add" width="16" height="16">
- Add Video
- </button>
- <button id="importUrlsBtn"
- class="border border-[#45556c] text-white px-4 py-2 rounded-lg text-sm font-medium flex items-center gap-2 h-9 tracking-[-0.1504px]">
- <img src="assets/icons/import.svg" alt="Import" width="16" height="16">
- Import URLs
- </button>
- </div>
- </div>
- <!-- Configuration Row -->
- <div class="flex items-center justify-between gap-4 h-8">
- <!-- Defaults Section -->
- <div class="flex items-center gap-2">
- <img src="assets/icons/clock.svg" alt="Clock" width="16" height="16">
- <span class="text-[#90a1b9] text-sm tracking-[-0.1504px]">Defaults:</span>
- <!-- Quality Dropdown -->
- <select id="defaultQuality"
- class="bg-[#314158] border border-[#45556c] text-[#cad5e2] px-3 py-1 rounded-lg text-xs h-7 font-medium"
- aria-label="Default video quality">
- <option value="Best">Best</option>
- <option value="1080p" selected>1080p</option>
- <option value="720p">720p</option>
- <option value="4K">4K</option>
- </select>
- <!-- Format Dropdown -->
- <select id="defaultFormat"
- class="bg-[#314158] border border-[#45556c] text-[#cad5e2] px-3 py-1 rounded-lg text-xs h-7 font-medium"
- aria-label="Default conversion format">
- <option value="None" selected>None</option>
- <option value="H264">H264</option>
- <option value="ProRes">ProRes</option>
- <option value="DNxHR">DNxHR</option>
- <option value="Audio only">Audio only</option>
- </select>
- <!-- Clipboard Monitoring -->
- <div class="flex items-center gap-2 ml-4">
- <span class="text-[#90a1b9] text-sm tracking-[-0.1504px]">Clipboard:</span>
- <label class="relative inline-flex items-center cursor-pointer">
- <input type="checkbox" id="clipboardMonitorToggle" class="sr-only peer">
- <div class="w-9 h-5 bg-[#45556c] peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-4 after:w-4 after:transition-all peer-checked:bg-[#155dfc]"></div>
- <span class="ml-2 text-xs text-[#cad5e2]">Monitor</span>
- </label>
- </div>
- </div>
- <!-- Settings Button -->
- <button id="settingsBtn2"
- class="border border-[#45556c] text-white px-4 py-2 rounded-lg font-medium flex items-center gap-2 h-8 text-sm tracking-[-0.1504px] hover:bg-[#45556c] transition-colors">
- <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
- <circle cx="12" cy="12" r="3"/>
- <path d="M12 1v6m0 6v6m8.66-10l-5.2 3M8.54 14l-5.2 3m15.52 0l-5.2-3M8.54 10l-5.2-3"/>
- </svg>
- Settings
- </button>
- </div>
- </section>
- <!-- Video List - Flex grow to fill remaining space -->
- <main class="flex-1 overflow-hidden" role="main" aria-label="Video download queue"
- aria-describedby="main-content-help">
- <div id="main-content-help" class="sr-only">
- Video download queue. Use arrow keys to navigate, Enter or Space to select videos, Delete to remove videos.
- </div>
- <!-- Table Header -->
- <div class="grid grid-cols-[40px_40px_1fr_120px_100px_120px_100px] gap-4 px-4 py-4 text-sm font-medium text-[#90a1b9] tracking-[-0.1504px]"
- role="row" aria-label="Video list column headers">
- <div role="columnheader" aria-label="Selection checkbox"></div>
- <div role="columnheader" aria-label="Drag handle"></div>
- <div role="columnheader">Title</div>
- <div role="columnheader">Duration</div>
- <div role="columnheader">Quality</div>
- <div role="columnheader">Conversion</div>
- <div role="columnheader">Status</div>
- </div>
- <!-- Video Items Container -->
- <div id="videoList" class="px-4 pt-2 pb-4 space-y-2 overflow-y-auto h-full" role="grid"
- aria-label="Video download queue" aria-describedby="video-list-instructions" tabindex="0">
- <div id="video-list-instructions" class="sr-only">
- Use arrow keys to navigate between videos. Press Enter or Space to select videos. Press Delete to remove
- videos. Press Ctrl+A to select all videos.
- </div>
- <!-- Sample Video Items - Matching Figma Design -->
- <!-- Video Item 1 - Ready State -->
- <div class="video-item grid grid-cols-[40px_40px_1fr_120px_100px_120px_100px] gap-4 items-center p-2 rounded bg-[#314158] hover:bg-[#3a4a68] transition-colors duration-200"
- data-video-id="video-1" role="gridcell" tabindex="0" aria-rowindex="1"
- aria-describedby="video-1-description">
- <!-- Checkbox -->
- <div class="flex items-center justify-center">
- <button
- class="video-checkbox w-6 h-6 rounded flex items-center justify-center hover:bg-[#45556c] transition-colors"
- role="checkbox" aria-checked="false" aria-label="Select Interstellar 2014 Trailer" tabindex="0">
- <svg width="16" height="16" viewBox="0 0 16 16" fill="none" class="text-white">
- <rect x="3" y="3" width="10" height="10" stroke="currentColor" stroke-width="1.5"
- fill="none" rx="2" />
- </svg>
- </button>
- </div>
- <!-- Drag Handle -->
- <div
- class="flex items-center justify-center text-[#90a1b9] hover:text-white cursor-grab transition-colors">
- <svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor">
- <circle cx="4" cy="4" r="1" />
- <circle cx="4" cy="8" r="1" />
- <circle cx="4" cy="12" r="1" />
- <circle cx="8" cy="4" r="1" />
- <circle cx="8" cy="8" r="1" />
- <circle cx="8" cy="12" r="1" />
- <circle cx="12" cy="4" r="1" />
- <circle cx="12" cy="8" r="1" />
- <circle cx="12" cy="12" r="1" />
- </svg>
- </div>
- <!-- Video Info -->
- <div class="flex items-center gap-3 min-w-0">
- <div class="w-16 h-12 bg-[#45556c] rounded overflow-hidden flex-shrink-0">
- <div
- class="w-full h-full bg-gradient-to-br from-[#4a5568] to-[#2d3748] flex items-center justify-center">
- <svg width="24" height="24" viewBox="0 0 24 24" fill="none" class="text-[#90a1b9]">
- <path d="M8 5V19L19 12L8 5Z" stroke="currentColor" stroke-width="2"
- stroke-linejoin="round" />
- </svg>
- </div>
- </div>
- <div class="min-w-0 flex-1">
- <div class="text-sm text-white truncate font-medium">Interstellar 2014 Trailer | 4K Ultra HD
- </div>
- </div>
- </div>
- <!-- Duration -->
- <div class="text-sm text-[#cad5e2] text-center">2:25</div>
- <!-- Quality Dropdown -->
- <div class="flex justify-center">
- <select
- class="bg-[#314158] border border-[#45556c] text-[#cad5e2] px-2 py-1 rounded text-xs font-medium min-w-0 w-full text-center"
- aria-label="Quality for Interstellar 2014 Trailer">
- <option value="Best">Best</option>
- <option value="4K" selected>4K</option>
- <option value="1080p">1080p</option>
- <option value="720p">720p</option>
- </select>
- </div>
- <!-- Format Dropdown -->
- <div class="flex justify-center">
- <select
- class="bg-[#314158] border border-[#45556c] text-[#cad5e2] px-2 py-1 rounded text-xs font-medium min-w-0 w-full text-center"
- aria-label="Format for Interstellar 2014 Trailer">
- <option value="None" selected>None</option>
- <option value="H264">H264</option>
- <option value="ProRes">ProRes</option>
- <option value="DNxHR">DNxHR</option>
- <option value="Audio only">Audio only</option>
- </select>
- </div>
- <!-- Status Badge -->
- <div class="flex justify-center status-column">
- <span class="status-badge ready" role="status" aria-live="polite"
- aria-label="Video ready for download">
- Ready
- </span>
- </div>
- <!-- Video Description for Screen Readers -->
- <div id="video-1-description" class="sr-only">
- Video: Interstellar 2014 Trailer | 4K Ultra HD, Duration: 2:25, Status: Ready. Press Enter or Space
- to select, Delete to remove.
- </div>
- </div>
- <!-- Video Item 2 - Downloading State -->
- <div class="video-item grid grid-cols-[40px_40px_1fr_120px_100px_120px_100px] gap-4 items-center p-2 rounded bg-[#314158] hover:bg-[#3a4a68] transition-colors duration-200"
- data-video-id="video-2">
- <!-- Checkbox -->
- <div class="flex items-center justify-center">
- <button
- class="w-6 h-6 rounded flex items-center justify-center hover:bg-[#45556c] transition-colors">
- <svg width="16" height="16" viewBox="0 0 16 16" fill="none" class="text-white">
- <rect x="3" y="3" width="10" height="10" stroke="currentColor" stroke-width="1.5"
- fill="none" rx="2" />
- </svg>
- </button>
- </div>
- <!-- Drag Handle -->
- <div
- class="flex items-center justify-center text-[#90a1b9] hover:text-white cursor-grab transition-colors">
- <svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor">
- <circle cx="4" cy="4" r="1" />
- <circle cx="4" cy="8" r="1" />
- <circle cx="4" cy="12" r="1" />
- <circle cx="8" cy="4" r="1" />
- <circle cx="8" cy="8" r="1" />
- <circle cx="8" cy="12" r="1" />
- <circle cx="12" cy="4" r="1" />
- <circle cx="12" cy="8" r="1" />
- <circle cx="12" cy="12" r="1" />
- </svg>
- </div>
- <!-- Video Info -->
- <div class="flex items-center gap-3 min-w-0">
- <div class="w-16 h-12 bg-[#45556c] rounded overflow-hidden flex-shrink-0">
- <div
- class="w-full h-full bg-gradient-to-br from-[#4a5568] to-[#2d3748] flex items-center justify-center">
- <svg width="24" height="24" viewBox="0 0 24 24" fill="none" class="text-[#90a1b9]">
- <path d="M8 5V19L19 12L8 5Z" stroke="currentColor" stroke-width="2"
- stroke-linejoin="round" />
- </svg>
- </div>
- </div>
- <div class="min-w-0 flex-1">
- <div class="text-sm text-white truncate font-medium">Greenland (2020) 4K Trailer | Upscaled
- Trailers</div>
- </div>
- </div>
- <!-- Duration -->
- <div class="text-sm text-[#cad5e2] text-center">2:30</div>
- <!-- Quality Dropdown -->
- <div class="flex justify-center">
- <select
- class="bg-[#314158] border border-[#45556c] text-[#cad5e2] px-2 py-1 rounded text-xs font-medium min-w-0 w-full text-center">
- <option value="Best">Best</option>
- <option value="1080p" selected>1080p</option>
- <option value="4K">4K</option>
- <option value="720p">720p</option>
- </select>
- </div>
- <!-- Format Dropdown -->
- <div class="flex justify-center">
- <select
- class="bg-[#314158] border border-[#45556c] text-[#cad5e2] px-2 py-1 rounded text-xs font-medium min-w-0 w-full text-center">
- <option value="ProRes" selected>ProRes</option>
- <option value="None">None</option>
- <option value="H264">H264</option>
- <option value="DNxHR">DNxHR</option>
- <option value="Audio only">Audio only</option>
- </select>
- </div>
- <!-- Status Badge with Integrated Progress -->
- <div class="flex justify-center status-column">
- <span class="status-badge downloading" role="status" aria-live="polite" aria-label="Downloading 65%"
- data-progress="65">
- Downloading 65%
- </span>
- </div>
- </div>
- <!-- Video Item 3 - Converting State -->
- <div class="video-item grid grid-cols-[40px_40px_1fr_120px_100px_120px_100px] gap-4 items-center p-2 rounded bg-[#314158] hover:bg-[#3a4a68] transition-colors duration-200"
- data-video-id="video-3">
- <!-- Checkbox -->
- <div class="flex items-center justify-center">
- <button
- class="w-6 h-6 rounded flex items-center justify-center hover:bg-[#45556c] transition-colors">
- <svg width="16" height="16" viewBox="0 0 16 16" fill="none" class="text-white">
- <rect x="3" y="3" width="10" height="10" stroke="currentColor" stroke-width="1.5"
- fill="none" rx="2" />
- </svg>
- </button>
- </div>
- <!-- Drag Handle -->
- <div
- class="flex items-center justify-center text-[#90a1b9] hover:text-white cursor-grab transition-colors">
- <svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor">
- <circle cx="4" cy="4" r="1" />
- <circle cx="4" cy="8" r="1" />
- <circle cx="4" cy="12" r="1" />
- <circle cx="8" cy="4" r="1" />
- <circle cx="8" cy="8" r="1" />
- <circle cx="8" cy="12" r="1" />
- <circle cx="12" cy="4" r="1" />
- <circle cx="12" cy="8" r="1" />
- <circle cx="12" cy="12" r="1" />
- </svg>
- </div>
- <!-- Video Info -->
- <div class="flex items-center gap-3 min-w-0">
- <div class="w-16 h-12 bg-[#45556c] rounded overflow-hidden flex-shrink-0">
- <div
- class="w-full h-full bg-gradient-to-br from-[#4a5568] to-[#2d3748] flex items-center justify-center">
- <svg width="24" height="24" viewBox="0 0 24 24" fill="none" class="text-[#90a1b9]">
- <path d="M8 5V19L19 12L8 5Z" stroke="currentColor" stroke-width="2"
- stroke-linejoin="round" />
- </svg>
- </div>
- </div>
- <div class="min-w-0 flex-1">
- <div class="text-sm text-white truncate font-medium">GREENLAND Trailer German Deutsch (2020)
- </div>
- </div>
- </div>
- <!-- Duration -->
- <div class="text-sm text-[#cad5e2] text-center">2:38</div>
- <!-- Quality Dropdown -->
- <div class="flex justify-center">
- <select
- class="bg-[#314158] border border-[#45556c] text-[#cad5e2] px-2 py-1 rounded text-xs font-medium min-w-0 w-full text-center">
- <option value="Best">Best</option>
- <option value="1080p" selected>1080p</option>
- <option value="4K">4K</option>
- <option value="720p">720p</option>
- </select>
- </div>
- <!-- Format Dropdown -->
- <div class="flex justify-center">
- <select
- class="bg-[#314158] border border-[#45556c] text-[#cad5e2] px-2 py-1 rounded text-xs font-medium min-w-0 w-full text-center">
- <option value="H264" selected>H264</option>
- <option value="None">None</option>
- <option value="ProRes">ProRes</option>
- <option value="DNxHR">DNxHR</option>
- <option value="Audio only">Audio only</option>
- </select>
- </div>
- <!-- Status Badge with Integrated Progress -->
- <div class="flex justify-center status-column">
- <span class="status-badge converting" role="status" aria-live="polite" aria-label="Converting 42%"
- data-progress="42">
- Converting 42%
- </span>
- </div>
- </div>
- <!-- Video Item 4 - Completed State -->
- <div class="video-item grid grid-cols-[40px_40px_1fr_120px_100px_120px_100px] gap-4 items-center p-2 rounded bg-[#314158] hover:bg-[#3a4a68] transition-colors duration-200"
- data-video-id="video-4">
- <!-- Checkbox -->
- <div class="flex items-center justify-center">
- <button
- class="w-6 h-6 rounded flex items-center justify-center hover:bg-[#45556c] transition-colors">
- <svg width="16" height="16" viewBox="0 0 16 16" fill="none" class="text-white">
- <rect x="3" y="3" width="10" height="10" stroke="currentColor" stroke-width="1.5"
- fill="none" rx="2" />
- </svg>
- </button>
- </div>
- <!-- Drag Handle -->
- <div
- class="flex items-center justify-center text-[#90a1b9] hover:text-white cursor-grab transition-colors">
- <svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor">
- <circle cx="4" cy="4" r="1" />
- <circle cx="4" cy="8" r="1" />
- <circle cx="4" cy="12" r="1" />
- <circle cx="8" cy="4" r="1" />
- <circle cx="8" cy="8" r="1" />
- <circle cx="8" cy="12" r="1" />
- <circle cx="12" cy="4" r="1" />
- <circle cx="12" cy="8" r="1" />
- <circle cx="12" cy="12" r="1" />
- </svg>
- </div>
- <!-- Video Info -->
- <div class="flex items-center gap-3 min-w-0">
- <div class="w-16 h-12 bg-[#45556c] rounded overflow-hidden flex-shrink-0">
- <div
- class="w-full h-full bg-gradient-to-br from-[#4a5568] to-[#2d3748] flex items-center justify-center">
- <svg width="24" height="24" viewBox="0 0 24 24" fill="none" class="text-[#90a1b9]">
- <path d="M8 5V19L19 12L8 5Z" stroke="currentColor" stroke-width="2"
- stroke-linejoin="round" />
- </svg>
- </div>
- </div>
- <div class="min-w-0 flex-1">
- <div class="text-sm text-white truncate font-medium">A Quiet Place (2018) - Official Trailer -
- Paramount Pictures</div>
- </div>
- </div>
- <!-- Duration -->
- <div class="text-sm text-[#cad5e2] text-center">1:56</div>
- <!-- Quality Dropdown -->
- <div class="flex justify-center">
- <select
- class="bg-[#314158] border border-[#45556c] text-[#cad5e2] px-2 py-1 rounded text-xs font-medium min-w-0 w-full text-center">
- <option value="Best">Best</option>
- <option value="720p" selected>720p</option>
- <option value="4K">4K</option>
- <option value="1080p">1080p</option>
- </select>
- </div>
- <!-- Format Dropdown -->
- <div class="flex justify-center">
- <select
- class="bg-[#314158] border border-[#45556c] text-[#cad5e2] px-2 py-1 rounded text-xs font-medium min-w-0 w-full text-center">
- <option value="Audio only" selected>Audio only</option>
- <option value="None">None</option>
- <option value="H264">H264</option>
- <option value="ProRes">ProRes</option>
- <option value="DNxHR">DNxHR</option>
- </select>
- </div>
- <!-- Status Badge -->
- <div class="flex justify-center status-column">
- <span class="status-badge completed" role="status" aria-live="polite"
- aria-label="Video download completed">
- Completed
- </span>
- </div>
- </div>
- <!-- Video Item 5 - Error State -->
- <div class="video-item grid grid-cols-[40px_40px_1fr_120px_100px_120px_100px] gap-4 items-center p-2 rounded bg-[#314158] hover:bg-[#3a4a68] transition-colors duration-200"
- data-video-id="video-5">
- <!-- Checkbox -->
- <div class="flex items-center justify-center">
- <button
- class="w-6 h-6 rounded flex items-center justify-center hover:bg-[#45556c] transition-colors">
- <svg width="16" height="16" viewBox="0 0 16 16" fill="none" class="text-white">
- <rect x="3" y="3" width="10" height="10" stroke="currentColor" stroke-width="1.5"
- fill="none" rx="2" />
- </svg>
- </button>
- </div>
- <!-- Drag Handle -->
- <div
- class="flex items-center justify-center text-[#90a1b9] hover:text-white cursor-grab transition-colors">
- <svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor">
- <circle cx="4" cy="4" r="1" />
- <circle cx="4" cy="8" r="1" />
- <circle cx="4" cy="12" r="1" />
- <circle cx="8" cy="4" r="1" />
- <circle cx="8" cy="8" r="1" />
- <circle cx="8" cy="12" r="1" />
- <circle cx="12" cy="4" r="1" />
- <circle cx="12" cy="8" r="1" />
- <circle cx="12" cy="12" r="1" />
- </svg>
- </div>
- <!-- Video Info -->
- <div class="flex items-center gap-3 min-w-0">
- <div class="w-16 h-12 bg-[#45556c] rounded overflow-hidden flex-shrink-0">
- <div
- class="w-full h-full bg-gradient-to-br from-[#4a5568] to-[#2d3748] flex items-center justify-center">
- <svg width="24" height="24" viewBox="0 0 24 24" fill="none" class="text-[#90a1b9]">
- <path d="M8 5V19L19 12L8 5Z" stroke="currentColor" stroke-width="2"
- stroke-linejoin="round" />
- </svg>
- </div>
- </div>
- <div class="min-w-0 flex-1">
- <div class="text-sm text-white truncate font-medium">Blade Runner 2049 - Official Trailer -
- Warner Bros. Pictures</div>
- </div>
- </div>
- <!-- Duration -->
- <div class="text-sm text-[#cad5e2] text-center">3:47</div>
- <!-- Quality Dropdown -->
- <div class="flex justify-center">
- <select
- class="bg-[#314158] border border-[#45556c] text-[#cad5e2] px-2 py-1 rounded text-xs font-medium min-w-0 w-full text-center">
- <option value="Best">Best</option>
- <option value="4K" selected>4K</option>
- <option value="1080p">1080p</option>
- <option value="720p">720p</option>
- </select>
- </div>
- <!-- Format Dropdown -->
- <div class="flex justify-center">
- <select
- class="bg-[#314158] border border-[#45556c] text-[#cad5e2] px-2 py-1 rounded text-xs font-medium min-w-0 w-full text-center">
- <option value="H264" selected>H264</option>
- <option value="None">None</option>
- <option value="ProRes">ProRes</option>
- <option value="DNxHR">DNxHR</option>
- <option value="Audio only">Audio only</option>
- </select>
- </div>
- <!-- Status Badge -->
- <div class="flex justify-center status-column">
- <span class="status-badge error" role="status" aria-live="polite"
- aria-label="Video download failed">
- Error
- </span>
- </div>
- </div>
- </div>
- </main>
- <!-- Control Panel - Exact Figma: 93px height -->
- <footer class="h-[93px] border-t border-[#314158] px-4 py-4 shrink-0 flex flex-col gap-2" role="contentinfo"
- aria-label="Download controls and actions" aria-describedby="control-panel-help">
- <div id="control-panel-help" class="sr-only">
- Control panel with actions for managing downloads. Use Ctrl+D to start downloads quickly.
- </div>
- <!-- Button Row -->
- <div class="flex items-center justify-between h-9">
- <div class="flex items-center gap-2">
- <button id="clearListBtn"
- class="border border-[#45556c] text-white px-4 py-2 rounded-lg text-sm font-medium flex items-center gap-2 h-9 tracking-[-0.1504px]"
- aria-label="Clear all videos from list">
- <img src="assets/icons/trash.svg" alt="" width="16" height="16" loading="lazy">
- Clear List
- </button>
- <button id="updateDepsBtn"
- class="border border-[#45556c] text-white px-4 py-2 rounded-lg text-sm font-medium flex items-center gap-2 h-9 tracking-[-0.1504px]"
- aria-label="Check for updates to yt-dlp and ffmpeg">
- <img src="assets/icons/refresh.svg" alt="" width="16" height="16" loading="lazy">
- Check for Updates
- </button>
- <button id="showHistoryBtn"
- class="border border-[#45556c] text-[#cad5e2] px-4 py-2 rounded-lg text-sm font-medium flex items-center gap-2 h-9 tracking-[-0.1504px] hover:bg-[#45556c] hover:text-white transition-colors"
- aria-label="View download history">
- <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
- <circle cx="12" cy="12" r="10"/>
- <polyline points="12 6 12 12 16 14"/>
- </svg>
- History
- </button>
- <button id="cancelDownloadsBtn"
- class="bg-[#e7000b] text-white px-4 py-2 rounded-lg text-sm font-medium flex items-center gap-2 h-9 tracking-[-0.1504px]"
- aria-label="Cancel all active downloads">
- <img src="assets/icons/close.svg" alt="Cancel" width="16" height="16">
- Cancel Downloads
- </button>
- </div>
- <button id="downloadVideosBtn"
- class="bg-[#00a63e] text-white px-6 py-2.5 rounded-lg text-sm font-medium flex items-center gap-2 h-9 tracking-[-0.1504px]">
- <img src="assets/icons/download.svg" alt="Download" width="16" height="16">
- Download Videos
- </button>
- </div>
- <!-- Status Message & Binary Versions -->
- <div class="flex items-center justify-between text-xs text-[#90a1b9] h-6 px-4">
- <!-- Left: Status Message -->
- <span id="statusMessage" role="status" aria-live="polite">Ready to download videos</span>
- <!-- Right: Binary Versions -->
- <div id="binaryVersions" class="flex items-center gap-4">
- <div id="ytdlpVersion" class="flex items-center gap-2">
- <span class="font-medium text-[#cad5e2]">yt-dlp:</span>
- <span id="ytdlpVersionNumber">--</span>
- <span id="ytdlpUpdateBadge" class="hidden update-badge" title="Update available">●</span>
- </div>
- <div id="ffmpegVersion" class="flex items-center gap-2">
- <span class="font-medium text-[#cad5e2]">ffmpeg:</span>
- <span id="ffmpegVersionNumber">--</span>
- </div>
- <span id="lastUpdateCheck" class="text-[#62748e] text-[10px]" title="Last update check">--</span>
- </div>
- </div>
- </footer>
- <!-- Playlist Modal -->
- <div id="playlistModal" class="fixed inset-0 bg-black/60 hidden items-center justify-center z-50">
- <div class="bg-[#314158] rounded-lg shadow-2xl w-[800px] max-h-[80vh] flex flex-col">
- <!-- Modal Header -->
- <div class="flex items-center justify-between p-4 border-b border-[#45556c]">
- <h2 id="playlistTitle" class="text-lg font-semibold text-white">Playlist Videos</h2>
- <button id="closePlaylistModal" class="text-[#90a1b9] hover:text-white transition-colors">
- <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
- <path d="M18 6L6 18M6 6l12 12"/>
- </svg>
- </button>
- </div>
- <!-- Playlist Info -->
- <div class="p-4 border-b border-[#45556c]">
- <p id="playlistInfo" class="text-sm text-[#cad5e2]">Loading playlist...</p>
- </div>
- <!-- Video List (Scrollable) -->
- <div id="playlistVideoList" class="flex-1 overflow-y-auto p-4 space-y-2">
- <!-- Videos will be inserted here -->
- </div>
- <!-- Modal Footer -->
- <div class="p-4 border-t border-[#45556c] flex items-center justify-between">
- <label class="flex items-center gap-2 text-sm text-[#cad5e2] cursor-pointer">
- <input type="checkbox" id="selectAllPlaylistVideos" class="w-4 h-4">
- <span>Select All</span>
- </label>
- <div class="flex gap-2">
- <button id="cancelPlaylistBtn" class="border border-[#45556c] text-white px-4 py-2 rounded-lg text-sm">
- Cancel
- </button>
- <button id="downloadSelectedPlaylistBtn" class="bg-[#155dfc] text-white px-4 py-2 rounded-lg text-sm font-medium">
- Download Selected
- </button>
- </div>
- </div>
- </div>
- </div>
- <!-- Toast Container -->
- <div id="toastContainer" class="fixed top-4 right-4 z-[100] flex flex-col gap-2 pointer-events-none">
- <!-- Toasts will be inserted here -->
- </div>
- <!-- Settings Modal -->
- <div id="settingsModal" class="fixed inset-0 bg-black/60 hidden items-center justify-center z-50">
- <div class="bg-[#314158] rounded-lg shadow-2xl w-[700px] max-h-[85vh] flex flex-col">
- <!-- Modal Header -->
- <div class="flex items-center justify-between p-4 border-b border-[#45556c]">
- <h2 class="text-lg font-semibold text-white">Settings</h2>
- <button id="closeSettingsModal" class="text-[#90a1b9] hover:text-white transition-colors">
- <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
- <path d="M18 6L6 18M6 6l12 12"/>
- </svg>
- </button>
- </div>
- <!-- Tabs -->
- <div class="flex border-b border-[#45556c] px-4">
- <button class="settings-tab px-4 py-3 text-sm font-medium text-[#cad5e2] border-b-2 border-transparent hover:text-white hover:border-[#155dfc] transition-colors active" data-tab="general">
- General
- </button>
- <button class="settings-tab px-4 py-3 text-sm font-medium text-[#cad5e2] border-b-2 border-transparent hover:text-white hover:border-[#155dfc] transition-colors" data-tab="downloads">
- Downloads
- </button>
- <button class="settings-tab px-4 py-3 text-sm font-medium text-[#cad5e2] border-b-2 border-transparent hover:text-white hover:border-[#155dfc] transition-colors" data-tab="cookie">
- Cookie
- </button>
- <button class="settings-tab px-4 py-3 text-sm font-medium text-[#cad5e2] border-b-2 border-transparent hover:text-white hover:border-[#155dfc] transition-colors" data-tab="data">
- Data
- </button>
- <button class="settings-tab px-4 py-3 text-sm font-medium text-[#cad5e2] border-b-2 border-transparent hover:text-white hover:border-[#155dfc] transition-colors" data-tab="shortcuts">
- Shortcuts
- </button>
- </div>
- <!-- Tab Content -->
- <div class="flex-1 overflow-y-auto p-6">
- <!-- General Tab -->
- <div id="tab-general" class="settings-content space-y-4">
- <div>
- <label class="block text-sm font-medium text-[#cad5e2] mb-2">Default Save Location</label>
- <div class="flex gap-2">
- <input type="text" id="settings-save-path" readonly class="flex-1 bg-[#1d293d] border border-[#45556c] rounded-lg px-3 py-2 text-sm text-[#cad5e2]">
- <button id="settings-change-path" class="border border-[#45556c] text-white px-4 py-2 rounded-lg text-sm">
- Browse
- </button>
- </div>
- </div>
- <div>
- <label class="flex items-center gap-2 cursor-pointer">
- <input type="checkbox" id="settings-auto-organize" class="w-4 h-4">
- <span class="text-sm text-[#cad5e2]">Auto-organize downloads by channel/playlist</span>
- </label>
- <p class="text-xs text-[#90a1b9] mt-1 ml-6">Creates separate folders for each channel or playlist</p>
- </div>
- <div>
- <label class="block text-sm font-medium text-[#cad5e2] mb-2">Filename Template</label>
- <input type="text" id="settings-filename-template" placeholder="%(title)s" class="w-full bg-[#1d293d] border border-[#45556c] rounded-lg px-3 py-2 text-sm text-[#cad5e2]">
- <p class="text-xs text-[#90a1b9] mt-1">Available: %(title)s, %(channel)s, %(id)s, %(upload_date)s</p>
- </div>
- <div>
- <label class="block text-sm font-medium text-[#cad5e2] mb-2">Max Retry Attempts</label>
- <input type="number" id="settings-max-retries" min="0" max="10" value="3" class="w-full bg-[#1d293d] border border-[#45556c] rounded-lg px-3 py-2 text-sm text-[#cad5e2]">
- </div>
- <div>
- <label class="block text-sm font-medium text-[#cad5e2] mb-2">Request Timeout (seconds)</label>
- <input type="number" id="settings-timeout" min="5" max="120" value="30" class="w-full bg-[#1d293d] border border-[#45556c] rounded-lg px-3 py-2 text-sm text-[#cad5e2]">
- </div>
- </div>
- <!-- Downloads Tab -->
- <div id="tab-downloads" class="settings-content space-y-4 hidden">
- <div>
- <label class="block text-sm font-medium text-[#cad5e2] mb-2">Concurrent Downloads</label>
- <div class="flex items-center gap-4">
- <input type="range" id="settings-concurrent-downloads" min="1" max="10" value="10" class="flex-1">
- <span id="concurrent-value" class="text-sm text-[#cad5e2] w-8">10</span>
- </div>
- <p class="text-xs text-[#90a1b9] mt-1">Maximum number of simultaneous downloads (1-10)</p>
- </div>
- <div>
- <label class="flex items-center gap-2 cursor-pointer">
- <input type="checkbox" id="settings-auto-download-subtitles" class="w-4 h-4">
- <span class="text-sm text-[#cad5e2]">Auto-download subtitles</span>
- </label>
- </div>
- <div>
- <label class="block text-sm font-medium text-[#cad5e2] mb-2">Subtitle Language</label>
- <select id="settings-subtitle-language" class="w-full bg-[#1d293d] border border-[#45556c] rounded-lg px-3 py-2 text-sm text-[#cad5e2]">
- <option value="en">English</option>
- <option value="es">Spanish</option>
- <option value="fr">French</option>
- <option value="de">German</option>
- <option value="it">Italian</option>
- <option value="ja">Japanese</option>
- <option value="ko">Korean</option>
- <option value="zh">Chinese</option>
- </select>
- </div>
- <div>
- <label class="flex items-center gap-2 cursor-pointer">
- <input type="checkbox" id="settings-desktop-notifications" class="w-4 h-4" checked>
- <span class="text-sm text-[#cad5e2]">Show desktop notifications</span>
- </label>
- </div>
- </div>
- <!-- Cookie Tab -->
- <div id="tab-cookie" class="settings-content space-y-4 hidden">
- <div>
- <label class="block text-sm font-medium text-[#cad5e2] mb-2">Cookie File (Optional)</label>
- <div class="flex gap-2">
- <input type="text" id="settings-cookie-file" readonly placeholder="No cookie file selected" class="flex-1 bg-[#1d293d] border border-[#45556c] rounded-lg px-3 py-2 text-sm text-[#cad5e2]">
- <button id="settings-select-cookie" class="border border-[#45556c] text-white px-4 py-2 rounded-lg text-sm">
- Select
- </button>
- <button id="settings-clear-cookie" class="border border-[#e7000b] text-[#e7000b] px-4 py-2 rounded-lg text-sm">
- Clear
- </button>
- </div>
- <!-- Cookie File Help Guide -->
- <div class="mt-3 bg-[#1d293d] border border-[#45556c] rounded-lg p-3 space-y-2">
- <div class="flex items-start gap-2">
- <svg width="16" height="16" class="mt-0.5 flex-shrink-0 text-[#155dfc]" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
- <circle cx="12" cy="12" r="10"/>
- <line x1="12" y1="16" x2="12" y2="12"/>
- <line x1="12" y1="8" x2="12.01" y2="8"/>
- </svg>
- <div class="flex-1">
- <p class="text-xs font-medium text-[#cad5e2]">Why do I need a cookie file?</p>
- <p class="text-xs text-[#90a1b9] mt-1">Some videos are age-restricted, private, or members-only. A cookie file lets GrabZilla download these videos by authenticating with your YouTube/Vimeo account.</p>
- </div>
- </div>
- <div class="border-t border-[#45556c] pt-2">
- <p class="text-xs font-medium text-[#cad5e2] mb-2">How to get a cookie file:</p>
- <ol class="text-xs text-[#90a1b9] space-y-1 ml-4 list-decimal">
- <li>Install a browser extension like <span class="text-[#155dfc] font-medium">"Get cookies.txt LOCALLY"</span> or <span class="text-[#155dfc] font-medium">"cookies.txt"</span></li>
- <li>Log in to YouTube or Vimeo in your browser</li>
- <li>Click the extension icon and export cookies for the site</li>
- <li>Save the <span class="text-[#cad5e2] font-mono">cookies.txt</span> file to your computer</li>
- <li>Select it here using the "Select" button above</li>
- </ol>
- </div>
- <div class="border-t border-[#45556c] pt-2">
- <div class="flex items-start gap-2">
- <svg width="16" height="16" class="mt-0.5 flex-shrink-0 text-[#00a63e]" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
- <path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/>
- <polyline points="22 4 12 14.01 9 11.01"/>
- </svg>
- <p class="text-xs text-[#90a1b9]">
- <span class="text-[#00a63e] font-medium">Tip:</span> Keep your cookie file updated. If downloads fail, try exporting a fresh cookie file from your browser.
- </p>
- </div>
- </div>
- </div>
- </div>
- </div>
- <!-- Data Tab -->
- <div id="tab-data" class="settings-content hidden space-y-4">
- <div class="space-y-3">
- <h3 class="text-sm font-semibold text-white mb-3">Import & Export</h3>
- <div class="flex flex-col gap-2">
- <button id="exportListBtnSettings" class="border border-[#45556c] text-white px-4 py-3 rounded-lg text-sm font-medium flex items-center gap-2 hover:bg-[#45556c] transition-colors">
- <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
- <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/>
- <polyline points="7 10 12 15 17 10"/>
- <line x1="12" y1="15" x2="12" y2="3"/>
- </svg>
- Export Video List
- </button>
- <p class="text-xs text-[#90a1b9] ml-6">Save your current video queue to a JSON file</p>
- </div>
- <div class="flex flex-col gap-2 mt-4">
- <button id="importListBtnSettings" class="border border-[#45556c] text-white px-4 py-3 rounded-lg text-sm font-medium flex items-center gap-2 hover:bg-[#45556c] transition-colors">
- <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
- <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/>
- <polyline points="17 8 12 3 7 8"/>
- <line x1="12" y1="3" x2="12" y2="15"/>
- </svg>
- Import Video List
- </button>
- <p class="text-xs text-[#90a1b9] ml-6">Load a previously saved video queue from JSON</p>
- </div>
- </div>
- <div class="border-t border-[#45556c] pt-4">
- <h3 class="text-sm font-semibold text-white mb-3">Binary Updates</h3>
- <div class="flex flex-col gap-2">
- <button id="updateDepsBtnSettings" class="border border-[#45556c] text-white px-4 py-3 rounded-lg text-sm font-medium flex items-center gap-2 hover:bg-[#45556c] transition-colors">
- <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
- <path d="M21.5 2v6h-6M2.5 22v-6h6M2 11.5a10 10 0 0 1 18.8-4.3M22 12.5a10 10 0 0 1-18.8 4.2"/>
- </svg>
- Check for Binary Updates
- </button>
- <p class="text-xs text-[#90a1b9] ml-6">Check for updates to yt-dlp and ffmpeg binaries</p>
- </div>
- </div>
- </div>
- <!-- Shortcuts Tab -->
- <div id="tab-shortcuts" class="settings-content hidden">
- <div class="space-y-3">
- <div class="flex justify-between items-center py-2 border-b border-[#45556c]">
- <span class="text-sm text-[#cad5e2]">Download selected videos</span>
- <kbd class="px-2 py-1 bg-[#1d293d] border border-[#45556c] rounded text-xs text-[#90a1b9]">Ctrl+D</kbd>
- </div>
- <div class="flex justify-between items-center py-2 border-b border-[#45556c]">
- <span class="text-sm text-[#cad5e2]">Pause/Resume selected downloads</span>
- <kbd class="px-2 py-1 bg-[#1d293d] border border-[#45556c] rounded text-xs text-[#90a1b9]">P</kbd>
- </div>
- <div class="flex justify-between items-center py-2 border-b border-[#45556c]">
- <span class="text-sm text-[#cad5e2]">Remove selected videos</span>
- <kbd class="px-2 py-1 bg-[#1d293d] border border-[#45556c] rounded text-xs text-[#90a1b9]">Delete</kbd>
- </div>
- <div class="flex justify-between items-center py-2 border-b border-[#45556c]">
- <span class="text-sm text-[#cad5e2]">Select/Deselect video</span>
- <kbd class="px-2 py-1 bg-[#1d293d] border border-[#45556c] rounded text-xs text-[#90a1b9]">Space</kbd>
- </div>
- <div class="flex justify-between items-center py-2 border-b border-[#45556c]">
- <span class="text-sm text-[#cad5e2]">Select all videos</span>
- <kbd class="px-2 py-1 bg-[#1d293d] border border-[#45556c] rounded text-xs text-[#90a1b9]">Ctrl+A</kbd>
- </div>
- <div class="flex justify-between items-center py-2 border-b border-[#45556c]">
- <span class="text-sm text-[#cad5e2]">Open settings</span>
- <kbd class="px-2 py-1 bg-[#1d293d] border border-[#45556c] rounded text-xs text-[#90a1b9]">Ctrl+,</kbd>
- </div>
- <div class="flex justify-between items-center py-2 border-b border-[#45556c]">
- <span class="text-sm text-[#cad5e2]">Show shortcuts</span>
- <kbd class="px-2 py-1 bg-[#1d293d] border border-[#45556c] rounded text-xs text-[#90a1b9]">Ctrl+/</kbd>
- </div>
- <div class="flex justify-between items-center py-2">
- <span class="text-sm text-[#cad5e2]">Close modal</span>
- <kbd class="px-2 py-1 bg-[#1d293d] border border-[#45556c] rounded text-xs text-[#90a1b9]">Esc</kbd>
- </div>
- </div>
- </div>
- </div>
- <!-- Modal Footer -->
- <div class="p-4 border-t border-[#45556c] flex justify-end gap-2">
- <button id="cancelSettingsBtn" class="border border-[#45556c] text-white px-4 py-2 rounded-lg text-sm">
- Cancel
- </button>
- <button id="saveSettingsBtn" class="bg-[#155dfc] text-white px-4 py-2 rounded-lg text-sm font-medium">
- Save Settings
- </button>
- </div>
- </div>
- </div>
- <!-- Download History Modal -->
- <div id="historyModal" class="fixed inset-0 bg-black/80 hidden items-center justify-center z-50">
- <div class="bg-[#314158] rounded-lg shadow-2xl w-[900px] max-h-[90vh] flex flex-col">
- <!-- Modal Header -->
- <div class="flex items-center justify-between p-4 border-b border-[#45556c]">
- <h2 class="text-lg font-semibold text-white">Download History</h2>
- <div class="flex items-center gap-2">
- <button id="clearHistoryBtn" class="text-sm text-[#e7000b] hover:text-white px-3 py-1 rounded border border-[#e7000b] hover:bg-[#e7000b] transition-colors">
- Clear All
- </button>
- <button id="closeHistoryModal" class="text-[#90a1b9] hover:text-white transition-colors">
- <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
- <path d="M18 6L6 18M6 6l12 12"/>
- </svg>
- </button>
- </div>
- </div>
- <!-- History List -->
- <div class="flex-1 overflow-y-auto p-4">
- <div id="historyList" class="space-y-2">
- <!-- History entries will be inserted here -->
- </div>
- <div id="historyEmptyState" class="hidden flex flex-col items-center justify-center h-full text-center py-12">
- <svg width="64" height="64" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" class="text-[#45556c] mb-4">
- <circle cx="12" cy="12" r="10"/>
- <polyline points="12 6 12 12 16 14"/>
- </svg>
- <p class="text-[#90a1b9] text-lg">No download history yet</p>
- <p class="text-[#62748e] text-sm mt-2">Completed downloads will appear here</p>
- </div>
- </div>
- </div>
- </div>
- <!-- Video Preview Modal -->
- <div id="previewModal" class="fixed inset-0 bg-black/80 hidden items-center justify-center z-50">
- <div class="bg-[#314158] rounded-lg shadow-2xl w-[900px] max-h-[90vh] flex flex-col">
- <!-- Modal Header -->
- <div class="flex items-center justify-between p-4 border-b border-[#45556c]">
- <h2 id="previewTitle" class="text-lg font-semibold text-white truncate flex-1 pr-4">Video Preview</h2>
- <button id="closePreviewModal" class="text-[#90a1b9] hover:text-white transition-colors flex-shrink-0">
- <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
- <path d="M18 6L6 18M6 6l12 12"/>
- </svg>
- </button>
- </div>
- <!-- Video Player -->
- <div class="aspect-video bg-black">
- <iframe id="previewPlayer" class="w-full h-full" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
- </div>
- <!-- Video Info -->
- <div class="p-4 space-y-3 overflow-y-auto flex-1">
- <div class="flex items-center gap-4 text-sm text-[#cad5e2]">
- <span id="previewDuration" class="flex items-center gap-1">
- <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
- <circle cx="12" cy="12" r="10"/>
- <polyline points="12 6 12 12 16 14"/>
- </svg>
- <span>--:--</span>
- </span>
- <span id="previewViews" class="flex items-center gap-1">
- <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
- <path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/>
- <circle cx="12" cy="12" r="3"/>
- </svg>
- <span>-- views</span>
- </span>
- <span id="previewLikes" class="flex items-center gap-1">
- <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
- <path d="M14 9V5a3 3 0 0 0-3-3l-4 9v11h11.28a2 2 0 0 0 2-1.7l1.38-9a2 2 0 0 0-2-2.3zM7 22H4a2 2 0 0 1-2-2v-7a2 2 0 0 1 2-2h3"/>
- </svg>
- <span>-- likes</span>
- </span>
- </div>
- <div>
- <h3 class="text-sm font-medium text-[#cad5e2] mb-1">Description</h3>
- <p id="previewDescription" class="text-sm text-[#90a1b9] whitespace-pre-wrap">Loading...</p>
- </div>
- </div>
- <!-- Modal Footer -->
- <div class="p-4 border-t border-[#45556c] flex justify-end gap-2">
- <button id="closePreviewBtn" class="border border-[#45556c] text-white px-4 py-2 rounded-lg text-sm">
- Close
- </button>
- <button id="downloadFromPreviewBtn" class="bg-[#155dfc] text-white px-4 py-2 rounded-lg text-sm font-medium">
- Download This Video
- </button>
- </div>
- </div>
- </div>
- <!-- Load modular scripts in dependency order -->
- <script>
- // Track script loading
- window.scriptLoadErrors = [];
- function loadScript(src, callback) {
- const script = document.createElement('script');
- script.src = src;
- script.onload = () => {
- console.log(`✓ Loaded: ${src}`);
- if (callback) callback();
- };
- script.onerror = () => {
- console.error(`✗ Failed to load: ${src}`);
- window.scriptLoadErrors.push(src);
- if (callback) callback();
- };
- document.head.appendChild(script);
- }
- // Load modular scripts in correct dependency order
- loadScript('scripts/utils/config.js', () => {
- loadScript('scripts/utils/url-validator.js', () => {
- loadScript('scripts/core/event-bus.js', () => {
- loadScript('scripts/models/Video.js', () => {
- loadScript('scripts/models/AppState.js', () => {
- loadScript('scripts/utils/error-handler.js', () => {
- loadScript('scripts/utils/desktop-notifications.js', () => {
- loadScript('scripts/utils/live-region-manager.js', () => {
- loadScript('scripts/utils/accessibility-manager.js', () => {
- loadScript('scripts/utils/keyboard-navigation.js', () => {
- loadScript('scripts/utils/ipc-integration.js', () => {
- loadScript('scripts/services/metadata-service.js', () => {
- loadScript('scripts/utils/enhanced-download-methods.js', () => {
- loadScript('scripts/app.js', () => {
- loadScript('scripts/utils/download-integration-patch.js', () => {
- console.log('✅ All modular scripts loaded successfully');
- if (window.scriptLoadErrors.length > 0) {
- console.warn('⚠️ Some scripts failed to load:', window.scriptLoadErrors);
- }
- // Initialize app after all scripts have loaded
- if (typeof window.initializeGrabZilla === 'function') {
- console.log('🚀 Initializing GrabZilla app...');
- window.initializeGrabZilla();
- } else {
- console.error('❌ initializeGrabZilla function not found');
- }
- });
- });
- });
- });
- });
- });
- });
- });
- });
- });
- });
- });
- });
- });
- });
- </script>
- <!-- Debug script -->
- <script>
- // Debug logging
- console.log('All scripts loaded');
- // Check if buttons exist when DOM is ready
- document.addEventListener('DOMContentLoaded', () => {
- console.log('DOM Content Loaded - checking buttons...');
- const buttons = ['addVideoBtn', 'importUrlsBtn', 'savePathBtn', 'cookieFileBtn'];
- buttons.forEach(id => {
- const btn = document.getElementById(id);
- console.log(`Button ${id}:`, btn ? 'FOUND' : 'NOT FOUND');
- });
- // Check if app was initialized and provide fallback
- setTimeout(() => {
- console.log('App instance:', window.app ? 'EXISTS' : 'NOT FOUND');
- console.log('Script load errors:', window.scriptLoadErrors || 'none');
- if (window.app) {
- console.log('App state:', window.app.state);
- console.log('App initialized successfully');
- } else {
- console.log('App not initialized, setting up fallback button listeners...');
- // Create a minimal app-like object for basic functionality
- window.fallbackApp = {
- handleAddVideo: function () {
- const urlInput = document.getElementById('urlInput');
- const inputText = urlInput ? urlInput.value.trim() : '';
- if (!inputText) {
- alert('Please enter a URL');
- return;
- }
- console.log('Processing URLs:', inputText);
- alert(`Would add video(s): ${inputText}`);
- if (urlInput) urlInput.value = '';
- },
- handleImportUrls: function () {
- alert('Import URLs functionality (requires Electron)');
- },
- handleSelectSavePath: function () {
- alert('Save path selection (requires Electron)');
- },
- handleSelectCookieFile: function () {
- alert('Cookie file selection (requires Electron)');
- }
- };
- // Attach fallback event listeners
- const addVideoBtn = document.getElementById('addVideoBtn');
- if (addVideoBtn) {
- addVideoBtn.addEventListener('click', window.fallbackApp.handleAddVideo);
- console.log('✓ Fallback listener attached to Add Video button');
- }
- const importUrlsBtn = document.getElementById('importUrlsBtn');
- if (importUrlsBtn) {
- importUrlsBtn.addEventListener('click', window.fallbackApp.handleImportUrls);
- console.log('✓ Fallback listener attached to Import URLs button');
- }
- const savePathBtn = document.getElementById('savePathBtn');
- if (savePathBtn) {
- savePathBtn.addEventListener('click', window.fallbackApp.handleSelectSavePath);
- console.log('✓ Fallback listener attached to Save Path button');
- }
- const cookieFileBtn = document.getElementById('cookieFileBtn');
- if (cookieFileBtn) {
- cookieFileBtn.addEventListener('click', window.fallbackApp.handleSelectCookieFile);
- console.log('✓ Fallback listener attached to Cookie File button');
- }
- console.log('Fallback initialization complete');
- }
- }, 3000);
- });
- // Catch any errors
- window.addEventListener('error', (e) => {
- console.error('JavaScript Error:', e.error);
- console.error('File:', e.filename, 'Line:', e.lineno);
- });
- </script>
- </body>
- </html>
|