Greasy Fork

Greasy Fork is available in English.

qq-music-download

下载歌单内全部音乐。请勿运用到商业用途。若用于商业用途与本人无关。

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

// ==UserScript==
// @name       qq-music-download
// @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 下载歌单内全部音乐。请勿运用到商业用途。若用于商业用途与本人无关。
// @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);