Chromeの拡張機能「Vkontakteから音声をダウンロードする」パート2を書いています

Chromeの拡張機能は引き続き作成し、VKontakteオーディオレコーディングごとに「ダウンロード」リンクを追加します。

前回 、セクション「マイレコーディング」を変更しました。

元々: それは拡張子付きになりました:
オリジナル結果




しかし、その時点では、拡張機能には重大な欠点がありました。ページからページに切り替えると機能しませんでした。

メインページに移動してから[マイオーディオレコード]に移動すると、曲へのリンクが表示されませんでした。

VKontakteは、ページを切り替えるときに、古典的な意味でページを更新するのではなく、プログラムでページレイアウトを変更し、アドレスバーを更新することを思い出してください。 これはブラウザが新しいページに移行する従来の方法ではないため、拡張機能は更新されていません。

それを修正しましょう。



前述のように、拡張機能は、記述ファイル(manifest.json)、埋め込みjsスクリプト(vk_inject.js)、および埋め込みスタイルファイル(vk_styles.css)の3つのファイルで構成されます。



主な拡張ファイルは、manifest.jsonです。 拡張記述子と埋め込みファイルへのリンクが含まれています。

manifest.json
{ "manifest_version": 2, "name": "   ", "description": "       .", "version": "2.0", "content_scripts": [{ "matches": ["*://vk.com/*"], "js": ["vk_inject.js"], "css": ["vk_styles.css"] }] }
      
      







マニフェストの「content_scripts」タグは、どのjsおよびcssファイルをページに埋め込むかを決定します。

私たちの拡張機能は、各VKontakteページ(http://vk.com/*またはhttps://vk.com/*)にvk_inject.jsおよびvk_styles.cssファイルを埋め込みます。



スタイルファイル(vk_styles.css)には、埋め込みリンクのスタイルが含まれています。 リンクにはcssクラスdownloadLinkがあります

クラスが元のページのスタイルと重複しないようにしてください。

リンクの境界線とホバーハイライトを作成しましょう。 最初のバージョンとは異なり、リンクを小さくします

曲用に定義されたスペースにより頻繁に収まるようにします。





もちろん、必要に応じてスタイルを再定義できます。

vk_styles.css
 .downloadLink { float: right; cursor: copy; border: 1px dotted #CED8DB; border-radius: 2px; padding: 0 4px; } .downloadLink:hover { background-color: #d0e6ff; border-color: #9DA5AE; }
      
      







拡張機能の主なアクションはすべて、vk_inject.js埋め込みコードで発生します。

だから私たちは何をします:



オーディオレコーディングのリストの各曲について、「ダウンロード」リンクを実装します。



idが「pad_playlist」、「pad_search_list」、「initial_list」、「search_list」、「choose_audio_rows」の要素をページで検索します。

オーディオ録音のリストが含まれています。 ただし、各要素は最初はページ上に存在する場合があり、

動的に作成/削除します。 したがって、ページのDOMへの要素の追加を監視する必要があります。



埋め込みスクリプトは別の仮想マシンで実行され、ページ上のスクリプトと対話できません。

したがって、元の関数を再定義したり、元のページのjsコードをインターセプトしたりすることはできません。

ただし、これらのスクリプトは両方ともDOMツリーを共有しています。 したがって、MutationObserverを使用してリストアイテムのDOMの更新を追跡します。

vk_inject.js
 (function (){ //     ,      //  observer          var trackObserver = new MutationObserver(listModified); // , ,         var list_ids = ['pad_playlist', 'pad_search_list', 'initial_list', 'search_list', 'choose_audio_rows']; for (var i= 0 ; i < list_ids.length; i++) { var list = document.getElementById(list_ids[i]); if (list) { //   ""   ,        trackObserver listFound(list); } } //     ,      css  list = document.getElementById('results'); if (list && list.classList.contains('audio_results')) { listFound(list); } //  observer         var listObserver = new MutationObserver(elementAdded); //    body,      listObserver.observe(document.body, {childList: true, subtree: true}); //     DOM  function elementAdded(mutations) { for (var i = 0; i < mutations.length; i++) { var added = mutations[i].addedNodes; //        for (var j = 0; j < added.length; j++) { findAudioLists(added[j]); } } } //             function findAudioLists(node) { if (node.id) //     id { for (var i = 0; i < list_ids.length; i++) // ,   id   { if (list_ids[i] == node.id) { listFound(node); return; //        } } if (node.id == 'results') //    '#results.audio_results' -   { if (node.classList.contains('audio_results')) { listFound(node); return; } } } //      var child = node.firstElementChild; while (child) { findAudioLists(child); //       child = child.nextElementSibling; } } //    ,     function listFound(listNode) { if (listNode.children.length) //       { for (var j = 0; j < listNode.children.length; j++) { addDownloadLink(listNode.children[j]); //      "" } } trackObserver.observe(listNode, {childList: true}); //      -> listModified() } // ,      ( )  function listModified(mutations) { for (var i = 0; i < mutations.length; i++) { var mut = mutations[i]; //     for (var j = 0; j < mut.addedNodes.length; j++) { addDownloadLink(mut.addedNodes[j]); } //   - mut.removedNodes  } } //   ""    function addDownloadLink(row) { //  -    ,    ,   if (!row.classList.contains('audio')) { // ,     " " row = row.querySelector('div.audio'); //    'div.audio',      if (!row) { return; } } var titleNode = row.querySelector('div.title_wrap'); //   +  if (!titleNode) //     -  (,   ?) { return; } // ,    ?  ,          if (titleNode.querySelector('a.downloadLink')) { return; //      } var input = row.querySelector('div.play_btn > input'); //  input,    url if (!input) { input = row.querySelector('div.play_btn_wrap + input'); //     if (!input) { return; //    } } var ref = input.getAttribute('value'); //  URL ref = ref.substr(0, ref.indexOf('?')); //    '?',      mp3 var link = document.createElement('a'); link.className = 'downloadLink'; //   'downloadLink'    link.textContent = "^"; link.setAttribute('title', ""); link.setAttribute('download', titleNode.textContent + '.mp3'); //     link.setAttribute('href', ref); link.addEventListener('click', function(event){ //     ,    event.stopPropagation(); }); titleNode.appendChild(link); } })();
      
      







拡張機能をインストールする



これで、3つのファイルの準備ができました。

投稿からコピーするか、アーカイブをダウンロードできます

Chromeで、設定ページに移動し、[ 拡張機能 ]タブを選択します(または、アドレスバーに「chrome:// extensions」と入力します)。

開発者モードをオンにします 。 次に、[ Unpacked Extensionのダウンロード... ]をクリックします。



拡張機能



これら3つのファイルを保存したフォルダーを選択します。 私の場合、これはD:\ Droopy \ work \ habr \ pluginです。

拡張機能がリストに表示されます。 オンにします。







仕組みを確認しましょう。 これを行うには、VKontakteに移動し、トップパネルの[ 音楽]セクションを選択します。







やばい、ダウンロードリンクが登場しました! さらに、同じページでオーディオ録音の検索を開始すると、見つかった曲ごとにダウンロードリンクも追加されます。 拡張機能。



しかし、以前の投稿で述べたように、ダウンロードする曲の名前には1つの困難があります。 「ダウンロード」リンクをクリックすると、ファイル保存ダイアログで「ダウンロード」属性で指定されたファイル名ではなく、サーバー上のファイル名が表示されます。 実際のところ、VKontakteはオーディオレコーディングを別のドメインに保存し、この場合のchromeはリンクで提案されているものの代わりにサーバー上のファイル名を使用します。

クロムバグトラッカー 、この場合、コンテキストメニューで[名前を付けリンクを保存 ]オプションを選択する必要があると言います。 その後、オーディオ録音の通常の名前が提供されます。







拡張機能の準備ができました。 オーディオ録音ごとに、ダウンロードリンクが表示されます。



展開されている(つまり、開発モードである)ため、ブラウザを再起動するたびに、ブラウザを無効にするように提案されます。

原則として、そうすることをお勧めします。また、曲をダウンロードするときに必要に応じてオンにします。 または、Chromeウェブストアにアップロードして継続的に使用できます。




All Articles