Greasy Fork

Greasy Fork is available in English.

QQ音乐歌单一键下载到本地

QQ音乐歌单一键式本地下载、音乐下载。(注意:使用前请登录qq音乐账号,再下载音乐,若遇到下载失败,请刷新后重试,或者检查网络流畅)使用流程: 进入qq音乐官网https://y.qq.com/n/ryqq。再选择需要下载的歌单播放歌单全部音乐。进入播放界面提示是否下载。点击确认获取本地音乐(歌曲多可能需要一段时间)。等待一段时间后,即可下载歌单内全部音乐。(适用于u盘音响设备,或者车内音响设备音乐下载本地)*****请勿运用到商业用途。若用于商业用途与本人无关。

当前为 2024-08-11 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name       QQ音乐歌单一键下载到本地
// @namespace  npm/vite-plugin-monkey
// @version    0.0.0
// @author     lsq_li
// @icon       https://vitejs.dev/logo.svg
// @match      https://y.qq.com/n/ryqq/player
// @description QQ音乐歌单一键式本地下载、音乐下载。(注意:使用前请登录qq音乐账号,再下载音乐,若遇到下载失败,请刷新后重试,或者检查网络流畅)使用流程: 进入qq音乐官网https://y.qq.com/n/ryqq。再选择需要下载的歌单播放歌单全部音乐。进入播放界面提示是否下载。点击确认获取本地音乐(歌曲多可能需要一段时间)。等待一段时间后,即可下载歌单内全部音乐。(适用于u盘音响设备,或者车内音响设备音乐下载本地)*****请勿运用到商业用途。若用于商业用途与本人无关。
// @license    GPL License
// @require    https://cdn.jsdelivr.net/npm/[email protected]/umd/react.production.min.js
// @require    https://cdn.jsdelivr.net/npm/[email protected]/umd/react-dom.production.min.js
// ==/UserScript==

