index.html 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694
  1. <html>
  2. <head>
  3. <meta name="apple-mobile-web-app-capable" content="yes" />
  4. <meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1, maximum-scale=1"/>
  5. <link rel="stylesheet" href="../script/semantic/semantic.css">
  6. <script src="jquery.min.js"></script>
  7. <script src="../script/semantic/semantic.js"></script>
  8. <script src="../script/ao_module.js"></script>
  9. <title>FFmpeg Factory</title>
  10. <style>
  11. .FFmpegStatus{
  12. padding:8px;
  13. border-bottom:1px solid #999999;
  14. }
  15. body{
  16. padding-top:0px !important;
  17. background-color:white;
  18. overflow:hidden;
  19. }
  20. @supports (backdrop-filter: none) {
  21. body {
  22. background: rgba(255, 255, 255, 0.9);
  23. backdrop-filter: blur(8px);
  24. }
  25. }
  26. .topMenu{
  27. padding-top:0px !important;
  28. border-bottom: 1px solid #999999;
  29. height: 40px;
  30. overflow-x: auto;
  31. overflow-y: hidden;
  32. }
  33. .selectableMenuItems{
  34. padding: 8px;
  35. display:inline-block !important;
  36. cursor:pointer;
  37. border-bottom:2px solid transparent;
  38. }
  39. .selectableMenuItems.enabled:hover{
  40. background-color:#f0f0f0;
  41. }
  42. .convertionList{
  43. width:100%;
  44. height: 100%;
  45. padding-left:8px;
  46. border-right: 1px solid #cfcfcf;
  47. overflow-y:auto;
  48. }
  49. .selectable{
  50. cursor:pointer;
  51. padding-left: 22px !important;
  52. border:1px solid transparent;
  53. }
  54. .selectable.item{
  55. padding:8x !important;
  56. }
  57. .selectable:hover{
  58. background-color:#f0f0f0;
  59. }
  60. .content{
  61. overflow-y: auto;
  62. }
  63. .filelist{
  64. padding: 12px !important;
  65. padding-bottom:0px !important;
  66. margin-right:20px;
  67. border: 1px solid transparent !important;
  68. cursor: pointer;
  69. }
  70. .filelist:hover{
  71. background-color:#f0fbff;
  72. border:1px solid #48b8e5 !important;
  73. }
  74. .selectedFile{
  75. background-color:#e0f7ff;
  76. border:1px solid #48b8e5 !important;
  77. }
  78. .selectedConvertTarget{
  79. background-color:#f0f0f0;
  80. border:1px solid #999999 !important;
  81. }
  82. .status{
  83. display:inline;
  84. }
  85. .selectableMenuItems.disabled{
  86. color: #a3a3a3;
  87. cursor: not-allowed !important;
  88. }
  89. .converting{
  90. background-color:#d3e4ff;
  91. }
  92. .done{
  93. background-color:#d1ffd3;
  94. }
  95. .failed{
  96. background-color: #ffd1d1;
  97. }
  98. #settingMenu{
  99. position:fixed;
  100. left:30px;
  101. right:30px;
  102. top:30px;
  103. max-height:80%;
  104. }
  105. .mainArea{
  106. margin-top:0px !important;
  107. }
  108. .ts.progress{
  109. margin-bottom:18px !important;
  110. }
  111. .ts.blue.progress .bar{
  112. background-color: #2185d0 !important;
  113. }
  114. #convertPendingList{
  115. overflow-y: scroll;
  116. }
  117. </style>
  118. </head>
  119. <body>
  120. <div id="headerNav" class="ui secondary attached mini menu">
  121. <a class="item" href="../"><i class="caret left icon"></i></a>
  122. <div class="item">
  123. <img class="ui avatar image" src="./img/small_icon.png">
  124. <span>FFmpeg Factory</span>
  125. </div>
  126. </div>
  127. <div class="topMenu">
  128. <div id="addFileBtn" class="selectableMenuItems enabled" onClick="openFileSelection(this);"><i class="plus icon"></i>Add Files</div>
  129. <div class="selectableMenuItems enabled" onClick="openFileLocation(this);"><i class="folder open icon"></i>Browse File Location</div>
  130. <div class="selectableMenuItems enabled" onClick="startQueue(this);"><i class="play icon"></i>Start Queue</div>
  131. <div class="selectableMenuItems enabled" onClick="stopQueue(this);"><i class="stop icon"></i>Stop Queue</div>
  132. <!-- <div class="selectableMenuItems enabled" onClick="viewCommand(this);"><i class="code icon"></i>View Command</div> -->
  133. <div class="selectableMenuItems enabled" onClick="showSettingMenu(this);"><i class="setting icon"></i>Settings</div>
  134. </div>
  135. <div class="ui stackable grid mainArea">
  136. <div class="four wide column sidebar">
  137. <div class="convertionList" >
  138. <div class="ui fluid accordion">
  139. <div class="title">
  140. <i class="dropdown icon"></i>
  141. <i class="play icon"></i>
  142. Video
  143. </div>
  144. <div class="content fileFormatSelector">
  145. <div id="v2v" class="ui relaxed divided list">
  146. </div>
  147. </div>
  148. <div class="title">
  149. <i class="dropdown icon"></i>
  150. <i class="music icon"></i>
  151. Music
  152. </div>
  153. <div class="content fileFormatSelector">
  154. <div id="v2a" class="ui relaxed divided list">
  155. </div>
  156. </div>
  157. <div class="title">
  158. <i class="dropdown icon"></i>
  159. <i class="file image icon"></i>
  160. Pictures
  161. </div>
  162. <div class="content fileFormatSelector">
  163. <div id="i2i" class="ui relaxed divided list">
  164. </div>
  165. </div>
  166. <div class="title">
  167. <i class="dropdown icon"></i>
  168. <i class="exchange icon"></i>
  169. Others
  170. </div>
  171. <div class="content fileFormatSelector">
  172. <div id="other" class="ui relaxed divided list">
  173. </div>
  174. </div>
  175. </div>
  176. <br>
  177. </div>
  178. </div>
  179. <div class="twelve wide column" ondrop="drop(event)" ondragover="allowdrag(event)" style="padding-right:22px;">
  180. <div id="actionOK" class="ui positive message transition" style="display:none;">
  181. <div class="header">
  182. You are eligible for a reward
  183. </div>
  184. <p class="message"></p>
  185. </div>
  186. <div id="emptylist" class="ui secondary blue segment">
  187. <i class="hashtag icon"></i> No Pending Tasks. Press the <i class="add icon"></i> button to add new conversion tasks.
  188. </div>
  189. <div id="convertPendingList" class="ui relaxed divided list" style="margin-top:0px !important;">
  190. </div>
  191. <div id="askSelectDimmer" class="ui dimmer" style="margin-top:14px; margin-left:-14px;">
  192. <div class="content">
  193. <h4 class="ui inverted icon header">
  194. <i class="arrow left icon"></i>
  195. Select a Target Conversion Format <br>
  196. On the list over there
  197. </h4>
  198. </div>
  199. </div>
  200. </div>
  201. </div>
  202. <div id="settingDimmer" class="ui dimmer"></div>
  203. <div id="settingMenu" style="z-index:1001;">
  204. <div class="ui raised segment">
  205. <div class="ui header">
  206. <i class="setting icon"></i>Conversion Settings
  207. <div class="sub header">Please adjust the following settings according to your Host devices specification.</div>
  208. </div>
  209. <div class="ui list">
  210. <div class="item"><i class="caret right icon"></i>Simultaneous Conversion File Counts</div>
  211. <div class="item">
  212. <select id="simFileCount" class="ui basic tiny dropdown" onChange="updateSimFiles(this);">
  213. <option>1</option>
  214. <option>2</option>
  215. <option>3</option>
  216. <option>4</option>
  217. <option>8</option>
  218. <option>16</option>
  219. </select>
  220. </div>
  221. <div class="item" style="font-size: 90%;"><small>Do not use "ALL" options unless your host is a dual CPU Xeon Server</small></div>
  222. <div class="item"><i class="caret right icon"></i>Allow Codec Copy Options (FFmpeg Expert Only)</div>
  223. <div class="item" onChange="">
  224. <select id="allowCodecCopy" class="ui basic tiny dropdown" onChange="updateAllowCodecCopy(this);">
  225. <option>false</option>
  226. <option>true</option>
  227. </select>
  228. </div>
  229. <div class="item" style="font-size: 90%;"><small>Codec Copy Error might crash the system. Please use with your own risk.</small></div>
  230. </div>
  231. <br><br>
  232. <ins><i class="save icon"></i>All changes will be saved automatically in server database.</ins>
  233. <br> <br>
  234. <button class="ui blue button" onClick="hideSettingMenu();">Close</button>
  235. </div>
  236. </div>
  237. <br><br><br><br>
  238. <script>
  239. //Global variables
  240. var convertPendingFiles = []; //Files pending to be converted
  241. var selectFormatPending = false; //Files selected and waiting to select a target format
  242. var targetConversionFormat = ""; //The target conversion format
  243. var selectedCommand = ""; //The target selected command template
  244. var selectedMediaType = "";
  245. //Conversion related settings
  246. var simFileCount = 1;
  247. var allowCodecCopy = false;
  248. var queueStarted = false;
  249. isMobile = function() {
  250. let check = false;
  251. (function(a){if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4))) check = true;})(navigator.userAgent||navigator.vendor||window.opera);
  252. return check;
  253. };
  254. if (ao_module_virtualDesktop){
  255. $("#headerNav").hide();
  256. }
  257. $(document).ready(function(){
  258. //Check if mobile. If yes, change the UI to responsive
  259. if (isMobile()){
  260. //Create a sidebar button
  261. $(".topMenu").prepend(`
  262. <div title="Toggle Sidebar" class="ui icon button" onclick="toggleSidebar(); "><i class="content icon" style="pointer-events: none;" ></i></div>
  263. `);
  264. //Hide the sidebar
  265. $(".sidebar").hide();
  266. //Simplify the toolbar
  267. $(".selectableMenuItems").each(function(){
  268. var originalText = $(this).text();
  269. console.log(originalText);
  270. $(this).html($(this).html().replace(originalText, ""));
  271. $(this).attr("title", originalText);
  272. $(this).attr("class", "ui basic icon button")
  273. $(this).css({
  274. "padding-top": "12px"
  275. });
  276. });
  277. }
  278. $("#settingMenu").hide();
  279. $('.ui.dropdown').dropdown();
  280. //Initialize the conversion types
  281. //<div class="item selectable"><i class="file video outline icon"></i></div>
  282. $.ajax({
  283. url: "config/v2v.json",
  284. method: "GET",
  285. dataType: "json",
  286. success: function(data){
  287. for (var [key, value] of Object.entries(data)) {
  288. value = encodeURIComponent(value);
  289. $("#v2v").append(`<div class="item selectable" mediatype="video" conv="${key}" command="${value}" onclick="selectThis(this, event);" ondblclick="selectViaFormat(this);"><i class="file video outline icon"></i> ${key}</div>`);
  290. }
  291. $('.ui.accordion').accordion();
  292. initUserSettings();
  293. }
  294. });
  295. $.ajax({
  296. url: "config/v2a.json",
  297. method: "GET",
  298. dataType: "json",
  299. success: function(data){
  300. for (var [key, value] of Object.entries(data)) {
  301. value = encodeURIComponent(value);
  302. $("#v2a").append(`<div class="item selectable" mediatype="music" conv="${key}" command="${value}" onclick="selectThis(this, event);" ondblclick="selectViaFormat(this);"><i class="file video outline icon"></i> ${key}</div>`);
  303. }
  304. $('.ui.accordion').accordion();
  305. initUserSettings();
  306. }
  307. });
  308. $.ajax({
  309. url: "config/i2i.json",
  310. method: "GET",
  311. dataType: "json",
  312. success: function(data){
  313. for (var [key, value] of Object.entries(data)) {
  314. value = encodeURIComponent(value);
  315. $("#i2i").append(`<div class="item selectable" mediatype="image" conv="${key}" command="${value}" onclick="selectThis(this, event);" ondblclick="selectViaFormat(this);"><i class="file video outline icon"></i> ${key}</div>`);
  316. }
  317. $('.ui.accordion').accordion();
  318. }
  319. });
  320. $.ajax({
  321. url: "config/other.json",
  322. method: "GET",
  323. dataType: "json",
  324. success: function(data){
  325. for (var [key, value] of Object.entries(data)) {
  326. value = encodeURIComponent(value);
  327. $("#other").append(`<div class="item selectable" mediatype="other" conv="${key}" command="${value}" onclick="selectThis(this, event);" ondblclick="selectViaFormat(this);"><i class="file video outline icon"></i> ${key}</div>`);
  328. }
  329. $('.ui.accordion').accordion();
  330. }
  331. });
  332. });
  333. //Open files to convert
  334. function openFileSelection(obj){
  335. if ($(obj).hasClass("disabled") == false){
  336. //Require format selection after select
  337. selectFormatPending = true;
  338. ao_module_openFileSelector(fileSelected, "user:/Desktop", "file",true);
  339. }
  340. }
  341. function toggleSidebar(){
  342. $(".sidebar").toggle();
  343. }
  344. //Catch drop events on ths main area
  345. function drop(event){
  346. event.preventDefault();
  347. var files = ao_module_utils.getDropFileInfo(event);
  348. if(files.length == 0){
  349. return;
  350. }
  351. selectFormatPending = true;
  352. fileSelected(files);
  353. }
  354. function allowdrag(ev) {
  355. ev.preventDefault();
  356. return true;
  357. }
  358. //Update the number of simultanous file conversion
  359. function updateSimFiles(obj){
  360. var fileNumber = obj.value;
  361. saveStorage("simconv",fileNumber);
  362. simFileCount = fileNumber;
  363. }
  364. function updateAllowCodecCopy(obj){
  365. var newValue = obj.value;
  366. allowCodecCopy = (newValue == "true");
  367. saveStorage("codecCopy",newValue);
  368. updateCodeCopyDisableList();
  369. }
  370. function initUserSettings(){
  371. readStorage("simconv", function(data){
  372. if (data != ""){
  373. simFileCount = parseInt(data);
  374. $('#simFileCount').dropdown('set selected', data);
  375. }
  376. });
  377. readStorage("codecCopy", function(data){
  378. if (data != ""){
  379. allowCodecCopy = (data == "true");
  380. $('#allowCodecCopy').dropdown('set selected', data);
  381. }
  382. updateCodeCopyDisableList();
  383. });
  384. }
  385. function updateCodeCopyDisableList(){
  386. //console.log(allowCodecCopy);
  387. if (allowCodecCopy == false){
  388. $(".item.selectable").each(function(){
  389. if ($(this).text().includes("codec copy")){
  390. $(this).addClass("disabled");
  391. }
  392. });
  393. }else{
  394. $(".item.selectable.disabled").each(function(){
  395. $(this).removeClass("disabled");
  396. });
  397. }
  398. }
  399. function saveStorage(key, value, callback = undefined){
  400. ao_module_agirun("FFmpeg Factory/backend/writeConfig.js", {
  401. key: key,
  402. value: value
  403. }, callback)
  404. }
  405. function readStorage(key, callback = undefined){
  406. ao_module_agirun("FFmpeg Factory/backend/readConfig.js", {key: key}, callback)
  407. }
  408. function selectThisTask(obj){
  409. $(".selectedFile").removeClass("selectedFile");
  410. $(obj).addClass("selectedFile")
  411. }
  412. //File selected using openFileSelected
  413. function fileSelected(data){
  414. convertPendingFiles = data;
  415. if (selectFormatPending == true){
  416. //Format not yet selected. Ask user to choose a target format
  417. $("#askSelectDimmer").addClass('active');
  418. $(".selectableMenuItems").addClass("disabled")
  419. if (isMobile()){
  420. $(".sidebar").show();
  421. }
  422. }else{
  423. //format alraedy selected. Append to conversion list
  424. for (var i =0; i < data.length; i++){
  425. var thisFile = convertPendingFiles[i];
  426. addTaskToList(thisFile.filename, thisFile.filepath, targetConversionFormat, selectedCommand, selectedMediaType);
  427. }
  428. targetConversionFormat="";
  429. selectedCommand="";
  430. selectedMediaType="";
  431. }
  432. }
  433. function showSettingMenu(){
  434. $("#settingDimmer").addClass("active");
  435. $("#settingMenu").transition('scale');
  436. }
  437. function hideSettingMenu(){
  438. $("#settingDimmer").removeClass("active");
  439. $("#settingMenu").transition('scale');
  440. }
  441. //Remove task from the task list
  442. function removeTask(obj){
  443. var taskObject = $(obj).parent().parent().parent();
  444. //msgbox("Task Removed", $(taskObject).attr("filepath"));
  445. $(taskObject).remove();
  446. //Check if there are anything left. If no, add a message
  447. if ($(".filelist.item").length == 0){
  448. $("#emptylist").show();
  449. }
  450. }
  451. function msgbox(title, message){
  452. $("#actionOK").stop().finish().slideDown("fast").delay(3000).slideUp("fast");
  453. $("#actionOK").find(".header").text(title);
  454. $("#actionOK").find(".message").text(message);
  455. }
  456. function addTaskToList(filename, filepath, targetFormat, command, mtype){
  457. $("#emptylist").hide();
  458. //Get the file extension of the filename
  459. var srcFormat = filename.split(".").pop();
  460. srcFormat = srcFormat.toUpperCase();
  461. console.log(filename, filepath, targetFormat, command, mtype);
  462. $("#convertPendingList").append(`<div class="item filelist ready" mtype="${mtype}" filepath="${filepath}" command="${command}" onclick="selectThisTask(this);">
  463. <i class="large file outline middle aligned icon"></i>
  464. <div class="content">
  465. <div class="header">${filename} [${srcFormat} <i class="right arrow icon"></i>${targetFormat}]</div>
  466. <div class="description" style="margin-top:8px;"><a onclick="startTask(this, event);" class="startTaskButton"><i class="exchange icon"></i> Start Convert</a> / <a onclick="removeTask(this);"><i class="trash icon"></i> Remove</a>
  467. </div>
  468. </div>
  469. <div class="ui black active tiny progress" style="margin-top:8px;">
  470. <div class="bar" style="width:0%; min-width:0px;"></div>
  471. </div>
  472. </div>`);
  473. }
  474. function selectViaFormat(obj){
  475. targetConversionFormat = $(obj).attr("conv");
  476. selectedCommand = $(obj).attr("command");
  477. selectedMediaType = $(obj).attr("mediatype");
  478. ao_module_openFileSelector(fileSelected, "user:/Desktop", "file",true);
  479. }
  480. function selectThis(obj){
  481. //A format has been selected
  482. if (selectFormatPending){
  483. //Unset the blocking
  484. $("#askSelectDimmer").removeClass('active');
  485. $(".selectableMenuItems").removeClass("disabled")
  486. //Hide the sidebar if on mobile mode
  487. if (isMobile()){
  488. $('.sidebar').hide();
  489. }
  490. //Get the target format and command
  491. var format = $(obj).attr("conv");
  492. var command = $(obj).attr("command");
  493. var mtype = $(obj).attr("mediatype");
  494. //Append the files item to list
  495. for (var i =0; i < convertPendingFiles.length; i++){
  496. var thisFile = convertPendingFiles[i];
  497. addTaskToList(thisFile.filename, thisFile.filepath, format, command, mtype);
  498. }
  499. selectFormatPending = false;
  500. }
  501. }
  502. function openFileLocation(){
  503. if ($(".selectedFile").length > 0){
  504. var filepath = $(".selectedFile").attr("filepath");
  505. filepath = filepath.split("/");
  506. filepath.pop();
  507. filepath = filepath.join("/")
  508. ao_module_openPath(filepath);
  509. }
  510. }
  511. //Handle window resize events
  512. resizeWindowEvents()
  513. $(window).on("resize",function(){
  514. resizeWindowEvents();
  515. })
  516. function resizeWindowEvents(){
  517. $(".sidebar").css("height",window.innerHeight - $(".topMenu").height());
  518. $("#convertPendingList").css("height", window.innerHeight - 60);
  519. }
  520. //Bind the queue listening events
  521. setInterval(function(){
  522. if (queueStarted){
  523. //Check next queue
  524. if (isNaN(simFileCount)){
  525. simFileCount = 1;
  526. }
  527. if ($(".filelist.converting").length < simFileCount){
  528. //Convert next item
  529. console.log("Next Object")
  530. if ($(".filelist.ready").length > 0){
  531. $($(".filelist.ready")[0]).find(".startTaskButton")[0].click();
  532. }else{
  533. //Conversion finished
  534. console.log("Conversion finished");
  535. queueStarted = false;
  536. }
  537. }
  538. }
  539. }, 1000);
  540. function startQueue(){
  541. //Start the queue with the given task number on the fly
  542. queueStarted = true;
  543. }
  544. function stopQueue(){
  545. queueStarted = false;
  546. }
  547. function startTask(taskObject, event){
  548. event.preventDefault();
  549. event.stopImmediatePropagation();
  550. //Travel back to the task object itself
  551. taskObject = $(taskObject).parent().parent().parent();
  552. //Try to validate conversion type
  553. var mediaType = {
  554. "music": ["m4a","flac","mp3","wav","ogg","aac","wma"],
  555. "video": ["mp4","avi","webm","mkv","wmv","mov","m4v","rmvb"],
  556. "image": ["png","jpg","jpeg","gif","tif","tiff"]
  557. }
  558. var srcExt = $(taskObject).attr("filepath").split(".").pop();
  559. var targetType = $(taskObject).attr("mtype");
  560. var srcType = "unknown";
  561. //Check which type of media is src
  562. if (mediaType["music"].includes(srcExt)){
  563. srcType = "music";
  564. }else if (mediaType["video"].includes(srcExt)){
  565. srcType = "video";
  566. }else if (mediaType["image"].includes(srcExt)){
  567. srcType = "image";
  568. }
  569. //Allow video -> (video or audio), music -> music and image -> image
  570. var requireConversionConfirm = true;
  571. if (srcType == "video" && targetType == "video"){
  572. requireConversionConfirm = false
  573. }else if (srcType == "video" && targetType == "music"){
  574. requireConversionConfirm = false
  575. }else if (srcType == "music" && targetType == "music"){
  576. requireConversionConfirm = false
  577. }else if (srcType == "image" && targetType == "image"){
  578. requireConversionConfirm = false
  579. }else if (targetType == "other"){
  580. //Just trust the user, they know what they are doing
  581. requireConversionConfirm = false
  582. }
  583. if (requireConversionConfirm){
  584. if (!confirm("We are not sure if the conversion media type is valid. Continue anyway?")){
  585. return
  586. }
  587. }
  588. //OK! Convert this file
  589. var filepath = $(taskObject).attr("filepath");
  590. var command = $(taskObject).attr("command");
  591. //Update the progress bar
  592. $(taskObject).find(".tiny.progress").attr("class","ui blue queried indeterminate tiny progress");
  593. $(taskObject).find(".bar").css("width","100%");
  594. $(taskObject).removeClass("ready").addClass("converting");
  595. //Hide the control buttons
  596. $(taskObject).find(".description").html("<span><i class='loading spinner icon'></i> Converting...</span>");
  597. ao_module_agirun("FFmpeg Factory/backend/convert.js",{
  598. filepath: filepath,
  599. command: command
  600. },function(data){
  601. if (data.error !== undefined){
  602. //Conversion failed
  603. console.log(data.error);
  604. $(taskObject).find(".tiny.progress").attr("class","ui red tiny progress");
  605. $(taskObject).find(".bar").css("width","100%");
  606. $(taskObject).removeClass("converting").addClass("failed");
  607. $(taskObject).find(".description").html(`<span><i class='remove icon'></i> ${data.error}</span> / <a onclick="removeTask(this);"><i class="trash icon"></i> Remove From List</a>`);
  608. }else{
  609. $(taskObject).find(".tiny.progress").attr("class","ui green tiny progress");
  610. $(taskObject).find(".bar").css("width","100%");
  611. $(taskObject).removeClass("converting").addClass("done");
  612. $(taskObject).find(".description").html(`<span><i class='checkmark icon'></i> Completed</span>`);
  613. }
  614. $(taskObject).find(".description").html('<a onclick="removeTask(this);"><i class="checkmark icon"></i> Close</a>');
  615. }, function(){
  616. //Failed callback
  617. $(taskObject).find(".tiny.progress").attr("class","ui red tiny progress");
  618. $(taskObject).find(".bar").css("width","100%");
  619. $(taskObject).removeClass("converting").addClass("failed");
  620. $(taskObject).find(".description").html(`<a onclick="removeTask(this);"><i class="remove icon"></i> Remove</a>`);
  621. });
  622. }
  623. </script>
  624. </body>
  625. </html>