index.html 67 KB

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