Greasy Fork is available in English.

VKDownloadMedia

Скачать фото/аудио/видео-файлы с соц. сети ВКонтакте.

اعتبارا من 09-01-2015. شاهد أحدث إصدار.

// ==UserScript==
// @name        VKDownloadMedia
// @namespace   http://vk-download-music.net/
// @version     3.0
// @date        2015-01-09
// @author      KJ86
// @description Скачать фото/аудио/видео-файлы с соц. сети ВКонтакте.
// @homepage    http://vk-download-music.net/
// @match       *://vk.com/*
// @include     *://vk.com/*
// @noframes
// @run-at      document-end
// @grant       none 
// ==/UserScript==

window.VKDM = {
    audioURLList: [],
    photoURLList: [],
    photoAlbumURLList: [],
    patternAudio: /http.*\.mp3/,
    patternVideo: /url([0-9]{3,4})=(.*?\?extra=.*?)&/g,

    createAudioLinks: function(audio, audioLength, newElement) {
        var i, id, mp3, input;

        for (i = 0; i < audioLength; i++) {
            input = geByTag1('input', audio[i]);

            if (!input) continue;

            mp3 = this.patternAudio.exec(input.value);

            if (!mp3) continue;

            this.audioURLList.push(mp3[0]);
            id = audio[i].id.slice(5);

            if (ge('download' + id)) continue;

            newElement.id = 'download' + id;

            geByClass1('actions', audio[i]).appendChild(newElement.cloneNode(true));
        }
    },

    createVideoLinks: function(flashvars) {
        geByClass1('mv_share_actions').insertBefore(cf('<div class="mv_more fl_l" id="mv_download">Скачать</div><div class="mv_rtl_divider fl_l"></div>'), ge('mv_more'));

        var flashvars = decodeURIComponent(flashvars);
        var m, items = [];

        while ((m = this.patternVideo.exec(flashvars)) !== null) {
            items.push([m[2], m[1]]);
        }

        new InlineDropdown('mv_download', {
            items: items.reverse(),
            withArrow: true,
            keepTitle: true,
            autoShow: true,
            autoHide: 300,
            sublists: {},
            onSelect: function(url) {
                VKDM.hiddenClick(url);
            }
        });
    },

    downloadFoundPhoto: function(switchTarget) {
        var photo = ge('content').querySelectorAll('[onclick*="showPhoto("]');

        if (photo.length === 0) return;

        hide(switchTarget);
        show(switchTarget.nextSibling);

        this.photoURLList = [];

        var k = 0;
        var photosID = [];
        var patternPhotoID = /showPhoto\('([0-9_-]+)'/;

        each(photo, function(i, el) {
            photosID.push(patternPhotoID.exec(el.getAttribute('onclick'))[1]);
        });

        photosID = (function(arr) {
            var obj = {};

            for (var i = 0; i < arr.length; i++) {
                obj[arr[i]] = true;
            }

            return Object.keys(obj);
        }(photosID));

        (function getAllPhotos(error) {
            if (error) {
                showDoneBox('<b style="color:red">Ошибка!</b> Не удалось получить данные. Попробуйте еще раз.');
                hide(switchTarget.nextSibling);
                show(switchTarget);
            } else if (k < photosID.length) {
                VKDM.getJSONP('https://api.vk.com/method/photos.getById?photos=' + photosID.slice(k, (k += 100)).join() + '&extended=0&photo_sizes=0&v=5.27&callback=VKDM.createFoundPhotoURLList', getAllPhotos);
            } else {
                VKDM.createFile('text/plain;charset=utf-8', VKDM.photoURLList.join('\r\n'),  VKDM.photoURLList.length + '_найденных фотографий.txt');
                hide(switchTarget.nextSibling);
                show(switchTarget);
            }
        })();
    },

    downloadPhotoAlbum: function(switchTarget) {
        var patternAlbumInfo = /^\/album(-?[0-9]+)_([0-9]+)$/;
        var albumID = patternAlbumInfo.exec(location.pathname);

        if (!albumID) return;

        switch (albumID[2]) {
            case '0': albumID[2] = 'profile'; break
            case '00': albumID[2] = 'wall'; break
            case '000': albumID[2] = 'saved'; break
        }

        hide(switchTarget);
        show(switchTarget.nextSibling);

        this.photoAlbumURLList = [];

        var offset = 100;
        var getAllPhotosFromAlbum = function(error) {
            if (error) {
                showDoneBox('<b style="color:red">Ошибка!</b> Не удалось получить данные. Попробуйте еще раз.');
                hide(switchTarget.nextSibling);
                show(switchTarget);
            } else if (offset < VKDM.downloadPhotoAlbum.count) {
                VKDM.getJSONP('https://api.vk.com/method/photos.get?owner_id=' + albumID[1] + '&album_id=' + albumID[2] + '&extended=0&photo_sizes=0&offset=' + offset + '&count=100&v=5.27&callback=VKDM.createPhotoAlbumURLList', getAllPhotosFromAlbum);
                offset += 100;
            } else {
                VKDM.createFile('text/plain;charset=utf-8', VKDM.photoAlbumURLList.join('\r\n'), document.title + '.txt');
                hide(switchTarget.nextSibling);
                show(switchTarget);
            }
        };

        VKDM.getJSONP('https://api.vk.com/method/photos.get?owner_id=' + albumID[1] + '&album_id=' + albumID[2] + '&extended=0&photo_sizes=0&offset=0&count=100&v=5.27&callback=VKDM.createPhotoAlbumURLList', getAllPhotosFromAlbum);
    },

    createFoundPhotoURLList: function(result) {
        each(result.response, function(i, el) {
            if (el.photo_2560) VKDM.photoURLList.push(el.photo_2560);
            else if (el.photo_1280) VKDM.photoURLList.push(el.photo_1280);
            else if (el.photo_807) VKDM.photoURLList.push(el.photo_807);
            else if (el.photo_604) VKDM.photoURLList.push(el.photo_604);
            else if (el.photo_130) VKDM.photoURLList.push(el.photo_130);
            else if (el.photo_75) VKDM.photoURLList.push(el.photo_75);
        });
    },

    createPhotoAlbumURLList: function(result) {
        this.downloadPhotoAlbum.count = result.response.count;

        each(result.response.items, function(i, el) {
            if (el.photo_2560) VKDM.photoAlbumURLList.push(el.photo_2560);
            else if (el.photo_1280) VKDM.photoAlbumURLList.push(el.photo_1280);
            else if (el.photo_807) VKDM.photoAlbumURLList.push(el.photo_807);
            else if (el.photo_604) VKDM.photoAlbumURLList.push(el.photo_604);
            else if (el.photo_130) VKDM.photoAlbumURLList.push(el.photo_130);
            else if (el.photo_75) VKDM.photoAlbumURLList.push(el.photo_75);
        });
    },

    getJSONP: function(url, callback) {
        var script = ce('script', {src: url});

        script.onload = function() {
            callback(false);
            re(script);
        };
        script.onerror = function() {
            callback(true);
            re(script);
        };

        geByTag1('head').appendChild(script);
    },

    createFile: function(type, data, fileName) {
        if (window.URL && URL.createObjectURL) {
            var url = URL.createObjectURL(new Blob([data], {type: type}));

            this.hiddenClick(url, fileName);
            setTimeout(function() {
                URL.revokeObjectURL(url);
            }, 100);
        } else {
            var url = 'data:' + type + ',' + encodeURI(data);

            this.hiddenClick(url, fileName);
        }
    },

    hiddenClick: function(url, fileName) {
        var a = ce('a', {href: url, download: fileName || ''});

        document.body.appendChild(a);
        a.click();
        re(a);
    }
};

// Init
(function() {
    geByTag1('head').appendChild(ce('style', {
        type: 'text/css', 
        innerHTML: '\
.audio .audio_download_wrap {margin: 6px 6px 6px 0px; opacity: 0.4; padding: 1px 4px 0px;}\
.audio .audio_download {background: url("data:image/gif;base64,R0lGODlhDQANAIABAF+AnwAAACH5BAEAAAEALAAAAAANAA0AAAIYjAOZx+2n1pstgmlxrDabrnCeKD0hhTgFADs=") 0px 0px no-repeat transparent; height: 13px; cursor: pointer; overflow: hidden; position: relative; visibility: hidden; width: 13px;}\
.audio.over .duration {display: none !important}\
.audio.over .audio_download {visibility: visible;}\
#audio.new .audio.over .title_wrap {width: 300px !important}\
#audio.new .audio_download_wrap {padding: 4px;}\
#pad_playlist_panel .audio_download_wrap {margin: 7px 7px 7px 0px; padding: 4px;}\
#audio.new .audio.current .audio_download, #pad_playlist_panel .audio.current .audio_download {background-image: url("data:image/gif;base64,R0lGODlhDQANAIABAP///////yH5BAEAAAEALAAAAAANAA0AAAIYjAOZx+2n1pstgmlxrDabrnCeKD0hhTgFADs=");}\
#VKDM_InfoBox {line-height: 1; position: fixed; right: 10px; top: 85px; z-index: 201;}\
#VKDM_InfoBox_ico {background: url("data:image/gif;base64,R0lGODlhDQANAIABAF+AnwAAACH5BAEAAAEALAAAAAANAA0AAAIYjAOZx+2n1pstgmlxrDabrnCeKD0hhTgFADs=") 10px 10px no-repeat #d9e0e8; cursor: pointer; height: 33px; width: 33px; float: right; opacity: 0.70; transition: opacity 200ms ease-out, background 200ms ease-out;}\
#VKDM_InfoBox_ico:hover {opacity: 1;}\
.VKDM_InfoBox_ico_active {background: url("data:image/gif;base64,R0lGODlhDQANAIABAP///////yH5BAEAAAEALAAAAAANAA0AAAIYjAOZx+2n1pstgmlxrDabrnCeKD0hhTgFADs=") 10px 10px no-repeat #5780AB !important; box-shadow: 0 0px 3px rgba(0, 0, 0, 0.2) !important; opacity: 1 !important;}\
#VKDM_InfoBox_content {box-shadow: 0px 0px 3px rgba(0, 0, 0, 0.2); color: #45688E; display: none; margin-right: 2px; min-width: 180px;}\
#VKDM_InfoBox_content_title {background-color: #5780AB; padding: 11px 0px; text-align: center;}\
#VKDM_InfoBox_content_title a {color: #FFFFFF; font-weight: 700;}\
#VKDM_InfoBox_content_body {background-color: #F2F5F7; border-bottom: 1px solid #D7DADE; border-left: 1px solid #D7DADE; border-right: 1px solid #D7DADE; margin: 0px; padding: 11px 11px 0px;}\
#VKDM_audioURLListLength, #VKDM_photoURLListLength {margin-left: 5px;}\
.VKDM_docs_item_icon {background: #e1e7ed url("/images/icons/darr.gif") 8px 7px no-repeat; width: 30px; height: 17px; border-radius: 3px; color: #6A839E; padding: 3px 0px 0px 20px; display: inline-block; line-height: 1.182;}\
.VKDM_docs_item_icon:hover {text-decoration: none;}\
.VKDM_loading {background-color: #E1E7ED; border-radius: 3px; display: inline-block; height: 17px; line-height: 1.182; padding-top: 3px; text-align: center; width: 50px;}\
.VKDM_FastBox_H {color: #36638E; font-size: 1.09em; font-weight: 700; margin-bottom: 17px;}' 
    }));
    document.body.appendChild(ce('div', {
        id: 'VKDM_InfoBox',
        innerHTML: '\
<div id="VKDM_InfoBox_ico" onclick="toggle(ge(\'VKDM_InfoBox_content\')); toggleClass(this, \'VKDM_InfoBox_ico_active\');"></div>\
<div id="VKDM_InfoBox_content" class="fl_l">\
  <div id="VKDM_InfoBox_content_title"><a href="http://vk-download-music.net" target="_blank">VKDownloadMedia 3.0</a></div>\
  <div id="VKDM_InfoBox_content_body">\
    <div style="padding-bottom: 11px;">\
      <div class="fl_l" style="background: url(/images/icons/mono_iconset.png) 0px -221px no-repeat transparent; height: 12px; margin-right: 5px; width: 11px;"></div>\
      <div class="fl_l"><a href="#" id="VKDM_showAudioDownloader">Найдено аудиозаписей</a>:</div>\
      <div class="fl_r"><b id="VKDM_audioURLListLength">0</b>\
      </div><div class="clear"></div>\
    </div>\
    <div style="padding-bottom: 11px;">\
      <div class="fl_l" style="background: url(/images/icons/mono_iconset.png) 0px -29px no-repeat transparent; height: 12px; margin-right: 5px; width: 11px;"></div>\
      <div class="fl_l"><a href="#" id="VKDM_showPhotoDownloader">Найдено фотографий</a>:</div>\
      <div class="fl_r"><b id="VKDM_photoURLListLength">0</b>\
      </div><div class="clear"></div>\
    </div>\
  </div>\
</div>'
    }));
    addEvent(ge('VKDM_showAudioDownloader'), 'click', function() {
        if (VKDM.audioURLList.length === 0) {
            showDoneBox('<b>Аудиозаписей не найдено.</b>');
            return false;
        }

        var title = 'Скачать Аудиозаписи';
        var content = '\
<div class="VKDM_FastBox_H">Найдено аудиозаписей: ' + VKDM.audioURLList.length + '</div>\
<p><a onclick="VKDM.createFile(\'audio/x-mpegurl;charset=utf-8\', \'#EXTM3U\\r\\n\' + VKDM.audioURLList.join(\'\\r\\n\'), \'ВКонтакте-плейлист.m3u\')" class="VKDM_docs_item_icon">M3U</a> &ndash; скачать плейлист найденных аудиозаписей.</p>\
<p><a onclick="VKDM.createFile(\'text/plain;charset=utf-8\', VKDM.audioURLList.join(\'\\r\\n\'), VKDM.audioURLList.length + \' найденных аудиозаписей.txt\')"  class="VKDM_docs_item_icon">txt</a> &ndash; скачать список URL-адресов найденных файлов.</p>\
<div class="info_msg">Чтобы скачать все аудиозаписи сразу, импортируйте список URL-адресов в менеджер закачек (рекомендуется <a href="http://www.westbyte.com/dm/" target="_blank">Download Master</a>).</div>';

        showFastBox({title: title, dark: 1, bodyStyle: 'padding: 17px 20px 18px;'}, content);
        return false;
    });
    addEvent(ge('VKDM_showPhotoDownloader'), 'click', function() {
        var photoLength = ge('content').querySelectorAll('[onclick*="showPhoto("]').length;

        if (photoLength === 0) {
            showDoneBox('<b>Фотографий не найдено.</b>');
            return false;
        }

        var title = 'Скачать фотографии';
        var content = '\
<div class="VKDM_FastBox_H">Найдено фотографий: ~' + photoLength + '</div>\
<p><a onclick="VKDM.downloadFoundPhoto(this)" class="VKDM_docs_item_icon">txt</a><span class="VKDM_loading" style="display: none"><img src="/images/upload.gif" /></span> &ndash; скачать список URL-адресов найденных файлов.</p>\
<div class="info_msg">Чтобы скачать все найденные фотографии сразу, импортируйте список URL-адресов в менеджер закачек (рекомендуется <a href="http://www.westbyte.com/dm/" target="_blank">Download Master</a>).</div>';

        showFastBox({title: title, dark: 1, bodyStyle: 'padding: 17px 20px 18px;'}, content);
        return false;
    });

    var preAudioLength = 0;
    var preAudioFirstID = null;
    var prePhotoLength = 0;
    var patternIsAlbum = /^\/album-?[0-9]+_[0-9]+$/;
    var VKDM_audioURLListLength = ge('VKDM_audioURLListLength');
    var VKDM_photoURLListLength = ge('VKDM_photoURLListLength');
    var adw = ce('div', {
        className: 'audio_download_wrap fl_r',
        innerHTML: '<div class="audio_download"></div>'
    });

    adw.setAttribute('onmouseover', "window.animate(this, {opacity: 1}, 200, showTooltip(this, {text: 'Скачать аудиозапись', black: 1, shift: [9, 5, 0]}))");
    adw.setAttribute('onmouseout', "window.animate(this, {opacity: 0.4}, 200)");
    adw.setAttribute('onclick', "VKDM.hiddenClick(geByTag1('input', ge(this.id.replace('download','audio'))).value); return cancelEvent(event);");

    (function refresh() {
        var audio = geByClass('audio');
        var audioLength = audio.length;
        var photoLength = ge('content').querySelectorAll('[onclick*="showPhoto("]').length;
        var video_player = ge('video_player');

        if (audioLength === 0) {
            if (preAudioLength !== 0) {
                preAudioLength = 0;
                preAudioFirstID = null;
                VKDM.audioURLList = [];
                VKDM_audioURLListLength.textContent = '0';
            }
        } else if (audio[0].id === preAudioFirstID && audioLength === preAudioLength) {
            /*******/
        } else {
            preAudioLength = audioLength;
            preAudioFirstID = audio[0].id;
            VKDM.audioURLList = [];
            VKDM.createAudioLinks(audio, audioLength, adw);
            VKDM_audioURLListLength.textContent = VKDM.audioURLList.length;
        }

        if (photoLength === 0) {
            if (prePhotoLength !== 0) {
                prePhotoLength = 0;
                VKDM_photoURLListLength.textContent = '0';
            }
        } else if (photoLength === prePhotoLength) {
            /*******/
        } else {
            prePhotoLength = photoLength;
            VKDM_photoURLListLength.textContent = '~' + photoLength;
        }

        if (location.pathname.search(patternIsAlbum) !== -1 && location.search.length === 0) {
            var photos_container = ge('photos_container') && ge('photos_container').parentNode;

            if (photos_container && !ge('VKDM_downloadPhotoAlbum')) {
                var fragment = cf();

                fragment.appendChild(ce('span', {className: 'divide', innerHTML: '|'}));
                fragment.appendChild(ce('span', {innerHTML: '<a id="VKDM_downloadPhotoAlbum">Скачать альбом</a>'}));
                geByClass1('summary', photos_container).appendChild(fragment);

                addEvent(ge('VKDM_downloadPhotoAlbum'), 'click', function() {
                    var title = 'Скачать альбом';
                    var content = '\
<div class="VKDM_FastBox_H">' + document.title + '</div>\
<p><a onclick="VKDM.downloadPhotoAlbum(this)" class="VKDM_docs_item_icon">txt</a><span class="VKDM_loading" style="display: none"><img src="/images/upload.gif" /></span> &ndash; скачать список URL-адресов всех фотографий с альбома.</p>\
<div class="info_msg">Чтобы скачать все фотографии сразу, импортируйте список URL-адресов в менеджер закачек (рекомендуется <a href="http://www.westbyte.com/dm/" target="_blank">Download Master</a>).</div>';

                    showFastBox({title: title, dark: 1, bodyStyle: 'padding: 17px 20px 18px;'}, content);
                    return false;
                });
            }
        } else {
            var VKDM_downloadPhotoAlbum = ge('VKDM_downloadPhotoAlbum');

            if (VKDM_downloadPhotoAlbum) {
                re(VKDM_downloadPhotoAlbum.parentNode.previousSibling);
                re(VKDM_downloadPhotoAlbum);
            }
        }

        if (video_player) {
            var flashvars = video_player.getAttribute('flashvars');

            if (!ge('mv_download')) {
                if (flashvars && flashvars.indexOf('vid=') !== -1) {
                    VKDM.createVideoLinks(flashvars);
                }
            }
        }

        setTimeout(refresh, 300);
    })();
})();