「スクリプト」の編集履歴(バックアップ)一覧に戻る

スクリプト - (2008/01/15 (火) 03:10:27) の編集履歴(バックアップ)


スクリプトによる機能拡張


ランキングを表示する

ソースファイルをメモ帳などに貼り付け、拡張子(.hta)で保存し、実行してください。
動画情報ウィンドウのページがいっぱいになったので、ランキング表示をこちらにもって来ました。pathOfDownloadとpathOfNicoPlayerをそれぞれの環境に合わせて編集してください(セパレータはダブルスラッシュ//です)。青枠がダウンロード済み(再生)、赤枠がまだ(ダウンロード)です。今回は音楽・マイリスト・本日ですが、変更するにはmylist/daily/musicの部分を編集してください。
<hta:application maximizebutton="no" selection="yes"
                 navigable="no" scroll="no" singleinstance="yes"/>
<html>
 <head>
  <meta http-equiv="MSThemeCompatible" content="yes">
  <style>
   #dummy { position:absolute; visibility:hidden; }
   td { text-align:center; }
   img { width:80; height:60; margin:3px; cursor:pointer }
   ul { list-style-type:none; margin:1px; }
   li { width:100%; border:3px double; margin:3px; font-size:12px }
  </style>
  <script type="text/javascript" src="prototype.js"></script>
  <script type="text/javascript">
   var pathOfDownload = "ダウンロードパス";
   var pathOfNicoPlayer = "NicoPlayerパス";
   
   var localFlvFiles;
   
   $_ = function( target, key ) {
    return $A( target.getElementsByTagName( key ) );
   }
   $_A = function( target, key ) {
    return target.getAttribute( key );
   }
   
   showRanking = function( link ) {
    resizeTo( 1080, 880 );
    searchFlvFiles();
    var url = "http://www.nicovideo.jp/ranking/mylist/daily/music";
    new Ajax.Request( url, { method : "get", onComplete : parseRankingPage } );
   }
   
   parseRankingPage = function( response ) {
    var dummy = $( "dummy" );
    dummy.innerHTML = response.responseText;
    
    var items = $A();
    var table = $_( dummy, "table" )[7];
    var trs = $_( table, "tr" ).findAll( function( tr, index ) {
     return ( index % 2 == 0 );
    } );
    trs.each( function( tr ) {
     var movieName = $_( tr, "a" )[1].href.match( /sm\d+/ )[0];
     var flag = localFlvFiles[movieName];
     var target = $_( tr, "p" )[1].innerHTML.match( /[\d,]+/ )[0];
     items.push( { date    : $_( tr, "strong" )[1].innerHTML
                 , time    : $_( tr, "strong" )[0].innerHTML
                 , play    : $_( tr, "strong" )[2].innerHTML
                 , comment : $_( tr, "strong" )[3].innerHTML
                 , mylist  : "-"
                 , title   : $_( tr, "a" )[1].innerHTML
                 , name    : movieName
                 , color   : flag ? "blue" : "red"
                 , action  : flag ? "play" : "download"
                 , src     : $_( tr, "img" )[1].src
                 , target  : target
                 } );
    } );
    
    dummy.innerHTML = "";
    showList( items );
   }
   
   showList = function( items ) {
    var template = new Template( "<img width='100' src='#{src}' />" );
    var tr = $( "target" ), td, ul;
    items.each( function( item, index ) {
     if( !( index % 10 ) ) {
      if( td && ul ) {
       td.appendChild( ul );
       tr.appendChild( td );
      }
      td = document.createElement( "td" );
      ul = document.createElement( "ul" );
     }
     var li = document.createElement( "li" );
     li.style.cssText = "border-color:" + item.color;
     var img = document.createElement( "img" );
     img.setAttribute( "src", item.src );
     img.setAttribute( "onclick" , new Function( item.action + "( \'" + item.name + "\' );" ) );
     img.setAttribute( "title", 
      item.title + "\n再生:" + item.play + " コメント:" + item.comment + " ターゲット:" + item.target
     )
     li.appendChild( img )
     ul.appendChild( li );
    } );
    td.appendChild( ul );
    tr.appendChild( td );
   }
   
   searchFlvFiles = function() {
    if( !localFlvFiles ) {
     localFlvFiles = $H();
     var fs = new ActiveXObject( "Scripting.FileSystemObject" );
     var files = new Enumerator( fs.GetFolder( pathOfDownload ).Files );
     while( !files.atEnd() ) {
      if( files.item().Name.match( /(sm\d+).*\.flv/ ) ) {
       localFlvFiles[RegExp.$1] = files.item();
      }
      files.moveNext();
     }
    }
   }
   
   function execBuildupCommand( argument )
   {
    var shellObject = new ActiveXObject( "WScript.Shell" );
    shellObject.Run( "\"" + pathOfNicoPlayer + "\\NicoPlayer.exe\" " + argument, 0, true );
    shellObject = null;
   }
   
   var play = function( movieName ) {
    execBuildupCommand( "\"" + localFlvFiles[movieName].Path + "\"" );
   }
   
   var download = function( movieName ) {
    execBuildupCommand( "http://www.nicovideo.jp/watch/" + movieName );
   }
  </script>
 </head>
 <body onload="showRanking();">
  <table border="0">
   <tr>
    <th> 1-10</th><th>11-20</th><th>21-30</th><th>31-40</th><th>41-50</th>
    <th>51-60</th><th>61-70</th><th>71-80</th><th>81-90</th><th>91-100</th>
   </tr>
   <tr id="target" />
  </table>
  <div id="dummy"></div>
  <div id="debug"></div>
 </body>
</html>

ローカルファイルを検索し表示

最上部のテキストボックスにキーワードを入力してTabキーを押すと、ローカルファイルを検索しマッチするファイルをリストアップします。お好きなファイルをクリックして再生してください。onchangeではなくonkeyupを使うとインクリメンタル検索になるのですが、このロジックだと重すぎて実用的ではないのでやめました。
<hta:application maximizebutton="no" selection="yes"
                 navigable="no" scroll="yes" singleinstance="yes"/>
<html>
 <head>
  <meta http-equiv="MSThemeCompatible" content="yes">
  <style>
   ul { list-style-type:none; margin:1px; }
   li { cursor:pointer; width:100%; border:3px double; margin:3px; font-size:12px }
  </style>
  <script type="text/javascript" src="prototype.js"></script>
  <script type="text/javascript">
   var pathOfDownload = "ダウンロードパス"; // ex) D:\\Download
   var pathOfNicoPlayer = "NicoPlayerインストールパス";
   
   var localFlvFiles;
   
   $_ = function( target, key ) {
    return $A( target.getElementsByTagName( key ) );
   }
   $_A = function( target, key ) {
    return target.getAttribute( key );
   }
   
   onLoad = function( link ) {
    resizeTo( 500, 800 );
    showList();
   }
   
   showList = function() {
    searchFlvFiles();
    
    // 検索
    var keyword = $F( "keyword" );
    if( keyword ) {
     localFlvFiles = localFlvFiles.findAll( function( file ) {
      return RegExp( keyword, "i" ).test( file.Name );
     } );
    }
    
    // リストクリア
    var ul = $( "target" );
    $A( ul.childNodes ).each( function( child ) {
     ul.removeChild( child );
    } );
    
    // リスト追加
    localFlvFiles.each( function( file, index ) {
     var li = document.createElement( "li" );
     li.setAttribute( "onclick", new Function( "play( \'" + index + "\' );" ) );
     file.Name.match( /(.*)\.flv$/ );
     var text = document.createTextNode( RegExp.$1 );
     li.appendChild( text );
     ul.appendChild( li );
    } );
   }
   
   searchFlvFiles = function() {
    if( !localFlvFiles ) {
     localFlvFiles = $A();
    } else {
     localFlvFiles.clear();
    }
    
    var fs = new ActiveXObject( "Scripting.FileSystemObject" );
    var files = new Enumerator( fs.GetFolder( pathOfDownload ).Files );
    while( !files.atEnd() ) {
     if( files.item().Name.match( /(sm\d+).*\.flv$/ ) ) {
      localFlvFiles.push( files.item() );
     }
     files.moveNext();
    }
   }
   
   execBuildupCommand = function( argument )
   {
    var shell = new ActiveXObject( "WScript.Shell" );
    shell.Run( "\"" + pathOfNicoPlayer + "\\NicoPlayer.exe\" " + argument, 0, true );
    shell = null;
   }
   
   play = function( index ) {
    execBuildupCommand( "\"" + localFlvFiles[index].Path + "\"" );
   }
  </script>
 </head>
 <body onload="onLoad();">
  <input type="text" id="keyword" onchange="showList();" />
  <ul id="target" />
 </body>
</html>


マイページに登録されているうち、ダウンロード済みアイテムのプレイリストを作成し開く

ソースファイルをメモ帳などに貼り付け、拡張子(.js)で保存してください。
pathOfNicoPlayerとpathOfDownloadをそれぞれの環境にあったパスに変更してください。
使う時はクリップボードにマイページのアドレス(http://~/0000000/000000:省略不可)を
コピーしてダブルクリックしてください。
またNicoPlayerのプレイリストウィンドウが表示されていれば、自動的に開きます。
// 環境設定
var pathOfNicoPlayer = "NicoPlayerのインストールパス(パスセパレータ \\)";
var pathOfDownload = "動画ファイルのダウンロードパス(同上)";

// クリップボードからマイページのアドレスを取得
var ieObject = new ActiveXObject( "InternetExplorer.Application" );
ieObject.Navigate( "about:blank" );
while ( ieObject.Busy ) {
 WScript.Sleep( 100 );
}
var addressOfMypage = ieObject.Document.parentWindow.clipboardData.getData( "text" );
ieObject.Quit();

// マイページアドレスが取得できなかった場合入力ウィンドウを表示(Excelのインストールが必要)
if( !addressOfMypage.match( /.*\/([0-9]+)\/([0-9]+)/ ) ) {
 var excelObject = WScript.CreateObject( "Excel.Application" );
 if( excelObject != null )
 {
  addressOfMypage  = excelObject.InputBox( "マイページのアドレスを入力してください" );
  excelObject.Quit();
 }
}

// Msxml2(IE6標準)によりマイページのGETリクエスト送出
var httpObject = WScript.CreateObject( "Msxml2.XMLHTTP" );
httpObject.onreadystatechange = function()
{
 if( httpObject.readyState == 4 )
 {
  getRequestPage( httpObject );
 }
}
// open( , , false )は同期指定(さもないと取得前にプログラムが終了する)
httpObject.open( "GET", addressOfMypage, false );
httpObject.send( "" );

function getRequestPage( httpObject )
{
 // マイページのテキストを検索しID(sm[0-9]+)をリストアップ
 var requestPageText = httpObject.responseText;
 var mypageIdList = requestPageText.match( /sm[0-9]+/g );
 if( mypageIdList == null ) {
  return; // IDが見つからず
 }
 
 // ダウンロードフォルダを検索し.flvファイルをIDに基づいてリストアップ
 var filesHash = {};
 var fsoObject = WScript.CreateObject( "Scripting.FileSystemObject" );
 var filesCollection = fsoObject.GetFolder( pathOfDownload ).Files;
 for( var file = new Enumerator( filesCollection ); !file.atEnd(); file.moveNext() ) {
  var fileName = file.item().Name;
  if( fsoObject.GetExtensionName( fileName ) == "flv" ) {
   filesHash[fileName.match( /sm[0-9]+/ )] = file.item().Path;
  }
 }
 
 // マイページのIDとローカルファイルを紐付けプレイリスト形式にする
 var newPlaylistText = "", newDownloadListText = "";
 for( var i = 0; i < mypageIdList.length; i += 2 ) {
  if( filesHash[mypageIdList[i] ] != undefined ) {
   newPlaylistText += filesHash[mypageIdList[i] ] + "\n";
  }
 }
 
 // プレイリストファイル(.m3u)に落とす
 addressOfMypage.match( /.*\/([0-9]+)\/([0-9]+)/ );
 var newPlylistFileName = RegExp.$1 + "_" + RegExp.$2 + ".m3u";
 // OpenTextFile( , 2, true )の2は書出指定(読込1・追記8)、trueは新規作成あり
 var pathOfNewPlaylistFile = pathOfNicoPlayer + "\\" + newPlylistFileName;
 var newPlaylistFile = fsoObject.OpenTextFile( pathOfNewPlaylistFile, 2, true );
 newPlaylistFile.Write( newPlaylistText );
 newPlaylistFile.Close();
 
 // NicoPlayerが.m3uファイルのD&Dに対応すると、以下の全ては次の1行になります
 // shellObject.Run( "\"" + pathOfNicoPlayer + "\\NicoPlayer.exe\" \"" + pathOfNewPlaylistFile + "\"" );
 
 // プレイリストファイルパスをクリップボードへコピー
 var ieObject = new ActiveXObject( "InternetExplorer.Application" );
 ieObject.Navigate( "about:blank" );
 while ( ieObject.Busy ) {
  WScript.Sleep( 100 );
 }
 ieObject.Document.parentWindow.clipboardData.setData( "text", pathOfNewPlaylistFile );
 ieObject.Quit();
 
 // NicoPlayerのプレイリストウィンドウに登録する
 var shellObject = WScript.CreateObject( "WScript.Shell" );
 shellObject.AppActivate( "NicoPlayer - プレイリスト" );
 WScript.Sleep( 100 );
 shellObject.SendKeys( "^O" );
 WScript.Sleep( 100 );
 shellObject.SendKeys( "^V" );
 WScript.Sleep( 100 );
 shellObject.SendKeys( "%O" );
}

プレイリストウィンドウにプレイリストファイルをドラッグ&ドロップする(Cランタイム使用)

使い勝手向上のためぜひともD&Dを実装したかったが、スクリプトのみでは実装できなかった。
WindowsAPIをVBAでラップすれば可能だが、あまりに煩雑なので断念した。

[マイページに登録されているうち、ダウンロード済みアイテムのプレイリストを作成し開く]の
\// NicoPlayerが.m3uファイルのD&Dに対応すると、以下の全ては次の1行になります
以下を次のように置き換える。
var shellObject = new ActiveXObject( "WScript.Shell" );
shellObject.Run( "\"ランタイム名.exe\" \"CWndPlayList\" \"NicoPlayer - プレイリスト\" \"" + pathOfNewPlaylistFile + "\"", 0 );
shellObject = null;
ランタイム(正確には違うが)のコードは以下の通り。
開発環境はMicrosoft公式を参考にしてください。
#define STRICT
#include <windows.h>
#include <cstring>

// DnD操作におけるOS領域のメモリ構造定義
typedef struct drop_files{
 DWORD pFiles;
 POINT pt;
 bool fNC;
 bool fWide;
} DropFiles;

int main( int argc, char *argv[] )
{
 // パラメータが3個([0]は実行ファイルのパス)未満なら終了
 if( argc < 4 ) {
  return 0;
 }
 
 // 指定窓が見つからなければ終了
 // ([1]:クラス名・[2]タイトル、空文字列も検索条件、無効にするにはNULL)
 HWND hWndTarget = FindWindowExA( NULL, NULL, argv[1], argv[2] );
 if( !hWndTarget ) {
  return 0;
 }
 
 // D&D操作のための情報を作成
 DropFiles df = { sizeof( DropFiles ), { 0, 0 }, false, false };
 char *file = argv[3];
 
 // OS領域のメモリリソースを確保し情報を転送
 HGLOBAL hGlobalMemory = GlobalAlloc( GHND, sizeof( DropFiles ) + strlen( file ) + 1 );
 void *p = GlobalLock( hGlobalMemory );
 memcpy( p, ( void * )&df, sizeof( DropFiles ) );
 memcpy( ( char * )p + sizeof( DropFiles ), ( void * )file, strlen( file ) + 1 );
 GlobalUnlock( hGlobalMemory );
 
 // 指定窓に通知
 PostMessageA( hWndTarget, WM_DROPFILES, ( WPARAM )hGlobalMemory, 0 );
 
 // OS領域のメモリリソースを開放
 GlobalFree( hGlobalMemory );
 
 return 0;
}

コメント

  • スクリプト実行時の制約を軽減(マウス・キーボードを触ると失敗しやすい等)したが、敷居が大幅に高くなってしまった。やはり本家に特定拡張子(.m3u / .lst等)のD&D対応をお願いしたいところ。 - 名無しさん 2007-11-24 17:58:53
  • [ローカルファイルを検索し表示]を追加。こちらはサイズ制限が先の話なので調子に乗ってます(^-^。膨張したライブラリの任意再生にどうぞ。 - 名無しさん 2008-01-15 02:54:44
  • [検索を表示する]を追加。パーサをシンプルにしようとしたら余計にカオスに…。 - 名無しさん 2008-01-19 16:33:52
  • [検索・ランキング・マイページをTubePlayerっぽく一覧表示する]でNicoPlayer以外で開くにはactionの中を書き換えるといいです。ブラウザで開くならwindow.open("~watch/" + movieName,"","");、HTAからSleipnirを開くなら(new ActiveXObject("Sleipnir.API")).NewWindow("~watch/"+movieName,true);でいけます。ちなみに拡張子を.htaではなく.htm[l]で保存してもブラウザでほぼ動きます(ただし警告でまくり、この場合Sleipnirでもwindow.open()で開ける)。 - 名無しさん 2008-01-26 17:29:21
  • [TubePlayerっぽく一覧表示]のフィードバック他を変更しました。テキストボックスでEnterがきくようになり、ソートの不具合が改善されました。 - 名無しさん 2008-01-27 11:01:14
  • [TubePlayerっぽく一覧表示]にランキングの画像表示を統合しました(マイリスト・検索にも対応)。一覧と画像一覧の作りこみの差が手に取るように分かりますがネ(。ω。 - 名無しさん 2008-01-27 19:20:31
  • [TubePlayerっぽく一覧表示]のpathOf~を自動取得するようにしてみました(NicoPlayerと同じフォルダにあることが前提)。任意に設定すればスルーするので、好きな場所におきたい方はそちらで。ini以下にnicoplayer.iniを階層維持のまま展開しているので何かに使えるかも。ini.main.RecentOpen0とかini.playlist.ListPathとかとか。 - 名無しさん 2008-01-30 23:08:16
  • [TubePlayerっぽく一覧表示]にエラー処理(prototype.jsがない/NicoPlayerが見つからない/JavaScriptが無効)を追加。iniを拡張して全域から参照可能にしました。ini.load(ファイルパス)で読み込み、ini.initで初期化。構造上init/loadセクションはあっても読み飛ばします。必要ならプロパティ名と例外判定/^(init|load)$/2箇所をいじってください。 - 名無しさん 2008-01-31 21:06:54
  • [TubePlayerっぽく一覧表示]のリスト管理を整理。ついでに戻ると進むを追加。検索・マイページ・ランキングを開くと進み、ソートは最後の並びが残ります。戻った状態で新たに開くと、それより先の記録はリセットされます。ブラウザの戻る・進むと同じ挙動です。listに格納する情報を追加すれば、履歴一覧とかも楽にいけます。 - 名無しさん 2008-02-02 02:24:59
  • [TubePlayerっぽく一覧表示]のバグバグを修正(検索時ページが更新されない・同じ動画を複数表示するとインデックスが狂う・他)。ダウンロードパスの全検索を起動時のみにし、以後はファイル名きめうちの二段構えにしてファイル数が多い場合体感で分かるほど軽く(ダウンロードが終了すると数秒以内に赤背景>緑背景になりますが、タイトルとファイル名が違う場合(*が含まれる場合など)は再起動するまで認識しません)。フィードバックをページ横断式に変更(同じ動画ならページを切り替えても強調が維持されます)。結果としてデザインとロジックが融合した素敵コードに…行数も500間近…そろそろ分離しないと。 - 名無しさん 2008-02-02 09:13:34
目安箱バナー