// ==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 // @downloadURL https://update.greasyfork.icu/scripts/433632/%E8%B1%86%E7%93%A3FM%20%E7%BA%A2%E5%BF%83%E6%AD%8C%E5%8D%95%E6%81%A2%E5%A4%8D%E6%92%AD%E6%94%BE.user.js // @updateURL https://update.greasyfork.icu/scripts/433632/%E8%B1%86%E7%93%A3FM%20%E7%BA%A2%E5%BF%83%E6%AD%8C%E5%8D%95%E6%81%A2%E5%A4%8D%E6%92%AD%E6%94%BE.meta.js // ==/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",""); } 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; } })();