(function (require$$0, require$$0$1) {
  'use strict';

  var __defProp = Object.defineProperty;
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
  var jsxRuntime = { exports: {} };
  var reactJsxRuntime_production_min = {};
  /**
   * @license React
   * react-jsx-runtime.production.min.js
   *
   * Copyright (c) Facebook, Inc. and its affiliates.
   *
   * This source code is licensed under the MIT license found in the
   * LICENSE file in the root directory of this source tree.
   */
  var f = require$$0, k = Symbol.for("react.element"), l = Symbol.for("react.fragment"), m$1 = Object.prototype.hasOwnProperty, n = f.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner, p = { key: true, ref: true, __self: true, __source: true };
  function q(c, a, g) {
    var b, d = {}, e = null, h = null;
    void 0 !== g && (e = "" + g);
    void 0 !== a.key && (e = "" + a.key);
    void 0 !== a.ref && (h = a.ref);
    for (b in a) m$1.call(a, b) && !p.hasOwnProperty(b) && (d[b] = a[b]);
    if (c && c.defaultProps) for (b in a = c.defaultProps, a) void 0 === d[b] && (d[b] = a[b]);
    return { $$typeof: k, type: c, key: e, ref: h, props: d, _owner: n.current };
  }
  reactJsxRuntime_production_min.Fragment = l;
  reactJsxRuntime_production_min.jsx = q;
  reactJsxRuntime_production_min.jsxs = q;
  {
    jsxRuntime.exports = reactJsxRuntime_production_min;
  }
  var jsxRuntimeExports = jsxRuntime.exports;
  var client = {};
  var m = require$$0$1;
  {
    client.createRoot = m.createRoot;
    client.hydrateRoot = m.hydrateRoot;
  }
  const syncRecursive = (data, index, callback, asnyCallback) => {
    if (index >= data.length) {
      callback(data);
      return;
    }
    console.log("Processing data:", data[index]);
    if (asnyCallback) asnyCallback(index);
    const audio = document.querySelector("audio");
    data[index] = { ...data[index], downUrl: audio.src };
    const btn = document.querySelector(".btn_big_next");
    btn.click();
    setTimeout(() => {
      syncRecursive(data, index + 1, callback, asnyCallback);
    }, 2e3);
  };
  const splitAndMoveElement = (arr, targetId) => {
    const targetIndex = arr.findIndex((item) => item.id === targetId);
    if (targetIndex === -1) {
      return arr;
    } else if (targetIndex === 0) {
      return arr;
    }
    const afterTargetElements = arr.slice(targetIndex);
    const beforeTargetElements = arr.slice(0, targetIndex - 1);
    return [...afterTargetElements, ...beforeTargetElements];
  };
  class FileDownloader {
    constructor(maxConcurrentDownloads = 1) {
      __publicField(this, "maxConcurrentDownloads");
      __publicField(this, "downloadQueue");
      __publicField(this, "numActiveDownloads");
      this.maxConcurrentDownloads = maxConcurrentDownloads;
      this.downloadQueue = [];
      this.numActiveDownloads = 0;
    }
    addToDownloadQueue(fileUrl, fileName) {
      this.downloadQueue.push({ fileUrl, fileName });
      this.processDownloadQueue();
    }
    processDownloadQueue() {
      while (this.numActiveDownloads < this.maxConcurrentDownloads && this.downloadQueue.length > 0) {
        const { fileUrl, fileName } = this.downloadQueue.shift();
        this.startDownload(fileUrl, fileName);
      }
    }
    startDownload(fileUrl, fileName) {
      this.numActiveDownloads++;
      fetch(fileUrl).then((response) => {
        return response.blob();
      }).then((blob) => {
        this.downloadFile(blob, fileName);
      }).catch((error) => {
        console.error("Error downloading file:", error);
      }).finally(() => {
        this.numActiveDownloads--;
        this.processDownloadQueue();
      });
    }
    downloadFile(blob, fileName) {
      const url = URL.createObjectURL(blob);
      const link = document.createElement("a");
      link.href = url;
      link.setAttribute("download", fileName + ".mp3");
      document.body.appendChild(link);
      link.click();
      document.body.removeChild(link);
      URL.revokeObjectURL(url);
    }
    async downloadFileConvert(response, fileName) {
      const file = new File([await response.blob()], fileName, { type: response.headers.get("content-type") });
      const formData = new FormData();
      formData.append("file", file);
      formData.append("targetformat", "mp3");
      formData.append("audiobitratetype", "0");
      formData.append("customaudiobitrate", "");
      formData.append("audiosamplingtype", "0");
      formData.append("customaudiosampling", "");
      formData.append("code", "82000");
      formData.append("filelocation", "local");
      formData.append("legal", "Our PHP programs can only be used in aconvert.com. We DO NOT allow using our PHP programs in any third-party websites, software or apps. We will report abuse to your cloud provider, Google Play and App store if illegal usage found!");
      const uploadResponse = await fetch("/postFilesToMp3/convert/convert9.php", {
        method: "POST",
        body: formData
      });
      if (uploadResponse.state === "SUCCESS") {
        console.log("SUCCESS");
      } else {
        console.error("Error uploading file:", await uploadResponse.text());
      }
    }
  }
  function App(props) {
    const [loadding, setLoading] = require$$0.useState(false);
    const [process, setProcess] = require$$0.useState(0);
    const [totalNum, setTotalNum] = require$$0.useState(0);
    require$$0.useEffect(() => {
      if (!window.isExceOne) {
        window.isExceOne = true;
        const msg = confirm("是否下载播放列表音乐.tip: 下载网页播放器内全部音乐,若需要挑选请点击取消,修改播放器内音乐,刷新页面点击确认等待全部下载!!!");
        if (msg === true) {
          setLoading(true);
          const body = document.querySelector("#app");
          body.style.visibility = "hidden";
          const addXMLRequestCallback = (callback) => {
            let oldSend = null;
            let i = null;
            if (XMLHttpRequest.callbacks) {
              XMLHttpRequest.callbacks.push(callback);
            } else {
              XMLHttpRequest.callbacks = [callback];
              oldSend = XMLHttpRequest.prototype.send;
              XMLHttpRequest.prototype.send = function() {
                for (i = 0; i < XMLHttpRequest.callbacks.length; i++) {
                  XMLHttpRequest.callbacks[i](this);
                }
                oldSend.apply(this, arguments);
              };
            }
          };
          addXMLRequestCallback((xhr) => {
            xhr.addEventListener("loadend", function() {
              var _a, _b, _c;
              if (xhr.readyState == 4 && xhr.status == 200) {
                if (xhr.responseURL.indexOf("cgi-bin/musics.fcg") !== -1) {
                  let list = JSON.parse(xhr.response);
                  let preUrl = void 0;
                  let songList = void 0;
                  let songId = void 0;
                  let songName = void 0;
                  (_a = Object.keys(list)) == null ? void 0 : _a.forEach((item) => {
                    var _a2, _b2, _c2, _d, _e, _f, _g, _h;
                    if (preUrl === void 0) {
                      preUrl = (_d = (_c2 = (_b2 = (_a2 = list[item]) == null ? void 0 : _a2.data) == null ? void 0 : _b2.midurlinfo) == null ? void 0 : _c2[0]) == null ? void 0 : _d.purl;
                    }
                    if (songList === void 0) {
                      songList = (_f = (_e = list[item]) == null ? void 0 : _e.data) == null ? void 0 : _f.tracks;
                    }
                    if (songId === void 0) {
                      songId = (_h = (_g = list[item]) == null ? void 0 : _g.data) == null ? void 0 : _h.songID;
                    }
                  });
                  if (songId !== void 0) {
                    songName = (_c = (_b = songList == null ? void 0 : songList.filter(
                      (item) => (item == null ? void 0 : item.id) === songId
                    )) == null ? void 0 : _b[0]) == null ? void 0 : _c.name;
                    songList == null ? void 0 : songList.findIndex(
                      (item) => (item == null ? void 0 : item.id) === songId
                    );
                    songList = splitAndMoveElement(songList, songId);
                    setTotalNum(songList == null ? void 0 : songList.length);
                  }
                  if (preUrl !== void 0 && songName !== void 0) {
                    const btn = document.querySelector(".btn_big_next");
                    btn.click();
                    songList[0] = {
                      ...songList[0],
                      downUrl: "https://ws6.stream.qqmusic.qq.com/" + preUrl
                    };
                    syncRecursive(
                      songList,
                      1,
                      (data) => {
                        console.log(data, "allData");
                        const fileDownloader2 = new FileDownloader(songList == null ? void 0 : songList.length);
                        songList == null ? void 0 : songList.forEach(
                          (item, i) => {
                            setTimeout(() => {
                              fileDownloader2.addToDownloadQueue(
                                item == null ? void 0 : item.downUrl,
                                item == null ? void 0 : item.name
                              );
                            }, 800 * i);
                          }
                        );
                        const body2 = document.querySelector("#app");
                        body2.style.visibility = "visible";
                        setLoading(false);
                      },
                      (index) => {
                        setProcess(index);
                      }
                    );
                    console.log(preUrl, "aaaa");
                  }
                }
              }
            });
          });
        }
      }
    }, []);
    return loadding ? /* @__PURE__ */ jsxRuntimeExports.jsxs(
      "div",
      {
        style: {
          width: "100%",
          height: "100vh",
          zIndex: 999999,
          background: "#cecece",
          fontSize: 24,
          color: "white",
          position: "absolute",
          top: 0,
          left: 0
        },
        children: [
          "下载中... ",
          "(" + process + "/" + totalNum + ")"
        ]
      }
    ) : /* @__PURE__ */ jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment, {});
  }
  const fileDownloader = new FileDownloader(10);
  client.createRoot(
    (() => {
      const app = document.createElement("div");
      document.body.append(app);
      return app;
    })()
  ).render(
    /* @__PURE__ */ jsxRuntimeExports.jsx(require$$0.StrictMode, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(
      App,
      {
        DownloadList: (url, filename) => fileDownloader.addToDownloadQueue(url, filename)
      }
    ) })
  );

})(React, ReactDOM);