├── .gitignore ├── screen.png ├── src ├── img │ ├── blue.png │ ├── green.png │ ├── icon.png │ └── yellow.png ├── js │ ├── log.js │ ├── options.js │ ├── yandex_api.js │ ├── background.js │ ├── downloader.js │ └── utils.js ├── manifest.json └── html │ └── options.html ├── readme.md └── song.svg /.gitignore: -------------------------------------------------------------------------------- 1 | nbproject/ 2 | -------------------------------------------------------------------------------- /screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepkagr/yandex-music-fisher/HEAD/screen.png -------------------------------------------------------------------------------- /src/img/blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepkagr/yandex-music-fisher/HEAD/src/img/blue.png -------------------------------------------------------------------------------- /src/img/green.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepkagr/yandex-music-fisher/HEAD/src/img/green.png -------------------------------------------------------------------------------- /src/img/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepkagr/yandex-music-fisher/HEAD/src/img/icon.png -------------------------------------------------------------------------------- /src/img/yellow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stepkagr/yandex-music-fisher/HEAD/src/img/yellow.png -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | #Yandex Music Fisher (0.1.8) 2 | 3 | Расширение Google Chrome для загрузки музыки с сервиса [Яндекс.Музыка](http://music.yandex.ru/). 4 | 5 | ![Yandex Music Fisher](/screen.png) 6 | 7 | ### Подключение 8 | 9 | [Скачайте](https://github.com/egoroof/yandex-music-fisher/archive/master.zip), 10 | перенесите папку __src__ на страницу расширений. 11 | 12 | ### Как пользоваться 13 | 14 | Открыть страницу на [Яндекс.Музыка](http://music.yandex.ru/) с нужным ![blue](/src/img/blue.png) треком, 15 | ![yellow](/src/img/yellow.png) альбомом или ![green](/src/img/green.png) плейлистом, нажать на появившуюся иконку. 16 | Далее пойдёт автоматический процесс скачивания. Можно покинуть сайт Яндекс Музыки. 17 | -------------------------------------------------------------------------------- /src/js/log.js: -------------------------------------------------------------------------------- 1 | var log = { 2 | string: '' 3 | }; 4 | 5 | log.addMessage = function (msg) { 6 | log.string += msg + "\r\n"; 7 | }; 8 | 9 | log.download = function () { 10 | log.addMessage(new Date()); 11 | chrome.downloads.download({ 12 | url: 'data:text/plain;charset=utf-8,' + encodeURIComponent(log.string), 13 | filename: 'log.txt' 14 | }); 15 | }; 16 | 17 | chrome.runtime.getPlatformInfo(function (platformInfo) { 18 | log.addMessage('Yandex Music Fisher ' + chrome.runtime.getManifest().version); 19 | log.addMessage(new Date()); 20 | log.addMessage('Operating system: ' + platformInfo.os); 21 | log.addMessage('Architecture: ' + platformInfo.arch); 22 | }); 23 | -------------------------------------------------------------------------------- /src/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "manifest_version": 2, 3 | "name": "Yandex Music Fisher", 4 | "description": "Скачивание музыки с сервиса Яндекс.Музыка", 5 | "version": "0.1.8", 6 | "permissions": [ 7 | "tabs", 8 | "downloads", 9 | "https://music.yandex.ru/" 10 | ], 11 | "minimum_chrome_version": "31.0", 12 | "background": { 13 | "scripts": ["js/log.js", "js/utils.js", "js/yandex_api.js", "js/downloader.js", "js/background.js"], 14 | "persistent": true 15 | }, 16 | "options_page": "html/options.html", 17 | "page_action": { 18 | "default_title": "Yandex Music Fisher" 19 | }, 20 | "icons": { 21 | "16": "img/icon.png", 22 | "32": "img/icon.png", 23 | "48": "img/icon.png", 24 | "128": "img/icon.png" 25 | }, 26 | "content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'" 27 | } 28 | -------------------------------------------------------------------------------- /src/js/options.js: -------------------------------------------------------------------------------- 1 | document.addEventListener('DOMContentLoaded', function () { 2 | var threadCount = localStorage.getItem('downloadThreadCount'); 3 | if (threadCount) { 4 | document.getElementById('downloadThreadCount').value = threadCount; 5 | } 6 | var coverSize = localStorage.getItem('albumCoverSize'); 7 | if (coverSize) { 8 | document.getElementById('albumCoverSize').value = coverSize; 9 | } 10 | }); 11 | 12 | document.getElementById('downloadThreadCount').addEventListener('change', function (e) { 13 | if (e.target.value > 10) { 14 | e.target.value = 10; 15 | } else if (e.target.value < 1) { 16 | e.target.value = 1; 17 | } 18 | localStorage.setItem('downloadThreadCount', e.target.value); 19 | }); 20 | 21 | document.getElementById('albumCoverSize').addEventListener('change', function (e) { 22 | localStorage.setItem('albumCoverSize', e.target.value); 23 | }); 24 | 25 | document.getElementById('btn-log').addEventListener('click', function (e) { 26 | e.preventDefault(); 27 | chrome.runtime.getBackgroundPage(function (backgroundPage) { 28 | backgroundPage.log.download(); 29 | }); 30 | }); 31 | -------------------------------------------------------------------------------- /src/html/options.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Yandex Music Fisher 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 28 | 29 |
ПараметрЗначение
Количество потоков загрузки
Размер обложки альбомов 21 | 27 |


