Greasy Fork is available in English.

Simple 163 Music Dl Helper

Download music from music.163.com

Version au 16/06/2015. Voir la dernière version.

// ==UserScript==
// @name         Simple 163 Music Dl Helper
// @namespace    org.xryl.music.163
// @version      1.1
// @description  Download music from music.163.com
///
//               火狐匹配地址
// @include      http://music.163.com/#*
///
//               TamperMonkey 匹配地址
// @include      http://music.163.com/
///
// @copyright    2014+, Jixun.Moe, 2015+, X-Ryl669
// @run-at       document-start
// @grant        GM_download
// ==/UserScript==


(function () {
	// I love prototype.
	String.prototype.format = function () {
		var $arg = arguments,
			$len = $arg.length;
		return this.replace (/\{(\d+)\}/g, function (z, num) {
			num = parseInt (num);
			if (num < $len) {
				return $arg[num];
			} else {
				return z;
			}
		});
	};

	var $bank = {};
	var $dlBtn = document.createElement ('a');
	$dlBtn.setAttribute ('target', '_blank');
	$dlBtn.setAttribute ('style', 'font-size:small;width:3em;left:initial;right:40px');
	$dlBtn.className = 'lytit';
	$dlBtn.textContent = 'down';
	$dlBtn.addEventListener ('click', function (e) {
		var $addr = this.getAttribute ('href');
        GM_download($addr, this.getAttribute('download'));
        e.preventDefault();
		e.stopPropagation ();
	}, false);
    var $blob = 0;

	var _updDownloadUrl = function (songId) {
		var $song = $bank[songId.toString()];
        var $info = '{0}.[{1}] {2} - {3}'.format (("0" + $song.index).slice(-2), $song.album, $song.artist, $song.name);
		console.info ('%s\n%s', $info, $song.url);
        
		$dlBtn.setAttribute ('title', 'Song: ' + $info);
        $dlBtn.setAttribute ('download', $info+'.mp3');
		$dlBtn.setAttribute ('href', $song.url);
	};

	var _addBank = function (songObj) {
		$bank[songObj.id.toString()] = {
			name: songObj.name,
			album: songObj.album.name,
			artist: songObj.artists.map(function (artist) {
				return artist.name;
			}).join ('& '),
			
			url: songObj.mp3Url,
            index: (Object.keys($bank).indexOf(songObj.id) == -1 ? Object.keys($bank).length : Object.keys($bank).indexOf(songObj.id)) + 1
		};
	};


	window.XMLHttpRequest.prototype.oldOpen = window.XMLHttpRequest.prototype.open;
	window.XMLHttpRequest.prototype.open = function (method, url) {
		console.info ('[REQ] %s: %s', method, url);
		
        if (!url.indexOf('/api/song/media') || !url.indexOf('/api/song/lyric')) {
			console.log ('Check $bank...');
			
            var $id = url.indexOf('/api/song/media') === 0 ? url.match (/\d+/)[0] : url.match(/id=(\d+)/)[1];
			if ($bank.hasOwnProperty($id)) {
				_updDownloadUrl ($id);
			} else {
				// First, search through local cache.
				var cacheSongObj;
				try {
					cacheSongObj = JSON.parse(localStorage['track-queue']).filter (function (s) {
						_addBank (s);
						return $id == s.id.toString();
					});
				} catch (err) { }

				if (cacheSongObj) {
					console.info ('Music found from cache.');
					_updDownloadUrl (cacheSongObj.id);
				} else {
					console.info ('Requesting song information...');
					var $http = new window.XMLHttpRequest ();
					var $args = [].slice.apply(arguments);
					$http.onreadystatechange = new Function ();
					$args[1] = '/api/song/detail/?id=' + $id + '&ids=%5B' + $id + '%5D&csrf_token=' + url.match(/csrf_token=([^&]*)/)[1];
					$http.open.apply ($http, $args);
					$http.send ();
				}
			}
		} else if (-1 != url.indexOf('/api/song/detail')) {
			try {
				var $this = this;
				var bkReadystatechange = this.onreadystatechange;
				this.onreadystatechange = function (e) {
					if ($this.readyState === 4) {
						JSON.parse($this.responseText.trim()).songs.forEach(function (e) {
							_addBank (e);
							_updDownloadUrl (e.id);
						});
					}
					
					return bkReadystatechange.apply (this, arguments);
				};
			} catch (err) {
				console.error (err);
			}
		}
		
		return this.oldOpen.apply(this, arguments);
	};

	(function () {
		var $t;
		var vv = setInterval (function () {
			if (!($t = document.querySelector ('.lytit')))
				return ;
			clearInterval (vv);
			
			$t.style.maxWidth = '302px';
			$t.parentNode.insertBefore ($dlBtn, $t.nextElementSibling);
		}, 200);
	})();

})();