index.html 69 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <title>GrabZilla 2.1</title>
  7. <script src="https://cdn.tailwindcss.com"></script>
  8. <link rel="stylesheet" href="styles/main.css">
  9. <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap" rel="stylesheet">
  10. </head>
  11. <body class="bg-[#1d293d] text-white min-h-screen flex flex-col font-['Inter']">
  12. <!-- Header - macOS Title Bar Style -->
  13. <header class="bg-[#0f172b] h-[41px] flex items-center justify-center border-b border-[#314158] shrink-0 relative"
  14. role="banner" aria-label="GrabZilla application header" style="-webkit-app-region: drag;">
  15. <!-- Centered Title -->
  16. <div class="flex items-center gap-2" style="-webkit-app-region: no-drag;">
  17. <div class="bg-[#155dfc] w-6 h-6 rounded flex items-center justify-center">
  18. <img src="assets/icons/logo.svg" alt="GrabZilla Logo" width="16" height="16">
  19. </div>
  20. <h1 class="font-medium text-base text-white tracking-[-0.3125px] leading-6">GrabZilla 2.1</h1>
  21. </div>
  22. <!-- Settings Button (Right side) -->
  23. <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+,)">
  24. <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  25. <circle cx="12" cy="12" r="3"/>
  26. <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"/>
  27. </svg>
  28. </button>
  29. </header>
  30. <!-- Input Section - Exact Figma: 161px height -->
  31. <section class="h-[161px] border-b border-[#314158] px-4 py-4 shrink-0 flex flex-col gap-4" role="region"
  32. aria-label="Video URL input and configuration" aria-describedby="input-section-help">
  33. <div id="input-section-help" class="sr-only">
  34. Enter YouTube or Vimeo URLs to add videos to the download queue. Configure default quality and format
  35. settings.
  36. </div>
  37. <!-- URL Input Row -->
  38. <div class="flex gap-2 h-20">
  39. <!-- Textarea -->
  40. <textarea id="urlInput"
  41. class="flex-1 bg-[#314158] border border-[#45556c] rounded-lg p-3 text-sm resize-none text-[#90a1b9] placeholder-[#90a1b9] tracking-[-0.1504px]"
  42. placeholder="Paste YouTube/Vimeo URLs here (one per line)..." aria-label="YouTube and Vimeo URLs input"
  43. aria-describedby="url-help"></textarea>
  44. <div id="url-help" class="sr-only">Enter one URL per line. Supports YouTube and Vimeo links.</div>
  45. <!-- Action Buttons -->
  46. <div class="flex flex-col gap-2 w-[140px]">
  47. <button id="addVideoBtn"
  48. 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]">
  49. <img src="assets/icons/add.svg" alt="Add" width="16" height="16">
  50. Add Video
  51. </button>
  52. <button id="importUrlsBtn"
  53. 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]">
  54. <img src="assets/icons/import.svg" alt="Import" width="16" height="16">
  55. Import URLs
  56. </button>
  57. </div>
  58. </div>
  59. <!-- Configuration Row -->
  60. <div class="flex items-center justify-between gap-4 h-8">
  61. <!-- Defaults Section -->
  62. <div class="flex items-center gap-2">
  63. <img src="assets/icons/clock.svg" alt="Clock" width="16" height="16">
  64. <span class="text-[#90a1b9] text-sm tracking-[-0.1504px]">Defaults:</span>
  65. <!-- Quality Dropdown -->
  66. <select id="defaultQuality"
  67. class="bg-[#314158] border border-[#45556c] text-[#cad5e2] px-3 py-1 rounded-lg text-xs h-7 font-medium"
  68. aria-label="Default video quality">
  69. <option value="Best">Best</option>
  70. <option value="1080p" selected>1080p</option>
  71. <option value="720p">720p</option>
  72. <option value="4K">4K</option>
  73. </select>
  74. <!-- Format Dropdown -->
  75. <select id="defaultFormat"
  76. class="bg-[#314158] border border-[#45556c] text-[#cad5e2] px-3 py-1 rounded-lg text-xs h-7 font-medium"
  77. aria-label="Default conversion format">
  78. <option value="None" selected>None</option>
  79. <option value="H264">H264</option>
  80. <option value="ProRes">ProRes</option>
  81. <option value="DNxHR">DNxHR</option>
  82. <option value="Audio only">Audio only</option>
  83. </select>
  84. <!-- Clipboard Monitoring -->
  85. <div class="flex items-center gap-2 ml-4 group relative">
  86. <span class="text-[#90a1b9] text-sm tracking-[-0.1504px]">Clipboard:</span>
  87. <label class="relative inline-flex items-center cursor-pointer">
  88. <input type="checkbox" id="clipboardMonitorToggle" class="sr-only peer">
  89. <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>
  90. <span class="ml-2 text-xs text-[#cad5e2]">Monitor</span>
  91. </label>
  92. <!-- Info Icon with Tooltip -->
  93. <div class="relative">
  94. <svg class="w-4 h-4 text-[#90a1b9] hover:text-[#155dfc] transition-colors cursor-help" fill="currentColor" viewBox="0 0 20 20">
  95. <path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z" clip-rule="evenodd"/>
  96. </svg>
  97. <!-- Tooltip -->
  98. <div class="absolute hidden group-hover:block bottom-full right-0 mb-2 w-64 px-3 py-2 text-xs text-white bg-[#1d293d] border border-[#45556c] rounded-lg shadow-lg z-50">
  99. <div class="font-semibold mb-1">Auto-detect Video URLs</div>
  100. <div class="text-[#cad5e2]">Automatically detects when you copy YouTube or Vimeo links. Your privacy is protected - only video URLs are checked.</div>
  101. <div class="absolute top-full right-4 -mt-1 border-4 border-transparent border-t-[#45556c]"></div>
  102. </div>
  103. </div>
  104. </div>
  105. </div>
  106. <!-- Settings Button -->
  107. <button id="settingsBtn2"
  108. 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">
  109. <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  110. <circle cx="12" cy="12" r="3"/>
  111. <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"/>
  112. </svg>
  113. Settings
  114. </button>
  115. </div>
  116. </section>
  117. <!-- Video List - Flex grow to fill remaining space -->
  118. <main class="flex-1 overflow-hidden" role="main" aria-label="Video download queue"
  119. aria-describedby="main-content-help">
  120. <div id="main-content-help" class="sr-only">
  121. Video download queue. Use arrow keys to navigate, Enter or Space to select videos, Delete to remove videos.
  122. </div>
  123. <!-- Table Header -->
  124. <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]"
  125. role="row" aria-label="Video list column headers">
  126. <div role="columnheader" aria-label="Selection checkbox"></div>
  127. <div role="columnheader" aria-label="Drag handle"></div>
  128. <div role="columnheader">Title</div>
  129. <div role="columnheader">Duration</div>
  130. <div role="columnheader">Quality</div>
  131. <div role="columnheader">Conversion</div>
  132. <div role="columnheader">Status</div>
  133. </div>
  134. <!-- Video Items Container -->
  135. <div id="videoList" class="px-4 pt-2 pb-4 space-y-2 overflow-y-auto h-full" role="grid"
  136. aria-label="Video download queue" aria-describedby="video-list-instructions" tabindex="0">
  137. <div id="video-list-instructions" class="sr-only">
  138. Use arrow keys to navigate between videos. Press Enter or Space to select videos. Press Delete to remove
  139. videos. Press Ctrl+A to select all videos.
  140. </div>
  141. <!-- Sample Video Items - Matching Figma Design -->
  142. <!-- Video Item 1 - Ready State -->
  143. <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"
  144. data-video-id="video-1" role="gridcell" tabindex="0" aria-rowindex="1"
  145. aria-describedby="video-1-description">
  146. <!-- Checkbox -->
  147. <div class="flex items-center justify-center">
  148. <button
  149. class="video-checkbox w-6 h-6 rounded flex items-center justify-center hover:bg-[#45556c] transition-colors"
  150. role="checkbox" aria-checked="false" aria-label="Select Interstellar 2014 Trailer" tabindex="0">
  151. <svg width="16" height="16" viewBox="0 0 16 16" fill="none" class="text-white">
  152. <rect x="3" y="3" width="10" height="10" stroke="currentColor" stroke-width="1.5"
  153. fill="none" rx="2" />
  154. </svg>
  155. </button>
  156. </div>
  157. <!-- Drag Handle -->
  158. <div
  159. class="flex items-center justify-center text-[#90a1b9] hover:text-white cursor-grab transition-colors">
  160. <svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor">
  161. <circle cx="4" cy="4" r="1" />
  162. <circle cx="4" cy="8" r="1" />
  163. <circle cx="4" cy="12" r="1" />
  164. <circle cx="8" cy="4" r="1" />
  165. <circle cx="8" cy="8" r="1" />
  166. <circle cx="8" cy="12" r="1" />
  167. <circle cx="12" cy="4" r="1" />
  168. <circle cx="12" cy="8" r="1" />
  169. <circle cx="12" cy="12" r="1" />
  170. </svg>
  171. </div>
  172. <!-- Video Info -->
  173. <div class="flex items-center gap-3 min-w-0">
  174. <div class="w-16 h-12 bg-[#45556c] rounded overflow-hidden flex-shrink-0">
  175. <div
  176. class="w-full h-full bg-gradient-to-br from-[#4a5568] to-[#2d3748] flex items-center justify-center">
  177. <svg width="24" height="24" viewBox="0 0 24 24" fill="none" class="text-[#90a1b9]">
  178. <path d="M8 5V19L19 12L8 5Z" stroke="currentColor" stroke-width="2"
  179. stroke-linejoin="round" />
  180. </svg>
  181. </div>
  182. </div>
  183. <div class="min-w-0 flex-1">
  184. <div class="text-sm text-white truncate font-medium">Interstellar 2014 Trailer | 4K Ultra HD
  185. </div>
  186. </div>
  187. </div>
  188. <!-- Duration -->
  189. <div class="text-sm text-[#cad5e2] text-center">2:25</div>
  190. <!-- Quality Dropdown -->
  191. <div class="flex justify-center">
  192. <select
  193. class="bg-[#314158] border border-[#45556c] text-[#cad5e2] px-2 py-1 rounded text-xs font-medium min-w-0 w-full text-center"
  194. aria-label="Quality for Interstellar 2014 Trailer">
  195. <option value="Best">Best</option>
  196. <option value="4K" selected>4K</option>
  197. <option value="1080p">1080p</option>
  198. <option value="720p">720p</option>
  199. </select>
  200. </div>
  201. <!-- Format Dropdown -->
  202. <div class="flex justify-center">
  203. <select
  204. class="bg-[#314158] border border-[#45556c] text-[#cad5e2] px-2 py-1 rounded text-xs font-medium min-w-0 w-full text-center"
  205. aria-label="Format for Interstellar 2014 Trailer">
  206. <option value="None" selected>None</option>
  207. <option value="H264">H264</option>
  208. <option value="ProRes">ProRes</option>
  209. <option value="DNxHR">DNxHR</option>
  210. <option value="Audio only">Audio only</option>
  211. </select>
  212. </div>
  213. <!-- Status Badge -->
  214. <div class="flex justify-center status-column">
  215. <span class="status-badge ready" role="status" aria-live="polite"
  216. aria-label="Video ready for download">
  217. Ready
  218. </span>
  219. </div>
  220. <!-- Video Description for Screen Readers -->
  221. <div id="video-1-description" class="sr-only">
  222. Video: Interstellar 2014 Trailer | 4K Ultra HD, Duration: 2:25, Status: Ready. Press Enter or Space
  223. to select, Delete to remove.
  224. </div>
  225. </div>
  226. <!-- Video Item 2 - Downloading State -->
  227. <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"
  228. data-video-id="video-2">
  229. <!-- Checkbox -->
  230. <div class="flex items-center justify-center">
  231. <button
  232. class="w-6 h-6 rounded flex items-center justify-center hover:bg-[#45556c] transition-colors">
  233. <svg width="16" height="16" viewBox="0 0 16 16" fill="none" class="text-white">
  234. <rect x="3" y="3" width="10" height="10" stroke="currentColor" stroke-width="1.5"
  235. fill="none" rx="2" />
  236. </svg>
  237. </button>
  238. </div>
  239. <!-- Drag Handle -->
  240. <div
  241. class="flex items-center justify-center text-[#90a1b9] hover:text-white cursor-grab transition-colors">
  242. <svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor">
  243. <circle cx="4" cy="4" r="1" />
  244. <circle cx="4" cy="8" r="1" />
  245. <circle cx="4" cy="12" r="1" />
  246. <circle cx="8" cy="4" r="1" />
  247. <circle cx="8" cy="8" r="1" />
  248. <circle cx="8" cy="12" r="1" />
  249. <circle cx="12" cy="4" r="1" />
  250. <circle cx="12" cy="8" r="1" />
  251. <circle cx="12" cy="12" r="1" />
  252. </svg>
  253. </div>
  254. <!-- Video Info -->
  255. <div class="flex items-center gap-3 min-w-0">
  256. <div class="w-16 h-12 bg-[#45556c] rounded overflow-hidden flex-shrink-0">
  257. <div
  258. class="w-full h-full bg-gradient-to-br from-[#4a5568] to-[#2d3748] flex items-center justify-center">
  259. <svg width="24" height="24" viewBox="0 0 24 24" fill="none" class="text-[#90a1b9]">
  260. <path d="M8 5V19L19 12L8 5Z" stroke="currentColor" stroke-width="2"
  261. stroke-linejoin="round" />
  262. </svg>
  263. </div>
  264. </div>
  265. <div class="min-w-0 flex-1">
  266. <div class="text-sm text-white truncate font-medium">Greenland (2020) 4K Trailer | Upscaled
  267. Trailers</div>
  268. </div>
  269. </div>
  270. <!-- Duration -->
  271. <div class="text-sm text-[#cad5e2] text-center">2:30</div>
  272. <!-- Quality Dropdown -->
  273. <div class="flex justify-center">
  274. <select
  275. class="bg-[#314158] border border-[#45556c] text-[#cad5e2] px-2 py-1 rounded text-xs font-medium min-w-0 w-full text-center">
  276. <option value="Best">Best</option>
  277. <option value="1080p" selected>1080p</option>
  278. <option value="4K">4K</option>
  279. <option value="720p">720p</option>
  280. </select>
  281. </div>
  282. <!-- Format Dropdown -->
  283. <div class="flex justify-center">
  284. <select
  285. class="bg-[#314158] border border-[#45556c] text-[#cad5e2] px-2 py-1 rounded text-xs font-medium min-w-0 w-full text-center">
  286. <option value="ProRes" selected>ProRes</option>
  287. <option value="None">None</option>
  288. <option value="H264">H264</option>
  289. <option value="DNxHR">DNxHR</option>
  290. <option value="Audio only">Audio only</option>
  291. </select>
  292. </div>
  293. <!-- Status Badge with Integrated Progress -->
  294. <div class="flex justify-center status-column">
  295. <span class="status-badge downloading" role="status" aria-live="polite" aria-label="Downloading 65%"
  296. data-progress="65">
  297. Downloading 65%
  298. </span>
  299. </div>
  300. </div>
  301. <!-- Video Item 3 - Converting State -->
  302. <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"
  303. data-video-id="video-3">
  304. <!-- Checkbox -->
  305. <div class="flex items-center justify-center">
  306. <button
  307. class="w-6 h-6 rounded flex items-center justify-center hover:bg-[#45556c] transition-colors">
  308. <svg width="16" height="16" viewBox="0 0 16 16" fill="none" class="text-white">
  309. <rect x="3" y="3" width="10" height="10" stroke="currentColor" stroke-width="1.5"
  310. fill="none" rx="2" />
  311. </svg>
  312. </button>
  313. </div>
  314. <!-- Drag Handle -->
  315. <div
  316. class="flex items-center justify-center text-[#90a1b9] hover:text-white cursor-grab transition-colors">
  317. <svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor">
  318. <circle cx="4" cy="4" r="1" />
  319. <circle cx="4" cy="8" r="1" />
  320. <circle cx="4" cy="12" r="1" />
  321. <circle cx="8" cy="4" r="1" />
  322. <circle cx="8" cy="8" r="1" />
  323. <circle cx="8" cy="12" r="1" />
  324. <circle cx="12" cy="4" r="1" />
  325. <circle cx="12" cy="8" r="1" />
  326. <circle cx="12" cy="12" r="1" />
  327. </svg>
  328. </div>
  329. <!-- Video Info -->
  330. <div class="flex items-center gap-3 min-w-0">
  331. <div class="w-16 h-12 bg-[#45556c] rounded overflow-hidden flex-shrink-0">
  332. <div
  333. class="w-full h-full bg-gradient-to-br from-[#4a5568] to-[#2d3748] flex items-center justify-center">
  334. <svg width="24" height="24" viewBox="0 0 24 24" fill="none" class="text-[#90a1b9]">
  335. <path d="M8 5V19L19 12L8 5Z" stroke="currentColor" stroke-width="2"
  336. stroke-linejoin="round" />
  337. </svg>
  338. </div>
  339. </div>
  340. <div class="min-w-0 flex-1">
  341. <div class="text-sm text-white truncate font-medium">GREENLAND Trailer German Deutsch (2020)
  342. </div>
  343. </div>
  344. </div>
  345. <!-- Duration -->
  346. <div class="text-sm text-[#cad5e2] text-center">2:38</div>
  347. <!-- Quality Dropdown -->
  348. <div class="flex justify-center">
  349. <select
  350. class="bg-[#314158] border border-[#45556c] text-[#cad5e2] px-2 py-1 rounded text-xs font-medium min-w-0 w-full text-center">
  351. <option value="Best">Best</option>
  352. <option value="1080p" selected>1080p</option>
  353. <option value="4K">4K</option>
  354. <option value="720p">720p</option>
  355. </select>
  356. </div>
  357. <!-- Format Dropdown -->
  358. <div class="flex justify-center">
  359. <select
  360. class="bg-[#314158] border border-[#45556c] text-[#cad5e2] px-2 py-1 rounded text-xs font-medium min-w-0 w-full text-center">
  361. <option value="H264" selected>H264</option>
  362. <option value="None">None</option>
  363. <option value="ProRes">ProRes</option>
  364. <option value="DNxHR">DNxHR</option>
  365. <option value="Audio only">Audio only</option>
  366. </select>
  367. </div>
  368. <!-- Status Badge with Integrated Progress -->
  369. <div class="flex justify-center status-column">
  370. <span class="status-badge converting" role="status" aria-live="polite" aria-label="Converting 42%"
  371. data-progress="42">
  372. Converting 42%
  373. </span>
  374. </div>
  375. </div>
  376. <!-- Video Item 4 - Completed State -->
  377. <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"
  378. data-video-id="video-4">
  379. <!-- Checkbox -->
  380. <div class="flex items-center justify-center">
  381. <button
  382. class="w-6 h-6 rounded flex items-center justify-center hover:bg-[#45556c] transition-colors">
  383. <svg width="16" height="16" viewBox="0 0 16 16" fill="none" class="text-white">
  384. <rect x="3" y="3" width="10" height="10" stroke="currentColor" stroke-width="1.5"
  385. fill="none" rx="2" />
  386. </svg>
  387. </button>
  388. </div>
  389. <!-- Drag Handle -->
  390. <div
  391. class="flex items-center justify-center text-[#90a1b9] hover:text-white cursor-grab transition-colors">
  392. <svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor">
  393. <circle cx="4" cy="4" r="1" />
  394. <circle cx="4" cy="8" r="1" />
  395. <circle cx="4" cy="12" r="1" />
  396. <circle cx="8" cy="4" r="1" />
  397. <circle cx="8" cy="8" r="1" />
  398. <circle cx="8" cy="12" r="1" />
  399. <circle cx="12" cy="4" r="1" />
  400. <circle cx="12" cy="8" r="1" />
  401. <circle cx="12" cy="12" r="1" />
  402. </svg>
  403. </div>
  404. <!-- Video Info -->
  405. <div class="flex items-center gap-3 min-w-0">
  406. <div class="w-16 h-12 bg-[#45556c] rounded overflow-hidden flex-shrink-0">
  407. <div
  408. class="w-full h-full bg-gradient-to-br from-[#4a5568] to-[#2d3748] flex items-center justify-center">
  409. <svg width="24" height="24" viewBox="0 0 24 24" fill="none" class="text-[#90a1b9]">
  410. <path d="M8 5V19L19 12L8 5Z" stroke="currentColor" stroke-width="2"
  411. stroke-linejoin="round" />
  412. </svg>
  413. </div>
  414. </div>
  415. <div class="min-w-0 flex-1">
  416. <div class="text-sm text-white truncate font-medium">A Quiet Place (2018) - Official Trailer -
  417. Paramount Pictures</div>
  418. </div>
  419. </div>
  420. <!-- Duration -->
  421. <div class="text-sm text-[#cad5e2] text-center">1:56</div>
  422. <!-- Quality Dropdown -->
  423. <div class="flex justify-center">
  424. <select
  425. class="bg-[#314158] border border-[#45556c] text-[#cad5e2] px-2 py-1 rounded text-xs font-medium min-w-0 w-full text-center">
  426. <option value="Best">Best</option>
  427. <option value="720p" selected>720p</option>
  428. <option value="4K">4K</option>
  429. <option value="1080p">1080p</option>
  430. </select>
  431. </div>
  432. <!-- Format Dropdown -->
  433. <div class="flex justify-center">
  434. <select
  435. class="bg-[#314158] border border-[#45556c] text-[#cad5e2] px-2 py-1 rounded text-xs font-medium min-w-0 w-full text-center">
  436. <option value="Audio only" selected>Audio only</option>
  437. <option value="None">None</option>
  438. <option value="H264">H264</option>
  439. <option value="ProRes">ProRes</option>
  440. <option value="DNxHR">DNxHR</option>
  441. </select>
  442. </div>
  443. <!-- Status Badge -->
  444. <div class="flex justify-center status-column">
  445. <span class="status-badge completed" role="status" aria-live="polite"
  446. aria-label="Video download completed">
  447. Completed
  448. </span>
  449. </div>
  450. </div>
  451. <!-- Video Item 5 - Error State -->
  452. <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"
  453. data-video-id="video-5">
  454. <!-- Checkbox -->
  455. <div class="flex items-center justify-center">
  456. <button
  457. class="w-6 h-6 rounded flex items-center justify-center hover:bg-[#45556c] transition-colors">
  458. <svg width="16" height="16" viewBox="0 0 16 16" fill="none" class="text-white">
  459. <rect x="3" y="3" width="10" height="10" stroke="currentColor" stroke-width="1.5"
  460. fill="none" rx="2" />
  461. </svg>
  462. </button>
  463. </div>
  464. <!-- Drag Handle -->
  465. <div
  466. class="flex items-center justify-center text-[#90a1b9] hover:text-white cursor-grab transition-colors">
  467. <svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor">
  468. <circle cx="4" cy="4" r="1" />
  469. <circle cx="4" cy="8" r="1" />
  470. <circle cx="4" cy="12" r="1" />
  471. <circle cx="8" cy="4" r="1" />
  472. <circle cx="8" cy="8" r="1" />
  473. <circle cx="8" cy="12" r="1" />
  474. <circle cx="12" cy="4" r="1" />
  475. <circle cx="12" cy="8" r="1" />
  476. <circle cx="12" cy="12" r="1" />
  477. </svg>
  478. </div>
  479. <!-- Video Info -->
  480. <div class="flex items-center gap-3 min-w-0">
  481. <div class="w-16 h-12 bg-[#45556c] rounded overflow-hidden flex-shrink-0">
  482. <div
  483. class="w-full h-full bg-gradient-to-br from-[#4a5568] to-[#2d3748] flex items-center justify-center">
  484. <svg width="24" height="24" viewBox="0 0 24 24" fill="none" class="text-[#90a1b9]">
  485. <path d="M8 5V19L19 12L8 5Z" stroke="currentColor" stroke-width="2"
  486. stroke-linejoin="round" />
  487. </svg>
  488. </div>
  489. </div>
  490. <div class="min-w-0 flex-1">
  491. <div class="text-sm text-white truncate font-medium">Blade Runner 2049 - Official Trailer -
  492. Warner Bros. Pictures</div>
  493. </div>
  494. </div>
  495. <!-- Duration -->
  496. <div class="text-sm text-[#cad5e2] text-center">3:47</div>
  497. <!-- Quality Dropdown -->
  498. <div class="flex justify-center">
  499. <select
  500. class="bg-[#314158] border border-[#45556c] text-[#cad5e2] px-2 py-1 rounded text-xs font-medium min-w-0 w-full text-center">
  501. <option value="Best">Best</option>
  502. <option value="4K" selected>4K</option>
  503. <option value="1080p">1080p</option>
  504. <option value="720p">720p</option>
  505. </select>
  506. </div>
  507. <!-- Format Dropdown -->
  508. <div class="flex justify-center">
  509. <select
  510. class="bg-[#314158] border border-[#45556c] text-[#cad5e2] px-2 py-1 rounded text-xs font-medium min-w-0 w-full text-center">
  511. <option value="H264" selected>H264</option>
  512. <option value="None">None</option>
  513. <option value="ProRes">ProRes</option>
  514. <option value="DNxHR">DNxHR</option>
  515. <option value="Audio only">Audio only</option>
  516. </select>
  517. </div>
  518. <!-- Status Badge -->
  519. <div class="flex justify-center status-column">
  520. <span class="status-badge error" role="status" aria-live="polite"
  521. aria-label="Video download failed">
  522. Error
  523. </span>
  524. </div>
  525. </div>
  526. </div>
  527. </main>
  528. <!-- Control Panel - Exact Figma: 93px height -->
  529. <footer class="h-[93px] border-t border-[#314158] px-4 py-4 shrink-0 flex flex-col gap-2" role="contentinfo"
  530. aria-label="Download controls and actions" aria-describedby="control-panel-help">
  531. <div id="control-panel-help" class="sr-only">
  532. Control panel with actions for managing downloads. Use Ctrl+D to start downloads quickly.
  533. </div>
  534. <!-- Button Row -->
  535. <div class="flex items-center justify-between h-9">
  536. <div class="flex items-center gap-2">
  537. <button id="clearListBtn"
  538. 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]"
  539. aria-label="Clear all videos from list">
  540. <img src="assets/icons/trash.svg" alt="" width="16" height="16" loading="lazy">
  541. Clear List
  542. </button>
  543. <button id="updateDepsBtn"
  544. 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]"
  545. aria-label="Check for updates to yt-dlp and ffmpeg">
  546. <img src="assets/icons/refresh.svg" alt="" width="16" height="16" loading="lazy">
  547. Check for Updates
  548. </button>
  549. <button id="showHistoryBtn"
  550. 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"
  551. aria-label="View download history">
  552. <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  553. <circle cx="12" cy="12" r="10"/>
  554. <polyline points="12 6 12 12 16 14"/>
  555. </svg>
  556. History
  557. </button>
  558. <button id="cancelDownloadsBtn"
  559. 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]"
  560. aria-label="Cancel all active downloads">
  561. <img src="assets/icons/close.svg" alt="Cancel" width="16" height="16">
  562. Cancel Downloads
  563. </button>
  564. </div>
  565. <button id="downloadVideosBtn"
  566. 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]">
  567. <img src="assets/icons/download.svg" alt="Download" width="16" height="16">
  568. Download Videos
  569. </button>
  570. </div>
  571. <!-- Status Message & Binary Versions -->
  572. <div class="flex items-center justify-between text-xs text-[#90a1b9] h-6 px-4">
  573. <!-- Left: Status Message -->
  574. <span id="statusMessage" role="status" aria-live="polite">Ready to download videos</span>
  575. <!-- Right: Binary Versions -->
  576. <div id="binaryVersions" class="flex items-center gap-4">
  577. <div id="ytdlpVersion" class="flex items-center gap-2">
  578. <span class="font-medium text-[#cad5e2]">yt-dlp:</span>
  579. <span id="ytdlpVersionNumber">--</span>
  580. <span id="ytdlpUpdateBadge" class="hidden update-badge" title="Update available">●</span>
  581. </div>
  582. <div id="ffmpegVersion" class="flex items-center gap-2">
  583. <span class="font-medium text-[#cad5e2]">ffmpeg:</span>
  584. <span id="ffmpegVersionNumber">--</span>
  585. </div>
  586. <span id="lastUpdateCheck" class="text-[#62748e] text-[10px]" title="Last update check">--</span>
  587. </div>
  588. </div>
  589. </footer>
  590. <!-- Playlist Modal -->
  591. <div id="playlistModal" class="fixed inset-0 bg-black/60 hidden items-center justify-center z-50">
  592. <div class="bg-[#314158] rounded-lg shadow-2xl w-[800px] max-h-[80vh] flex flex-col">
  593. <!-- Modal Header -->
  594. <div class="flex items-center justify-between p-4 border-b border-[#45556c]">
  595. <h2 id="playlistTitle" class="text-lg font-semibold text-white">Playlist Videos</h2>
  596. <button id="closePlaylistModal" class="text-[#90a1b9] hover:text-white transition-colors">
  597. <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
  598. <path d="M18 6L6 18M6 6l12 12"/>
  599. </svg>
  600. </button>
  601. </div>
  602. <!-- Playlist Info -->
  603. <div class="p-4 border-b border-[#45556c]">
  604. <p id="playlistInfo" class="text-sm text-[#cad5e2]">Loading playlist...</p>
  605. </div>
  606. <!-- Video List (Scrollable) -->
  607. <div id="playlistVideoList" class="flex-1 overflow-y-auto p-4 space-y-2">
  608. <!-- Videos will be inserted here -->
  609. </div>
  610. <!-- Modal Footer -->
  611. <div class="p-4 border-t border-[#45556c] flex items-center justify-between">
  612. <label class="flex items-center gap-2 text-sm text-[#cad5e2] cursor-pointer">
  613. <input type="checkbox" id="selectAllPlaylistVideos" class="w-4 h-4">
  614. <span>Select All</span>
  615. </label>
  616. <div class="flex gap-2">
  617. <button id="cancelPlaylistBtn" class="border border-[#45556c] text-white px-4 py-2 rounded-lg text-sm">
  618. Cancel
  619. </button>
  620. <button id="downloadSelectedPlaylistBtn" class="bg-[#155dfc] text-white px-4 py-2 rounded-lg text-sm font-medium">
  621. Download Selected
  622. </button>
  623. </div>
  624. </div>
  625. </div>
  626. </div>
  627. <!-- Toast Container -->
  628. <div id="toastContainer" class="fixed top-4 right-4 z-[100] flex flex-col gap-2 pointer-events-none">
  629. <!-- Toasts will be inserted here -->
  630. </div>
  631. <!-- Settings Modal -->
  632. <div id="settingsModal" class="fixed inset-0 bg-black/60 hidden items-center justify-center z-50">
  633. <div class="bg-[#314158] rounded-lg shadow-2xl w-[700px] max-h-[85vh] flex flex-col">
  634. <!-- Modal Header -->
  635. <div class="flex items-center justify-between p-4 border-b border-[#45556c]">
  636. <h2 class="text-lg font-semibold text-white">Settings</h2>
  637. <button id="closeSettingsModal" class="text-[#90a1b9] hover:text-white transition-colors">
  638. <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
  639. <path d="M18 6L6 18M6 6l12 12"/>
  640. </svg>
  641. </button>
  642. </div>
  643. <!-- Tabs -->
  644. <div class="flex border-b border-[#45556c] px-4">
  645. <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">
  646. General
  647. </button>
  648. <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">
  649. Downloads
  650. </button>
  651. <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">
  652. Cookie
  653. </button>
  654. <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">
  655. Data
  656. </button>
  657. <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">
  658. Shortcuts
  659. </button>
  660. </div>
  661. <!-- Tab Content -->
  662. <div class="flex-1 overflow-y-auto p-6">
  663. <!-- General Tab -->
  664. <div id="tab-general" class="settings-content space-y-4">
  665. <div>
  666. <label class="block text-sm font-medium text-[#cad5e2] mb-2">Default Save Location</label>
  667. <div class="flex gap-2">
  668. <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]">
  669. <button id="settings-change-path" class="border border-[#45556c] text-white px-4 py-2 rounded-lg text-sm">
  670. Browse
  671. </button>
  672. </div>
  673. </div>
  674. <div>
  675. <label class="flex items-center gap-2 cursor-pointer">
  676. <input type="checkbox" id="settings-auto-organize" class="w-4 h-4">
  677. <span class="text-sm text-[#cad5e2]">Auto-organize downloads by channel/playlist</span>
  678. </label>
  679. <p class="text-xs text-[#90a1b9] mt-1 ml-6">Creates separate folders for each channel or playlist</p>
  680. </div>
  681. <div>
  682. <label class="block text-sm font-medium text-[#cad5e2] mb-2">Filename Template</label>
  683. <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]">
  684. <p class="text-xs text-[#90a1b9] mt-1">Available: %(title)s, %(channel)s, %(id)s, %(upload_date)s</p>
  685. </div>
  686. <div>
  687. <label class="block text-sm font-medium text-[#cad5e2] mb-2">Max Retry Attempts</label>
  688. <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]">
  689. </div>
  690. <div>
  691. <label class="block text-sm font-medium text-[#cad5e2] mb-2">Request Timeout (seconds)</label>
  692. <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]">
  693. </div>
  694. </div>
  695. <!-- Downloads Tab -->
  696. <div id="tab-downloads" class="settings-content space-y-4 hidden">
  697. <div>
  698. <label class="block text-sm font-medium text-[#cad5e2] mb-2">Concurrent Downloads</label>
  699. <div class="flex items-center gap-4">
  700. <input type="range" id="settings-concurrent-downloads" min="1" max="10" value="10" class="flex-1">
  701. <span id="concurrent-value" class="text-sm text-[#cad5e2] w-8">10</span>
  702. </div>
  703. <p class="text-xs text-[#90a1b9] mt-1">Maximum number of simultaneous downloads (1-10)</p>
  704. </div>
  705. <div>
  706. <label class="flex items-center gap-2 cursor-pointer">
  707. <input type="checkbox" id="settings-auto-download-subtitles" class="w-4 h-4">
  708. <span class="text-sm text-[#cad5e2]">Auto-download subtitles</span>
  709. </label>
  710. </div>
  711. <div>
  712. <label class="block text-sm font-medium text-[#cad5e2] mb-2">Subtitle Language</label>
  713. <select id="settings-subtitle-language" class="w-full bg-[#1d293d] border border-[#45556c] rounded-lg px-3 py-2 text-sm text-[#cad5e2]">
  714. <option value="en">English</option>
  715. <option value="es">Spanish</option>
  716. <option value="fr">French</option>
  717. <option value="de">German</option>
  718. <option value="it">Italian</option>
  719. <option value="ja">Japanese</option>
  720. <option value="ko">Korean</option>
  721. <option value="zh">Chinese</option>
  722. </select>
  723. </div>
  724. <div>
  725. <label class="flex items-center gap-2 cursor-pointer">
  726. <input type="checkbox" id="settings-desktop-notifications" class="w-4 h-4" checked>
  727. <span class="text-sm text-[#cad5e2]">Show desktop notifications</span>
  728. </label>
  729. </div>
  730. </div>
  731. <!-- Cookie Tab -->
  732. <div id="tab-cookie" class="settings-content space-y-4 hidden">
  733. <div>
  734. <label class="block text-sm font-medium text-[#cad5e2] mb-2">Cookie File (Optional)</label>
  735. <div class="flex gap-2">
  736. <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]">
  737. <button id="settings-select-cookie" class="border border-[#45556c] text-white px-4 py-2 rounded-lg text-sm">
  738. Select
  739. </button>
  740. <button id="settings-clear-cookie" class="border border-[#e7000b] text-[#e7000b] px-4 py-2 rounded-lg text-sm">
  741. Clear
  742. </button>
  743. </div>
  744. <!-- Cookie File Help Guide -->
  745. <div class="mt-3 bg-[#1d293d] border border-[#45556c] rounded-lg p-3 space-y-2">
  746. <div class="flex items-start gap-2">
  747. <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">
  748. <circle cx="12" cy="12" r="10"/>
  749. <line x1="12" y1="16" x2="12" y2="12"/>
  750. <line x1="12" y1="8" x2="12.01" y2="8"/>
  751. </svg>
  752. <div class="flex-1">
  753. <p class="text-xs font-medium text-[#cad5e2]">Why do I need a cookie file?</p>
  754. <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>
  755. </div>
  756. </div>
  757. <div class="border-t border-[#45556c] pt-2">
  758. <p class="text-xs font-medium text-[#cad5e2] mb-2">How to get a cookie file:</p>
  759. <ol class="text-xs text-[#90a1b9] space-y-1 ml-4 list-decimal">
  760. <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>
  761. <li>Log in to YouTube or Vimeo in your browser</li>
  762. <li>Click the extension icon and export cookies for the site</li>
  763. <li>Save the <span class="text-[#cad5e2] font-mono">cookies.txt</span> file to your computer</li>
  764. <li>Select it here using the "Select" button above</li>
  765. </ol>
  766. </div>
  767. <div class="border-t border-[#45556c] pt-2">
  768. <div class="flex items-start gap-2">
  769. <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">
  770. <path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/>
  771. <polyline points="22 4 12 14.01 9 11.01"/>
  772. </svg>
  773. <p class="text-xs text-[#90a1b9]">
  774. <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.
  775. </p>
  776. </div>
  777. </div>
  778. </div>
  779. </div>
  780. </div>
  781. <!-- Data Tab -->
  782. <div id="tab-data" class="settings-content hidden space-y-4">
  783. <div class="space-y-3">
  784. <h3 class="text-sm font-semibold text-white mb-3">Import & Export</h3>
  785. <div class="flex flex-col gap-2">
  786. <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">
  787. <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  788. <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/>
  789. <polyline points="7 10 12 15 17 10"/>
  790. <line x1="12" y1="15" x2="12" y2="3"/>
  791. </svg>
  792. Export Video List
  793. </button>
  794. <p class="text-xs text-[#90a1b9] ml-6">Save your current video queue to a JSON file</p>
  795. </div>
  796. <div class="flex flex-col gap-2 mt-4">
  797. <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">
  798. <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  799. <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/>
  800. <polyline points="17 8 12 3 7 8"/>
  801. <line x1="12" y1="3" x2="12" y2="15"/>
  802. </svg>
  803. Import Video List
  804. </button>
  805. <p class="text-xs text-[#90a1b9] ml-6">Load a previously saved video queue from JSON</p>
  806. </div>
  807. </div>
  808. <div class="border-t border-[#45556c] pt-4">
  809. <h3 class="text-sm font-semibold text-white mb-3">Binary Updates</h3>
  810. <div class="flex flex-col gap-2">
  811. <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">
  812. <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  813. <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"/>
  814. </svg>
  815. Check for Binary Updates
  816. </button>
  817. <p class="text-xs text-[#90a1b9] ml-6">Check for updates to yt-dlp and ffmpeg binaries</p>
  818. </div>
  819. </div>
  820. </div>
  821. <!-- Shortcuts Tab -->
  822. <div id="tab-shortcuts" class="settings-content hidden">
  823. <div class="space-y-3">
  824. <div class="flex justify-between items-center py-2 border-b border-[#45556c]">
  825. <span class="text-sm text-[#cad5e2]">Download selected videos</span>
  826. <kbd class="px-2 py-1 bg-[#1d293d] border border-[#45556c] rounded text-xs text-[#90a1b9]">Ctrl+D</kbd>
  827. </div>
  828. <div class="flex justify-between items-center py-2 border-b border-[#45556c]">
  829. <span class="text-sm text-[#cad5e2]">Pause/Resume selected downloads</span>
  830. <kbd class="px-2 py-1 bg-[#1d293d] border border-[#45556c] rounded text-xs text-[#90a1b9]">P</kbd>
  831. </div>
  832. <div class="flex justify-between items-center py-2 border-b border-[#45556c]">
  833. <span class="text-sm text-[#cad5e2]">Remove selected videos</span>
  834. <kbd class="px-2 py-1 bg-[#1d293d] border border-[#45556c] rounded text-xs text-[#90a1b9]">Delete</kbd>
  835. </div>
  836. <div class="flex justify-between items-center py-2 border-b border-[#45556c]">
  837. <span class="text-sm text-[#cad5e2]">Select/Deselect video</span>
  838. <kbd class="px-2 py-1 bg-[#1d293d] border border-[#45556c] rounded text-xs text-[#90a1b9]">Space</kbd>
  839. </div>
  840. <div class="flex justify-between items-center py-2 border-b border-[#45556c]">
  841. <span class="text-sm text-[#cad5e2]">Select all videos</span>
  842. <kbd class="px-2 py-1 bg-[#1d293d] border border-[#45556c] rounded text-xs text-[#90a1b9]">Ctrl+A</kbd>
  843. </div>
  844. <div class="flex justify-between items-center py-2 border-b border-[#45556c]">
  845. <span class="text-sm text-[#cad5e2]">Open settings</span>
  846. <kbd class="px-2 py-1 bg-[#1d293d] border border-[#45556c] rounded text-xs text-[#90a1b9]">Ctrl+,</kbd>
  847. </div>
  848. <div class="flex justify-between items-center py-2 border-b border-[#45556c]">
  849. <span class="text-sm text-[#cad5e2]">Show shortcuts</span>
  850. <kbd class="px-2 py-1 bg-[#1d293d] border border-[#45556c] rounded text-xs text-[#90a1b9]">Ctrl+/</kbd>
  851. </div>
  852. <div class="flex justify-between items-center py-2">
  853. <span class="text-sm text-[#cad5e2]">Close modal</span>
  854. <kbd class="px-2 py-1 bg-[#1d293d] border border-[#45556c] rounded text-xs text-[#90a1b9]">Esc</kbd>
  855. </div>
  856. </div>
  857. </div>
  858. </div>
  859. <!-- Modal Footer -->
  860. <div class="p-4 border-t border-[#45556c] flex justify-end gap-2">
  861. <button id="cancelSettingsBtn" class="border border-[#45556c] text-white px-4 py-2 rounded-lg text-sm">
  862. Cancel
  863. </button>
  864. <button id="saveSettingsBtn" class="bg-[#155dfc] text-white px-4 py-2 rounded-lg text-sm font-medium">
  865. Save Settings
  866. </button>
  867. </div>
  868. </div>
  869. </div>
  870. <!-- Download History Modal -->
  871. <div id="historyModal" class="fixed inset-0 bg-black/80 hidden items-center justify-center z-50">
  872. <div class="bg-[#314158] rounded-lg shadow-2xl w-[900px] max-h-[90vh] flex flex-col">
  873. <!-- Modal Header -->
  874. <div class="flex items-center justify-between p-4 border-b border-[#45556c]">
  875. <h2 class="text-lg font-semibold text-white">Download History</h2>
  876. <div class="flex items-center gap-2">
  877. <button id="clearHistoryBtn" class="text-sm text-[#e7000b] hover:text-white px-3 py-1 rounded border border-[#e7000b] hover:bg-[#e7000b] transition-colors">
  878. Clear All
  879. </button>
  880. <button id="closeHistoryModal" class="text-[#90a1b9] hover:text-white transition-colors">
  881. <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
  882. <path d="M18 6L6 18M6 6l12 12"/>
  883. </svg>
  884. </button>
  885. </div>
  886. </div>
  887. <!-- History List -->
  888. <div class="flex-1 overflow-y-auto p-4">
  889. <div id="historyList" class="space-y-2">
  890. <!-- History entries will be inserted here -->
  891. </div>
  892. <div id="historyEmptyState" class="hidden flex flex-col items-center justify-center h-full text-center py-12">
  893. <svg width="64" height="64" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" class="text-[#45556c] mb-4">
  894. <circle cx="12" cy="12" r="10"/>
  895. <polyline points="12 6 12 12 16 14"/>
  896. </svg>
  897. <p class="text-[#90a1b9] text-lg">No download history yet</p>
  898. <p class="text-[#62748e] text-sm mt-2">Completed downloads will appear here</p>
  899. </div>
  900. </div>
  901. </div>
  902. </div>
  903. <!-- Video Preview Modal -->
  904. <div id="previewModal" class="fixed inset-0 bg-black/80 hidden items-center justify-center z-50">
  905. <div class="bg-[#314158] rounded-lg shadow-2xl w-[900px] max-h-[90vh] flex flex-col">
  906. <!-- Modal Header -->
  907. <div class="flex items-center justify-between p-4 border-b border-[#45556c]">
  908. <h2 id="previewTitle" class="text-lg font-semibold text-white truncate flex-1 pr-4">Video Preview</h2>
  909. <button id="closePreviewModal" class="text-[#90a1b9] hover:text-white transition-colors flex-shrink-0">
  910. <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
  911. <path d="M18 6L6 18M6 6l12 12"/>
  912. </svg>
  913. </button>
  914. </div>
  915. <!-- Video Player -->
  916. <div class="aspect-video bg-black">
  917. <iframe id="previewPlayer" class="w-full h-full" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
  918. </div>
  919. <!-- Video Info -->
  920. <div class="p-4 space-y-3 overflow-y-auto flex-1">
  921. <div class="flex items-center gap-4 text-sm text-[#cad5e2]">
  922. <span id="previewDuration" class="flex items-center gap-1">
  923. <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
  924. <circle cx="12" cy="12" r="10"/>
  925. <polyline points="12 6 12 12 16 14"/>
  926. </svg>
  927. <span>--:--</span>
  928. </span>
  929. <span id="previewViews" class="flex items-center gap-1">
  930. <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
  931. <path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/>
  932. <circle cx="12" cy="12" r="3"/>
  933. </svg>
  934. <span>-- views</span>
  935. </span>
  936. <span id="previewLikes" class="flex items-center gap-1">
  937. <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
  938. <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"/>
  939. </svg>
  940. <span>-- likes</span>
  941. </span>
  942. </div>
  943. <div>
  944. <h3 class="text-sm font-medium text-[#cad5e2] mb-1">Description</h3>
  945. <p id="previewDescription" class="text-sm text-[#90a1b9] whitespace-pre-wrap">Loading...</p>
  946. </div>
  947. </div>
  948. <!-- Modal Footer -->
  949. <div class="p-4 border-t border-[#45556c] flex justify-end gap-2">
  950. <button id="closePreviewBtn" class="border border-[#45556c] text-white px-4 py-2 rounded-lg text-sm">
  951. Close
  952. </button>
  953. <button id="downloadFromPreviewBtn" class="bg-[#155dfc] text-white px-4 py-2 rounded-lg text-sm font-medium">
  954. Download This Video
  955. </button>
  956. </div>
  957. </div>
  958. </div>
  959. <!-- Load modular scripts in dependency order -->
  960. <script>
  961. // Track script loading
  962. window.scriptLoadErrors = [];
  963. function loadScript(src, callback) {
  964. const script = document.createElement('script');
  965. script.src = src;
  966. script.onload = () => {
  967. console.log(`✓ Loaded: ${src}`);
  968. if (callback) callback();
  969. };
  970. script.onerror = () => {
  971. console.error(`✗ Failed to load: ${src}`);
  972. window.scriptLoadErrors.push(src);
  973. if (callback) callback();
  974. };
  975. document.head.appendChild(script);
  976. }
  977. // Load modular scripts in correct dependency order
  978. loadScript('scripts/utils/config.js', () => {
  979. loadScript('scripts/utils/url-validator.js', () => {
  980. loadScript('scripts/core/event-bus.js', () => {
  981. loadScript('scripts/models/Video.js', () => {
  982. loadScript('scripts/components/clipboard-consent-dialog.js', () => {
  983. loadScript('scripts/models/AppState.js', () => {
  984. loadScript('scripts/utils/error-handler.js', () => {
  985. loadScript('scripts/utils/desktop-notifications.js', () => {
  986. loadScript('scripts/utils/live-region-manager.js', () => {
  987. loadScript('scripts/utils/accessibility-manager.js', () => {
  988. loadScript('scripts/utils/keyboard-navigation.js', () => {
  989. loadScript('scripts/utils/ipc-integration.js', () => {
  990. loadScript('scripts/services/metadata-service.js', () => {
  991. loadScript('scripts/utils/enhanced-download-methods.js', () => {
  992. loadScript('scripts/app.js', () => {
  993. loadScript('scripts/utils/download-integration-patch.js', () => {
  994. console.log('✅ All modular scripts loaded successfully');
  995. if (window.scriptLoadErrors.length > 0) {
  996. console.warn('⚠️ Some scripts failed to load:', window.scriptLoadErrors);
  997. }
  998. // Initialize app after all scripts have loaded
  999. if (typeof window.initializeGrabZilla === 'function') {
  1000. console.log('🚀 Initializing GrabZilla app...');
  1001. window.initializeGrabZilla();
  1002. } else {
  1003. console.error('❌ initializeGrabZilla function not found');
  1004. }
  1005. });
  1006. });
  1007. });
  1008. });
  1009. });
  1010. });
  1011. });
  1012. });
  1013. });
  1014. });
  1015. });
  1016. });
  1017. });
  1018. });
  1019. });
  1020. });
  1021. </script>
  1022. <!-- Debug script -->
  1023. <script>
  1024. // Debug logging
  1025. console.log('All scripts loaded');
  1026. // Check if buttons exist when DOM is ready
  1027. document.addEventListener('DOMContentLoaded', () => {
  1028. console.log('DOM Content Loaded - checking buttons...');
  1029. const buttons = ['addVideoBtn', 'importUrlsBtn', 'savePathBtn', 'cookieFileBtn'];
  1030. buttons.forEach(id => {
  1031. const btn = document.getElementById(id);
  1032. console.log(`Button ${id}:`, btn ? 'FOUND' : 'NOT FOUND');
  1033. });
  1034. // Check if app was initialized and provide fallback
  1035. setTimeout(() => {
  1036. console.log('App instance:', window.app ? 'EXISTS' : 'NOT FOUND');
  1037. console.log('Script load errors:', window.scriptLoadErrors || 'none');
  1038. if (window.app) {
  1039. console.log('App state:', window.app.state);
  1040. console.log('App initialized successfully');
  1041. } else {
  1042. console.log('App not initialized, setting up fallback button listeners...');
  1043. // Create a minimal app-like object for basic functionality
  1044. window.fallbackApp = {
  1045. handleAddVideo: function () {
  1046. const urlInput = document.getElementById('urlInput');
  1047. const inputText = urlInput ? urlInput.value.trim() : '';
  1048. if (!inputText) {
  1049. alert('Please enter a URL');
  1050. return;
  1051. }
  1052. console.log('Processing URLs:', inputText);
  1053. alert(`Would add video(s): ${inputText}`);
  1054. if (urlInput) urlInput.value = '';
  1055. },
  1056. handleImportUrls: function () {
  1057. alert('Import URLs functionality (requires Electron)');
  1058. },
  1059. handleSelectSavePath: function () {
  1060. alert('Save path selection (requires Electron)');
  1061. },
  1062. handleSelectCookieFile: function () {
  1063. alert('Cookie file selection (requires Electron)');
  1064. }
  1065. };
  1066. // Attach fallback event listeners
  1067. const addVideoBtn = document.getElementById('addVideoBtn');
  1068. if (addVideoBtn) {
  1069. addVideoBtn.addEventListener('click', window.fallbackApp.handleAddVideo);
  1070. console.log('✓ Fallback listener attached to Add Video button');
  1071. }
  1072. const importUrlsBtn = document.getElementById('importUrlsBtn');
  1073. if (importUrlsBtn) {
  1074. importUrlsBtn.addEventListener('click', window.fallbackApp.handleImportUrls);
  1075. console.log('✓ Fallback listener attached to Import URLs button');
  1076. }
  1077. const savePathBtn = document.getElementById('savePathBtn');
  1078. if (savePathBtn) {
  1079. savePathBtn.addEventListener('click', window.fallbackApp.handleSelectSavePath);
  1080. console.log('✓ Fallback listener attached to Save Path button');
  1081. }
  1082. const cookieFileBtn = document.getElementById('cookieFileBtn');
  1083. if (cookieFileBtn) {
  1084. cookieFileBtn.addEventListener('click', window.fallbackApp.handleSelectCookieFile);
  1085. console.log('✓ Fallback listener attached to Cookie File button');
  1086. }
  1087. console.log('Fallback initialization complete');
  1088. }
  1089. }, 3000);
  1090. });
  1091. // Catch any errors
  1092. window.addEventListener('error', (e) => {
  1093. console.error('JavaScript Error:', e.error);
  1094. console.error('File:', e.filename, 'Line:', e.lineno);
  1095. });
  1096. </script>
  1097. </body>
  1098. </html>