30 | 31 | Скачать файл с отладочной информацией 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /song.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/js/yandex_api.js: -------------------------------------------------------------------------------- 1 | var yandex = {}; 2 | 3 | yandex.getTrackLinks = function (storageDir, success, fail) { 4 | var url = '/api/v1.4/jsonp.xml?action=getTrackSrc&p=download-info/' 5 | + storageDir + '/2.mp3&r=' + Math.random(); 6 | utils.ajax(url, function (jsonp) { 7 | // чистим jsonp до json 8 | var jsonStr = jsonp.replace(/^[^[]+/, '').replace(/\);$/, ''); 9 | try { 10 | // json кривой, поэтому извлекаем через eval 11 | var json = eval(jsonStr)[0]; 12 | } catch (e) { 13 | var message = 'Не удалось распарсить строку' + jsonp; 14 | console.error(message); 15 | log.addMessage(message); 16 | fail(); 17 | return; 18 | } 19 | var hosts = json['regional-hosts']; 20 | hosts.push(json.host); 21 | 22 | var md5 = utils.md5('XGRlBW9FXlekgbPrRHuSiA' + json.path.substr(1) + json.s); 23 | var urlBody = '/get-mp3/' + md5 + '/' + json.ts + json.path; 24 | var links = hosts.map(function (host) { 25 | return 'http://' + host + urlBody; 26 | }); 27 | success(links); 28 | }, fail); 29 | }; 30 | 31 | yandex.getTrack = function (trackId, success, fail) { 32 | var url = '/handlers/track.jsx?track=' + trackId 33 | + '&r=' + Math.random(); 34 | utils.ajax(url, success, fail); 35 | }; 36 | 37 | yandex.getAlbum = function (albumId, success, fail) { 38 | var url = '/handlers/album.jsx?album=' + albumId 39 | + '&r=' + Math.random(); 40 | utils.ajax(url, success, fail); 41 | }; 42 | 43 | yandex.getPlaylist = function (username, playlistId, success, fail) { 44 | var url = '/handlers/playlist.jsx?owner=' + username 45 | + '&kinds=' + playlistId 46 | + '&r=' + Math.random(); 47 | utils.ajax(url, function (json) { 48 | success(json.playlist); 49 | }, fail); 50 | }; 51 | -------------------------------------------------------------------------------- /src/js/background.js: -------------------------------------------------------------------------------- 1 | // todo: предварительная загрузка страницы может не вызвать это событие 2 | chrome.tabs.onUpdated.addListener(function (tabId, changeInfo, tab) { 3 | if (changeInfo.status === 'loading') { 4 | utils.addIconToTab(tab); 5 | } 6 | }); 7 | 8 | chrome.pageAction.onClicked.addListener(function (tab) { 9 | chrome.pageAction.hide(tab.id); 10 | var page = utils.getUrlInfo(tab.url); 11 | if (page.isPlaylist) { 12 | yandex.getPlaylist(page.username, page.playlistId, downloader.downloadPlaylist, function () { 13 | // ajax transport fail 14 | utils.addIconToTab(tab); 15 | }); 16 | } else if (page.isTrack) { 17 | yandex.getTrack(page.trackId, function (track) { 18 | downloader.add([track]); 19 | }, function () { 20 | // ajax transport fail 21 | utils.addIconToTab(tab); 22 | }); 23 | } else if (page.isAlbum) { 24 | yandex.getAlbum(page.albumId, downloader.downloadAlbum, function () { 25 | // ajax transport fail 26 | utils.addIconToTab(tab); 27 | }); 28 | } 29 | }); 30 | 31 | chrome.downloads.onChanged.addListener(function (delta) { 32 | chrome.downloads.search({ 33 | id: delta.id 34 | }, function (downloads) { 35 | var parts = downloads[0].filename.split('.'); 36 | var name = downloads[0].byExtensionName; 37 | if (!name || name !== 'Yandex Music Fisher' || parts[parts.length - 1] !== 'mp3') { 38 | return; 39 | } 40 | if (delta.state) { 41 | switch (delta.state.current) { 42 | case 'complete': 43 | case 'interrupted': 44 | downloader.activeThreadCount--; 45 | if (!downloader.queue.length && !downloader.activeThreadCount) { 46 | chrome.downloads.show(delta.id); 47 | } 48 | chrome.downloads.erase({ 49 | id: delta.id 50 | }); 51 | downloader.download(); 52 | break; 53 | } 54 | } else if (delta.paused) { 55 | if (delta.paused.current) { 56 | console.info('Приостановленна загрузка', delta); 57 | } else { 58 | console.info('Возобновленна загрузка', delta); 59 | } 60 | } 61 | }); 62 | }); 63 | 64 | chrome.runtime.onInstalled.addListener(function (details) { 65 | // todo: перейти с localStorage на chrome.storage 66 | if (!localStorage.getItem('downloadThreadCount')) { 67 | localStorage.setItem('downloadThreadCount', 4); 68 | } 69 | if (!localStorage.getItem('albumCoverSize')) { 70 | localStorage.setItem('albumCoverSize', '460x460'); 71 | } 72 | chrome.tabs.query({ 73 | url: '*://music.yandex.ru/*' 74 | }, function (tabs) { 75 | for (var i = 0; i < tabs.length; i++) { 76 | utils.addIconToTab(tabs[i]); 77 | } 78 | }); 79 | }); 80 | -------------------------------------------------------------------------------- /src/js/downloader.js: -------------------------------------------------------------------------------- 1 | var downloader = { 2 | queue: [], 3 | activeThreadCount: 0 4 | }; 5 | 6 | downloader.clearPath = function (path) { 7 | return path.replace(/[\\/:*?"<>|]/g, '_'); // Windows path illegals 8 | }; 9 | 10 | downloader.getPrefix = function (i, max) { 11 | var prefix = ''; 12 | max = max.toString(); 13 | switch (max.length) { 14 | case 2: 15 | prefix = (i < 10) ? '0' + i : i; 16 | break; 17 | case 3: 18 | prefix = (i < 10) ? '00' + i : ((i < 100) ? '0' + i : i); 19 | break; 20 | case 4: 21 | // надеюсь 9999 хватит 22 | prefix = (i < 10) ? '000' + i : ((i < 100) ? '00' + i : ((i < 1000) ? '0' + i : i)); 23 | break; 24 | default: 25 | prefix = i; 26 | } 27 | return prefix + ' - '; 28 | }; 29 | 30 | downloader.download = function () { 31 | var track = downloader.queue.shift(); 32 | if (!track) { 33 | return; 34 | } 35 | if (track.error) { 36 | var message = 'Ошибка: ' + track.error; 37 | console.error(message, track); 38 | log.addMessage(message); 39 | downloader.download(); 40 | return; 41 | } 42 | downloader.activeThreadCount++; 43 | var artists = track.artists.map(function (artist) { 44 | return artist.name; 45 | }).join(', '); 46 | if (track.version) { 47 | track.title += ' (' + track.version + ')'; 48 | } 49 | var savePath = downloader.clearPath(artists + ' - ' + track.title + '.mp3'); 50 | if (track.namePrefix) { 51 | savePath = track.namePrefix + savePath; 52 | } 53 | if (track.saveDir) { 54 | savePath = track.saveDir + '/' + savePath; 55 | } 56 | yandex.getTrackLinks(track.storageDir, function (links) { 57 | if (links.length) { 58 | chrome.downloads.download({ 59 | url: links[0], 60 | filename: savePath, 61 | saveAs: false, 62 | conflictAction: 'prompt' 63 | }); 64 | } else { 65 | var message = 'Не удалось найти ссылки'; 66 | console.error(message, track); 67 | log.addMessage(message); 68 | downloader.activeThreadCount--; 69 | downloader.download(); 70 | } 71 | }, function () { 72 | // ajax transport fail или json не распарсили 73 | downloader.activeThreadCount--; 74 | downloader.download(); 75 | }); 76 | }; 77 | 78 | downloader.add = function (tracks) { 79 | // todo: сделать страницу с обзором закачек 80 | downloader.queue = downloader.queue.concat(tracks); 81 | var newThreadCount = localStorage.getItem('downloadThreadCount') - downloader.activeThreadCount; 82 | for (var i = 0; i < newThreadCount; i++) { 83 | downloader.download(); 84 | } 85 | }; 86 | 87 | downloader.downloadAlbum = function (album) { 88 | var tracks = []; 89 | var artists = album.artists.map(function (artist) { 90 | return artist.name; 91 | }).join(', '); 92 | if (album.version) { 93 | album.title += ' (' + album.version + ')'; 94 | } 95 | var saveDir = downloader.clearPath(artists + ' - ' + album.title); 96 | if (album.volumes.length > 1) { 97 | for (var i = 0; i < album.volumes.length; i++) { 98 | album.volumes[i].forEach(function (track, j) { 99 | track.saveDir = saveDir + '/CD' + (i + 1); 100 | track.namePrefix = downloader.getPrefix(j + 1, album.volumes[i].length); 101 | }); 102 | tracks = tracks.concat(album.volumes[i]); 103 | } 104 | } else { 105 | album.volumes[0].forEach(function (track, i) { 106 | track.saveDir = saveDir; 107 | track.namePrefix = downloader.getPrefix(i + 1, album.volumes[0].length); 108 | }); 109 | tracks = album.volumes[0]; 110 | } 111 | downloader.add(tracks); 112 | chrome.downloads.download({ 113 | url: 'https://' + album.coverUri.replace('%%', localStorage.getItem('albumCoverSize')), 114 | filename: saveDir + '/cover.jpg', 115 | saveAs: false, 116 | conflictAction: 'prompt' 117 | }); 118 | }; 119 | 120 | downloader.downloadPlaylist = function (playlist) { 121 | playlist.tracks.forEach(function (track, i) { 122 | track.saveDir = downloader.clearPath(playlist.title); 123 | track.namePrefix = downloader.getPrefix(i + 1, playlist.tracks.length); 124 | }); 125 | downloader.add(playlist.tracks); 126 | }; 127 | -------------------------------------------------------------------------------- /src/js/utils.js: -------------------------------------------------------------------------------- 1 | var utils = {}; 2 | 3 | utils.ajax = function (url, success, fail) { 4 | var xhr = new XMLHttpRequest(); 5 | xhr.open('GET', 'https://music.yandex.ru' + url, true); 6 | xhr.timeout = 10000; 7 | xhr.onload = function () { 8 | if (xhr.status === 200) { 9 | if (xhr.responseXML) { 10 | success(xhr.responseXML); // xml 11 | } else { 12 | var reply; 13 | try { 14 | reply = JSON.parse(xhr.responseText); // json 15 | } catch (e) { 16 | reply = xhr.responseText; // plain text 17 | } 18 | success(reply); 19 | } 20 | } else { 21 | var message = 'HTTP error code: ' + xhr.status; 22 | console.error(message); 23 | log.addMessage(message); 24 | fail(); 25 | } 26 | }; 27 | xhr.onerror = function () { 28 | var message = 'AJAX error: ' + url; 29 | console.error(message); 30 | log.addMessage(message); 31 | fail(); 32 | }; 33 | xhr.ontimeout = function () { 34 | var message = 'AJAX timeout: ' + url; 35 | console.error(message); 36 | log.addMessage(message); 37 | fail(); 38 | }; 39 | xhr.send(); 40 | }; 41 | 42 | utils.getUrlInfo = function (url) { 43 | var info = {}; 44 | var parts = url.replace(/\?.*/, '').split('/'); 45 | //["http:", "", "music.yandex.ru", "users", "furfurmusic", "playlists", "1000"] 46 | info.isYandexMusic = (parts[2] === 'music.yandex.ru'); 47 | if (!info.isYandexMusic) { 48 | return info; 49 | } 50 | info.isPlaylist = (parts[3] === 'users' && parts[5] === 'playlists' && !!parts[6]); 51 | info.isTrack = (parts[3] === 'album' && parts[5] === 'track' && !!parts[6]); 52 | info.isAlbum = (parts[3] === 'album' && !!parts[4]); 53 | if (info.isPlaylist) { 54 | info.username = parts[4]; 55 | info.playlistId = parts[6]; 56 | } else if (info.isTrack) { 57 | info.trackId = parts[6]; 58 | } else if (info.isAlbum) { 59 | info.albumId = parts[4]; 60 | } 61 | return info; 62 | }; 63 | 64 | utils.addIconToTab = function (tab) { 65 | chrome.pageAction.hide(tab.id); 66 | var page = utils.getUrlInfo(tab.url); 67 | if (!page.isYandexMusic) { 68 | return; 69 | } else if (page.isPlaylist) { 70 | chrome.pageAction.setIcon({ 71 | tabId: tab.id, 72 | path: 'img/green.png' 73 | }); 74 | chrome.pageAction.show(tab.id); 75 | } else if (page.isTrack) { 76 | chrome.pageAction.setIcon({ 77 | tabId: tab.id, 78 | path: 'img/blue.png' 79 | }); 80 | chrome.pageAction.show(tab.id); 81 | } else if (page.isAlbum) { 82 | chrome.pageAction.setIcon({ 83 | tabId: tab.id, 84 | path: 'img/yellow.png' 85 | }); 86 | chrome.pageAction.show(tab.id); 87 | } 88 | }; 89 | 90 | // источник: http://jquerymy.com/js/md5.js 91 | utils.md5 = (function () { 92 | function e(e, t) { 93 | var o = e[0], u = e[1], a = e[2], f = e[3]; 94 | o = n(o, u, a, f, t[0], 7, -680876936); 95 | f = n(f, o, u, a, t[1], 12, -389564586); 96 | a = n(a, f, o, u, t[2], 17, 606105819); 97 | u = n(u, a, f, o, t[3], 22, -1044525330); 98 | o = n(o, u, a, f, t[4], 7, -176418897); 99 | f = n(f, o, u, a, t[5], 12, 1200080426); 100 | a = n(a, f, o, u, t[6], 17, -1473231341); 101 | u = n(u, a, f, o, t[7], 22, -45705983); 102 | o = n(o, u, a, f, t[8], 7, 1770035416); 103 | f = n(f, o, u, a, t[9], 12, -1958414417); 104 | a = n(a, f, o, u, t[10], 17, -42063); 105 | u = n(u, a, f, o, t[11], 22, -1990404162); 106 | o = n(o, u, a, f, t[12], 7, 1804603682); 107 | f = n(f, o, u, a, t[13], 12, -40341101); 108 | a = n(a, f, o, u, t[14], 17, -1502002290); 109 | u = n(u, a, f, o, t[15], 22, 1236535329); 110 | o = r(o, u, a, f, t[1], 5, -165796510); 111 | f = r(f, o, u, a, t[6], 9, -1069501632); 112 | a = r(a, f, o, u, t[11], 14, 643717713); 113 | u = r(u, a, f, o, t[0], 20, -373897302); 114 | o = r(o, u, a, f, t[5], 5, -701558691); 115 | f = r(f, o, u, a, t[10], 9, 38016083); 116 | a = r(a, f, o, u, t[15], 14, -660478335); 117 | u = r(u, a, f, o, t[4], 20, -405537848); 118 | o = r(o, u, a, f, t[9], 5, 568446438); 119 | f = r(f, o, u, a, t[14], 9, -1019803690); 120 | a = r(a, f, o, u, t[3], 14, -187363961); 121 | u = r(u, a, f, o, t[8], 20, 1163531501); 122 | o = r(o, u, a, f, t[13], 5, -1444681467); 123 | f = r(f, o, u, a, t[2], 9, -51403784); 124 | a = r(a, f, o, u, t[7], 14, 1735328473); 125 | u = r(u, a, f, o, t[12], 20, -1926607734); 126 | o = i(o, u, a, f, t[5], 4, -378558); 127 | f = i(f, o, u, a, t[8], 11, -2022574463); 128 | a = i(a, f, o, u, t[11], 16, 1839030562); 129 | u = i(u, a, f, o, t[14], 23, -35309556); 130 | o = i(o, u, a, f, t[1], 4, -1530992060); 131 | f = i(f, o, u, a, t[4], 11, 1272893353); 132 | a = i(a, f, o, u, t[7], 16, -155497632); 133 | u = i(u, a, f, o, t[10], 23, -1094730640); 134 | o = i(o, u, a, f, t[13], 4, 681279174); 135 | f = i(f, o, u, a, t[0], 11, -358537222); 136 | a = i(a, f, o, u, t[3], 16, -722521979); 137 | u = i(u, a, f, o, t[6], 23, 76029189); 138 | o = i(o, u, a, f, t[9], 4, -640364487); 139 | f = i(f, o, u, a, t[12], 11, -421815835); 140 | a = i(a, f, o, u, t[15], 16, 530742520); 141 | u = i(u, a, f, o, t[2], 23, -995338651); 142 | o = s(o, u, a, f, t[0], 6, -198630844); 143 | f = s(f, o, u, a, t[7], 10, 1126891415); 144 | a = s(a, f, o, u, t[14], 15, -1416354905); 145 | u = s(u, a, f, o, t[5], 21, -57434055); 146 | o = s(o, u, a, f, t[12], 6, 1700485571); 147 | f = s(f, o, u, a, t[3], 10, -1894986606); 148 | a = s(a, f, o, u, t[10], 15, -1051523); 149 | u = s(u, a, f, o, t[1], 21, -2054922799); 150 | o = s(o, u, a, f, t[8], 6, 1873313359); 151 | f = s(f, o, u, a, t[15], 10, -30611744); 152 | a = s(a, f, o, u, t[6], 15, -1560198380); 153 | u = s(u, a, f, o, t[13], 21, 1309151649); 154 | o = s(o, u, a, f, t[4], 6, -145523070); 155 | f = s(f, o, u, a, t[11], 10, -1120210379); 156 | a = s(a, f, o, u, t[2], 15, 718787259); 157 | u = s(u, a, f, o, t[9], 21, -343485551); 158 | e[0] = m(o, e[0]); 159 | e[1] = m(u, e[1]); 160 | e[2] = m(a, e[2]); 161 | e[3] = m(f, e[3]); 162 | } 163 | function t(e, t, n, r, i, s) { 164 | t = m(m(t, e), m(r, s)); 165 | return m(t << i | t >>> 32 - i, n); 166 | } 167 | function n(e, n, r, i, s, o, u) { 168 | return t(n & r | ~n & i, e, n, s, o, u); 169 | } 170 | function r(e, n, r, i, s, o, u) { 171 | return t(n & i | r & ~i, e, n, s, o, u); 172 | } 173 | function i(e, n, r, i, s, o, u) { 174 | return t(n ^ r ^ i, e, n, s, o, u); 175 | } 176 | function s(e, n, r, i, s, o, u) { 177 | return t(r ^ (n | ~i), e, n, s, o, u); 178 | } 179 | function o(t) { 180 | var n = t.length, r = [1732584193, -271733879, -1732584194, 271733878], i; 181 | for (i = 64; i <= t.length; i += 64) { 182 | e(r, u(t.substring(i - 64, i))); 183 | } 184 | t = t.substring(i - 64); 185 | var s = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; 186 | for (i = 0; i < t.length; i++) 187 | s[i >> 2] |= t.charCodeAt(i) << (i % 4 << 3); 188 | s[i >> 2] |= 128 << (i % 4 << 3); 189 | if (i > 55) { 190 | e(r, s); 191 | for (i = 0; i < 16; i++) 192 | s[i] = 0; 193 | } 194 | s[14] = n * 8; 195 | e(r, s); 196 | return r; 197 | } 198 | function u(e) { 199 | var t = [], n; 200 | for (n = 0; n < 64; n += 4) { 201 | t[n >> 2] = e.charCodeAt(n) + (e.charCodeAt(n + 1) << 8) + (e.charCodeAt(n + 2) << 16) + (e.charCodeAt(n + 3) << 24); 202 | } 203 | return t; 204 | } 205 | function c(e) { 206 | var t = "", n = 0; 207 | for (; n < 4; n++) 208 | t += a[e >> n * 8 + 4 & 15] + a[e >> n * 8 & 15]; 209 | return t; 210 | } 211 | function h(e) { 212 | for (var t = 0; t < e.length; t++) 213 | e[t] = c(e[t]); 214 | return e.join(""); 215 | } 216 | function d(e) { 217 | return h(o(unescape(encodeURIComponent(e)))); 218 | } 219 | function m(e, t) { 220 | return e + t & 4294967295; 221 | } 222 | var a = "0123456789abcdef".split(""); 223 | return d; 224 | })(); --------------------------------------------------------------------------------