usamimi2323

JDownloader2 EventScript - リネーム系アクション集

Oct 23rd, 2024 (edited)
29
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
JavaScript 52.21 KB | Source Code | 0 0
  1. //
  2. // JDownloader2 EventScript - リネーム系アクション集
  3. //
  4. //
  5. //   ダウンロードリストコンテキストメニュー選択時
  6. //   or
  7. //   リンクグラバーリストコンテキストメニュー選択時
  8. //
  9. // 同一スクリプトで両方対応できる
  10. //
  11. // 内容貼り付けでも
  12. // require('C:\\scripts\\jdownloader_es_ver_0.9.js');
  13. // でもいい
  14. //
  15. // 【設定ここから】とある部分を環境に合わせて適当に書き換える
  16. //
  17. // メニューへの登録は、手動でちまちまやるか
  18. // 自動登録用の別スクリプトを作成しているのでそちらを使用
  19. //
  20. // なお、当方は日本語ファイル名での運用が基本なので、
  21. // 作者名やタイトルを操作するものは、日本語ファイル名で
  22. // 命名規則に則っていないと機能しない
  23. // (カテゴリ) [作者名A×作者名B] タイトル.zip
  24. //
  25. // Windows環境しかないので後は自分の環境に合わせて適当に改変すりゃいいです
  26. //
  27. //
  28. //
  29. //
  30. // コードを使用することで生じるいかなる損失、被害、影響もコード製作者は責任を負いません
  31. // 切り貼り改変など全て自由にどうぞ
  32. //
  33.  
  34. /*
  35.  
  36. 実装済み:
  37. ・リネーム各種
  38. ・ファイル検索(EveryThing)
  39. ・WEB検索
  40. ・リンクグラバーに再登録
  41. ・特定ホストだけを有効/無効
  42. ・名前付き新しいパッケージに移動
  43.  (既存の標準メニューにも「新しいパッケージに移動」は存在するが、
  44.  ダイアログが開くのでその無駄を省く)
  45.  
  46. */
  47.  
  48. disablePermissionChecks();
  49.  
  50. const variousPackage='様々なファイル';
  51. const defaultPackageName='任意';
  52.  
  53. const firstBrackets=1;
  54. const firstBrackets_oneword=2;
  55. const firstPhrase=3;
  56. var Config =
  57. {
  58. ///////////////////////////////////////////////////////////////////////////////////////////////
  59. // 【↓設定ここから】
  60.  
  61.     everything_path     : 'C:\\Program Files\\Everything\\Everything.exe',
  62.     browser_path        : 'C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe',
  63.     filer_path          : 'C:\\windows\\explorer.exe',
  64. //  filer_path          : getEnv('WINDIR')+'\\explorer.exe',
  65.  
  66. ///////////////////////////////////////////////////////////////////////////////////////////////
  67.     web_search_table: {
  68.     /////////
  69.     //
  70.     // 書式 'name': [part,'URL'],
  71.     //
  72.     // name  メニュー名
  73.     //
  74.     // part  検索ワードに使うファイル名の部分
  75.     //       (firstPhrase|firstBrackets|firstBrackets_oneword)
  76.     //
  77.     // 【例】(一般小説) [ワシ×オマエ] ドM哲学 ~深淵編~ 第01巻.zip
  78.     //   firstPhrase            タイトル部分   【例】 検索ワード'ドM哲学'
  79.     //   firstBrackets          []内の作者名部分全て 【例】 検索ワード'ワシ OR オマエ'
  80.     //   firstBrackets_oneword  []内の作者名部分先頭 【例】 検索ワード'ワシ'
  81.     //
  82.     // URL   %REP%が検索ワードに置換されたURLがブラウザに渡されます
  83.     //       null => "https://name/?s=%REP%"
  84.     //
  85.     //------------------------------------------------------------------------------------------------------------
  86.  
  87.         'x***.net'          : [firstBrackets_oneword,   null],
  88.         'bs***.com'         : [firstBrackets_oneword,   null],
  89.         '*****.se'          : [firstPhrase,             'https://*****.se/search/%REP%/'],
  90.         '888**.**'          : [firstBrackets_oneword,   'https://888**.**/search.php?q=%REP%'],
  91.         '**********s.com'   : [firstBrackets_oneword,   'https://**********s.com/public/search.php?x=12&y=17&q=%REP%'],
  92.         '678**.***'         : [firstBrackets_oneword,   null],
  93.         '*****77.***'       : [firstBrackets_oneword,   null],
  94.         'dl-***.***'        : [firstBrackets_oneword,   null],
  95.         'raw*****.cc'       : [firstBrackets_oneword,   null],
  96.         '*****-zone.***'    : [firstBrackets_oneword,   'http://www.*****-zone.***/?submit=Search&s=%REP%'],
  97.         '******core.***'    : [firstBrackets_oneword,   null],
  98.         '******omg.***'     : [firstBrackets_oneword,   null],
  99.         'n******.net'       : [firstBrackets_oneword,   'https://n******.net/search/?q=%REP%'],
  100.  
  101.  
  102.         //--------------------------------------------------------------------------------------------------------
  103.         'google.com (作者)'       : [firstBrackets,       'https://www.google.com/search?q=%REP%&ie=utf-8&oe=utf-8'],
  104.         'google.com (タイトル)' : [firstPhrase,         'https://www.google.com/search?q=%REP%&ie=utf-8&oe=utf-8'],
  105.     /////////
  106.     },
  107. //
  108. // "(○○) >>" でファイル名先頭に文字列(○○)を追加/置換(先頭には(カテゴリ)しか追加しない)
  109. // "<< ○○" でファイル名末尾に文字列○○を追加
  110. // "aaaa.comを無効" でaaaa.comというホストのリンクを無効化
  111. // "bbbb.com以外を無効" でbbbb.comというホストのリンク以外を無効化
  112.  
  113. //
  114. //
  115. ///////////////////////////////////////////////////////////////////////////////////////////////
  116.     use_WSH: true,
  117. //  use_WSH: false,
  118.     open_browser_interval: 2000,    // ミリ秒
  119.     open_browser_max:10,
  120.    
  121.     waittime_for_expand_package:100,    // ミリ秒
  122.     expand_after_newpackage: false,     //  パッケージに移動後にツリー展開したくない場合はfalseにする
  123.  
  124. // 【↑設定ここまで】
  125. ///////////////////////////////////////////////////////////////////////////////////////////////
  126.  
  127. // 外部プログラム起動系検索系
  128.     dispatch_table: {
  129. // 外部プログラム系
  130.         'EveryThingで検索(タイトル)'             : openEveryThingByTitle,
  131.         'EveryThingで検索(作者名)'                    : openEveryThingByAuthorName,
  132.         'ブラウザで開く'                         : openLink,
  133.         'uploadbank.comのみを開く'                 : openLinkOnlyUploadbank,       // ブラウザで開いてReCaptcha通過後にURLを登録するため
  134.         'JDバックアップフォルダを開く'             : openJDCfgFolder,
  135.         '登録元ページを開く'                       : openSourceURL,
  136.        
  137. // リネーム系
  138.         'パッケージ名で名前を揃える'               : renameLinksByPackageName,
  139.         'このリンクの名前でパッケージ内を全て揃える': renamePackageAndLinksByContextLinkName,
  140.  
  141.         '名前を揃える'                                : renameLinkByLinkName,     // 複数のリンクを選択してから右クリックし、右クリック直下のファイル名 (○○) [△△] □□.zip→(○○) [△△] □□を揃える
  142.         '名前を揃える(作者名)'                     : renameLinkByLinkAuthor,   // (○○) [△△] □□.zip→[△△]部を揃える
  143.         '名前を揃える(タイトル)'                  : renameLinkByLinkTitle,    // (○○) [△△] □□ ~××~第01巻.zip→□□部を揃える
  144.         '名前を揃える(カテゴリ+作者名+タイトル)'   : renameLinkByLinkLongTitle,
  145.        
  146.         '先頭括弧を後方送り'                       : renameBracketsMoveToEndAndAddDojinshi,
  147.         '末尾の括弧削除'                         : renameRemoveTrailingBrackets,
  148.         '第○○巻化'                               : renameNumberingFormat,
  149.  
  150.         '[]内のスワップ'                          : renameAuthorSwap, // [○○×△△]→[△△×○○]
  151.         '[]内の末尾切り捨て'                        : renameAuthorChop, // [○○×△△×□□]→[○○×△△]
  152.         '[]内のxを×に変換'                           : renameAuthorXtoBatsu, // [○○x△△]→[○○×△△]
  153.        
  154.         '元の名前に戻す'                         : renameToOriginalNameByComment,
  155.         '連番桁揃え'                               : renameSequentialNumbersWithZeroPadding,   // 数字のみのファイル名のみ
  156. // 移動系
  157.         'この名前を使用して新しいパッケージに移動'  : moveToNewPackageWithFileName,
  158.         '同じ名前のパッケージをまとめる'         : moveSameNamePackagesToPackage,
  159.         'リンクグラバーへ再登録'                 : addLinksToLinkGrabber,
  160.         'リンクを同じ名前のパッケージに移動'       : moveLinkToSameNamePackage,
  161.  
  162.         '優先ホスト以外を無効'                        : disableLinksMyRules,
  163. //      'dashfile.net以外を無効'                   : disableLinksWithoutDashfile,
  164. //      'rosefile.net以外を無効'                   : disableLinksWithoutRosefile,
  165. //      'btafile.com以外を無効'                        : disableLinksWithoutBtafile,
  166. //      'dailyuploads.net以外を無効'               : disableLinksWithoutDailyuploads,
  167. //      'uploadbank.netを無効'                       : disableLinksUploadbank
  168.     },
  169.    
  170.     menu : null,
  171.     name : null,
  172.     selection : null
  173. };
  174.  
  175. ////////////////////////////////////////////////////////////////////////////////////////////////
  176. // init
  177. try
  178. {
  179.     Config.menu = menu;
  180.     Config.name = name;
  181.    
  182.     if (Config.menu == "DOWNLOAD_TABLE_CONTEXT_MENU_BUTTON")
  183.         Config.selection = dlSelection;
  184.     else if (Config.menu == "LINKGRABBER_TABLE_CONTEXT_MENU_BUTTON")
  185.         Config.selection = lgSelection;
  186.     else
  187.     {
  188.         alert(Config.menu);
  189.         throw Error();
  190.     }
  191. }
  192. catch(e)
  193. {
  194.     throw Error(
  195.         'イベントトリガーのタイプが正しく設定されていません\r\n\r\n'+
  196.         '解決方法:イベントスクリプトの設定から本スクリプトのトリガーに\r\n'+
  197.         '     【ダウンロードリストコンテキストメニュー選択時】か、\r\n'+
  198.         '     【リンクグラバーコンテキストメニュー選択時】を選択し、\r\n'+
  199.         '     リストビュー画面の右クリックのコンテキストメニューから実行してください\r\n'
  200.     );
  201. }
  202.  
  203.  
  204. (Config.dispatch_table[Config.name] || defaultDispatcher)();
  205.  
  206.  
  207.  
  208. function defaultDispatcher()
  209. {
  210.     switch(true)
  211.     {
  212.     case Config.name in Config.web_search_table:
  213.         searchOnWEBSite();
  214.         break;
  215.     case /^.+ *>>$/.test(Config.name):
  216.         renameAddMenunameToBegin();
  217.         break;
  218.     case /^<< *.+$/.test(Config.name):
  219.         renameAddMenunameToEnd();
  220.         break;
  221.     case /^[-\da-zA-Z\.]+を無効$/.test(Config.name):
  222.         disableLinksByHost();
  223.         break;
  224.     case /^[-\da-zA-Z\.]+以外を無効$/.test(Config.name):
  225.         disableLinksByHostExclude();
  226.         break;
  227.        
  228. //  case /^[^\.]+\.[^\.]+(\.[^\.]+)?$/.test(name):
  229. //      searchOnWEBSite();
  230. //      break;
  231.     }
  232. }
  233.  
  234.  
  235. ////////////////////////////////////////////////////////////////////////////////////////////////
  236. function isDefaultFolderName(n){return n==variousPackage||n==defaultPackageName||n=='folder'}
  237. function isDownloadTable(){return(Config.menu == "DOWNLOAD_TABLE_CONTEXT_MENU_BUTTON")}
  238. function isLinkGrabberTable(){return(Config.menu == "LINKGRABBER_TABLE_CONTEXT_MENU_BUTTON")}
  239. function getSelection(){return(Config.selection)}
  240. function zeroPadding(s,l){return((s.length<l?'0'.repeat(l-s.length):'')+s)}
  241.  
  242. function getDefaultDownloadFolder()
  243. {
  244.     return callAPI("config", "get", "org.jdownloader.settings.GeneralSettings", null, "DefaultDownloadFolder");
  245. }
  246.  
  247. function stripDoubleQuotes(s)
  248. {
  249.     return s.replace(/^[\s\xA0]*"?|"?[\s\xA0]*$/g, '');
  250. }
  251. function setDoubleQuotes(s)
  252. {
  253.     return '"'+ s.trim() +'"';
  254. }
  255. function T(str)
  256. {
  257.     return str||'';
  258. }
  259.  
  260. // アップローダーのURLでダウンロードに不要な部分を削除
  261. function trimUploaderUrl(url)
  262. {
  263.     return url.replace(/^(https:\/\/(?:fikper\.com|mexa\.sh|katfile\.com|ddownload\.com|hexupload\.net|filerice\.com|www\.uploadbank\.com|rapidgator\.net\/file)\/[^\/]+)\/[^\/]+$/i,'$1');
  264. }
  265.  
  266. /////////////////////////////////////////////////////////////////////////////////////////////////
  267. //
  268. // ファイル名などにする文字列の正規化
  269. //
  270. function normalizeTitle(s)
  271. {
  272.     var NT1 = {
  273. //基本1文字からの変換
  274. "\!":"!","\"":"”","\$":"$","\%":"%","\&":"&","'":"’","~":" ̄","|":"|",
  275. "*":"*",":":":","<":"<",">":">","?":"?","/":"/","\\":"¥","`":"‘",",":","
  276. //特殊濁点半濁点→日本語濁点半濁点(分離)
  277. //"\u3099":"\u309B","\u309A":"\u309C"
  278.     };
  279.     var NT2 = {
  280. //記号
  281. " ":" ","〜":"~","&times;":"+","&amp;":"&","♡":"","♥":"","―":"-","─":"-","━":"-",
  282.  
  283. //半角カナ→全角カナ
  284. 'ガ': 'ガ', 'ギ': 'ギ', 'グ': 'グ', 'ゲ': 'ゲ', 'ゴ': 'ゴ',
  285. 'ザ': 'ザ', 'ジ': 'ジ', 'ズ': 'ズ', 'ゼ': 'ゼ', 'ゾ': 'ゾ',
  286. 'ダ': 'ダ', 'ヂ': 'ヂ', 'ヅ': 'ヅ', 'デ': 'デ', 'ド': 'ド',
  287. 'バ': 'バ', 'ビ': 'ビ', 'ブ': 'ブ', 'ベ': 'ベ', 'ボ': 'ボ',
  288. 'パ': 'パ', 'ピ': 'ピ', 'プ': 'プ', 'ペ': 'ペ', 'ポ': 'ポ',
  289. 'ヴ': 'ヴ', 'ヷ': 'ヷ', 'ヺ': 'ヺ',
  290. 'ア': 'ア', 'イ': 'イ', 'ウ': 'ウ', 'エ': 'エ', 'オ': 'オ',
  291. 'カ': 'カ', 'キ': 'キ', 'ク': 'ク', 'ケ': 'ケ', 'コ': 'コ',
  292. 'サ': 'サ', 'シ': 'シ', 'ス': 'ス', 'セ': 'セ', 'ソ': 'ソ',
  293. 'タ': 'タ', 'チ': 'チ', 'ツ': 'ツ', 'テ': 'テ', 'ト': 'ト',
  294. 'ナ': 'ナ', 'ニ': 'ニ', 'ヌ': 'ヌ', 'ネ': 'ネ', 'ノ': 'ノ',
  295. 'ハ': 'ハ', 'ヒ': 'ヒ', 'フ': 'フ', 'ヘ': 'ヘ', 'ホ': 'ホ',
  296. 'マ': 'マ', 'ミ': 'ミ', 'ム': 'ム', 'メ': 'メ', 'モ': 'モ',
  297. 'ヤ': 'ヤ', 'ユ': 'ユ', 'ヨ': 'ヨ',
  298. 'ラ': 'ラ', 'リ': 'リ', 'ル': 'ル', 'レ': 'レ', 'ロ': 'ロ',
  299. 'ワ': 'ワ', 'ヲ': 'ヲ', 'ン': 'ン',
  300. 'ァ': 'ァ', 'ィ': 'ィ', 'ゥ': 'ゥ', 'ェ': 'ェ', 'ォ': 'ォ',
  301. 'ッ': 'ッ', 'ャ': 'ャ', 'ュ': 'ュ', 'ョ': 'ョ',
  302. '。': '。', '、': '、', 'ー': 'ー', '「': '「', '」': '」', '・': '・',
  303. //よくある簡体字、繁体字→日本語常用漢字
  304. '卷':'巻','學':'学','黑':'黒','關':'関','繪':'絵','會':'会','亞':'亜','髙':'高','說':'説'
  305.  
  306.     };
  307. //濁点半濁点結合
  308.     var NT3={
  309. 'ウ゛':'ヴ','ワ゛':'ヷ','ヲ゛':'ヺ',
  310. 'カ゛':'ガ','キ゛':'ギ','ク゛':'グ','ケ゛':'ゲ','コ゛':'ゴ',
  311. 'サ゛':'ザ','シ゛':'ジ','ス゛':'ズ','セ゛':'ゼ','ソ゛':'ゾ',
  312. 'タ゛':'ダ','チ゛':'ヂ','ツ゛':'ヅ','テ゛':'デ','ト゛':'ド',
  313. 'ハ゛':'バ','ヒ゛':'ビ','フ゛':'ブ','ヘ゛':'ベ','ホ゛':'ボ',
  314. 'ハ゜':'パ','ヒ゜':'ピ','フ゜':'プ','ヘ゜':'ペ','ホ゜':'ポ',
  315. 'か゛':'が','き゛':'ぎ','く゛':'ぐ','け゛':'げ','こ゛':'ご',
  316. 'さ゛':'ざ','し゛':'じ','す゛':'ず','せ゛':'ぜ','そ゛':'ぞ',
  317. 'た゛':'だ','ち゛':'ぢ','つ゛':'づ','て゛':'で','と゛':'ど',
  318. 'は゛':'ば','ひ゛':'び','ふ゛':'ぶ','へ゛':'べ','ほ゛':'ぼ',
  319. 'は゜':'ぱ','ひ゜':'ぴ','ふ゜':'ぷ','へ゜':'ぺ','ほ゜':'ぽ',
  320.     };
  321.     if (s==null||s=="") return s;
  322. //  var pat1=new RegExp('(?:['+Object.keys(NT1).map(c=>'\\'+c).join('')+']', 'g');
  323. //  alert('(?:['+Object.keys(NT1).join('')+']');
  324.  
  325.  
  326.  
  327.     var pat1=new RegExp('['+Object.keys(NT1).join('')+']', 'g');
  328.     var pat2=new RegExp('(?:' + Object.keys(NT2).join('|') + ')', 'g');
  329. //  var pat3=new RegExp('(['+Object.keys(NT3).map(function(s){return s[0]}).join('')+'])([\u3099\u309B\u309A\u309C])', 'g');
  330.     var pat3=new RegExp('([ウワヲカキクケコサシスセソタチツテトハヒフヘホうかきくけこさしすせそたちつてとはひふへほ])([\u3099\u309B\u309A\u309C])', 'g');
  331.     return( s
  332.             .replace(/[A-Za-z0-9]/g, function(s){return String.fromCharCode(s.charCodeAt(0)-0xFEE0);})
  333.             .replace(pat1,function(m){return(m in NT1?NT1[m]:m)})
  334.             .replace(pat2,function(m){return(m in NT2?NT2[m]:m)})
  335.             .replace(pat3,function(m,s1,s2){var x=s1+{'\u3099':'\u309B','\u309B':'\u309B','\u309A':'\u309C','\u309C':'\u309C'}[s2];return(x in NT3?NT3[x]:x)})
  336.             .replace(/([\]\)])([^\s\.])/g, '$1 $2')
  337.             .replace(/([^ ])([\[\(])/g, '$1 $2')
  338.             .replace(/ {2,}/g," ")
  339.         );
  340. }
  341.  
  342. //
  343. // WSHを利用し確認メッセージボックスを表示して結果を得る
  344. //
  345. function ConfirmBox(message, title)
  346. {
  347.     var ret = "";
  348.     var created = false;
  349.     var rand_str = Math.random().toString(36).slice(-8);
  350.    
  351.     // TEMPフォルダにJSファイルを作成し、cscript.exeで実行
  352.     var tempdir = getEnv("TEMP");
  353.     var tempfile = tempdir+"\\"+"JD_confirm_"+rand_str+".js";
  354.     var scriptdata =
  355.         'var a=WScript.Arguments;if(0<a.Count()){var t="",m=a.Item(0);'
  356.         +'1<a.Count()&&(t=a.Item(1));var s=new ActiveXObject("WScript.Shell");'
  357.         +'1==s.Popup(m,-1,t,33)&&WScript.StdOut.Write("OK");s=null};';
  358.     var f = getPath(tempfile);
  359.     try
  360.     {
  361.         if (f.exists())
  362.         {
  363.             f.deleteFile(tempfile,false);
  364.         }
  365.         writeFile(tempfile, scriptdata, false);
  366.         created = true;
  367.         ret = callSync('cscript.exe',"//NOLOGO",tempfile,message||"",title||"");
  368.     }
  369.     catch(e)
  370.     {
  371.     }
  372.     finally
  373.     {
  374.         if (created) deleteFile(tempfile,false);
  375.     }
  376.     return ret=="OK";
  377. }
  378.  
  379. function getExt(f)
  380. {
  381.     var r = f.match(/((\.part\d+|\.mp3|\.zip|\.rar|\.tar)?\.[\da-z]{2,6})$/i);
  382.     return r ? r[1] : '';
  383. }
  384. function getFileSpec(f)
  385. {
  386.     var r = f.match(/^(.+)((\.part\d+|\.mp3|\.zip|\.rar|\.tar)?\.[\da-z]{2,6})$/i);
  387.     return r ? r[1] : f;
  388. }
  389.  
  390. function replaceCategory(filename, str)
  391. {
  392.     if (!str) return filename;
  393.  
  394. //  var regexp_category_and_author = /^ *\((?:一般|同人|成年|18禁|アニメ|BL|官能|少女|ライトノベル|書籍)[^\)]*\)(?: *\[[^\]]+\])? *$/;
  395.     var regexp_category = /^\((?:一般|同人|成年|18禁|アニメ|BL|官能|少女|ライトノベル|書籍)[^\)]*\) */;
  396.    
  397.     // 追加する文字列がカテゴリじゃなければ、先頭に追記して返す
  398.     // 元ファイル名がカテゴリを含んでいなければ、先頭に追記して返す
  399. //  if (!regexp_category_and_author.test(str) || !regexp_category.test(filename))
  400.     if (!regexp_category.test(str) || !regexp_category.test(filename))
  401.         return str.trim() + ' ' + filename;
  402.    
  403.     return filename.replace(regexp_category, str.trim() + ' ');
  404. }
  405.  
  406.  
  407. //
  408. // IN:  sel = lgSelection or dlSelection
  409. // OUT: packages or links or []
  410. //
  411. function getItemsByContextType(sel)
  412. {
  413.     return (sel.isPackageContext() ? sel.packages : (sel.isLinkContext() ? sel.links : []));
  414. }
  415.  
  416. //
  417. // IN:  sel = lgSelection or dlSelection
  418. // OUT: package or link or null
  419. //
  420. function getContextItemByContextType(sel)
  421. {
  422.     return (sel.isPackageContext() ? sel.contextPackage : (sel.isLinkContext() ? sel.contextLink : null));
  423. }
  424.  
  425.  
  426.  
  427. /////////////////////////////////////////////////////////////////////////////////////////////////
  428. //
  429. // リネーム系(1アイテムで完結)
  430. //
  431.  
  432. //
  433. // /*String*/ dest_name = function funcRename(/*String*/ orig_name, /*String*/ hint)
  434. // 各リンク・パッケージをリネームする毎に呼び出される
  435. // 各リンク・パッケージそれぞれの変更前の名前とfuncGetHintで返したヒントが渡されるので、変更後の名前を返す
  436. //
  437. function genericRenamer(func)
  438. {
  439.     getItemsByContextType(getSelection()).forEach(function(l)
  440.     {
  441.         var orig_name = l.name;
  442.         var dest_name = (func)(orig_name);
  443.         if (dest_name && orig_name != dest_name)
  444.             l.name = dest_name;
  445.     });
  446. }
  447.  
  448.  
  449. /////////////////////////////////////////////////////////////////////////////////////////////////
  450. //
  451. // ファイル名の先頭に指定文字列を追加
  452. // ※ (○○) がカテゴリ名っぽかったら、置換モード
  453. //
  454. //  メニュー名 "(一般小説) >>"
  455. //  "[作者名] 作品名.zip" =>  "(一般小説) [作者名] 作品名.zip"
  456. //
  457. function renameAddMenunameToBegin()
  458. {
  459.     genericRenamer(function(orig){
  460.         var res = Config.name.match(/^(.+?) *>>$/);
  461.         if (!res) return '';
  462.         return replaceCategory(orig, res[1]);
  463.     });
  464. }
  465.  
  466.  
  467. /////////////////////////////////////////////////////////////////////////////////////////////////
  468. //
  469. // ファイル名の末尾にメニュー名を追加
  470. // ※ファイル名内にメニュー名があればリネームしない
  471. //
  472. //  メニュー名 "<< 寄せ集め"
  473. //  "[作者名] 作品名.zip" =>  "[作者名] 作品名 寄せ集め.zip"
  474. //
  475. function renameAddMenunameToEnd()
  476. {
  477.     genericRenamer(function(orig){
  478.         var res = Config.name.match(/^<< *(.+?) *$/);
  479.         if (!res) return '';
  480.         if (orig.indexOf(res[1]) != -1) return '';
  481.         return getFileSpec(orig) + ' ' + res[1] + getExt(orig);
  482.     });
  483. }
  484.  
  485. function renameRemoveTrailingBrackets()
  486. {
  487.     genericRenamer(function(orig){
  488.         var regexp_bottom_various_brackets = / *(?:\[.+?\]|\(.+?\)|【.+?)(.*?)$/;
  489.         return orig_name.replace(regexp_bottom_various_brackets, "$1");
  490.     });
  491. }
  492.  
  493. /////////////////////////////////////////////////////////////////////////////////////////////////
  494. //
  495. // 先頭括弧を後方送り
  496. //
  497. //  同人誌用
  498. //  例)"(C100) [作者名] 作品名.zip" =>  "(同人誌) [作者名] 作品名(C100).zip"
  499. //
  500. function renameBracketsMoveToEndAndAddDojinshi()
  501. {
  502.     genericRenamer(function(orig){
  503.         var topbrackets_and_otherpart
  504.             = /^(\([^\)]*\)) *(.+?)((?:\.part\d+|\.mp3|\.zip|\.rar|\.tar)?\.[0-9a-z]{2,6})?$/i;
  505.         return replaceCategory(orig.replace(topbrackets_and_otherpart, "$2 $1$3"), '(同人誌)');
  506.     });
  507. }
  508.  
  509.  
  510. function comicNumbering(str)
  511. {
  512.     return (isNaN(str)||str.length==2)?str:(str.length==1)?('0'+str):str.replace(/^0+(\d\d)$/,'$1');
  513. }
  514. function replaceNums(str)
  515. {
  516.     return str.replace(/\d+/g,function(x){return comicNumbering(x);})
  517. }
  518.  
  519. /////////////////////////////////////////////////////////////////////////////////////////////////
  520. //
  521. // 第○○巻化
  522. //
  523. // v02→第02巻、v01-03→第01-03巻 へのリネーム
  524. //
  525. // 【右クリックされた項目】
  526. //   パッケージをクリックしていればパッケージ名を対象とする
  527. //   リンクをクリックしていればリンク名を対象とする
  528. //
  529. // 【選択されている項目】
  530. //   選択されているパッケージ、リンクの名前をリネーム対象とする
  531. //
  532.  
  533. function renameNumberingFormat()
  534. {
  535.     genericRenamer(function(orig){
  536.         const anno = {w:' 透かし有り',s:' 寄せ集め',b:' 別スキャン',e:' (完)',A:' 単行本'};
  537.         var dest = '';
  538.         var res = [];
  539.        
  540.         // 既に「巻」がある
  541.         if (res = /^(.+?)(第|全)?(\d{1,3}(?:[-+]\d{1,3})*巻.*)$/.exec(orig))
  542.         {
  543.             if (res[2]) return '';
  544.            
  545.             // 「第」抜け
  546.             dest = res[1]+'第'+res[3];
  547.         }   // 「話」
  548.         else if (res = /^(.+?)[ _]ch?[-\.]?(\d{1,}(?:-\d{1,})?)(.*)$/i.exec(orig))
  549.             dest = res[1] +' 第'+ replaceNums(res[2]) +'話'+ res[3];
  550.         else
  551.         {
  552.             // "Lv." 誤認識を予め排除
  553.             const reg_vol_num = /^(.+?[^Ll])(?:(?:v|[vV]ol(?:ume)?|VOL(?:UME)?)[ \.]? *)(\d{1,3}(?:[-+]\d{1,3})*)(e?A|[esbw]+)?\b(.*?)$/;
  554.             const reg_numonly = /^(.+?) (\d{1,3}(?:[-+]\d{1,3})*)(e?A|[esbw]+)?( .+?)?$/;
  555.            
  556.             if ( (res = reg_vol_num.exec(orig)) || (res = reg_numonly.exec(orig)) )
  557. //              ||  (res = /^(.+?) *(?:[vV](?:[oO][lL][ \.]? *)?)?(\d{1,3}(?:[-+]\d{1,3})*)(e?A|[esbw]+)?\b(.*)$/.exec(orig)) )
  558.             {
  559.                 dest = res[1] +' 第'+ replaceNums(res[2]) +'巻';
  560.                 if (res[3] && (res[3] in anno))
  561.                     dest += anno[res[3]];
  562.                 if (res[4])
  563.                     dest += res[4];
  564.                 dest = dest.replace(/  +/g, ' ').trim();
  565.             }
  566.         }
  567.         return dest;
  568.     });
  569. }
  570.  
  571. /////////////////////////////////////////////////////////////////////////////////////////////////
  572. // []内のスワップ
  573. // [○○×△△]→[△△×○○]
  574. function renameAuthorSwap()
  575. {
  576.     genericRenamer(function(orig){return orig.replace(/\[(.+?)×([^×]+?)\]/, '[$2×$1]');});
  577. }
  578.  
  579. // []内の末尾切り捨て
  580. // [○○×△△×□□]→[○○×△△]
  581. function renameAuthorChop()
  582. {
  583.     genericRenamer(function(orig){return orig.replace(/\[(.+?)×(?:[^×]+?)\]/, '[$1]');});
  584. }
  585.  
  586. // []内のxを×に変換
  587. // [○○x△△]→[○○×△△]
  588. function renameAuthorXtoBatsu()
  589. {
  590.     genericRenamer(function(orig){return orig.replace(/\[([^×]+?)x([^×]+?)\]/, '[$1×$2]');});
  591. }
  592.  
  593.  
  594. /////////////////////////////////////////////////////////////////////////////////////////////////
  595. //
  596. // リネーム系(他のアイテムと絡む)
  597. //
  598.  
  599. //
  600. // 汎用関数 genericRenamerWithHint(funcGetHint, funcRename)
  601. //
  602. // /*String*/ hint = function funcGetHint(/*String*/ contextItemName)
  603. // 右クリック直下のアイテムの名前が渡されるので、各リンク・パッケージをリネームする際に渡されるヒントを返す
  604. // (右クリック直下のアイテムが無ければ、選択された一番上のアイテム)
  605. //
  606. // /*String*/ dest_name = function funcRename(/*String*/ orig_name, /*String*/ hint)
  607. // 各リンク・パッケージをリネームする毎に呼び出される(リネーム直前)
  608. // 各リンク・パッケージそれぞれの変更前の名前とfuncGetHintで返したヒントが渡されるので、変更後の名前を返す
  609. //
  610. function genericRenamerWithHint(funcGetHint, funcRename)
  611. {
  612.     var sel = getSelection();
  613.  
  614.     var items=null;
  615.     var contextItemName = '';
  616.     var contextItemUUID = 0;
  617.  
  618. //  * 2024/01/20    希にsel.contextPackageが右クリック直下のパッケージではなく、
  619. //                  最後に選択したパッケージor選択の一番下のパッケージになる場合がある。
  620. //                  JDの再起動で直るが、スクリプトからでは判別不能のため代替措置は無理。
  621.  
  622.     if (sel.isPackageContext())
  623.     {
  624.         items = sel.packages;
  625.         contextItemName = sel.contextPackage.name;
  626.         contextItemUUID = sel.contextPackage.UUID;
  627.     }
  628.     else if (sel.isLinkContext())
  629.     {
  630.         items = sel.links;
  631.         contextItemName = sel.contextLink.name;
  632.         contextItemUUID = sel.contextLink.UUID;
  633.     }
  634. //  if (! items ) return;
  635.     if (! items || items.length <= 1) return;
  636.     if (contextItemName == '') contextItemName = items[0].name;
  637.    
  638.     var hint = funcGetHint ? ((funcGetHint)(contextItemName)) : contextItemName;
  639.     if (!hint) return;
  640.    
  641.     items.forEach(function(l)
  642.     {
  643.         if (l.UUID == contextItemUUID) return;
  644.        
  645.         var orig_name = l.name;
  646.         var dest_name = funcRename ? ((funcRename)(orig_name, hint)) : hint;
  647.         if (dest_name && orig_name != dest_name)
  648.             l.name = dest_name;
  649.     });
  650. }
  651.  
  652.  
  653. function renameToOriginalNameByComment()
  654. {
  655.     getSelection().links.forEach(function (l)
  656.     {
  657.         var r = T(l.getComment()).match(/(?:^|\|)orgfilename=([^\|]*)/);
  658.         if (! r) return;
  659.         l.name = r[1];
  660.     });
  661. }
  662.  
  663. /////////////////////////////////////////////////////////////////////////////////////////////////
  664. //
  665. // 連番桁数揃え
  666. // ※数字のみのファイル名が対象
  667. //
  668. function renameSequentialNumbersWithZeroPadding()
  669. {
  670.     const min_length = 3;// 最小桁数
  671.     const regexp_name = /^0*(\d*?)(\..+)?$/i;
  672.  
  673.     var max_length = 0;         // 最大桁数を取得
  674.     getSelection().links.forEach(function (x){
  675.         var r = getFileSpec(x.name).match(regexp_name);
  676.         if (r && (r[1].length > max_length))
  677.             max_length = r[1].length;
  678.     });
  679.     max_length = Math.max(min_length, max_length);
  680.     genericRenamer(
  681.         function(orig){
  682.             return orig.replace(regexp_name,function(m,m1,m2){return zeroPadding(m1.trim(),max_length)+m2});
  683.         }
  684.     );
  685. }
  686.  
  687.  
  688. /////////////////////////////////////////////////////////////////////////////////////////////////
  689. //
  690. // 名前を揃える
  691. //
  692. // 【クリックされたファイルの名前】で、【選択されているファイルの名前】を揃える
  693. //
  694. // パッケージ名同士を揃える必要はないし、パッケージを跨いで名前を揃える必要もないため
  695. // 同一パッケージ内のリンクのみ対象
  696. // 一つのパッケージ内でのみ有効
  697. //
  698. function renameLinkByLinkName()
  699. {
  700.     var sel = getSelection();
  701.     if (sel.isPackageContext()) return;         // パッケージがクリックされているか
  702.     if (1 != sel.packages.length) return;       // 2つ以上のパッケージが選択されているか
  703.     if (! sel.packages[0].expanded) return;     // パッケージが閉じているか
  704.    
  705.     genericRenamerWithHint(null, null);
  706. }
  707.  
  708.  
  709. /////////////////////////////////////////////////////////////////////////////////////////////////
  710. //
  711. // ファイル名[作者名]を揃える
  712. //
  713. // 【クリックされたファイルの[]内】で、【選択されているファイルの[]内】を揃える
  714. //
  715. //
  716. function renameLinkByLinkAuthor()
  717. {
  718. // ( ()先頭括弧 繰り返し ) ( [] 繰り返し)
  719.     var regexp_name
  720.         = /^((?:\([^\(\)]+\) *)*)((?:\[[^\[\]]*(?:\[[^\[\]]+\][^\[\]]*)*\] *)*)(.+)$/i;
  721.     genericRenamerWithHint(
  722.         function(orig){var r=orig.match(regexp_name);return r?r[2]:null;},
  723.         function(orig, hint){return orig.replace(regexp_name,function(m,m1,m2,m3){return m1.trim()+' '+hint.trim()+' '+m3.trim()});}
  724.     );
  725. }
  726.  
  727. /////////////////////////////////////////////////////////////////////////////////////////////////
  728. //
  729. // ファイル名 タイトルを揃える
  730. //
  731. // 【クリックされたファイルの(○○) [△△] □□の□□部分】で、【選択されているファイルの□□】を揃える
  732. //
  733. //
  734. // 巻数話数があるものだけ
  735. function renameLinkByLinkTitle()
  736. {
  737.     var regexp_name
  738.         = /^((?:\([^\(\)]+\) *)*(?:\[[^\[\]]*(?:\[[^\[\]]+\][^\[\]]*)*\] *)*)(.+?) *((?:v(?:ol)?[-\._]?\d+|No[-\._]\d+|[第全]\d+|ch?[-\._]?\d+|[\(\[]| *透かし[あ有]り | *(?:雑誌)?寄せ集め| *別スキャン| *単行本| 20\d\d[-年]?\d+(?:-\d+)?月?号?| \d+).*)(?:\.part\d+\.rar|\.zip|\.[0-9a-z]{2,6})?$/i;
  739.     genericRenamerWithHint(
  740.         function(orig){var r=orig.match(regexp_name);return r?r[2]:null;},
  741.         function(orig, hint){return orig.replace(regexp_name,function (m,m1,m2,m3){return m1.trim()+' '+hint.trim()+' '+m3.trim();});}
  742.     );
  743. }
  744.  
  745. /////////////////////////////////////////////////////////////////////////////////////////////////
  746. //
  747. // ファイル名 (カテゴリ)[作者名]タイトルまで揃える
  748. //
  749. // 【クリックされたファイルの(○○) [△△] □□の□□部分】で、【選択されているファイルの□□】を揃える
  750. //
  751. //
  752. // 巻数話数があるものだけ
  753. function renameLinkByLinkLongTitle()
  754. {
  755.     var regexp_name
  756.         = /^((?:\([^\(\)]+\) *)*(?:\[[^\[\]]*(?:\[[^\[\]]+\][^\[\]]*)*\] *)*.+?) *((?:v(?:ol)?[-\._]?\d+|No[-\._]\d+|[第全]\d+|ch?[-\._]?\d+|[\(\[]| *透かし[あ有]り | *(?:雑誌)?寄せ集め| *別スキャン| *単行本| 20\d\d[-年]?\d+(?:-\d+)?月?号?| \d+).*)(?:\.part\d+\.rar|\.zip|\.[0-9a-z]{2,6})?$/i;
  757.     genericRenamerWithHint(
  758.         function(orig){var r=orig.match(regexp_name);return r?r[1]:null;},
  759.         function(orig, hint){return orig.replace(regexp_name,function(m,m1,m2){return hint.trim()+' '+m2.trim()});}
  760.     );
  761. }
  762.  
  763. /////////////////////////////////////////////////////////////////////////////////////////////////
  764. //
  765. // パッケージ内リネーム系
  766. //
  767.  
  768. /////////////////////////////////////////////////////////////////////////////////////////////////
  769. //
  770. // このリンクの名前でパッケージ内をリネーム
  771. //
  772. // 【右クリックされた項目】--- (複数パッケージを同時処理するため)
  773. //
  774. // 【選択されている項目】
  775. //     『右クリックされたリンクのファイル名』が取得できない場合、
  776. //     『選択されたリンクのファイル名』で、パッケージ名と
  777. //     そのパッケージ内全リンクの名前を揃える。
  778. //
  779. //  ※ 安全のため、デフォルトパッケージ名に関わる『様々なファイル』『任意』が
  780. //     先頭に含まれた名前のパッケージはリネームしない
  781. //     リネームしたければパッケージ名を先に変更しておく
  782. //
  783. //  ※ 各パッケージ内で「リンクは一つだけ選択」する
  784. //     二つ以上のリンクが選択されたパッケージはリネームしない
  785. //     拡張子は維持
  786. //
  787. function renamePackageAndLinksByContextLinkName()
  788. {
  789.     const defaultExtension = '.rar';
  790.  
  791.     var bad_package_uiid_list = {};
  792.     var items = getSelection().links;
  793. //  if (0 == items.length) return;
  794.    
  795.     // パッケージが重複するリンク+デフォルト名を弾くため
  796.     // 弾くパッケージUUIDをbad_package_uiid_listに登録
  797.     // 同一パッケージのリンクは配列内で隣接する
  798.     var prev_puuid = 0;
  799.     items.forEach(function (l)
  800.     {
  801.         var p = l.package;
  802.         if (isDefaultFolderName(p.name)
  803.             || p.UUID == prev_puuid)
  804.             bad_package_uiid_list[p.UUID] = 1;
  805.         prev_puuid = p.UUID;
  806.     });
  807.    
  808.     items.forEach(function (l)
  809.     {
  810.         var p = l.package;
  811.        
  812.         // パッケージが重複するリンクorデフォルト名なら、次へ
  813.         if (p.UUID in bad_package_uiid_list) return;
  814.        
  815.         var dest = getFileSpec(l.name);
  816.         if (! dest) return;
  817.        
  818.         // パッケージをリネーム
  819.         p.name = dest;
  820.        
  821.         // デフォルト拡張子を設定
  822.         // パッケージ内の先頭の拡張子をデフォルトにする
  823.         // 無ければ.rar
  824.         var default_ext = '';
  825.         if (!p.downloadLinks.some(function(x){
  826.             var e=getExt(x.name);
  827.             return e && (default_ext=e);
  828.         }))
  829.             default_ext = defaultExtension;
  830.  
  831.         // パッケージ内の全リンクをリネーム
  832.         p.downloadLinks.forEach(function(x)
  833.         {
  834.             //リネーム元リンクをスキップ
  835.             if (x.UUID == l.UUID) return;
  836.            
  837.             // リンクをリネーム
  838.             x.name = dest + (getExt(x.name)||default_ext);
  839.         });
  840.     });
  841. }
  842.  
  843. /////////////////////////////////////////////////////////////////////////////////////////////////
  844. //
  845. // パッケージ名で名前を揃える
  846. //
  847. // 【パッケージ名】で【パッケージ内全ファイルの名前】を揃える
  848. //  /^様々なファイル/ なパッケージではリネームしない
  849. //
  850. // 選択対象:リンクが選択された場合、親パッケージが対象になる
  851. //           右クリックは対象とはしない
  852. //
  853. // ※書庫ファイル以外がある場合は警告後に強制終了
  854. //
  855.  
  856.  
  857. function renameLinksByPackageName()
  858. {
  859.     const defaultExtension = '.rar';
  860.     getSelection().packages.forEach(function(p)
  861.     {
  862.         if ((! p.name) || isDefaultFolderName(p.name)) return;
  863.        
  864.         var default_ext = '';
  865.         if (p.downloadLinks.some(function(x){
  866.             var e = getExt(x.name);
  867.            
  868.             // 連番画像ファイルなど、パッケージ名でリネームする事故防止
  869.             if (!/(?:^|\.(?:zip|rar|cbr|cbz|7z|html?|epub))$/i.test(e))
  870.                 return true;
  871.            
  872.             if (e && !default_ext) default_ext = e;
  873.         }))
  874.         {
  875.             alert('リネームの実行を中止しました\r\n\r\n【パッケージ名で名前を揃える】アクションは\r\n書庫ファイルに対してのみ実行可能です');
  876.             return;
  877.         }
  878.         if (!default_ext) default_ext = defaultExtension;
  879.        
  880.         p.downloadLinks.forEach(function(l){l.name = p.name+(getExt(l.name)||default_ext)});
  881.     });
  882. }
  883.  
  884. /*
  885. //old version
  886. function renameLinksByPackageName()
  887. {
  888.     getSelection().packages.forEach(function(p)
  889.     {
  890.         var dest = p.name;
  891.         if ((!dest) || isDefaultFolderName(dest))
  892.             return;
  893.        
  894.         if (p.downloadLinks.some(function(l){return false == /(?:^|\.(?:zip|rar|cbr|cbz|7z|html?))$/i.test(getExt(l.name));}))
  895.         {
  896.             alert('リネームの実行を中止しました\r\n\r\n【パッケージ名で名前を揃える】アクションは\r\n書庫ファイルに対してのみ実行可能です');
  897.             return;
  898.         }
  899.        
  900.         var default_ext = '';
  901.         p.downloadLinks.forEach(function(l)
  902.         {
  903.             // 拡張子
  904.             var ext = getExt(l.name);
  905.             if (ext == '')
  906.                 if (default_ext == '')
  907.                     ext = '.rar';
  908.                 else
  909.                     ext = default_ext;
  910.             if (default_ext == '')
  911.                 default_ext = ext;
  912.            
  913.             l.name = dest + ext;
  914.         });
  915.     });
  916. }
  917. */
  918.  
  919.  
  920. ////////////////////////////////////////////////////////////////////////////////////////////////////////
  921.  
  922.  
  923.  
  924. // ファイル名から作者名またはタイトルを返す
  925. function getKeywordFromFilename(filename, part, delim)
  926. {
  927.     var search_word = '';
  928.     var r = filename.match(/^(?:(?:\([^\(\)]+?\) *)*\[([^\]]+)\] *)?((?:(?:COMIC|\u30B3\u30DF\u30C3\u30AF) *)?([a-z]+(?: [a-z]+?)*?(?:$|\.|(?= v\d+))|(?:[-+ a-z]+)+|[^ -]+))/i);
  929.     if (r)
  930.         if (part == firstPhrase
  931.             || (r[1] && (r[1] == '\u30A2\u30F3\u30BD\u30ED\u30B8\u30FC'
  932.             || r[1] == '\u96D1\u8A8C')))
  933.             search_word = r[2].replace(/(?:[!?!?。、]+)$/,'');//検索ワードの末尾感嘆符などは不要
  934.         else if (r[1])
  935.         {
  936.             if (part == firstBrackets)
  937.                 search_word = r[1].split(/\u00D7|\uFF06|\uFF0F/).join((delim===undefined) ? '|' : delim);
  938.             else if (part == firstBrackets_oneword)
  939.                 search_word = (r[1].split(/\u00D7|\uFF06|\uFF0F/))[0];
  940.         }
  941.     return(search_word.trim());
  942. }
  943.  
  944.  
  945. //
  946. // ブラウザを開く個数が設定上限を超えているかどうか、
  947. // 超えていた場合、
  948. // Config.use_WSHがtrueならば、WSHを使って確認メッセージボックスを出して
  949. // 制限を超えて開くかどうかYES/NOの結果をboolで返す
  950. // Config.use_WSHがfalseならば、alertで警告を出してfalseを返す
  951. //
  952. // return true: YES
  953. //        false: NO
  954. function confirmAboutOpenBrowserCount(url_count)
  955. {
  956.     const max_open = Config.open_browser_max;
  957.     if (url_count <= max_open) return true;
  958.     if (! Config.use_WSH)
  959.         alert(url_count + " 個の検索用URLをブラウザで開こうとしています\r\n現在、一度に開けるのは "+max_open +" 個までです。\r\n設定上限を超えていますので中断します");
  960.     else if (ConfirmBox(url_count + " 個の検索用URLをブラウザで開こうとしています。\r\n\r\n本当に実行しますか?","確認"))
  961.         return true;
  962.     return false;
  963. }
  964.  
  965. ////////////////////////////////////////////////////////////////////////////////////////////////////////
  966. //
  967. // WEBブラウザで検索
  968. //
  969. // 選択されたリンクのファイル名から検索ワードを取得して、重複を取り除いた後、ブラウザで検索
  970. //
  971. //
  972. // ESL連想配列に
  973. // {"メニュー名":["URL(%REP%をキーワードに置換して引数として渡す)", position(firstBrackets|firstPhrase)]}
  974. //   メニュー名は、リストビューのコンテキストメニュー(右クリックメニュー)での名前
  975. //   URLは、"https://www.google.com/?q=%REP%"で、%REP%を検索ワードに置換してブラウザに渡す
  976. //   positionは、ファイル名から取得する検索ワードの位置。
  977. //     例)"(カテゴリ) [作者名] ワイのポエム -サブタイトルや- 第101巻.zip"
  978. //        firstBrackets:検索ワード="作者名"
  979. //        firstPhrase:検索ワード="ワイのポエム"
  980. //
  981. function searchOnWEBSite()
  982. {
  983.     var links = getSelection().links;
  984.    
  985.     var interval_time = Config.open_browser_interval;
  986.     var WST = Config.web_search_table;
  987.     var _name = Config.name;
  988.     if (! _name in WST) return;
  989.    
  990.     var L = [];
  991.     var parttype = WST[_name][0];
  992.     var template_url = (WST[_name][1] || ('https://'+_name+'/?s=%REP%'));
  993.    
  994.     // 選択されたリンク.親が展開されているか?そのリンクから検索ワード:親の名前から検索ワード
  995.     links.forEach(function (l)
  996.     {
  997.         var n = l.package.expanded ? l.name :l.package.name;
  998.         if (n == '' || isDefaultFolderName(n))
  999.             return;
  1000.         var search_word = getKeywordFromFilename(n, parttype, ' ');
  1001.         if (parttype != firstPhrase && search_word == '')
  1002.             search_word = getKeywordFromFilename(n, firstPhrase);
  1003.         if (search_word != '') L.push(search_word);
  1004.     });
  1005.    
  1006.    
  1007.     // 順番を維持して重複削除
  1008.     L = L.filter(function(v,i){return L.indexOf(v)===i});
  1009.    
  1010.     if (! confirmAboutOpenBrowserCount(L.length))
  1011.         return;
  1012.    
  1013.     L.forEach(function (w,i)
  1014.     {
  1015.         if (i) sleep(interval_time);
  1016.         callSync(Config.browser_path, '"'+ template_url.replace("%REP%", w) +'"');
  1017.     });
  1018. }
  1019.  
  1020. //
  1021. // パッケージ内のURLパターンにマッチするリンクを有効/無効にする
  1022. //(マッチしないパッケージでは何もしない)
  1023. //
  1024. function setEnableSelectedPackagesWithUrlPattern(enabled, pattern)
  1025. {
  1026.     getSelection().packages.forEach(function(p)
  1027.     {
  1028.         // デフォルトパッケージ名ならスキップ
  1029.         if (isDefaultFolderName(p.name))
  1030.             return;
  1031.        
  1032.         // パターンにマッチしたURLリンクを持たないパッケージはスキップ
  1033.         if (! p.downloadLinks.some(function(l){return pattern.test(l.contentURL)}) )
  1034.             return;
  1035.        
  1036.         p.downloadLinks.forEach(function(l){l.setEnabled( pattern.test(l.contentURL)?enabled:!enabled )});
  1037.     });
  1038. }
  1039.  
  1040. function disableLinksWithoutDashfile()
  1041. {
  1042.     setEnableSelectedPackagesWithUrlPattern(true, /^https?:\/\/dashfile\.net\/.+/);
  1043. }
  1044.  
  1045. function disableLinksWithoutRosefile()
  1046. {
  1047.     setEnableSelectedPackagesWithUrlPattern(true, /^https?:\/\/rosefile\.net\/.+/);
  1048. }
  1049. function disableLinksWithoutBtafile()
  1050. {
  1051.     setEnableSelectedPackagesWithUrlPattern(true, /^https?:\/\/btafile\.com\/.+/);
  1052. }
  1053.  
  1054. function disableLinksWithoutDailyuploads()
  1055. {
  1056.     setEnableSelectedPackagesWithUrlPattern(true, /^https?:\/\/dailyuploads\.net\/.+/);
  1057. }
  1058.  
  1059. function disableLinksUploadbank()
  1060. {
  1061.     setEnableSelectedPackagesWithUrlPattern(false, /^https?:\/\/www\.uploadbank\.com\/.+/);
  1062. }
  1063.  
  1064.  
  1065. function disableLinksMyRules()
  1066. {
  1067.     getSelection().packages.forEach(function(p)
  1068.     {
  1069.         // デフォルトパッケージ名ならスキップ
  1070.         if (isDefaultFolderName(p.name))
  1071.             return;
  1072.        
  1073.         // パターンにマッチしたURLリンクを持たないパッケージはスキップ
  1074.         var patterns = [
  1075.             /hexload\.com/,
  1076.             /frdl\.to/,
  1077.             /dashfile\.net/,
  1078.             /dailyuploads\.net/     // reCaptchaが必須になった
  1079.         ];
  1080.         patterns.some(function(pattern)
  1081.         {
  1082.             if (! p.downloadLinks.some(function(l){return pattern.test(l.contentURL)}) )
  1083.                 return false;
  1084.            
  1085.             p.downloadLinks.forEach(function(l){l.setEnabled( pattern.test(l.contentURL) )});
  1086.             return true;
  1087.         });
  1088.     });
  1089.  
  1090. }
  1091.  
  1092. function disableLinksByHost()
  1093. {
  1094.     var res = Config.name.match(/^([-\da-zA-Z\.]+)を無効$/);
  1095.     if (!res) return '';
  1096.    
  1097.     setEnableSelectedPackagesWithUrlPattern(false, new RegExp('^https?:\/\/' + res[1] + '\/.+'));
  1098. }
  1099.  
  1100.  
  1101. function disableLinksByHostExclude()
  1102. {
  1103.     var res = Config.name.match(/^([-\da-zA-Z\.]+)以外を無効$/);
  1104.     if (!res) return '';
  1105.    
  1106.     setEnableSelectedPackagesWithUrlPattern(true, new RegExp('^https?:\/\/' + res[1] + '\/.+'));
  1107. }
  1108.  
  1109.  
  1110. /////////////////////////////////////////////////////////////////////////////////////////////////
  1111. //
  1112. // ブラウザで開く
  1113. //
  1114. // 【右クリックされた項目】---
  1115. // 【選択されている項目】リンクのcontentURLをブラウザで開く
  1116. //
  1117. // RegExp url_regexp = (NULL | 正規表現オブジェクト) マッチングするURLのみを開く
  1118. //
  1119. function openLink(url_regexp)
  1120. {
  1121.     var max_open = Config.open_browser_max;
  1122.     var interval_time = Config.open_browser_interval;
  1123.    
  1124.     var items = getSelection().links;
  1125.    
  1126.     items = items.map(function(l){return l.contentURL});
  1127.     if (url_regexp)
  1128.         items = items.filter(function(url){return url_regexp.test(url)});
  1129.     if (! confirmAboutOpenBrowserCount(items.length))
  1130.         return;
  1131.    
  1132.     items.forEach(function (url,i)
  1133.     {
  1134.         if (i) sleep(interval_time);
  1135.         callSync(Config.browser_path, '"'+ url +'"');
  1136.     });
  1137. }
  1138.  
  1139. /////////////////////////////////////////////////////////////////////////////////////////////////
  1140. //
  1141. // uploadbank.comのリンクをブラウザで開く
  1142. //
  1143. // 【右クリックされた項目】---
  1144. // 【選択されている項目】リンクのcontentURLでuploadbank.comのみブラウザで開く
  1145. //
  1146. function openLinkOnlyUploadbank()
  1147. {
  1148.     openLink(/^https:\/\/www\.uploadbank\.com/i);
  1149. }
  1150.  
  1151. function openSourceURL()
  1152. {
  1153.     var max_open = Config.open_browser_max;
  1154.     var interval_time = Config.open_browser_interval;
  1155.     var items = {};
  1156.     getSelection().links.forEach(function(l){var u = l.getOriginURL();if (u) items[u]=1;});
  1157.     var urls = Object.keys(items);
  1158.     if (! confirmAboutOpenBrowserCount(urls.length))
  1159.         return;
  1160.    
  1161.     urls.forEach(function (url,i)
  1162.     {
  1163.         if (i) sleep(interval_time);
  1164.         callSync( Config.browser_path, '"'+ url +'"');
  1165.     });
  1166. }
  1167.  
  1168.  
  1169.  
  1170. /////////////////////////////////////////////////////////////////////////////////////////////////
  1171. //
  1172. // EveryThingで検索(作者名)
  1173. //
  1174. // 【右クリックされた項目】パッケージorリンクの名前から最初の[]内の単語をEveryThingで検索
  1175. // 【選択されている項目】---
  1176. //
  1177. // ※ 複数項目は不要
  1178. //
  1179. function openEveryThingByAuthorName()
  1180. {
  1181.     openEveryThing(firstBrackets)
  1182. }
  1183. /////////////////////////////////////////////////////////////////////////////////////////////////
  1184. //
  1185. // EveryThingで検索(タイトル)
  1186. //
  1187. // 【右クリックされた項目】パッケージorリンクの名前から最初の[]の後ろの単語をEveryThingで検索
  1188. // 【選択されている項目】---
  1189. //
  1190. function openEveryThingByTitle()
  1191. {
  1192.     openEveryThing(firstPhrase)
  1193. }
  1194.  
  1195. function openEveryThing(part)
  1196. {
  1197.     var contextItem = getContextItemByContextType(getSelection());
  1198.     if (!contextItem) return;
  1199.     var search_word = getKeywordFromFilename(getFileSpec(contextItem.name), part||firstBrackets);
  1200.     if (search_word)
  1201.         callSync( Config.everything_path, '-s', '"'+search_word+'"' );
  1202. }
  1203.  
  1204.  
  1205. /////////////////////////////////////////////////////////////////////////////////////////////////
  1206. //
  1207. // 同じ名前のパッケージをまとめる
  1208. //
  1209. //
  1210. // 【右クリックされた項目】---
  1211. //
  1212. // 【選択されている項目】選択されているパッケージで同じ名前のものがあればまとめる
  1213. //
  1214. //
  1215.  
  1216. function moveSameNamePackagesToPackage()
  1217. {
  1218.     // ダウンロード/リンクグラバーで使用API、関数を切り替える
  1219.     var lg_dl = ([
  1220.         {
  1221.             apiname:'linkgrabberv2',
  1222.             getPackageByUUID:(getCrawledPackageByUUID)
  1223.         },
  1224.         {
  1225.             apiname:'downloadsV2',
  1226.             getPackageByUUID:(getDownloadPackageByUUID)
  1227.         }
  1228.     ])[isDownloadTable()?1:0];
  1229.    
  1230.     var duptable = {};
  1231.     var hitnames = {};
  1232.     getSelection().packages.forEach(function(x)
  1233.     {
  1234.         if (x.name in duptable)
  1235.         {
  1236.             duptable[x.name].push(x.UUID);
  1237.             hitnames[x.name] = duptable[x.name];
  1238.         }
  1239.         else
  1240.             duptable[x.name] = new Array(x.UUID);
  1241.     });
  1242.    
  1243.     for (var x in hitnames)
  1244.     {
  1245.         var link_uuids = [];
  1246.         var p_uuids = hitnames[x];
  1247.         for (var i=1; i < p_uuids.length; i++)
  1248.         {
  1249.             var p = (lg_dl.getPackageByUUID)(p_uuids[i]);
  1250.             if (!p) continue;
  1251.            
  1252.             var items = p.downloadLinks;
  1253.             if (items.length==0) continue;
  1254.            
  1255.             link_uuids = link_uuids.concat( items.map(function (l){return l.UUID;}) );
  1256.         }
  1257.        
  1258.         if (link_uuids)
  1259.             callAPI(lg_dl.apiname, 'moveLinks', link_uuids, null, p_uuids[0]);
  1260.     }
  1261. }
  1262.  
  1263. /////////////////////////////////////////////////////////////////////////////////////////////////
  1264. //
  1265. // リンクを同じ名前のパッケージに移動(turbobit)
  1266. //
  1267. function moveLinkToSameNamePackage()
  1268. {
  1269.     var links = getSelection().links;
  1270. //  links.sort(function(a,b){return a.name.localeCompare(b.name, 'ja');});
  1271.  
  1272.     // ダウンロード/リンクグラバーで使用API、関数を切り替える
  1273.     var lg_dl = ([
  1274.         {
  1275.             apiname:'linkgrabberv2',
  1276.             get_all_package: getAllCrawledPackages
  1277.         },
  1278.         {
  1279.             apiname:'downloadsV2',
  1280.             get_all_package: getAllFilePackages
  1281.         }
  1282.     ])[isDownloadTable()?1:0];
  1283.    
  1284.     var all_p = (lg_dl.get_all_package)();
  1285.    
  1286.     links.forEach(function(l)
  1287.     {
  1288.         var fname = getFileSpec(l.name).replace(/[_ ]/g,'');
  1289. //      alert("moveLinkToSameNamePackage()\n"+fname);
  1290.         all_p.some(function(p)
  1291.         {
  1292. //          alert("moveLinkToSameNamePackage()\n"+fname+"\n"+p.name.replace(/[_ ]/g,'').replace(/shit/gi, ''));
  1293.            
  1294.             if (fname == p.name.replace(/[_ ]/g,'').replace(/shit/gi, ''))
  1295.             {
  1296.                 callAPI(lg_dl.apiname, 'moveLinks', [l.UUID], null, p.UUID);
  1297.                 return true;
  1298.             }
  1299. //          return true;
  1300.         });
  1301.     });
  1302. }
  1303.  
  1304.  
  1305. /////////////////////////////////////////////////////////////////////////////////////////////////
  1306. //
  1307. // この名前を使用して新しいパッケージに移動
  1308. //
  1309. //
  1310. // 【右クリックされた項目】
  1311. //   名前/ダウンロードフォルダを新しいパッケージ名に使用
  1312. //   取得できなければ何もしない
  1313. //
  1314. //   ※既存パッケージ名が使用された場合は、既存パッケージへの移動に切替
  1315. //
  1316. // 【選択されている項目】
  1317. //   選択されているリンクを新しいパッケージに移動
  1318. //   パッケージのみが選択されている項目はパッケージ内全リンクを移動
  1319. //
  1320. function moveToNewPackageWithFileName()
  1321. {
  1322.     var sel = getSelection();
  1323.     var expand_after_newpackage = !!Config,expand_after_newpackage;
  1324.     var waittime = Config.waittime_for_expand_package;
  1325.    
  1326.     //-----------------------------------------------------------
  1327.     var newname = '';
  1328.     var dlpath = null;
  1329.     var dest_p = null;
  1330.     var context_package_UUID = -1;          // 新規パッケージの位置用
  1331.     var prev_context_package_UUID = -1;     // 新規パッケージの位置用予備
  1332.    
  1333.     // ダウンロード/リンクグラバーで使用API、関数を切り替える
  1334.     var lg_dl = ([
  1335.         {
  1336.             apiname:'linkgrabberv2',
  1337.             get_all_package: getAllCrawledPackages,
  1338.             get_link_by_UUID: getCrawledLinkByUUID,
  1339.             get_package_by_UUID: getCrawledPackageByUUID
  1340.         },
  1341.         {
  1342.             apiname:'downloadsV2',
  1343.             get_all_package: getAllFilePackages,
  1344.             get_link_by_UUID: getDownloadLinkByUUID,
  1345.             get_package_by_UUID: getDownloadPackageByUUID
  1346.         }
  1347.     ])[isDownloadTable()?1:0];
  1348.    
  1349.     if (sel.isLinkContext())
  1350.     {
  1351.         newname = getFileSpec(sel.contextLink.name);
  1352.         dlpath = sel.contextLink.package.downloadFolder;
  1353.         context_package_UUID = sel.contextLink.package.UUID;
  1354.     }
  1355.     else if (sel.isPackageContext())
  1356.     {
  1357.         dest_p = sel.contextPackage;
  1358.        
  1359.         newname = dest_p.name;
  1360.         dlpath = dest_p.downloadFolder;
  1361.         context_package_UUID = dest_p.UUID;
  1362.     }
  1363.     if (newname == '') return;
  1364.  
  1365.     var all_p = (lg_dl.get_all_package)();
  1366.     var prev = 0;
  1367.     if (all_p.some(function(p)
  1368.     {
  1369.         if (p.UUID == context_package_UUID)
  1370.             return true;
  1371.         prev = p.UUID;
  1372.     }))
  1373.         prev_context_package_UUID = prev;
  1374.    
  1375.     // 既存パッケージ名かどうかチェック、ES5なのでArray.prototype.findが無い
  1376.     if (! dest_p)
  1377.     {
  1378.         all_p.some(function(p)
  1379.         {
  1380.             if (p.name == newname)
  1381.             {
  1382.                 dest_p = p;
  1383.                 return true;
  1384.             }
  1385.         });
  1386.     }
  1387.  
  1388.     var items = sel.links.map(function(l){return l.UUID});
  1389.    
  1390.     if (dest_p)
  1391.     {   // 既存パッケージ
  1392.         callAPI(lg_dl.apiname, 'moveLinks', items, null, dest_p.UUID);
  1393.         if (context_package_UUID == -1)
  1394.         {
  1395.             sleep(10);
  1396.             callAPI(lg_dl.apiname, 'movePackages', [dest_p.UUID], context_package_UUID);
  1397.         }
  1398.        
  1399.         sleep(500);
  1400. //      dest_p.setExpanded(expand_after_newpackage);
  1401.     }
  1402.     else
  1403.     {   // 新規パッケージ
  1404.         callAPI(lg_dl.apiname, 'movetoNewPackage', items, null, newname, dlpath);
  1405.         sleep(waittime);// UIが反映されるのはPCスペック依存なので少し待機
  1406.         var l = (lg_dl.get_link_by_UUID)(items[0]);
  1407.         callAPI(lg_dl.apiname, 'movePackages', [l.package.UUID], (lg_dl.get_package_by_UUID)(context_package_UUID)?context_package_UUID:prev_context_package_UUID);
  1408.         sleep(300);
  1409. //      l.package.setExpanded(expand_after_newpackage);
  1410.     }
  1411. }
  1412.  
  1413. ////////////////////////////////////////////////////////////////////////////
  1414. //
  1415. // リンクグラバーへ再登録
  1416. //
  1417. // 選択されているリンクを全てリンクグラバーに追加
  1418. // URL、ファイル名、パッケージ名、パッケージのダウンロード先フォルダのみ設定
  1419. //
  1420. // 対象:選択されているリンク(パッケージ選択時はパッケージ内全リンク)
  1421. //
  1422. // ※ リンクグラバーの登録は時間が掛かる処理であるため、処理時間が異常に長過ぎた場合、
  1423. //    登録後のファイル名の設定をせずにスクリプトを終了
  1424. //
  1425.  
  1426. function addLinksToLinkGrabber()
  1427. {
  1428.     if (!isDownloadTable()) return;
  1429.  
  1430.     var sellinks = getSelection().links;
  1431.     if (0 == sellinks.length) return;
  1432.  
  1433.     var jobid_list = [];
  1434.     var url2jobid_table = {};
  1435.  
  1436.     sellinks.forEach(function(l)
  1437.     {
  1438.         //
  1439.         // addLinks時にファイル名を設定できないので、JOBID取得後、
  1440.         // queryLinksでリンクを取得してファイル名を設定する
  1441.         //
  1442.         var jobid = callAPI("linkgrabberv2", "addLinks",
  1443.         {
  1444.             links: (l.pluginURL||l.contentURL),
  1445.             packageName: l.package.name,
  1446.             overwritePackagizerRules:true,
  1447.             destinationFolder:l.package.downloadFolder,
  1448.             deepDecrypt:false,
  1449.             assignJobID:true
  1450.         });
  1451.         if (!jobid) return;
  1452.        
  1453.         jobid_list.push(jobid.id);
  1454.         url2jobid_table[(l.pluginURL||l.contentURL)] = jobid.id;
  1455.     });
  1456.    
  1457.     var link_count = sellinks.length;
  1458.     var limit_time = link_count * 2000 + 30000;
  1459.     var check_interval = 400;
  1460.     var start_time = (new Date()).getTime();
  1461.    
  1462.     while (1)
  1463.     {
  1464.         sleep(check_interval);
  1465.        
  1466.         //
  1467.         // addLinksは即完了しない。 queryLinksでjobUUIDsを指定すると
  1468.         // 完了しているJOBによって登録されたCrawledLinkのリストが返ってくる
  1469.         //
  1470.         var c_links = callAPI('linkgrabberv2','queryLinks',
  1471.         {
  1472.             jobUUIDs:jobid_list,
  1473.             availability:true,
  1474.             url:true,
  1475.             status:true,
  1476.             uuid:true
  1477.         });
  1478.        
  1479.         // 追加されたリンクのURLが同じかどうかで判定し、ファイル名を設定
  1480.         c_links.forEach(function(cl)
  1481.         {
  1482.             var cl_url = cl.url;
  1483.             var l = getCrawledLinkByUUID(cl.uuid);
  1484.             sellinks.some(function(sel_l)
  1485.             {
  1486.                 if (cl_url == sel_l.pluginURL
  1487.                     || cl_url == sel_l.contentURL)
  1488.                 {
  1489.                     l.name = sel_l.name;
  1490.                     return true;
  1491.                 }
  1492.             });
  1493.            
  1494.             // 登録完了したリンクのJobIDを、queryLinksに使うJobID Listから削除
  1495.             var jobid = url2jobid_table[cl_url];
  1496.             if (! jobid) return;
  1497.            
  1498.             jobid_list = jobid_list.filter(function(j){return j != jobid});
  1499.         });
  1500.        
  1501.         // 完了判定
  1502.         link_count -= c_links.length;
  1503.         if (link_count <= 0 || 0 == jobid_list.length) break;
  1504.        
  1505.         // タイムオーバー判定
  1506.         if (limit_time < ((new Date()).getTime() - start_time))
  1507.         {
  1508.             alert('リンクグラバーへの再登録で時間オーバーになりました');
  1509.             break;
  1510.         }
  1511.        
  1512.         // 残ったJobID ListのqueryLinksへ戻る
  1513.     }
  1514.    
  1515. //  alert('リンクグラバー再登録完了:'+sellinks.length+'リンク');
  1516. }
  1517.  
  1518.  
  1519.  
  1520. function openJDCfgFolder()
  1521. {
  1522.     callSync( Config.filer_path,  '"'+JD_HOME+'\\cfg"' );
  1523. }
  1524.  
  1525.  
  1526.  
Add Comment
Please, Sign In to add comment