Advertisement
Guest User

gethtmldat.jst$$

a guest
May 26th, 2015
1,202
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /********************************************************************/
  2. /*  gethtmldat.js :   ver.0.33   2015/05/17                         */
  3. /********************************************************************/
  4. //
  5. //  Jane2ch.exeでhtmlから過去ログを取得しdat形式に変換してLogsフォルダに格納する
  6. //  htmltodat-convert2.wsf+htmltodat.exeと同じ機能を果たす
  7. //  htmltodat-convert2.wsfとGetLog.wsfからコードを盗用してます(許して)
  8. //
  9. //--------------------------------------------------------------------
  10. //  ※ 重要 ※
  11. //  なお、このスクリプトはこのサイトから DOWNLOAD するのではなく、RAW で表示したものか又はRAW Paste Data から、
  12. //  コピー&ペースト(CTRL+A,CTRL+C,CTRL+V)で、テキストエディタに貼り付け、gethtmldat.js という名前で
  13. //  Shift-JISコード(メモ帳ではANSI)で保存し、Jane2ch.exe のあるフォルダに格納してください
  14. //  ※重要※ DOWNLOADすると、文字コードがUTF-8となり実行できなくなるので注意してください
  15. //--------------------------------------------------------------------
  16. //
  17. //  Jane Styleでのコマンド登録方法は、メニュー - ツール - 設定 - 機能 - コマンド で
  18. //    コマンド名   - 過去ログ取得(gethtmldat)  ※ここには任意の名称をつけられます
  19. //    コマンド内容 - wscript "$BASEPATHgethtmldat.js" $LINK$URL
  20. //  を入力して、追加、OKします
  21. //       ※ なお、Jane直下フォルダでは無い場合はパスをフルパスで指定してください
  22. //          jane styleの下のscriptフォルダに入れた場合は、wscript "$BASEPATHscript\gethtmldat.js" $LINK$URL
  23. //
  24. //  コマンド登録時のパラメタに /w 又は /w:999(待ち時間) を追加するとキー送信(CTL+W)により、スレを閉じて再度開く動作をします
  25. //          wscript "$BASEPATHgethtmldat.js" $LINK$URL /w
  26. //    ※注意※ 当該スレが開く前にキー送信がなされると現在開いている別スレが閉じてしまいます
  27. //
  28. //  起動オプション: 順不同
  29. //    http://~      url指定
  30. //    [/n:]999       レス番指定(そのレス番に飛ぶ)
  31. //    /f             urlを強制的に問い合わせる
  32. //    /w[:999]       スレを指定時間待って閉じ、開き直す(数値省略時 1200ms)
  33. //    /-w            スレを閉じない(デフォルト)
  34. //    /a[ppend]      差分のみ取得(管理人削除などで既存のログとサーバー上のデータに違いがあっても関知しない)
  35. //    /b[ak][1]      バックアップを取る(Logs\bak\の下に既存のdatファイルをコピーする) /b1 は1回限りで上書きしない
  36. //    /redraw[:999]  再描画 スレを開いた後、指定時間待ってからキーコード('ALT','T','G','0')を送る (数値省略時 1200ms)
  37. //    /z             Jane2ch.exeを終了し、情報(db,idx)設定後、再起動する(この場合 /w は不要)
  38. //                   ※ 高速Merge有効時には、SQLite3 ODBC Driver 又は sqlite3.exe のどちらかが必要
  39. //                       SQLite3 ODBC Driver : http://www.ch-werner.de/sqliteodbc/sqliteodbc.exe をダウンロード・インストール
  40. //                                             (インストールは上記exeを実行し、Next,I Agree,Next,Install,Finishボタンで進める)
  41. //                       sqlite3.exe         : http://www.sqlite.org/download.html から、sqlite-shell-win32-x86-3080900.zip
  42. //                                             をダウンロード・解凍し、本スクリプトと同じフォルダに格納する
  43. //    /log[:][path]  トレースログを指定のファイルに追加書き込みします(ファイルパス名省略時は %temp%\gethtmldat.log)
  44. //
  45. //  使い方:
  46. //    Jane Styleで、過去ログを開いた(空白の)レス表示欄で、
  47. //    又は、別スレに書かれているリンクを、
  48. //    又は、書き込みウィンドウ、メモ欄にURLを書き込みプレビューで現れるリンクを、
  49. //    右クリックして上で登録したコマンドを選択する
  50. //    レスが表示・認識されない場合は、再描画、スレを閉じリンククリックで開き直す、>>1などのリンクをクリックなどしてください
  51. //--------------------------------------------------------------------------------
  52.  
  53. /*@cc_on
  54.     @set @DEBUG = false;
  55.     @set @EnabledTest2chJSON = false; // =true で2chで最初にJSONでの取得を試みる(お遊び機能:仕様等一切不明、過去ログは無理)
  56. @*/
  57.  
  58. var HTTP_HEADERS = {
  59. //  "If-Modified-Since" : "Thu, 01 Jun 1970 00:00:00 GMT"
  60. //  ,"Content-Type" : "application/x-www-form-urlencoded"
  61. //  ,"User-Agent" : "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1;)"
  62. };
  63. var HTTP_TIMEOUT = 10 * 1000;
  64. var IDX_STATE = { "2ch":3 , "jbbs":3 }; //=0:現役 =3:dat落ち =10:過去ログ
  65. var JBBS_ABN_STR = "透明あぼーん<><> <><>";
  66.  
  67. var fso   = new ActiveXObject("Scripting.FileSystemObject");
  68. var shell = new ActiveXObject("WScript.Shell");
  69. var sha   = new ActiveXObject("Shell.Application");
  70. var strm  = new ActiveXObject("ADODB.Stream");
  71. var http; try { http = new ActiveXObject("Msxml2.ServerXMLHTTP.6.0"); } catch(e){}
  72.           if (!http) try { http = new ActiveXObject("Msxml2.XMLHTTP.6.0"); } catch(e){}
  73.           if (!http) { http  = new ActiveXObject("Msxml2.XMLHTTP.3.0"); }
  74.  
  75. var JANE_PATH = shell.CurrentDirectory.replace(/[^\\]$/,"$&\\");
  76. var SCRIPT_PATH = fso.GetParentFolderName( WScript.ScriptFullName ).replace(/[^\\]$/,"$&\\");
  77. shell.CurrentDirectory = JANE_PATH;
  78. var JANE_EXE  = "Jane2ch.exe";
  79. var JANE_INI  = "Jane2ch.ini";
  80. var JANE_BRD  = "Jane2ch.brd";
  81. var JANE_LOGS = "Logs\\2ch\\";
  82. var JANE_BAK  = "Logs\\bak\\";
  83. var JANE_BRDCUSTOMIZE_INI = "brdcustomize.ini";
  84. var MY_NAME   = WScript.ScriptName.split(/\.(?=[^.]+$)/)[0];
  85. var TRACE_LOG = replaceEnv("%temp%\\"+MY_NAME+".log").replace(/\\\\/g,"\\");
  86.  
  87. //--------------------------------------------------------------------------------
  88. String.prototype.expand = function(v) { return this.replace(/\$(\d)/g, function(m, n) { return v[n]; }); }
  89. String.prototype.convDontUseStr = function() {
  90.     var tbl0 = { "CON":"$CON", "AUX":"$AUX", "NUL":"$NUL" /*, "PRN":"$PRN", "COM([0-2])":"$COM$1", "LPT([0-2])":"$LPT$1" */ }
  91.     var tbl1 = { "\\":"$Backslash", "/":"$Slash", ":":"$Colon", "*":"$Asterisk", "?":"$Question" }
  92.     var s = this;
  93.     for(var i in tbl0) { s=s.replace( new RegExp("^"+i+"$","i") , tbl0[i]); }
  94.     return s.replace(/[\\/:*?]/g, function (w){return tbl1[w];});
  95. }
  96. function Err(s,t) { s=ErrMsg(s,t); trace("---- "+s+" ----",2); throw new Error(s); }
  97. function ErrMsg(s,t) { return (ERROR_MSG[s]?ERROR_MSG[s]:"Unknown error") + (t?t:"");}
  98.  
  99. function o(s) { /*@if (@DEBUG) WScript.Echo(s); @end @*/ }
  100. function q() {WScript.Quit();}
  101.  
  102. var ERROR_MSG = {
  103.      "E_already_there" : "このスレは既に取得しています"
  104.     ,"E_illegal_url" : "このURLでは処理できません"
  105.     ,"E_remained_garbage" : "レスデータのみの抽出に失敗しました"
  106.     ,"E_block_not_found" : "htmlからスレブロックが見つかりません"
  107.     ,"E_title_not_found" : "スレタイトルが見つかりません"
  108.     ,"E_require_sqlite" : "sqlite3.exe 又は SQLite3 ODBC Driver が必要です"
  109.     ,"E_require_sqlODBC" : "SQLite3 ODBC Driver が必要です"
  110.     ,"E_stop" : "処理を中止しました"
  111.     ,"E_no_data" : "取得データはありません"
  112.     ,"E_http_timeout" : "受信タイムアウト"
  113.     ,"E_http_recieve" : "http受信エラー"
  114.     ,"E_bbs_not_found" : "掲示板番号が不正です"
  115.     ,"E_key_not_found" :"スレッド番号が不正です"
  116.     ,"E_thread_not_found" : "スレッドがありません"
  117.     ,"E_brditem_not_found" : "dat格納場所が見つかりません"
  118.     ,"E_unmatched_res_count" : "抽出したレス数が合いません"
  119.     ,"E_loadfile" : "ファイル読み込みエラー"
  120.     ,"E_savefile" : "ファイル書き込みエラー"
  121. }
  122.  
  123. function object(o) {
  124.     var f = object.f, i, len, n, prop;
  125.     f.prototype = o;
  126.     n = new f;
  127.     for (i=1, len=arguments.length; i<len; ++i) for (prop in arguments[i]) n[prop] = arguments[i][prop];
  128.     return n;
  129. }
  130. object.f = function(){};
  131. //--- http://with-love-from-siberia.blogspot.jp/2009/12/msgbox-inputbox-in-jscript.html -----------
  132. var vb = {};
  133. vb.Function = function(func) { return function() { return vb.Function.eval.call(this, func, arguments); }; };
  134. vb.Function.eval = function(func) {
  135.     var args = Array.prototype.slice.call(arguments[1]);
  136.     for (var i = 0; i < args.length; i++) {
  137.         if ( typeof args[i] != 'string' ) { continue; }
  138.         args[i] = '"' + args[i].replace(/"/g, '" + Chr(34) + "') + '"';
  139.     }
  140.     var vbe;
  141.     vbe = new ActiveXObject('ScriptControl');
  142.     vbe.Language = 'VBScript';
  143.     return vbe.eval(func + '(' + args.join(', ') + ')');
  144. };
  145. var InputBox = vb.Function('InputBox');
  146. var MsgBox = vb.Function('MsgBox');
  147. //--------------------------------------------------------------------------------
  148.  
  149. var args = parmParse(WScript.Arguments);
  150.  
  151. var WMI = (function () {
  152.     var locator = new ActiveXObject("WbemScripting.SWbemLocator");
  153.     var services = locator.ConnectServer(null, "root\\CIMV2");
  154.     return {
  155.         isAliveProcess :
  156.             function (pName, pPath) {
  157.                 var query = "SELECT * FROM Win32_Process WHERE name='"+pName+"'";
  158.                 var props = this.wmiProps(query);
  159.                 for (var i=0, status=false; i<props.length; i++) { if(props[i].ExecutablePath == pPath) {status = true;} }
  160.                 return status;
  161.             }
  162.         ,wmiProps :
  163.             function (query) {
  164.                 var result = [];
  165.                 try {
  166.                     var set = services.ExecQuery(query);
  167.                     var e = new Enumerator(set);
  168.                     while (!e.atEnd()) { result.push(e.item()); e.moveNext(); }
  169.                 } catch (e) { throw e; }
  170.                 return result;
  171.             }
  172.          ,getProcessID :
  173.             function (pName, pPath) {
  174.                 var query = "SELECT * FROM Win32_Process WHERE name='"+pName+"'";
  175.                 do {
  176.                     var props = this.wmiProps(query);
  177.                     for (var i=0,c=0,pid; i<props.length; i++) {
  178.                         if (props[i].ExecutablePath == pPath) { c++; pid=props[i].ProcessID; }
  179.                     }
  180.                 } while (c>1);
  181.                 return pid;
  182.             }
  183.     }
  184. })();
  185.  
  186. var URL_2ch = {
  187.   RE_SITE : new RegExp("^http://\\w+\\.(?:2ch\\.net|bbspink\\.com|2ch\\.sc)/")  //この定義は未使用
  188.  ,RE_URL  : new RegExp("^http://((\\w+)(\\.(\\w+).+?))/(?:test/.+?/)?(\\w+)/(?:kako/.+?/)?(((\\d+)\\d)\\d{5})(/|\\.html|\\.dat(?:\\.gz)?)?")
  189.  ,setInfo : function(url) {
  190.                 this.kako = /\/kako\//.test(url);
  191.                 this.prm  = url.match(this.RE_URL) || Err("E_illegal_url");
  192.                 this.url  = this.prm[0];
  193.                 this.url2 = this.prm[0];
  194.                 if (!this.kako) { this.url2 += (args.opt_n) ? args.opt_n : (url.match(/\/n?(\d+)[^\/]*$/)||[])[1]||"";}
  195.                 else    { delete args.append; }
  196.                 this.site     = this.prm[1];
  197.                 this.category = "";
  198.                 this.brdID    = this.prm[5];
  199.                 this.thrID    = this.prm[6];
  200.             }
  201. }
  202. var URL_jbbs = {
  203.   RE_SITE : new RegExp("^http://jbbs\\.(?:shitaraba|livedoor)\\.(?:net|jp|com)/")
  204.  ,RE_URL  : new RegExp("^http://(jbbs\\.shitaraba\\.net)/bbs/\\w+\\.cgi/(\\w+)/(\\d+)/(\\d+)/?")
  205.  ,setInfo : function(url) {
  206.                 // this.kako = /\/(storage|read_archive\.cgi)\//.test(url);
  207.                 this.prm  = url.match(this.RE_URL) || Err("E_illegal_url");
  208.                 this.url  = this.prm[0];
  209.                 this.url2 = this.prm[0] + (args.opt_n || (url.match(/\/n?(\d+)[^\/]*$/)||[])[1]||"");
  210.                 this.site     = this.prm[1];
  211.                 this.category = this.prm[2];
  212.                 this.brdID    = this.prm[3];
  213.                 this.thrID    = this.prm[4];
  214.             }
  215. }
  216. var URL = URL_2ch;
  217.  
  218. var Jane_2ch = {
  219.  ini          : loadFile(JANE_INI)
  220.  ,brd         : ""
  221.  ,LogBasePath : ""
  222.  ,init        : function() { this._setLogBasePath(); this._loadBRD(); }
  223.  ,getINI      : function(p) { var m=this._search(this.ini, this._re_ini, p); return m && m[1] || p[3]; }
  224.  ,getBRD      : function(p) {
  225.                     var m = this._search(this.brd, this._re_brd, p);
  226.                     return (m) ? m[1].convDontUseStr()+"\\"+m[2].convDontUseStr()+"\\" : null;
  227.                 }
  228.  ,_re_ini     : "^\\[$1\\]\\r\\n(?:.*\\r\\n)*?(?:$2=(.*)|\\[.*\\])\\r\\n"
  229.  ,_re_brd     : "^(\\S+).*\\r\\n(?:\\t.*\\r\\n)*?\\t\\w+$3\\t$5\\t(\\S+)\\r\\n"
  230.  ,_search     : function(f,s,p) { var re,x,y; re=new RegExp(this._expand(s,p),"img"); while(x=re.exec(f)) {y=x;} return y; }
  231.  ,_expand     : function(s,p) { return s.replace(/\$(\d)/g, function(m, n) { return (""+p[n]).replace(/\./g,"\\."); }); }
  232.  ,_setLogBasePath : function() { this.LogBasePath = this.getINI([,"PATH","LogBasePath",""]); }
  233.  ,_loadBRD     : function() { this.brd = loadFile(this.LogBasePath + JANE_BRD); }
  234. }
  235. var Jane_jbbs = object(Jane_2ch,{
  236.   _re_brd : "^(\\S+).*\\r\\n(?:\\t.*\\r\\n)*?\\t$1/$2\\t$3\\t(\\S+)\\r\\n"
  237. });
  238. var Jane = Jane_2ch;
  239. Jane.init();
  240.  
  241. var DatInfo = {
  242.   cnt      : 0
  243.  ,title    : ""
  244.  ,setInfo  : function(dat,bak,brd) {
  245.                 this.dat = dat;
  246.                 this.bak = bak;
  247.                 this.brd = brd;
  248.                 if (fso.FileExists(dat)) {
  249.                     var s = loadFile2(dat);
  250.                     this.cnt  = s.replace(/^.*$/mg,"").length;
  251.                     this.title = (s.match(/<>((?:(?!<>).)*)$/m)||[])[1];
  252.                 }
  253.              }
  254.  ,copyDat  : function() {
  255.                 if (fso.FileExists(this.dat)) {
  256.                     path(this.bak);
  257.                     if (args.bak<0 || !fso.FileExists(this.bak) )
  258.                         try{ trace(); fso.CopyFile(this.dat, this.bak, true); trace("copy file:"+this.bak);} catch(e) {}
  259.                 }
  260.              }
  261.  ,setNewDatInfo : function(title, lines) {
  262.                     this.title = title;
  263.                     this.lines = parseInt(lines,10);
  264.                   }
  265. }
  266.  
  267. var Trace = function() {
  268.     var logfile = TRACE_LOG;
  269.     var flag    = true;
  270.     var first   = true;
  271.     var t       = [];
  272.     if(args.trace) logfile = replaceEnv(args.trace);
  273.     if(!fso.FileExists(logfile)) {
  274.     var env = new ENV();
  275.     try{
  276.         var f = fso.CreateTextFile(logfile);
  277.         f.WriteLine("["+MY_NAME+"]");
  278.         f.WriteLine("Jane Type = "+chkJaneProg()+"\t"+fso.GetFileVersion(JANE_PATH+JANE_EXE));
  279.         f.WriteLine("current path = "+JANE_PATH);
  280.         f.WriteLine("Logs path = "+Jane.LogBasePath+JANE_LOGS);
  281.         f.WriteLine("script path = "+SCRIPT_PATH);
  282.         f.WriteLine("UAC = "+env.UAC);
  283.         f.WriteLine("64bit? = "+env.PROCESSOR_ARCHITECTURE+"\t"+env.PROCESSOR_ARCHITEW6432);
  284.         f.WriteLine("----------------------------------------------------------------------");
  285.         f.Close();
  286.     } catch(e) {flag=false; if(f) f.Close();}
  287.     env = null;
  288.     }
  289.     return function(s,n) {
  290.         if(flag) try{
  291.             if(!n) n=0;
  292.             var f = fso.OpenTextFile(logfile,8,true,0);
  293.             if(first) {first=false; f.WriteLine("");}
  294.             var tt=new Date();
  295.             if(!s) { t[n] = new Date();}
  296.             else   { f.WriteLine(formatDate(tt,3)+"\t"+((n in t)?formatNum(tt-t[n],7)+"ms":"         ")+"\t"+s); }
  297.             f.Close();
  298.         } catch(e) {if(f) f.Close();}
  299.     }
  300. }
  301. function getEnv(s) { var wse = shell.Environment("Process"); return wse(s); }
  302. function replaceEnv(s) { return s.replace(/\%([^%]+)\%/ig, function(w0,w1) {return getEnv(w1);}); }
  303. function formatDate(d,n) {
  304.     return [d.getFullYear()
  305.             , "/"  , ("0"+(d.getMonth()+1)).slice(-2)
  306.             , "/"  , ("0"+d.getDate()).slice(-2)
  307.             , "("  , "日月火水木金土".substr(d.getDay(),1)
  308.             , ") " , ("0"+d.getHours()).slice(-2)
  309.             , ":"  , ("0"+d.getMinutes()).slice(-2)
  310.             , ":"  , ("0"+d.getSeconds()).slice(-2)
  311.             , "."  , ("00"+parseInt(d.getMilliseconds(),10)+" ").slice(-4,n-4)
  312.           ].join("");
  313. }
  314. function formatNum(d,n) {
  315.     return ("        "+d).slice(-n);
  316. }
  317.  
  318. function ENV() {
  319.      this.UAC = sha.IsRestricted("system", "EnableLUA");
  320.      this.PROCESSOR_ARCHITECTURE = getEnv("PROCESSOR_ARCHITECTURE");
  321.      this.PROCESSOR_ARCHITEW6432 = getEnv("PROCESSOR_ARCHITEW6432")
  322.      return this;
  323. }
  324. if (args.trace !== void 0) { trace = new Trace(); } else { trace = function(){}; }
  325.  
  326. //--------------------------------------------------------------------------------
  327.  
  328. var Thread = {
  329.   re_thr      : /^[\s\S]*?<dl[^>]*>\s*(?:<font[^>]*>.*<\/font>.*\s*)?((?:<dt>.+?<dd>.+\n?)+)(\s*<\/dl>)?/i
  330.  ,re_msg      : /<dt.*?>([0-9]+).+?(?:"mailto:(.+?)">)?<b[^>]*>(.*?)<\/b>(?:<\/font>|<\/a>)?(?: ?投稿日)? ?:(.*?)<dd>(.*?)(?:<br>)*(?=<dt.*?>|$)/img
  331.  ,msg         : ""
  332.  ,isExistAbn  : false
  333.  ,init        : function() {}
  334.  ,urlReplace  : function(u) { return u; }
  335.  ,preReplace  : function() {}
  336.  ,mainReplace : function() { this.msg = this.msg.replace(this.re_msg, "$3<>$2<>$4<>$5<>"); }
  337.  ,postReplace : function() {}
  338.  ,createBrdFolder : function() { return null;}
  339.  ,urlAppendFirstNum : function(u) { return u + ((args.append && DatInfo.cnt) ? DatInfo.cnt + "n-" : ""); }
  340.  ,getTBlock   : function() { this.msg = (this.msg.match(this.re_thr,"$1")||[])[1]; }
  341.  ,getTitle    : function(s) { this.title = (s.match(/<title>(.*?)<\/title>/i)||[])[1]; }
  342.  ,readHTTP    : function(url) { this.msg = readHTTP(url); this.getTitle(this.msg); this.getTBlock(); return true; }
  343.  ,getFirst    : function() { return parseInt((this.msg.match(/^<dt[^>]*>(\d+)/i)||[])[1],10); }
  344.  ,getLast     : function() { return parseInt((this.msg.match(/<dt[^>]*>(\d+).*<dd>.*\n$/i)||[])[1],10); }
  345.  ,delContents : function(s) { return s.replace(/^(?:(?:(?!<>).)*<>){4}.*$/mg, ""); }
  346.  ,checkData   : function(s) {
  347.                     var ln = this.checkData0(s);
  348.                     if (this.last-this.first+1 != ln.length)
  349.                         {Err("E_unmatched_res_count"," 先頭=$1 末尾=$2 レス数=$3".expand([,this.first,this.last,ln.length]));}
  350.                 }
  351.  ,checkData0  : function(s) {
  352.                     var ln = this.delContents(s);
  353.                     if (ln.replace(/\n/g,"").length > 0) Err("E_remained_garbage");
  354.                     return ln;
  355.                 }
  356.  ,addTitle    : function() { this.msg = this.msg.replace(/^.*?$/m, "$&"+this.title); }
  357.  ,delDupData  : function() { //わざと重複して要求した先頭レス番データ削除
  358.                     if ((this.msg.match(/^<dt[^>]*>(\d+)/i)||[])[1] == DatInfo.cnt) { this.msg = this.msg.replace(/^.*\n/m, ""); }
  359.                 }
  360.  ,delBeforeFirstData : function() {}
  361.  ,insertAbn   : function() {}
  362.  ,proc        : function() {
  363.                     trace("--- start ---   "+args.url,1);trace("",1)
  364.                     this.init();
  365.                     URL.setInfo(this.urlReplace(args.url));
  366.                     var brd = Jane.getBRD(URL.prm);
  367.                     if (!brd) brd = this.createBrdFolder();
  368.                     if (!brd) Err("E_brditem_not_found");
  369.                     var dat = Jane.LogBasePath + JANE_LOGS + brd + URL.thrID + ".dat";
  370.                     var bak = Jane.LogBasePath + JANE_BAK + brd + URL.thrID + ".dat";
  371.                     DatInfo.setInfo(dat, bak, brd);
  372.                     URL.url = this.urlAppendFirstNum(URL.url);
  373.                     if (trace()|this.readHTTP(URL.url)|trace("HTTP total read time")) {
  374.                         if (!this.msg) Err("E_block_not_found");
  375.                         if (!this.title) Err("E_title_not_found");
  376.                         this.preReplace();
  377.                         if (args.append) {
  378.                             trace(); this.delDupData(); trace("del dupdata time");
  379.                             if(this.msg=="") Err("E_already_there");
  380.                         }
  381.                         this.first = this.getFirst();
  382.                         this.last  = this.getLast();
  383.                         trace(); this.mainReplace(); trace("html->dat main replace time");
  384.                         this.checkData(this.msg);
  385.                         if (this.first==1) { this.addTitle(); }
  386.                         if(this.isExistAbn) { trace(); this.insertAbn(); trace("透明abnレス挿入"); }
  387.                         this.postReplace();
  388.                     }
  389.                     trace("スレタイトル:"+this.title+"\tレス数:"+this.last+"\tサイズ:"+this.msg.length,9);
  390.                     saveDat(dat, this.msg);
  391.                     DatInfo.setNewDatInfo(this.title, this.last);
  392.                     saveIdx("http://"+URL.site+((URL.category)?"/"+URL.category:"")+"/"+URL.brdID);
  393.                     invokeJaneStyle(URL.url2);
  394.                     trace("---- end ----",1);
  395.                 }
  396. }
  397.  
  398. var Thread_2ch = object(Thread,{
  399.   preReplace  : function() { this.msg = this.msg.replace(/(<a href=)"\/cdn-cgi\/l\/(email-protection\#.*?">)/ig,'$1"mailto:$2'); }
  400.  ,postReplace : function() {
  401.                     this.msg = this.msg.replace(/<a href="http.*?>(.*?)<\/a>/ig, "$1")
  402.                                 .replace(/<a href="javascript:be\((\d+?)\)[^>]*>\?(.*?)<\/a>/ig, "BE:$1-$2")
  403.                                 .replace(/<img src="http:\/\/(img\.2ch\.net\/.+?)">/ig, "sssp://$1");
  404.                 }
  405.  ,_getKakoUrl :
  406.     function() {
  407.         var p = URL.prm;
  408.         if(URL.thrID<1000000000)
  409.             { url="http://$1/$2/kako/$3/$4.dat.gz".expand([,p[1],p[5],p[6].substr(0,3),p[6]]);}
  410.         else
  411.             {url="http://$1/$2/kako/$3/$4/$5.dat.gz".expand([,p[1],p[5],p[6].substr(0,4),p[6].substr(0,5),p[6]]);}
  412.         return url;
  413.     }
  414.  ,readHTTP  :
  415.     function(url) {
  416.         /*@if (@EnabledTest2chJSON)
  417.             o("1st try json");
  418.             this.msg = get2chJSON();
  419.             if(this.msg=="") Err("E_already_there");
  420.             if(this.msg) return false;
  421.             o("2nd try html");
  422.         @end @*/
  423.         this.kakoUrl = this._getKakoUrl();
  424.         if(URL.kako) if(!this.readHTTP2(this.kakoUrl)) return false;
  425.         trace("try URL="+url,9);
  426.         this.msg = readHTTP(url);
  427.         var ss = this.msg.match(this.re_thr,"$1");
  428.         if (!ss) {
  429.             var u = this.kakoUrl.replace(/\.dat\.gz$/,".html");
  430.             if (u!=url) {
  431.                 switch(this.readHTTP3(u)) {
  432.                     case 0: return false;
  433.                     case 1: url=u;  ss=this.msg.match(this.re_thr,"$1"); break;
  434.                     default: break // case -1
  435.                 }
  436.             }
  437.         }
  438.         this.getTitle(this.msg);
  439.         if(!ss) {
  440.             ss = "<URL>="+url+"\n<TITLE>="+this.title+"\n<メッセージ長>="+this.msg.length+"\n\n";
  441.             ss += ((this.msg.match(/^((?=.*LoadAverage|人大杉).*$)/im)||[])[1])
  442.                     || ((this.msg.match(/<h1[^>]*>([\s\S]*?)<\/h1>/m)||[])[1])
  443.                     || ((this.msg.match(/<p[^>]*>\n*(.*\s+.*\s*)$/m)||[])[1])
  444.                     || "不明";
  445.             Err("E_block_not_found", "\nもしかしたら以下のはメッセージかも\n\n"+ss+"\n");
  446.         }
  447.         if (!ss[2]) {
  448.             if (MsgBox("途中でデータが途切れているようですが続行しますか?",4+48,MY_NAME)!=6) Err("E_stop");
  449.         }
  450.         var s = ss[1] || "";
  451.         if (s.substr(s.length-1)!="\n") s += "\n";
  452.         this.msg = s;
  453.         return true;
  454.     }
  455.  ,readHTTP2 :
  456.     function(url) {
  457.         var re = /^(?:(?!<>).)*<>(?:(?!<>).)*<>(?:(?!<>).)*<>(?:(?!<>).)*<>(.*)\s*$/m;
  458.         trace("try URL="+url,9);
  459.         var s = readHTTP(url); //9999999999.dat.gz
  460.         var r = s.match(re);
  461.         if(!r) {url=url.replace(/\.gz$/,""); trace("try URL="+url,9); s=readHTTP(url); r=s.match(re); }
  462.         if(r) {
  463.             this.msg = s;
  464.             this.last = this.checkData0(s).replace(/^.*$/m,"").length;
  465.             this.title = r[1];
  466.             URL.kako = true;
  467.             delete args.append;
  468.             return false;
  469.         }
  470.         return true;
  471.     }
  472.  ,readHTTP3 :
  473.     function(url) {
  474.         var title=((this.msg.match(/<title>(.*)<\/title>/im)||[])[1]||"");
  475.         trace("HTTP title="+title,9);
  476.         if (/error/i.test(title)) {
  477.             if(!this.readHTTP2(this.kakoUrl)) return 0; //最初に/kako/.../9999999999.dat.gzを試す
  478.             trace("try URL="+url,9);
  479.             var s = readHTTP(url);  //9999999999.html
  480.             if(/<dl.*>/.test(s)) { // hit
  481.                 URL.kako = true;
  482.                 delete args.append;
  483.                 return 1;
  484.             }
  485.             trace("HTTP title="+((s.match(/<title>(.*)<\/title>/im)||[])[1]||""),9);
  486.         }
  487.         return -1;
  488.     }
  489. });
  490.  
  491. var Thread_jbbs = object(Thread,{
  492.   init        : function() { Jane=Jane_jbbs; URL=URL_jbbs; }
  493.  ,re_thr      : {}
  494.  ,re_msg      : /<DT><A.*?>([0-9]+).+?(?:<A HREF="mailto:(.+?)">)?<B> ?(?:<font color.*?>)?(.*?)(?:<\/font>)? ?<\/B>(?:<\/A>|<\/FONT>)(?: 投稿日)?: ?(.*?)(?:<BR>)?<DD>(.*) ?<BR><BR>/img
  495.  ,urlReplace  : function(u) {
  496.                     //したらばの事前URL変換:旧site名、/storage/ URLを現在のURLに置換
  497.                     return  u.replace(URL.RE_SITE,"http://jbbs.shitaraba.net/")
  498.                              .replace( /\/\w+\.cgi\//, "/read.cgi/")
  499.                              .replace(/^(http:\/\/[^\/]+\/)([^\/]+\/)([^\/]+\/)storage\/(\d+).*$/,"$1bbs/read.cgi/$2$3$4/");
  500.                 }
  501. // ,preReplace : function() {
  502. //                  s = s.replace(/^\s*$/mg,"");
  503. //                  s = s.replace(/\n\n/g,"\n");
  504. //                  s = s.replace(/\s*<div[^>]+>(?:(?!<\/div>)[\s\S])*<\/div>\s*/ig,"\n"); //100レス毎に入る公告を除去
  505. //               }
  506.  ,delDupData  : function() { //わざと重複して要求した先頭レス番データ削除
  507.                     if ((this.msg.match(/^(\d+)/)||[])[1] == DatInfo.cnt) { this.msg = this.msg.replace(/^.*\n/m, ""); }
  508.                 }
  509.  ,mainReplace :
  510.     function() {
  511.         this.msg = this.msg.replace(/^(\d+<>.*?<>.*?<>.*?)(<>.*<>)((?:(?!<>).)*)$/mg, function($0,$1,$2,$3) {return ($3)?$1+" ID:"+$3+$2:$0;});
  512.     }
  513.  ,createBrdFolder :
  514.     function() {
  515.         var s = readHTTP( URL.url.replace( /\/\w+\.cgi(\/\w+\/\w+\/).*$/, "/api/setting.cgi$1") );
  516.         var bbs_title = (s.match(/^BBS_TITLE=(.*)$/m)||[])[1];
  517.         var category = (s.match(/^CATEGORY=(.*)$/m)||[])[1];
  518.         bbs_title || category || Err("E_brditem_not_found");
  519.         brd = [ "【したらば】" + category.convDontUseStr() , bbs_title.convDontUseStr() , ""].join("\\");
  520.         path(Jane.LogBasePath + JANE_LOGS + brd + URL.thrID + ".dat");
  521.         return brd;
  522.     }
  523.  ,getFirst    : function() { return (args.append) ? DatInfo.cnt + 1 : 1; }
  524.  ,getLast     : function() { return parseInt((this.msg.match(/(\d+).*\n$/)||[])[1],10); }
  525.  ,checkData   :
  526.     function(s) {
  527.         if (this.last-this.first+1 != s.replace(/^.*$/mg,"").length) {
  528.             this.isExistAbn = true;
  529.             // 末尾のIDを削除
  530.             this.msg = s.replace(/^(.*?)<>((?!<>).)*$/mg, "$1");
  531.         } else {
  532.             // 先頭のレス番と末尾のIDを削除
  533.             this.msg = s.replace(/^\d+<>(.*?)<>((?!<>).)*$/mg, "$1");
  534.         }
  535.     }
  536.  ,getTitle    : function(s) {
  537.                     this.title = (s.match(/<>((?:(?!<>).)*)<>(?:(?!<>).)*$/m)||[])[1];
  538.                     if(!this.title) this.title=DatInfo.title;
  539.                 }
  540.  ,addTitle    : function() {}
  541.  ,insertAbn   :
  542.     function() {
  543.         // 透明あぼーんレスを挿入する
  544.         var d = [];
  545.         n = this.first;
  546.         var s = this.msg.split("\n");
  547.         for (var i=0; i<s.length; i++) {
  548.             for (var j=n; j<parseInt(s[i].replace(/^(\d+).+$/, "$1"),10); j++) { d.push(JBBS_ABN_STR); n++; }
  549.             d.push(s[i].replace(/^\d+<>(.+)$/, "$1")); n++;
  550.         }
  551.         this.msg = d.join("\n");
  552.     }
  553.  ,readHTTP  :
  554.     function(url) {
  555.         //-- 1st try : rawmode read ----
  556.         var raw_url = url.replace(/\/\w+\.cgi\//, "/rawmode.cgi/");
  557.         trace("try URL="+raw_url,9);
  558.         var s = readHTTP( raw_url, true);
  559.         switch( errmsg = (s[1].match(/^ERROR: *(?! )(.*?)$/m)||[])[1]||"" ) {
  560.             case "BBS NOT FOUND": Err("E_bbs_not_found");
  561.             case "KEY NOT FOUND": Err("E_key_not_found");
  562.             case "THREAD NOT FOUND": Err("E_thread_not_found");
  563.             case "STORAGE IN":
  564.                 this.getTitle = this.getTitle2;
  565.                 this.getLast = this.getLast2;
  566.                 this.delDupData = this.delDupData2
  567.                 this.mainReplace = this.mainReplace2;
  568.                 this.checkData = this.checkData2;
  569.                 this.readHTTP2(URL.prm[0]);
  570.                 delete this.addTitle;
  571.                 break;
  572.             case "": //正常取得
  573.                 s = s[0];
  574.                 this.getTitle(s);
  575.                 IDX_STATE["jbbs"] = 0;
  576.                 this.msg = s;
  577.                 break;
  578.             default: Err("E_http_recieve", "(rawmode) : " + errmsg);
  579.         }
  580.         return true;
  581.     }
  582.  ,readHTTP2 :
  583.     function(url) {
  584.         //-- 2nd try : read html text --
  585.         trace("try URL="+url,9);
  586.         this.msg = readHTTP(url); //途中からデータを取ることができない
  587.         this.getTitle(this.msg);
  588.         var re_thr1 = /^[\s\S]*?<dl\s+(?:class|id)="thread[^>]*?>\s*(<dt>(?:(?!<\/dl>)[\s\S])*?\s*)<\/dl>[\s\S]*$/i
  589.         var re_thr2 = /^[\s\S]*?<dl[^>]*?>(?:(?!<dt>)[\s\S])*(<dt>(?:(?!<\/dl>)[\s\S])*)<\/dl>[\s\S]*$/i
  590.         if (re_thr1.test(this.msg) != 0) { this.re_thr = re_thr1 }
  591.         else if (re_thr2.test(this.msg) != 0) { this.re_thr = re_thr2; }
  592.         this.getTBlock();
  593.     }
  594.  ,getLast2    : function() { return parseInt((this.msg.match(/<dt><a[^>]*?>(\d+).*<dd>.*\n$/i)||[])[1],10); }
  595.  ,getTitle2   : function(s) {
  596.                     this.title = (s.match(/<h1 class="thread-title">(.*?)<\/h1>/i)||[])[1]
  597.                                  || (s.match(/<title>(.*?)<\/title>/i)||[])[1] || "";
  598.                 }
  599.  ,delDupData2 :
  600.     function() {
  601.         //append時、既存のレス数分データを読み飛ばす
  602.         while( (this.msg.match(/^<dt><a[^>]*?>(\d+)/i)||[])[1] < DatInfo.cnt+1) { this.msg = this.msg.replace(/^.*\n/m,""); }
  603.     }
  604.  ,mainReplace2 : function() { this.msg = this.msg.replace(this.re_msg, "$1<>$3<>$2<>$4<>$5<>"); }
  605.  ,checkData2   :
  606.     function(s) {
  607.         var ln = this.checkData0(s);
  608.         if (this.last-this.first+1 != ln.length) {
  609.             this.isExistAbn = true;
  610.         } else {
  611.             // 先頭のレス番を削除
  612.             this.msg = s.replace(/^\d+<>/mg, "");
  613.         }
  614.     }
  615. });
  616.  
  617. //-------------------------------------------------------------------------------
  618. function loadFile(f) {
  619.     var s;
  620.     try {
  621.         strm.Type = 2;
  622.         strm.Charset = 'shift_jis';
  623.         strm.Open();
  624.         strm.loadFromFile(f);
  625.         s = strm.ReadText(-1);
  626.         strm.Close();
  627.     } catch(e) { strm.Close(); Err("E_loadfile", "\n"+e.message+"\ncurrent="+shell.CurrentDirectory+"\nfile="+f); }
  628.     return s;
  629. }
  630. function loadFile2(f) {
  631.     var s;
  632.     try {
  633.         var file = fso.OpenTextFile( f, 1, false, 0);
  634.         s = file.ReadAll();
  635.         file.close();
  636.     } catch(e) { if(file) file.close(); Err("E_loadfile", "\n"+e.message+"\ncurrent="+shell.CurrentDirectory+"\nfile="+f); }
  637.     return s;
  638. }
  639.  
  640. function saveFile(f,s) {
  641.     strm.Type = 2;
  642.     strm.Charset = 'shift_jis';
  643.     strm.Open();
  644.     if (args.append) { try {strm.loadFromFile(f); strm.Position = strm.Size;} catch(e){} }
  645.     strm.WriteText(s);
  646.     try { strm.Savetofile(f, 2); }
  647.     catch(e) { strm.Close(); Err("E_savefile", "\n"+e.message+"\ncurrent="+shell.CurrentDirectory+"\nfile="+f); }
  648.     strm.Close();
  649. }
  650. function saveFile2(f,s) {
  651.     try{
  652.         var file = fso.OpenTextFile( f, (args.append)?8:2 , true, 0);
  653.         file.Write(s);
  654.         file.Close();
  655.     } catch(e) { if(file) file.Close(); Err("E_savefile", "\n"+e.message+"\ncurrent="+shell.CurrentDirectory+"\nfile="+f); }
  656. }
  657.  
  658. function readHTTP(u, withHeaders) {
  659.     var s="", r="";
  660.     http.open("GET", u, true);
  661.     for(var i in HTTP_HEADERS) { http.setRequestHeader(i, HTTP_HEADERS[i]); }
  662.     http.send();
  663.     for (var t0=new Date(); http.readyState<4; ) {
  664.         if (new Date() - t0 > HTTP_TIMEOUT) { http.abort(); Err("E_http_timeout"); }
  665.         WScript.Sleep(50);
  666.     }
  667.     if (http.status != 200 && !http.status==0) Err("E_http_recieve", " status="+http.status);
  668.     var header = http.getResponseHeader("Content-Type");
  669.     if (withHeaders) r = http.getAllResponseHeaders();
  670.     s = http.responseText;
  671.     if (!/charset=/i.test(header)) {
  672.         if(http.responseBody !== void 0) {
  673.             trace("HTTP文字コード変換開始",9);
  674.             var cs = (s.match(/<meta[^>]*charset=([^>;"'\s]+)/i)||[])[1] || '_autodetect';
  675.             strm.Type = 1;
  676.             strm.Open();
  677.             strm.Write(http.responseBody);
  678.             strm.Position = 0;
  679.             strm.Type = 2;
  680.             strm.Charset = cs;
  681.             s = strm.ReadText(-1);
  682.             strm.Close();
  683.         }
  684.     }
  685.     http.abort();
  686.     if(!s) s="";
  687.     return withHeaders ? [s,r] : s;
  688. }
  689.  
  690. function saveDat(dat,s) {
  691.     if (args.append) {
  692.         if(s=="") Err("E_already_there");
  693.     } else {
  694.         if(s.match(/\n/g)==null) Err("E_no_data");
  695.         if(DatInfo.cnt>=s.match(/\n/g).length) {
  696.             if (MsgBox("既存のスレデータの方が同じか又は大きいですが、置換を続行しますか?",4+32+256,MY_NAME) != 6){
  697.                 Err("E_stop");
  698.             }
  699.         }
  700.     }
  701.     if(args.bak) DatInfo.copyDat();
  702.     trace(); saveFile2(path(dat), s); trace("save file:"+dat);
  703. }
  704.  
  705. function invokeJaneStyle(url) {
  706.     shell.Exec(JANE_EXE + " " + url);
  707.     if(args.sendkey && args.sendkey > 0) {
  708.         WScript.Sleep(args.sendkey);
  709.         shell.SendKeys('^(w)');
  710.         WScript.Sleep(200);
  711.         shell.Exec(JANE_EXE + " " + url);
  712.     }
  713.     if(args.redraw) {
  714.         WScript.Sleep(args.redraw);
  715.         shell.SendKeys('%');
  716.         WScript.Sleep(20);
  717.         shell.SendKeys('T');
  718.         WScript.Sleep(10);
  719.         shell.SendKeys('G');
  720.         WScript.Sleep(10);
  721.         shell.SendKeys('0');
  722.     }
  723. }
  724.  
  725. function terminateJaneExe() {
  726.     shell.Exec(JANE_EXE);
  727.     WScript.Sleep(200);
  728.     shell.SendKeys("%({F4})");
  729.     do {
  730.         var cnt=20;
  731.         while(cnt && WMI.isAliveProcess(JANE_EXE, JANE_PATH+JANE_EXE)) { WScript.Sleep(100); cnt--;}
  732.         if(!cnt) { WScript.Echo(JANE_EXE+"を終了させてください"); }
  733.     } while(!cnt);
  734. }
  735.  
  736. function saveIdx(boardUrl) {
  737.     var i,s,r;
  738.     var use_db = parseInt(Jane.getINI([,"OPTIONS","QuickMerge",""]),10);
  739.     if(chkJaneProg().indexOf('Xeno')>=0) { use_db = parseInt(Jane.getINI([,"OJVIEW","QuickMerge",""]),10); }
  740.     var basedir = shell.CurrentDirectory;
  741.     var dir = fso.GetParentFolderName(fso.GetFile(DatInfo.dat).Path);
  742.     var datName = DatInfo.dat.replace(/^.*\\([^\\]+)\.dat$/,"$1");
  743.    
  744.     var maxRes = getBrdCustomizeIni(boardUrl) || 1000;
  745.     var state = (DatInfo.lines>=maxRes) ? 0 : IDX_STATE[ (URL===URL_2ch) ? "2ch" : "jbbs" ];
  746.     if (URL.kako) state = 10;
  747.    
  748.     var last_got = Number(new Date(fso.GetFile(DatInfo.dat).DateLastModified)/1000+9*60*60);
  749.     var idx = [ datName,DatInfo.title,'',DatInfo.lines,'0','',boardUrl,state,DatInfo.lines,'','','0',last_got,'0','0' ];
  750.     var idxText = [];
  751.     for(i=0; i<idx.length; i++) { idxText[i] = "'" + idx[i] + "'"; }
  752.     var SQL_CMD_1 = "CREATE TABLE IF NOT EXISTS tableversion (tablename PRIMARY KEY, version);"
  753.                     + 'INSERT OR IGNORE INTO "tableversion" VALUES(' + "'board_db','00000001');"
  754.                     + 'INSERT OR IGNORE INTO "tableversion" VALUES(' + "'idxlist','00000002');"
  755.                     + "CREATE TABLE IF NOT EXISTS idxlist ("
  756.                     + "datname TEXT PRIMARY KEY, title TEXT, last_modified TEXT, lines TEXT, view_pos TEXT, idx_mark TEXT,"
  757.                     + " uri TEXT, state TEXT,new_lines TEXT, write_name TEXT, write_mail TEXT,"
  758.                     + " last_wrote TEXT, last_got TEXT, read_pos TEXT, record_be TEXT,"
  759.                     + " etc1 TEXT, etc2 TEXT);";
  760.     var SQL_CMD_2 = 'INSERT OR IGNORE INTO idxlist VALUES(' + idxText.join(",") + ",NULL,NULL);";
  761.     var SQL_CMD_3 = "update idxlist set new_lines=new_lines+$2-lines where datname='$1';".expand([,datName,DatInfo.lines]);
  762.     var SQL_CMD_4 = "update idxlist set lines=" + idxText[3] + ",uri=" + idxText[6] + ",title=" + idxText[1]
  763.                      + ",state=" + idxText[7] + ",last_got=" + idxText[12] + " where datname=" + idxText[0] + ";";
  764.  
  765.     if (use_db && args.restart) {
  766.         var sql = new Sql();
  767.         if(chkJaneProg().substr(0,4)=='Xeno' && !sql.isSqlite_ODBC) Err("E_require_sqlODBC");
  768.         sql.isSqlite_ODBC || sql.isSqlite_exe || Err("E_require_sqlite");
  769.     }
  770.     if(args.restart) terminateJaneExe();
  771.    
  772.     if (use_db && args.restart) {
  773.     switch(chkJaneProg()) {
  774.         case 'Style' :
  775.         case 'Style?':
  776.             shell.CurrentDirectory = dir;
  777.             r=sql.exec("BoardDB.db",SQL_CMD_1+SQL_CMD_2+SQL_CMD_3+SQL_CMD_4);
  778.             break;
  779.         case 'Xeno':
  780.         case 'Xeno?':
  781.             var qmerge3 = Jane.LogBasePath+JANE_LOGS+"qmerge3.db";
  782.             if(!fso.FileExists(qmerge3)) break;
  783.             idx.splice(14,1,last_got);
  784.             idxText = [];
  785.             for(i=0; i<idx.length; i++) { idxText[i] = "'" + idx[i] + "'"; }
  786.             var brd=DatInfo.brd.slice(0,-1);
  787.             var SQL_CMD_XENO1 = "select board_id,max(board_id) from board where board_name='"+brd+"';";
  788.             var SQL_CMD_XENO2 = 'insert into board VALUES((select max(board_id)+1 from board),'+"'"+brd+"'"+');';
  789.             var SQL_CMD_XENO3 = "select board_id from thread where board_id=$1 and datname='"+datName+"';";
  790.             var SQL_CMD_XENO4 = "insert into thread values($1,"+idxText.join(",")+");";
  791.             var SQL_CMD_XENO5 = "update thread set new_lines=new_lines+$2-lines where datname='$1';".expand([,datName,DatInfo.lines]);
  792.             var SQL_CMD_XENO6 = "update thread set lines=" + idxText[3] + ",uri=" + idxText[6] + ",title=" + idxText[1]
  793.                                 + ",state=" + idxText[7] + ",last_got=" + idxText[12] + " where datname=" + idxText[0] + ";";
  794.             var board_id = sql.select(qmerge3,SQL_CMD_XENO1);
  795.             board_id = (board_id[0].match(/^(\d+)/)||[])[1];
  796.             if (!board_id) { sql.exec(qmerge3, SQL_CMD_XENO2); board_id=((sql.select(qmerge3,SQL_CMD_XENO1))[0].match(/^(\d+)/)||[])[1]; }
  797.             if(!((sql.select(qmerge3,SQL_CMD_XENO3.expand([,board_id])))[0].match(/^\d+/))) {
  798.                 sql.exec(qmerge3, SQL_CMD_XENO4.expand([,board_id]));
  799.             } else {
  800.                 sql.exec(qmerge3, SQL_CMD_XENO5);
  801.                 sql.exec(qmerge3, SQL_CMD_XENO6);
  802.             }
  803.             default: break;
  804.         }
  805.         sql.finalize();
  806.     }
  807.    
  808.     // idxファイルの更新
  809.     shell.CurrentDirectory = dir;
  810.     var isExistIdx = false;
  811.     if(fso.FileExists(datName+".idx")) {
  812.         s = loadFile(datName+".idx").replace(/\r/g,"").split("\n");
  813.         if(s.length>=12) {
  814.             isExistIdx = true;
  815.             s[7]  = "" + (parseInt(s[7],10) + DatInfo.lines - parseInt(s[2],10));
  816.             s[2]  = "" + idx[3];
  817.             s[5]  = idx[6];
  818.             s[6]  = "" + idx[7];
  819.             s[11] = "" + last_got;
  820.             s[0]  = idx[1];
  821.         }
  822.     }
  823.     if(!isExistIdx) {
  824.         s = idx;
  825.         s.splice(0,1);
  826.         s.push("");
  827.     }
  828.     s = s.join("\r\n");
  829.     try { saveFile(datName+".idx", s); } catch(e) {}
  830.    
  831.     // subject.txtの更新
  832.     if(fso.FileExists("subject.txt")) {
  833.         var re = new RegExp("^"+datName+"\\..*\\((\\d+)\\)(\\s*)$", "m");
  834.         s = loadFile("subject.txt");
  835.         r = s.match(re);
  836.         if(r) {
  837.             s = s.replace(re, r[0].replace(/\((\d+)\)(\s*)$/,"("+DatInfo.lines+")$2"));
  838.             try { saveFile("subject.txt",s); } catch(e) {}
  839.         }
  840.     }
  841.     shell.CurrentDirectory = basedir;
  842. }
  843.  
  844. function Sql(){
  845.     var DRIVER = "DRIVER=SQLite3 ODBC Driver;";
  846.     var db = new ActiveXObject("ADODB.Connection");
  847.     this.isSqlite_exe  = fso.FileExists(SCRIPT_PATH + "sqlite3.exe");
  848.     this.isSqlite_ODBC = (function(){var s=true; try {db.Open(DRIVER);db.Close();} catch(e){s=false;}; return s;})();
  849.     this.finalize = function() { db = null; }
  850.     var funcTables  = [ "exec", "select" ];
  851.     var types = (this.isSqlite_ODBC) ? "ODBC" : "exe";
  852.     for(var i=0; i<funcTables.length; i++) { eval( "this."+ funcTables[i] + "=" + funcTables[i] + "_" + types + ";"); }
  853.     function exec_ODBC(dbFile,sql) {
  854.         try {
  855.             var s="";
  856.             db.Open(DRIVER+"Database="+dbFile);
  857.             db.Execute(sql);
  858.         } catch(e) { s = e.message; }
  859.         try { db.Close(); } catch(e) { s += " | Connection Close:"+e.message; }
  860.         return [,s];
  861.     }
  862.     function select_ODBC(dbFile,sql) {
  863.         var r="",s="";
  864.         var rs = new ActiveXObject("ADODB.Recordset");
  865.         try {
  866.             db.Open(DRIVER+"Database="+dbFile);
  867.             rs.Open(sql,db);
  868.             while(!rs.Eof) {
  869.                 var rr=[];
  870.                 for(var i=0; i<rs.Fields.count; i++) { rr.push(rs(i).Value); }
  871.                 r += rr.join("|")+"\n";
  872.                 rs.MoveNext();
  873.             }
  874.         } catch(e) { s = e.message; }
  875.         try { rs.Close(); } catch(e) { s += " | Recordset Close:"+e.message; }
  876.         try { db.Close(); } catch(e) { s += " | Connection Close:"+e.message; }
  877.         rs = null;
  878.         return [r, s];
  879.     }
  880.     function exec_exe(dbFile,sql) { return select_exe(dbFile, sql); }
  881.     function select_exe(dbFile, sql) {
  882.         var sqlite = shell.Exec(SCRIPT_PATH + "sqlite3.exe");
  883.         sqlite.StdIn.WriteLine(".open '"+ dbFile+ "'");
  884.         sqlite.StdIn.WriteLine(sql);
  885.         sqlite.StdIn.WriteLine(".quit");
  886.         return [ sqlite.StdOut.ReadAll(), sqlite.StdErr.ReadAll() ];
  887.     }
  888. }
  889.  
  890. function getBrdCustomizeIni(brdurl) {
  891.     if(!fso.FileExists(JANE_BRDCUSTOMIZE_INI)) return null;
  892.     var s=loadFile(JANE_BRDCUSTOMIZE_INI),r,u;
  893.     brdurl=brdurl.replace(/^http:\/\//,"").replace(/\./g,"\\.");
  894.     do {
  895.         if (r = s.match(new RegExp("^\\[$1/?\\]\\s+MaxResNum=(\\d+)".expand([,"http://"+brdurl]),"im"))) break;
  896.         u = brdurl.split(/\/(?=[^\/]+$)/);
  897.         brdurl =u[0];
  898.     } while(u[1])
  899.     return r&&r[1];
  900. }
  901.  
  902. function chkJaneProg() {
  903.     var i,n1=0,n2=0;
  904.     var folder=sha.Namespace(JANE_PATH);
  905.     var items=folder.Items();
  906.     for(i=0; i<items.Count-1;i++) {
  907.         if(folder.GetDetailsOf(items, i) == '説明') { n1=i; }
  908.         if(folder.GetDetailsOf(items, i) == '製品名') { n2=i; }
  909.     }
  910.     if(n1>0)  var description = folder.GetDetailsOf(folder.ParseName("Jane2ch.exe"),n1);
  911.     if(n2>0)  var productname = folder.GetDetailsOf(folder.ParseName("Jane2ch.exe"),n2);
  912.     if (description=="JaneXeno") return "Xeno";
  913.     if (description=="JaneView") return "View";
  914.     if (productname=="Jane Style") return "Style";
  915.     var fileversion = parseFloat(fso.GetFileVersion(JANE_PATH+JANE_EXE));
  916.     if (fileversion>3.0) return "Style?";
  917.     if (fileversion<1.0) return "Xeno?";
  918.     return "Unknown";
  919. }
  920. //--------------------------------------------------------------------------------
  921. function path(p) {
  922.     var d = p.match(/[^\\]+\\/g), e = "";
  923.     for (var i = 0; d[i]; i++) fso.FolderExists(e += d[i]) || fso.CreateFolder(e);
  924.     return p;
  925. }
  926.  
  927. function parmParse(args) {
  928.     var ptn = [ "^(?:/n:)?(\\d+)", "^/f", "^http://", "^/w:?(-?\\d+)?$", "^/-w", "^/a(?:ppend)?"
  929.                 , "^/b(?:ak)?(1)?", "^/z", "^/redraw:?(\\d+)?$", "/log:?(.*)$" ];
  930.     var p = {};
  931.     for (var i=0; i<args.length; i++) {
  932.     for (var j=0,n=-1; j<ptn.length;j++) {if ((new RegExp(ptn[j],"i")).test(args(i))) { n=j; break;} }
  933.     switch (n) {
  934.         case 0: p["opt_n"] = ((args(i).match(new RegExp(ptn[n],"i"))||[])[1]||"");
  935.                 break;
  936.         case 1: p["url"] = InputBox("URLを指定してください",MY_NAME) || "";
  937.                 break;
  938.         case 2: p["url"] = args(i);
  939.                 break;
  940.         case 3: p["sendkey"] = ((args(i).match(new RegExp(ptn[n],"i"))||[])[1]||1200);
  941.                 break;
  942.         case 4: p["sendkey"] = -1;
  943.                 break;
  944.         case 5: p["append"] = true;
  945.                 break;
  946.         case 6: p["bak"] = -1;
  947.                 if ((args(i).match(new RegExp(ptn[n],"i"))||[])[1]) { p["bak"] = 1; }
  948.                 break;
  949.         case 7: p["restart"] = true;
  950.                 break;
  951.         case 8: p["redraw"] = ((args(i).match(new RegExp(ptn[n],"i"))||[])[1]||1200);
  952.                 break;
  953.         case 9: p["trace"] = ((args(i).match(new RegExp(ptn[n],"i"))||[])[1]||"");
  954.                 break;
  955.         default: break;
  956.     }
  957.     }
  958.     if (!("url" in p)) p["url"] = InputBox("URLを指定してください",MY_NAME) || "";
  959.     p.url = p.url.replace(/^(http:\/\/.*?)http:\/\/.*$/, "$1")
  960.     return p;
  961. }
  962.  
  963. //--------------------------------------------------------------------------------
  964.  
  965. function main() {
  966.     if (URL_jbbs.RE_SITE.test(args.url)) Thread_jbbs.proc();
  967.     else Thread_2ch.proc();
  968. }
  969.  
  970. /*@if (@DEBUG)
  971.     main();
  972.     @else @*/
  973.     try {main();} catch (e) {WScript.Echo(e.message);}
  974. /*@end @*/
  975.  
  976. //--------------------------------------------------------------------------------
  977. /*@if (@EnabledTest2chJSON)
  978. function get2chJSON() {
  979.     var urlJSON = "http://itest.2ch.net/public/newapi/client.php?subdomain=$2&board=$5&dat=$6".expand(URL.prm);
  980.     trace("try URL=" + urlJSON,9);
  981.     var s = readHTTP(urlJSON);
  982.     if(!s) return null;
  983.     var total_count = (s.match(/"total_count":(\d+)/)||[])[1];
  984.     var thread      = s.match(/"thread":\[(\d+),(\d+),("[^"]*"),("[^"]*"),("[^"]*"),("[^"]*")\]/);
  985.     var comments    = (s.match(/"comments":\[((?:\[(\d+),("[^"]*"),("[^"]*"),(\d+),("[^"]*"),("[^"]*"),("[^"]*")\],?)+)\]/)||[])[1];
  986.     if (!thread || !comments) return null;
  987.     eval("var title ="+thread[6]+";");
  988.     comments = comments.replace(/(\[(?:\d+),(?:"[^"]*"),(?:"[^"]*"),(?:\d+),(?:"[^"]*"),(?:"[^"]*"),(?:"[^"]*")\]),/g,"$1\n").split("\n");
  989.     Thread_2ch.title = title;
  990.     Thread_2ch.last = comments.length;
  991.     if(args.append && DatInfo.cnt>0) { comments.splice(0,DatInfo.cnt); }
  992.     for(var i=0; i<comments.length; i++) {
  993.         var res,d,id="",be="";
  994.         var res = comments[i].substring(1,comments[i].length-1);
  995.         res = res.match(/^(\d+),("[^"]*"),("[^"]*"),(\d+),("[^"]*"),("[^"]*"),("[^"]*")$/);
  996.         var name = eval(res[2]).replace(/(◆.+)$/,"</b>$1<b>").replace(/(転載ダメ&copy;2ch\.net)/,"<small>$1</small>");
  997.        
  998.         d = new Date( (res[4]<365*24*60*60*1000) ? res[4]*1000 : res[4] );
  999.         d = formatDate(d,2);
  1000.         if (res[5]!='""')  id = " ID:" + eval(res[5]);
  1001.         if (res[6]!='""')  be = " BE:" + eval(res[6]);
  1002.         comments[i] = [ name, eval(res[3]), d + id + be, eval(res[7]), ].join("<>");
  1003.     }
  1004.     s = "";
  1005.     if(comments.length>0) {
  1006.         if(!args.append || !DatInfo.cnt) { comments[0] += title; }
  1007.         s = comments.join("\n") + "\n";
  1008.     }
  1009.     return s;
  1010. }
  1011. @end @*/
  1012.  
  1013. //--------------------------------------------------------------------
  1014. // History :
  1015. //  v.0.1 2015/03/26 created
  1016. //  v.0.2 2015/03/27 fixed
  1017. //          email-protection から mailto: へ置換を追加
  1018. //  v.0.3 2015/03/27 fixed
  1019. //          スレッドデータ抽出判定を変更
  1020. //  v.0.4 2015/03/27 added
  1021. //          スレッドデータ抽出できなかった場合のエラーチェックを追加
  1022. //  v.0.5 2015/03/28
  1023. //          試験的に「したらば」の過去ログ取得をサポート(ほぼ未検証)
  1024. //          通信が非同期になってなかったのを修正
  1025. //          bbspink.comの場合も2ch.netの処理に飛ぶようにした
  1026. //          スレッドデータからレスを正常に抽出できない場合のチェックを追加
  1027. //          既存のdatがあった場合に、レス数が大きくない場合は置換するかどうか問い合わせするようにした
  1028. //  v.0.6 2015/03/28
  1029. //          dat格納場所が見つからない場合のチェックを追加
  1030. //          URLにレス番の指定が無い場合レス番1をURLに追加し、スレの先頭から表示されるようにした
  1031. //          一度スレを閉じるための"ALT","T","C","C"のキーを送る時に適当にウェイトを入れた
  1032. //  v.0.7 2015/03/29
  1033. //          キー送信のウェイトを再度調整 300ms->600ms
  1034. //          (メニューが残るのは最初の起動で開く処理がキー操作の途中にくるタイミングなのでキー送信を全体に遅らせた)
  1035. //          既存のdatが存在した場合は、現在のレス位置とし、再度開く時にスレの先頭に移動しないようにした
  1036. //  v.0.8 2015/03/29
  1037. //          LogsファイルをJane Style直下のフォルダ以外に移動している場合、brdファイル読み込みエラーになるのを修正
  1038. //          起動パラメタ(オプション指定)を追加しました
  1039. //          パラメタなし : urlを問い合わせる(対話型)
  1040. //          第1パラメタ  : URL
  1041. //          第2パラメタ以降  :
  1042. //              http://~  第1パラメタを無視してこちらをurlとして優先する
  1043. //              /f         第1パラメタのurlを無視してurlを問い合わせる
  1044. //              /n:999     レス番を指定(そのレス番に飛ぶ)
  1045. //          コマンド登録時に、wscript "$BASEPATHgethttpdat.js" "$LINK$URL" $INPUT としておくと動的にオプションを指定できます
  1046. //  v.0.9 2015/03/30
  1047. //          【したらば】の過去ログ取得を拡張
  1048. //              ・/bbs/read.cgi/ 以外、/bbs/read_archive.cgi/ でも取得する
  1049. //              ・まず rawmode.cgi での取得を試みる
  1050. //              ・事前にカテゴリ/板を開いたことが無いスレでも取得できるようにした(スレ一覧も開きます)
  1051. //          パラメタのレス番指定は、/n:を省略可能 数字のみでよい
  1052. //  v.0.10 2015/03/30
  1053. //          【したらば】のスレデータ受信時予期せぬエラーの場合正常としていたのを修正
  1054. //  v.0.11 2015/03/31
  1055. //          板一覧(Jane2ch.brd)に複数の板識別子が存在する場合、最後のものを採用するように変更
  1056. //          【したらば】過去ログで、
  1057. //              透明あぼーん(番号が飛んでいる)の場合に「透明あぼーん」を追加しレス番ずれを防止
  1058. //              スレデータを抽出できない場合があったのを修正
  1059. //  v.0.12 2015/03/31
  1060. //          2chのデータの中に<a href="mailto:xxx"></a>が無い場合や最後に<br><br>が付いてない場合も抽出できるようにした
  1061. //              ( [ここ壊れてます]のようなデータのこと)
  1062. //          スレ抽出できない場合サーバーメッセージらしきものをエラーメッセージに追加?(datが存在しません/人大杉)
  1063. //          したらばのrawmodeで取得したデータでの透明あぼーん処理を追加
  1064. //          引数追加とデフォルト動作変更
  1065. //              /w      スレを閉じて開きなおす(600ms)
  1066. //              /w:999  スレを閉じて開きなおす(wait指定)
  1067. //              /-w     スレを閉じない(デフォルト)
  1068. //  v.0.13 2015/04/03
  1069. //          2chのデータの中に名前が無い(<font.*><b></b></font>)場合に抽出できなかったのを修正
  1070. //          引数の指定を順不同にし、以下を追加
  1071. //              /a, /append  既存のデータに追加する(差分のみ取得)
  1072. //              /b, /bak     保存前に既存のdatファイルが存在した場合は、Logs\bak\フォルダにバックアップコピーする
  1073. //          したらばの透明あぼーん補正処理は必要のない場合スキップする
  1074. //          2chのサーバーエラーメッセージで"LoadAverage ="が抜けていたのを修正
  1075. //  v.0.14 2015/04/04
  1076. //          /a 指定時、したらばの過去ログを正常に追加できていなかったのを修正(したらばは過去ログの部分取得が無理なため)
  1077. //  v.0.15 2015/04/12
  1078. //          レス数を正しく認識できない場合があった(レス番抽出正規表現の間違い)のを修正
  1079. //          /a 指定時、2chのdatが無い場合、先頭レス番1が消えるのを修正
  1080. //  v.0.16 2015/04/16
  1081. //          2chでデータが途中で途切れている場合のチェックを追加
  1082. //          (ftp:// のようなデータがある場合、現状では、エラーにならず途切れていることがある)
  1083. //  v.0.17 2015/04/17
  1084. //          考えを変えて、データが途中で途切れている場合も取得したところまでで処理を続行するように変更した
  1085. //          オプションに、/b1, /bak1 を追加(bakupは1回限りでファイルが存在していたら上書きしない)
  1086. //  v.0.18 2015/04/21
  1087. //          オプション /z を追加(Jane2ch.exeを終了させて、db、idx、subject.txtに情報を設定し、再起動する)
  1088. //           (なお、高速Merge有効時にはsqlite3.exeが必要)
  1089. //           (stateは=3(dat落ち)に設定) ※本来の処理としては、レス数1000(10000)以上では=0のままで良く、未満時は=10(過去ログ)?
  1090. //  v.0.19 2015/04/21
  1091. //          引数にurlが含まれていない場合、url入力ボックスが出ずにエラーになってたのを修正
  1092. //  v.0.20 2015/04/27
  1093. //          したらばの旧過去ログURL(http://[したらばsite]/[カテゴリ]/[掲示板番号]/storage/[スレッド番号].html)もサポート
  1094. //          /z オプション時、高速Merge無効時の処理を修正
  1095. //                           高速Merge有効時、sqlite3.exeに加えてSQLite3 ODBC Driverもサポート(どちらか一方があればよい)
  1096. //          db,idxのstate値は、=0(brdcustomize.iniの設定値又は1000以上の時)、それ以外は =3(dat落ち) にする
  1097. //  v.0.21 2015/04/27
  1098. //          /z オプション時、高速Merge有効時、sqlite3.exeとSQLite3 ODBC Driverの両方とも無い場合エラーになってたのを修正
  1099. //  v.0.22 2015/04/29
  1100. //          2chの過去ログURL形式(/[板識別子]/kako/[スレID(3or4)桁]/([スレID5桁]/)[スレID].html 又は.dat)をサポート
  1101. //          ただし、サーバー移転等でURLのサーバー名と過去ログ倉庫が不一致の場合は不可
  1102. //          kako形式の場合には/nオプションや/aオプションは無効となる
  1103. //          /z 時のdb,idxのstate値は=10に設定される
  1104. //          それと関連して、通常URLでメッセージ「error 4002」が返ってきた場合は、URLをkako形式に変えて再トライする
  1105. //          また、「error 3001」(datが無い)が返ってきた場合はkako形式のURLに変えて実行すると取得できるかもしれない
  1106. //  v.0.23 2015/04/29
  1107. //          2chでURLにレス番指定(/l50,/-n10)がくっ付いている場合、正常に処理できなくなっていたのを修正
  1108. //  v.0.24 2015/04/29
  1109. //          2chで/a指定時、既存のdatファイルが存在していると正常に処理できなくなっていたのを修正
  1110. //  v.0.25 2015/04/29
  1111. //          したらばで、カテゴリ名に / が含まれている場合に正常に処理できなくなってたのを修正
  1112. //  v.0.26 2015/05/04
  1113. //          /b オプションが正常に処理できなくなっていたのを修正
  1114. //          (また、Logsフォルダを指定してない場合 /b を付けて無くてもバックアップされてしまっていた)
  1115. //          Jane2ch.exeに送るキーコードを変更(/wの時 CTL+w でスレを閉じる, /z の時 ALT+F4 で終了する)
  1116. //  v.0.27 2015/05/04
  1117. //          ファイル読み書きエラー時、付随情報としてカレントパス、ファイル名を正常に出力するするように修正
  1118. //          /redraw (/redraw:999) オプション追加 (スレを開いた後キーコード('T','G','0')を送る)
  1119. //          Xenoでは/zオプション時sqlite3.exeは弾くようにした(dbがutf16の場合、日本語が化けるため)、またタイトルも書き換える
  1120. //  v.0.28 2015/05/04
  1121. //          /redraw 'ALT'を送るのが抜けていたのを修正
  1122. //  v.0.29 2015/05/07
  1123. //          brdファイル検索時の正規表現文字列の生成(ピリオドが曖昧にマッチしていた)を修正
  1124. //          (具体的には、xxx.2ch.netとnext2ch.netの両方が存在していると、後ろのnext2chの方にdatファイルが作成されていた)
  1125. //  v.0.30 2015/05/17
  1126. //          オプション /log[:][path] を追加 path名の指定には環境変数が使えます(path省略時 %temp%\gethtmldat.log)
  1127. //          /w, /redraw のデフォルトのwaitを1200msに変更
  1128. //          2ch  - .dat.gz/.dat read追加,URL変換は「error 4002」に限定しない
  1129. //          jbbs - board_info.cgi->/api/setting.cgiに変更
  1130. //  v.0.31 2015/05/17
  1131. //          一部のエラーメッセージがきちんと表示されないのを修正
  1132. //          jbbs - 現役のスレ(rawmode.cgi)でスレタイトルとIDが異常になるのを修正、dat落ち扱いしないように修正
  1133. //          ファイルアクセスを、ADODB StreamからFileSystemObjectに変更(read速度が大幅に改善)
  1134. //  v.0.32 2015/05/17
  1135. //          2ch - URL変換再試行時もエラーの場合、最初のエラー内容を表示するように修正
  1136. //  v.0.33 2015/05/17
  1137. //          2ch - URL変換再試行は「error」に限定(人大杉/LoadAverageは除外)
  1138. //--------------------------------------------------------------------
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement