- // ==UserScript==
- // @name 豆瓣FM 红心歌单恢复播放
- // @namespace http://thatwind.com/
- // @version 0.2
- // @description 豆瓣FM网页版 可以解锁红心歌单里不能放的歌曲
- // @icon data:image/svg+xml;charset=utf-8;base64,PHN2ZyBzdHlsZT0nd2lkdGg6IDFlbTsgaGVpZ2h0OiAxZW07dmVydGljYWwtYWxpZ246IG1pZGRsZTtmaWxsOiBjdXJyZW50Q29sb3I7b3ZlcmZsb3c6IGhpZGRlbjsnIHZpZXdCb3g9JzAgMCAxMDI0IDEwMjQnIHZlcnNpb249JzEuMScgeG1sbnM9J2h0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnJz48cGF0aCBkPSdNNTEwLjgxMzQ3NiA5MTEuOTY4NDM3Yy0zLjk0OTk2MiAwLTcuODU0ODk4LTEuMDEwMDAzLTExLjQzNTQ0Ny0yLjkzODkzNS00LjQxMDQ1LTIuNDgxNTE4LTEwOS4zOTQ1MDMtNjEuMjMyNTk2LTIxNS45ODQxMjMtMTU3LjQ2NDMxMS02My4wNjYzNjEtNTYuOTEyMTk4LTExMy40MTIwMDMtMTE1LjExMTcxNC0xNDkuNzIzLTE3My4wODA5ODctNDYuMjc4LTczLjkwODI5LTY5LjcwNDU0OC0xNDcuNjU0ODk4LTY5LjcwNDU0OC0yMTkuMTk4MzI4IDAtMTM2LjE3MjM3OSAxMTAuNzcwODQ5LTI0Ni45NDIyMDUgMjQ2Ljk0MTE4Mi0yNDYuOTQyMjA1IDQ2LjA5Njg3NCAwIDk1LjA2NDEyMyAxNy4yNzEzNjIgMTM3Ljg3MzExNCA0OC42NDQ5MDcgMjUuMDA5NjAzIDE4LjMyNzQxNCA0Ni4zMjQwNDggNDAuNDQ0MTMxIDYyLjAzMjgyMiA2My45MTc3NTIgMTUuNzEyODY3LTIzLjQ3MzYyMSAzNy4wMjUyNjUtNDUuNTkwMzM4IDYyLjAxNDQwMi02My45MTc3NTIgNDIuODA3OTY4LTMxLjM3MzU0NSA5MS43NzUyMTYtNDguNjQ0OTA3IDEzNy44OTE1MzQtNDguNjQ0OTA3IDEzNi4xNTE5MTMgMCAyNDYuOTQzMjI4IDExMC43Njk4MjYgMjQ2Ljk0MzIyOCAyNDYuOTQyMjA1IDAgNzEuNTQzNDMtMjMuNDcxNTc0IDE0NS4yOTAwMzctNjkuNzI3MDYxIDIxOS4xOTgzMjgtMzYuMjQxNDEyIDU3Ljk2ODI1LTg2LjYzMTA1NiAxMTYuMTY3NzY2LTE0OS42NTQ0MzggMTczLjA4MDk4Ny0xMDYuNTY4MTMxIDk2LjIzMTcxNS0yMTEuNTc0Njk2IDE1NC45ODI3OTQtMjE1Ljk4MzA5OSAxNTcuNDY0MzExLTMuNTgxNTcyIDEuOTI4OTMyLTcuNDg0NDYyIDIuOTM4OTM1LTExLjQzNjQ3IDIuOTM4OTM1TDUxMC44MTM0NzYgOTExLjk2ODQzN3onIGZpbGw9JyNmZjJjNTYnPjwvcGF0aD48L3N2Zz4=
- // @author allFull
- // @match *://douban.fm/*
- // @match *://www.douban.fm/*
- // @match *://fm.douban.com/*
- // @grant unsafeWindow
- // @run-at document-start
- // ==/UserScript==
-
- (function() {
-
- executePageFunc(function(){
- return new Promise(function(resolve){
-
- (function(e, a) { for(var i in a) e[i] = a[i]; }(window, /******/ (function(modules) { // webpackBootstrap
- /******/ // The module cache
- /******/ var installedModules = {};
- /******/
- /******/ // The require function
- /******/ function __webpack_require__(moduleId) {
- /******/
- /******/ // Check if module is in cache
- /******/ if(installedModules[moduleId]) {
- /******/ return installedModules[moduleId].exports;
- /******/ }
- /******/ // Create a new module (and put it into the cache)
- /******/ var module = installedModules[moduleId] = {
- /******/ i: moduleId,
- /******/ l: false,
- /******/ exports: {}
- /******/ };
- /******/
- /******/ // Execute the module function
- /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
- /******/
- /******/ // Flag the module as loaded
- /******/ module.l = true;
- /******/
- /******/ // Return the exports of the module
- /******/ return module.exports;
- /******/ }
- /******/
- /******/
- /******/ // expose the modules object (__webpack_modules__)
- /******/ __webpack_require__.m = modules;
- /******/
- /******/ // expose the module cache
- /******/ __webpack_require__.c = installedModules;
- /******/
- /******/ // identity function for calling harmony imports with the correct context
- /******/ __webpack_require__.i = function(value) { return value; };
- /******/
- /******/ // define getter function for harmony exports
- /******/ __webpack_require__.d = function(exports, name, getter) {
- /******/ if(!__webpack_require__.o(exports, name)) {
- /******/ Object.defineProperty(exports, name, {
- /******/ configurable: false,
- /******/ enumerable: true,
- /******/ get: getter
- /******/ });
- /******/ }
- /******/ };
- /******/
- /******/ // getDefaultExport function for compatibility with non-harmony modules
- /******/ __webpack_require__.n = function(module) {
- /******/ var getter = module && module.__esModule ?
- /******/ function getDefault() { return module['default']; } :
- /******/ function getModuleExports() { return module; };
- /******/ __webpack_require__.d(getter, 'a', getter);
- /******/ return getter;
- /******/ };
- /******/
- /******/ // Object.prototype.hasOwnProperty.call
- /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
- /******/
- /******/ // __webpack_public_path__
- /******/ __webpack_require__.p = "";
- /******/
- /******/ // Load entry module and return exports
- /******/ return __webpack_require__(__webpack_require__.s = 3);
- /******/ })
- /************************************************************************/
- /******/ ([
- /* 0 */
- /***/ (function(module, exports, __webpack_require__) {
-
- "use strict";
-
-
- Object.defineProperty(exports, "__esModule", {
- value: true
- });
-
- var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
-
- exports.configEvent = configEvent;
- exports.hook = hook;
- exports.unHook = unHook;
- /*
- * author: wendux
- * email: 824783146@qq.com
- * source code: https://github.com/wendux/Ajax-hook
- */
-
- // Save original XMLHttpRequest as _rxhr
- var realXhr = "_rxhr";
-
- function configEvent(event, xhrProxy) {
- var e = {};
- for (var attr in event) {
- e[attr] = event[attr];
- } // xhrProxy instead
- e.target = e.currentTarget = xhrProxy;
- return e;
- }
-
- function hook(proxy) {
- // Avoid double hookAjax
- window[realXhr] = window[realXhr] || XMLHttpRequest;
-
- XMLHttpRequest = function XMLHttpRequest() {
- var xhr = new window[realXhr]();
- // We shouldn't hookAjax XMLHttpRequest.prototype because we can't
- // guarantee that all attributes are on the prototype。
- // Instead, hooking XMLHttpRequest instance can avoid this problem.
- for (var attr in xhr) {
- var type = "";
- try {
- type = _typeof(xhr[attr]); // May cause exception on some browser
- } catch (e) {}
- if (type === "function") {
- // hookAjax methods of xhr, such as `open`、`send` ...
- this[attr] = hookFunction(attr);
- } else {
- Object.defineProperty(this, attr, {
- get: getterFactory(attr),
- set: setterFactory(attr),
- enumerable: true
- });
- }
- }
- var that = this;
- xhr.getProxy = function () {
- return that;
- };
- this.xhr = xhr;
- };
-
- // Generate getter for attributes of xhr
- function getterFactory(attr) {
- return function () {
- var v = this.hasOwnProperty(attr + "_") ? this[attr + "_"] : this.xhr[attr];
- var attrGetterHook = (proxy[attr] || {})["getter"];
- return attrGetterHook && attrGetterHook(v, this) || v;
- };
- }
-
- // Generate setter for attributes of xhr; by this we have an opportunity
- // to hookAjax event callbacks (eg: `onload`) of xhr;
- function setterFactory(attr) {
- return function (v) {
- var xhr = this.xhr;
- var that = this;
- var hook = proxy[attr];
- // hookAjax event callbacks such as `onload`、`onreadystatechange`...
- if (attr.substring(0, 2) === 'on') {
- that[attr + "_"] = v;
- xhr[attr] = function (e) {
- e = configEvent(e, that);
- var ret = proxy[attr] && proxy[attr].call(that, xhr, e);
- ret || v.call(that, e);
- };
- } else {
- //If the attribute isn't writable, generate proxy attribute
- var attrSetterHook = (hook || {})["setter"];
- v = attrSetterHook && attrSetterHook(v, that) || v;
- this[attr + "_"] = v;
- try {
- // Not all attributes of xhr are writable(setter may undefined).
- xhr[attr] = v;
- } catch (e) {}
- }
- };
- }
-
- // Hook methods of xhr.
- function hookFunction(fun) {
- return function () {
- var args = [].slice.call(arguments);
- if (proxy[fun]) {
- var ret = proxy[fun].call(this, args, this.xhr);
- // If the proxy return value exists, return it directly,
- // otherwise call the function of xhr.
- if (ret) return ret;
- }
- return this.xhr[fun].apply(this.xhr, args);
- };
- }
-
- // Return the real XMLHttpRequest
- return window[realXhr];
- }
-
- function unHook() {
- if (window[realXhr]) XMLHttpRequest = window[realXhr];
- window[realXhr] = undefined;
- }
-
- /***/ }),
- /* 1 */
- /***/ (function(module, exports, __webpack_require__) {
-
- "use strict";
-
-
- Object.defineProperty(exports, "__esModule", {
- value: true
- });
- exports.proxy = proxy;
- exports.unProxy = unProxy;
-
- var _xhrHook = __webpack_require__(0);
-
- var events = ['load', 'loadend', 'timeout', 'error', 'readystatechange', 'abort']; /*
- * author: wendux
- * email: 824783146@qq.com
- * source code: https://github.com/wendux/Ajax-hook
- */
-
- var eventLoad = events[0],
- eventLoadEnd = events[1],
- eventTimeout = events[2],
- eventError = events[3],
- eventReadyStateChange = events[4],
- eventAbort = events[5];
-
- var singleton,
- prototype = 'prototype';
-
- function proxy(proxy) {
- if (singleton) throw "Proxy already exists";
- return singleton = new Proxy(proxy);
- }
-
- function unProxy() {
- singleton = null;
- (0, _xhrHook.unHook)();
- }
-
- function trim(str) {
- return str.replace(/^\s+|\s+$/g, '');
- }
-
- function getEventTarget(xhr) {
- return xhr.watcher || (xhr.watcher = document.createElement('a'));
- }
-
- function triggerListener(xhr, name) {
- var xhrProxy = xhr.getProxy();
- var callback = 'on' + name + '_';
- var event = (0, _xhrHook.configEvent)({ type: name }, xhrProxy);
- xhrProxy[callback] && xhrProxy[callback](event);
- var evt;
- if (typeof Event === 'function') {
- evt = new Event(name, { bubbles: false });
- } else {
- // https://stackoverflow.com/questions/27176983/dispatchevent-not-working-in-ie11
- evt = document.createEvent('Event');
- evt.initEvent(name, false, true);
- }
- getEventTarget(xhr).dispatchEvent(evt);
- }
-
- function Handler(xhr) {
- this.xhr = xhr;
- this.xhrProxy = xhr.getProxy();
- }
-
- Handler[prototype] = Object.create({
- resolve: function resolve(response) {
- var xhrProxy = this.xhrProxy;
- var xhr = this.xhr;
- xhrProxy.readyState = 4;
- xhr.resHeader = response.headers;
- xhrProxy.response = xhrProxy.responseText = response.response;
- xhrProxy.statusText = response.statusText;
- xhrProxy.status = response.status;
- triggerListener(xhr, eventReadyStateChange);
- triggerListener(xhr, eventLoad);
- triggerListener(xhr, eventLoadEnd);
- },
- reject: function reject(error) {
- this.xhrProxy.status = 0;
- triggerListener(this.xhr, error.type);
- triggerListener(this.xhr, eventLoadEnd);
- }
- });
-
- function makeHandler(next) {
- function sub(xhr) {
- Handler.call(this, xhr);
- }
-
- sub[prototype] = Object.create(Handler[prototype]);
- sub[prototype].next = next;
- return sub;
- }
-
- var RequestHandler = makeHandler(function (rq) {
- var xhr = this.xhr;
- rq = rq || xhr.config;
- xhr.withCredentials = rq.withCredentials;
- xhr.open(rq.method, rq.url, rq.async !== false, rq.user, rq.password);
- for (var key in rq.headers) {
- xhr.setRequestHeader(key, rq.headers[key]);
- }
- xhr.send(rq.body);
- });
-
- var ResponseHandler = makeHandler(function (response) {
- this.resolve(response);
- });
-
- var ErrorHandler = makeHandler(function (error) {
- this.reject(error);
- });
-
- function Proxy(proxy) {
- var onRequest = proxy.onRequest,
- onResponse = proxy.onResponse,
- onError = proxy.onError;
-
- function handleResponse(xhr, xhrProxy) {
- var handler = new ResponseHandler(xhr);
- if (!onResponse) return handler.resolve();
- var ret = {
- response: xhrProxy.response,
- status: xhrProxy.status,
- statusText: xhrProxy.statusText,
- config: xhr.config,
- headers: xhr.resHeader || xhr.getAllResponseHeaders().split('\r\n').reduce(function (ob, str) {
- if (str === "") return ob;
- var m = str.split(":");
- ob[m.shift()] = trim(m.join(':'));
- return ob;
- }, {})
- };
- onResponse(ret, handler);
- }
-
- function onerror(xhr, xhrProxy, e) {
- var handler = new ErrorHandler(xhr);
- var error = { config: xhr.config, error: e };
- if (onError) {
- onError(error, handler);
- } else {
- handler.next(error);
- }
- }
-
- function preventXhrProxyCallback() {
- return true;
- }
-
- function errorCallback(xhr, e) {
- onerror(xhr, this, e);
- return true;
- }
-
- function stateChangeCallback(xhr, xhrProxy) {
- if (xhr.readyState === 4 && xhr.status !== 0) {
- handleResponse(xhr, xhrProxy);
- } else if (xhr.readyState !== 4) {
- triggerListener(xhr, eventReadyStateChange);
- }
- return true;
- }
-
- return (0, _xhrHook.hook)({
- onload: preventXhrProxyCallback,
- onloadend: preventXhrProxyCallback,
- onerror: errorCallback,
- ontimeout: errorCallback,
- onabort: errorCallback,
- onreadystatechange: function onreadystatechange(xhr) {
- return stateChangeCallback(xhr, this);
- },
- open: function open(args, xhr) {
- var _this = this;
- var config = xhr.config = { headers: {} };
- config.method = args[0];
- config.url = args[1];
- config.async = args[2];
- config.user = args[3];
- config.password = args[4];
- config.xhr = xhr;
- var evName = 'on' + eventReadyStateChange;
- if (!xhr[evName]) {
- xhr[evName] = function () {
- return stateChangeCallback(xhr, _this);
- };
- }
-
- var defaultErrorHandler = function defaultErrorHandler(e) {
- onerror(xhr, _this, (0, _xhrHook.configEvent)(e, _this));
- };
- [eventError, eventTimeout, eventAbort].forEach(function (e) {
- var event = 'on' + e;
- if (!xhr[event]) xhr[event] = defaultErrorHandler;
- });
-
- // 如果有请求拦截器,则在调用onRequest后再打开链接。因为onRequest最佳调用时机是在send前,
- // 所以我们在send拦截函数中再手动调用open,因此返回true阻止xhr.open调用。
- //
- // 如果没有请求拦截器,则不用阻断xhr.open调用
- if (onRequest) return true;
- },
- send: function send(args, xhr) {
- var config = xhr.config;
- config.withCredentials = xhr.withCredentials;
- config.body = args[0];
- if (onRequest) {
- // In 'onRequest', we may call XHR's event handler, such as `xhr.onload`.
- // However, XHR's event handler may not be set until xhr.send is called in
- // the user's code, so we use `setTimeout` to avoid this situation
- var req = function req() {
- onRequest(config, new RequestHandler(xhr));
- };
- config.async === false ? req() : setTimeout(req);
- return true;
- }
- },
- setRequestHeader: function setRequestHeader(args, xhr) {
- // Collect request headers
- xhr.config.headers[args[0].toLowerCase()] = args[1];
- return true;
- },
- addEventListener: function addEventListener(args, xhr) {
- var _this = this;
- if (events.indexOf(args[0]) !== -1) {
- var handler = args[1];
- getEventTarget(xhr).addEventListener(args[0], function (e) {
- var event = (0, _xhrHook.configEvent)(e, _this);
- event.type = args[0];
- event.isTrusted = true;
- handler.call(_this, event);
- });
- return true;
- }
- },
- getAllResponseHeaders: function getAllResponseHeaders(_, xhr) {
- var headers = xhr.resHeader;
- if (headers) {
- var header = "";
- for (var key in headers) {
- header += key + ': ' + headers[key] + '\r\n';
- }
- return header;
- }
- },
- getResponseHeader: function getResponseHeader(args, xhr) {
- var headers = xhr.resHeader;
- if (headers) {
- return headers[(args[0] || '').toLowerCase()];
- }
- }
- });
- }
-
- /***/ }),
- /* 2 */,
- /* 3 */
- /***/ (function(module, exports, __webpack_require__) {
-
- "use strict";
-
-
- Object.defineProperty(exports, "__esModule", {
- value: true
- });
- exports.ah = undefined;
-
- var _xhrHook = __webpack_require__(0);
-
- var _xhrProxy = __webpack_require__(1);
-
- // ah(ajax hook)
- /*
- * author: wendux
- * email: 824783146@qq.com
- * source code: https://github.com/wendux/Ajax-hook
- */
-
- var ah = exports.ah = {
- proxy: _xhrProxy.proxy,
- unProxy: _xhrProxy.unProxy,
- hook: _xhrHook.hook,
- unHook: _xhrHook.unHook
- };
-
- /***/ })
- /******/ ])));
-
- //ajaxhook.min.js used to hook the ajax of the page to change the data.
-
- resolve();
- })
- },[],function(){
- unsafeWindow.ah.hook({
- responseText: {
- getter: ajaxReParse
- },
- response: {
- getter:ajaxReParse
- }
- });
-
- function ajaxReParse(v){
- var temp=JSON.parse(v);
- if(temp&&temp.songs){
- for(let song of temp.songs){
- song.is_douban_playable=true;
- song.status=0;
- song.playable=true;
- song.is_royal=true;
- song.is_site_song=true;
- if(song.item_info){
- song.item_info.comment="";
- }
- }
- }
- if(temp&&temp[0]&&(temp[0].is_douban_playable!==undefined)){
- for(let song of temp){
- song.is_douban_playable=true;
- song.status=0;
- song.playable=true;
- song.is_royal=true;
- song.is_site_song=true;
- }
- }
- if(temp&&temp.songlist){
- for(let song of temp.songlist.songs){
- song.is_douban_playable=true;
- song.status=0;
- song.playable=true;
- song.is_royal=true;
- song.is_site_song=true;
- }
- }
- return JSON.stringify(temp);
- }
- })
-
- function executePageFunc(func, argus = [], after) {
- if (window.executePageFuncIndexor === undefined) {
- window.executePageFuncIndexor = 0;
- }
- if (!document.querySelector("#zd_executePageFuncPromiseResult_ele")) {
- document.documentElement.insertAdjacentHTML("beforeend","<span id='zd_executePageFuncPromiseResult_ele' style='display:none;'></span>");
- }
- if (after) {
- var promiseSessionStorageName = "zd_excutePageFuncPromise_result_" + (executePageFuncIndexor++) + "_" + (new Date()).getTime();
- var observer = new MutationObserver(function (mutationsList) {
- if (document.querySelector("#zd_executePageFuncPromiseResult_ele").getAttribute("data-result-name") == promiseSessionStorageName) {
- after();
- var result;
- try {
- result = JSON.parse(sessionStorage[promiseSessionStorageName]);
- } catch (e) {
- result = null;
- }
- after(result);
- observer.disconnect();
- }
- });
- observer.observe(document.querySelector("#zd_executePageFuncPromiseResult_ele"), {
- "attributes": true,
- "attributeFilter": ["data-result-name"]
- });
- }
- var ele = document.createElement("script");
- ele.innerHTML = "sessionStorage.zd_executePageFuncTempResult=JSON.stringify((" + func.toString() + ")(...JSON.parse('" + JSON.stringify(argus) + "'))" +
- (after ? (".then(function(result){sessionStorage." + promiseSessionStorageName + "=JSON.stringify(result);document.getElementById('zd_executePageFuncPromiseResult_ele').setAttribute('data-result-name','" + promiseSessionStorageName + "')})") : "") +
- ");";
- document.documentElement.appendChild(ele);
- var result;
- try {
- result = JSON.parse(sessionStorage.zd_executePageFuncTempResult);
- } catch (e) {
- result = null;
- }
- return result;
- }
-
- })();