UNPKG

evdh

Version:

evdh : EisF Video Download Helper, auto download videos on web pages.

849 lines (628 loc) 18.2 kB
/* evdh.js, evdh: main bin file for evdh : EisF Video Download Helper, sceext <sceext@foxmail.com> 2009EisF2015, 2015.02 * version 0.1.14.0 test201502141956 (public version) * author sceext <sceext@foxmail.com> 2015.02 * copyright 2015 sceext * * This is FREE SOFTWARE, released under GNU GPLv3+ * please see README.md and LICENSE for more information. * * evdh : EisF Video Download Helper, auto download videos with analyse service provided by flv.cn (api.flvxz.com) * Copyright (C) 2015 sceext <sceext@foxmail.com> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * * exit code * 0 ok * 1 unknow * 2 command line format error * 3 other error * */ /* require import modules */ var _m = require('../lib/main.js'); // evdh main module // get modules from _m var _b = _m.b_; var _log = _m.log_; var _ui = _m.ui_; var _aurl = _m.aurl_; var fs = _m.fs_; // set main module // set config _m.etc.config_file = './etc/evdh.conf.xml'; // main config file location _m.etc.refresh_log_timeout_ms = 5e3; // refresh log every 5s // import time_log from _m for global use var time_log = _m.time_log; // get main global object var _ = _m._; /* functions */ // watch_dl, auto watch dl status function watch_dl() { // no callback var _host = {}; _host.error = null; _host.timeout = null; // timeout object _host.index = {}; _host.last_line = 0; _host.stop = false; var _next = watch_dl_next; _next(1, _host); return function(){ _host.stop = true; clearTimeout(_host.timeout); }; // use this function to stop watch } function watch_dl_next(_step, _host) { var _next = watch_dl_next; switch (_step) { case 1: // first step // set timeout to show download status _host.timeout = setTimeout(function(){ _next('show_status', _host); }, 1e3); // every 1s break; case 'show_status': case 2: // _step = 2; // get o_host_task all file and done file var oh_st = _.oh.get_status(); var oh_all_file = oh_st.count.all_file; var oh_done_file = oh_st.count.done; var oh_error_file = oh_st.count.error; // get o_host_task status var task_i = _.oh.get_status(); // reset last_line _host.last_line = 0; // before refresh, clear screen down _ui.clear_down(); var fw = _ui.force_width; // print a line console.log(''); // console task info time_log('task info : ' + '(' + fw(oh_done_file, 2, true) + '/' + fw(oh_all_file, 2, true) + ') ' + ' error ' + fw(oh_error_file, 2, true) + ' ' + '=========================' ); _host.last_line += 2; // get ids var ids = _.dl.get_id_list(); for (var j = 0; j < ids.length; j++) { // process each ids var id = ids[j]; var st = _.dl.get_status(id); var old_byte = 0; // get old byte if (!_host.index[id]) { _host.index[id] = {}; _host.index[id].old_byte = 0; } else { old_byte = _host.index[id].old_byte; } var ed_byte = st.ed_byte; _host.index[id].old_byte = ed_byte; var speed = ed_byte - old_byte; var ed_ms = ((new Date()).getTime()) - (st.start_time.getTime()); var ed_s = Math.floor(ed_ms / 1e3); // get all byte var all_byte = 0; var iid = parseInt(id, 10); var ifile = task_i.list[iid]; if (ifile) { all_byte = ifile.all_byte; } var finished_p = 0; if (all_byte != 0) { finished_p = ed_byte / all_byte; } // console out console.log(' ' + fw(id, 3, true) + ' : [ ' + st.status + ' ]' + fw(_ui.make_rest_num(finished_p * 1e2, 2) + '%', 8, true) + ' ' + fw(_ui.get_show_file_size(ed_byte), 10, true) + ' ' + fw('(' + ed_byte + ' Byte)', 17, true) + ' ' + _ui.get_show_time(ed_s) + ' ' + fw(_ui.get_show_dl_speed(speed), 13, true) + ' ' ); // count last line _host.last_line ++; } // just move up, after print info _ui.move_by(0, - _host.last_line); _host.last_line = 0; if (_host.stop) { return; } // re set timeout if (!this.error) { _host.timeout = setTimeout(function(){ _next('show_status', _host); }, 1e3); } break; case 0: // ok finish step _host.callback(); break; case -1: // error step _host.callback(_host.error); break; default: // step error time_log('ERROR: evdh.js watch_dl_file_next: step error ! '); } } // test host task function test_host_task(callback) { // finish callback(error); var _host = {}; _host.callback = callback; _host.error = null; var _next = test_host_task_next; _next(1, _host); } function test_host_task_next(_step, _host) { var _next = test_host_task_next; switch (_step) { case 1: // first step // check log file _host.log_file = _.ol.log_file; // check it exist fs.exists(_host.log_file, function(exist){ _host.log_file_exist = exist; _next(_step + 1, _host); }); break; case 2: // read log if (!_host.log_file_exist) { // not exist _next('create_new_task', _host); return; } _.ol.read(function(err){ if (err) { time_log('ERROR: read log failed ! '); // just start a new task _next('create_new_task', _host); } else { _next(_step + 1, _host); } }); break; case 3: // check auto_url mode if (_.cl_global_mode == 'auto_url') { // do not check log, just create new task console.log(''); time_log('INFO: in \'auto_url\' mode, not check log, just create new task. \n'); _next('create_new_task', _host); return; } // check log var logs = _.ol.get_list(); var found = [false, false]; var item_l = []; // check log items for (var i = 0; i < logs.length; i++) { var ilog = logs[i]; switch (ilog.type) { case 'o_host_file_dl': if (ilog.json !== null) { found[0] = true; item_l[0] = ilog; } break; case 'o_host_task': if (ilog.json !== null) { found[1] = true; item_l[1] = ilog; } break; } } // check found if (!found[1]) { // not found unfinished task time_log('INFO: not found unfinished task '); _next('create_new_task', _host); return; } // save found, and item_l to host _host.log_item_found = found; _host.log_item_item_l = item_l; // print task info var task_i = item_l[1].json; console.log(''); time_log('INFO: found 1 unfinished task; task info: '); console.log(' host_url : ' + task_i.host_url); console.log(' base_path : ' + task_i.base_path); console.log(' site : ' + task_i.site); console.log(' hd : ' + task_i.hd + ', quality : ' + task_i.quality); console.log(' title : ' + task_i.title); // count console.log('\n count ' + task_i.count.all_file + ' files, ' + _ui.get_show_file_size(task_i.count.all_byte) + ' ' + _ui.get_show_time(task_i.count.all_time_s) + ', doing ' + task_i.count.doing + ', wait ' + task_i.count.wait + ', error ' + task_i.count.error + ' '); console.log(' done ' + task_i.count.done + ' files, ' + _ui.get_show_file_size(task_i.count.ed_byte) + ', ' + (_ui.make_rest_num((task_i.count.ed_byte / task_i.count.all_byte) * 1e2, 2)) + '% \n'); // check auto_continue mode if (_.cl_global_mode == 'auto_continue') { console.log(''); time_log('INFO: in \'auto_continue\' mode, do not ask user, just auto answer YES to continue unfinished task. \n'); _host.answer = 'y'; _next(_step + 1, _host); return; } // ask user _ui.ask_line(' Do you want to continue it ? (y/N) : ', function(text){ _host.answer = text; _next(_step + 1, _host); }); break; case 4: // got answer console.log(''); if (_host.answer == 'N') { // start new task _next('create_new_task', _host); return; } // re get found, item_l var found = _host.log_item_found; var item_l = _host.log_item_item_l; // set o_host_task log _.oh.set_log(item_l[1].json); time_log('INFO: continue task ... '); // now, read log, load task, and restart done _next('start_task', _host); break; case 'create_new_task': case 5: // _step = 5; // check auto_continue mode if (_.cl_global_mode == 'auto_continue') { console.log(''); time_log('ERROR: in \'auto_continue\' mode. Can not continue task. Not create new task. \n'); _host.error = true; _next(-1, _host); return; } // check auto_url mode if (_.cl_global_mode == 'auto_url') { // input url from command line _host.input_url = _.cl_url; console.log(''); time_log('INFO: in \'auto_url\' mode, auto get url from command line. \n'); _next(_step + 1, _host); return; } console.log(''); // input a url _ui.ask_line(' please input a URL of a video play page : ', function(text){ _host.input_url = _b.pure_string(text); _next(_step + 1, _host); }); break; case 6: // got url console.log(''); time_log('INFO: got URL [[' + _host.input_url + ']] \n'); // analyse it _aurl.aurl(_host.input_url, function(err, info){ if (err) { time_log('ERROR: analyse url failed ! '); _host.error = err; _next(-1, _host); } else { _host.ainfo = info; _next(_step + 1, _host); } }); break; case 7: // got info // check video numbers var info = _host.ainfo.video; var v_num = info.length; if (v_num > 0) { time_log('[ OK ] found ' + v_num + ' videos ! '); } else { time_log('ERROR: found ' + v_num + ' video ! '); } // auto choose quality _m.select_quality(info, function(err, info){ if (err) { time_log('ERROR: auto select video quality failed ! '); _host.error = err; _next(-1, _host); } else { _host.auto_info = info; // check selected info if (!info) { time_log('ERROR: no such video: auto select video quality failed ! '); _host.error = true; _next(-1, _host); return; } _next(_step + 1, _host); } }); break; case 8: // got selected video // print video info time_log('INFO: auto select this video : '); _m.show_video_info([_host.auto_info]); console.log(''); // check auto_url mode if (_.cl_global_mode == 'auto_url') { console.log(''); time_log('INFO: in \'auto_url\' mode, do not ask user, just auto answer YES. \n'); _next(_step + 1, _host); return; } // ask ok _ui.ask_line(' Is this ok ? (Y/n) : ', function(text){ var t = _b.pure_string(text); if (t != 'Y') { time_log('INFO: you selected quit. '); _next(0, _host); } else { _next(_step + 1, _host); } }); break; case 9: // got answer, yes, continue // try to add task, get info var t_url = _host.input_url; var v_info = _host.auto_info; var t_hd = v_info.hd; var t_quality = v_info.quality; var t_title = v_info.title; var t_base_path = _.ci.download_path; // set path v_info.base_path = t_base_path; // set path of each file make_dl_path(v_info); // try to add task _.oh.create(t_url, t_hd, t_quality, t_title, _host.ainfo.video); // print out time_log('[ OK ] add 1 task, task info : '); console.log(' url : ' + t_url); console.log(' hd : ' + t_hd + ', quality : ' + t_quality); console.log(' title : ' + t_title); console.log(' base_path : ' + t_base_path); console.log(' paths examples : '); // show some paths for (var i = 0; i < v_info.file.length; i++) { var fpath = v_info.file[i].path; console.log(' ' + fpath); if (i > 3) { // show at most 5 paths break; } } console.log(''); // check auto_url mode if (_.cl_global_mode == 'auto_url') { console.log(''); time_log('INFO: in \'auto_url\' mode, do not ask user, just auto answer YES. \n'); _host.answer = 'Y'; _next(_step + 1, _host); return; } // ask user _ui.ask_line(' Is this ok ? (Y/n) : ', function(text){ _host.answer = _b.pure_string(text); _next(_step + 1, _host); }); break; case 10: // got answer // check answer if (_host.answer != 'Y') { time_log('INFO: you selected quit. '); _next(0, _host); return; } // refresh log _m.refresh_log(function(err){ if (err) { time_log('ERROR: refresh log failed ! 3 \n'); } }); _next(_step + 1, _host); break; case 'start_task': case 11: // _step = 11; // before start task, set something _.oh.callback = function(event){ // refresh log _m.refresh_log(function(err){ if (err) { time_log('ERROR: refresh log failed ! 4 \n'); } }); // check event type switch (event.type) { case 'dl_done': // event is 'dl_done' // next step _next(_step + 1, _host); return; break; case 'part_done': time_log('[ OK ] part file download done. id ' + event.id + ' '); console.log(''); break; case 'part_error': time_log('ERROR: part file download failed ! id ' + event.id + ' '); console.log(event.list); // show detile error info console.log(''); break; } }; time_log('INFO: starting dl ... '); // start watch _host.stop_watch = watch_dl(); // start id _.oh.start(); // start refresh log _.refresh_log_obj = setTimeout(function refresh_log(){ _m.refresh_log(function(err){ if (err) { time_log('ERROR: refresh log failed ! 7 \n'); } }); // set this if (_.refresh_log_flag) { _.refresh_log_obj = setTimeout(refresh_log, _m.etc.refresh_log_timeout_ms); } }, _m.etc.refresh_log_timeout_ms); _.refresh_log_flag = true; break; case 12: // all file dl ok console.log(''); time_log('[ OK ] all files download done ! \n'); console.log('\n'); // stop refresh_log _.refresh_log_flag = false; clearTimeout(_.refresh_log_obj); // stop watch _host.stop_watch(); // get task info _host.task_info = _.oh.get_status(); // refresh log _m.refresh_log(function(err){ if (err) { time_log('ERROR: refresh log failed ! 5 \n'); } }); // start merge time_log('INFO: start auto merge video ... '); _m.merge_video(_host.task_info, function(code){ _host.exit_code = code; _next(_step + 1, _host); }); break; case 13: // merge video done console.log(''); time_log('[ OK ] merge video done. exit_code : ' + _host.exit_code); // check exit code if (_host.exit_code == 0) { // merge ok // remove task _.oh.remove(); // refresh log _m.refresh_log(function(err){ if (err) { time_log('ERROR: refresh log failed ! 9 \n'); } else { time_log('[ OK ] all works done. '); } }); } // ok finished _next(0, _host); break; case 0: // ok finish step _host.callback(null); break; case -1: // err step _host.callback(_host.error); break; default: // step error time_log('ERROR: evdh.js test_host_task_next: step error ! '); } } // make path function make_dl_path(video_object) { var vs = video_object.file; var title = video_object.title; // get first number from title var fn = _m.get_first_number_from_string(title); var title2 = _m.make_num_l(fn, 4) + '_' + title; // make each path for (var j = 0; j < vs.length; j++) { var f = vs[j]; var type = f.type; var path2 = title2 + '_' + _m.make_num_l(j + 1, 4) + '.' + type; f.path = _m.remove_chars(path2); } // done } /* main function */ function main() { // use main _next for steps var _host = {}; _host.error = null; // error info object var _next = main_next; _next(1, _host); } function main_next(_step, _host) { var _next = main_next; switch (_step) { case 1: // first step // process command line args switch (process.argv[2]) { // first argument case 'mode_normal': // normal mode, interactive download // just save it to _ _.cl_global_mode = 'normal'; // cl command line, global mode break; case 'mode_auto_url': // auto mode, input url, no interactive ask any more _.cl_global_mode = 'auto_url'; _.cl_url = process.argv[3]; // save inputed url break; case 'mode_auto_continue': // auto mode, auto continue unfinished task _.cl_global_mode = 'auto_continue'; break; default: // command line format error time_log('ERROR: command line error ! '); process.exit(2); // exit now return; } // init _m.init(function(err){ // init finish callback if (err) { time_log('ERROR: init failed ! '); _host.error = err; _next(-1, _host); } else { _next(_step + 1, _host); } }); break; case 2: // after init // print init done time_log('[ OK ] init done. '); // start test test_host_task(function(err){ if (err) { _host.error = err; _next(-1, _host); } else { _next(_step + 1, _host); } }); break; case 3: // done // remember to close ui CLI interface _ui.close(); _next(0, _host); break; case 0: // finish step // exit ok process.exit(0); break; case -1: // error time_log('ERROR: test error ! '); // close ui interface _ui.close(); // print error info if (_host.error !== true) { console.log(_host.error); } // exit error process.exit(3); break; default: // step error time_log('ERROR: evdh.js main_next: step error ! '); } } /* start from main */ main(); /* end evdh.js */