// ==UserScript==
// @name:en Userscript Helper for Flat-Style Netease Music Userstyle 适用于网易云音乐扁平风格样式表的辅助用户脚本
// @description:en Provides a better experience for Flat-Style Netease Music Userstyle. 为网易云音乐扁平风格样式表提供更佳的用户体验。
// @name:zh 适用于网易云音乐扁平风格样式表的辅助用户脚本
// @description:zh 为网易云音乐扁平风格样式表提供更佳的用户体验。
// @name 适用于网易云音乐扁平风格样式表的辅助用户脚本
// @description 为网易云音乐扁平风格样式表提供更佳的用户体验。
// @namespace wTonyChen.flatnmusich
// @version 0.2.18-0.9.20
// @author wTonyChen
// @copyright 2022 wTonyChen (https://github.com/wTonyChen)
// @compatible chrome 101+
// @compatible edge 101+
// @compatible opera 87+
// @compatible firefox 100+ 有限支持
// @license GPL-3.0-or-later
// @homepage https://wtonychen.github.io/flatnmusic/
// @supportURL https://github.com/wTonyChen/flatnmusic/issues
// @match http*://music.163.com/*
// @run-at document-end
// @grant none
// ==/UserScript==
!(function () {
"use strict";
let e = "0.2.18-0.9.20",
t = "wk-fnm-hi-cfg",
l = document.querySelector("." + t);
l ||
((l = document.createElement("div")),
(l.className = t),
document.body.appendChild(l));
let s,
a = getComputedStyle(l),
i = {
86: "1f603",
85: "1f60a",
359: "263a",
95: "1f60d",
363: "1f618",
96: "1f631",
356: "1f62d",
362: "1f619",
352: "1f633",
87: "1f61e",
343: "1f601",
348: "1f61d",
353: "1f612",
361: "1f621",
341: "1f60f",
97: "1f613",
346: "1f616",
354: "1f630",
350: "1f628",
351: "1f637",
357: "1f602",
355: "1f635",
115: "1f47f",
360: "1f604",
94: "1f61c",
342: "1f614",
358: "1f622",
33: "2764",
34: "1f494",
303: "1f498",
309: "2b50",
314: "1f4a2",
89: "1f4a9",
13: "1f44d",
372: "1f44e",
14: "1f64f",
379: "1f46b",
380: "1f46f",
374: "1f645",
262: "1f481",
106: "1f48f",
376: "1f491",
367: "1f444",
81: "1f436",
78: "1f431",
100: "1f437",
459: "1f430",
450: "1f424",
461: "1f414",
116: "1f47b",
411: "1f385",
101: "1f47d",
52: "1f48e",
107: "1f381",
0: "1f466",
1: "1f467",
337: "1f382",
186: "1f51e",
312: "2b55",
313: "274c",
},
n = "/style/web2/emt/emoji_",
x = (e) => {
let t = a.getPropertyValue("--" + e);
if (t)
try {
t &&
t.indexOf("/") > -1 &&
(t = decodeURIComponent(t.replace(/\//g, "%")));
} catch (e) {}
return (
((0 === t.indexOf('"') && t.lastIndexOf('"') === t.length - 1) ||
(0 === t.indexOf("'") && t.lastIndexOf("'") === t.length - 1)) &&
(t = t.substr(1, t.length - 2)),
t
);
},
r = (e) => {
let t;
return window.localStorage && (t = localStorage.getItem(e)), t;
},
c = (e, t) => {
window.localStorage && localStorage.setItem(e, t);
},
o = x("wkhi-a"),
d = x("wkhi-b");
if (!d) return void l.parentElement.removeChild(l);
document.documentElement.setAttribute("wk-style-assist", "true");
let p = r("wkoptin") || !1,
f = function () {
let e = arguments[0];
for (let t = 1; t < arguments.length; t++) {
let l = RegExp("\\{" + t + "\\}", "g");
e = e.replace(l, arguments[t]);
}
return e;
};
((e) => {
let t,
l = 0,
s = !1,
a = document.querySelector("#g-topbar"),
i = document.querySelector("#g_iframe"),
n = 0,
x = 0,
c = !0;
if (!a || !Object.is(window.self, window.top)) return;
let o = 1.6 * a.getBoundingClientRect().height,
d = (e) => {
t && t.cancel(),
(x = 0),
(n = 0),
(l = 0),
(c = !1),
(t = a.animate([{ transform: "translateY(0)" }], {
duration: 200,
fill: "backwards",
easing: "cubic-bezier(.16,1,.29,.99)",
})),
(t.onfinish = (e) => {
(c = !0), (a.style.transform = "translateY(0)");
});
};
i.addEventListener("load", (e) => {
i.contentWindow.addEventListener("beforeunload", d),
i.contentDocument.addEventListener("scroll", (e) => {
c || t.cancel(),
(l = i.contentWindow.scrollY),
s ||
(window.requestAnimationFrame((e) => {
((e) => {
if (r("wksdscrolling")) {
let t = e - n;
(x = Math.max(Math.min(x + t, o), 0)),
(a.style.top = "0 !important"),
(a.style.transform = `translateY(-${x}px)`);
} else (a.style.top = ""), (a.style.transform = ""), (x = 0);
n = e;
})(l),
(s = !1);
}),
(s = !0));
});
});
})();
let m = "",
b = (e) => {
let t = document.querySelector("a.u-btni-fav-dis,a.u-btni-fav-dis2");
if (t) {
let e = t.parentElement.querySelector("[data-res-id]");
e &&
((t.href = "/playlist?id=" + e.dataset.resId),
(t.innerHTML =
"<i title='跳转到歌单'>前往歌单</i>"),
t.classList.remove("u-btni-fav-dis", "u-btni-fav-dis2"));
}
};
r("wkstoplistjump") &&
0 === location.pathname.indexOf("/discover/toplist") &&
b(),
r("wksmylistjump") &&
0 === location.pathname.indexOf("/my") &&
setInterval((e) => b(), 1e3);
let u = (e) => {
let t = "" + e,
l = 0;
for (let e = 0; e < t.length; e++) l += t[e].charCodeAt();
return l;
},
w = (e) => {
if (!Object.is(window.self, window.top)) return;
let t = document.querySelectorAll(
".m-playbar .listlyric>p:not(.wk-upgraded)"
);
for (let e = 0; e < t.length; e++)
(t[e].innerText = t[e].innerText.split("\n")[0]),
(t[e].innerHTML = t[e].innerHTML.replace(/\ /g, " ")),
t[e].classList.add("wk-upgraded");
};
r("wklrctrans") && document.body.classList.add("wk-playlist-applied"),
(DocumentFragment.prototype.appendChildHost =
DocumentFragment.prototype.appendChild),
(DocumentFragment.prototype.appendChild = function () {
if (
r("wksplayinguiani") &&
arguments[0].classList.contains("m-layer") &&
arguments[0].parentElement
) {
let e = arguments[0].cloneNode(!0);
arguments[0].dataset &&
arguments[0].dataset.wkAdvisedSize &&
((e.style.minHeight = arguments[0].dataset.wkAdvisedSize + "px"),
(arguments[0].dataset.wkAdvisedSize = "")),
arguments[0].parentElement.insertBefore(e, arguments[0]),
e.addEventListener("animationend", (t) => {
e.remove();
}),
e.classList.add("hidden");
}
let e = "",
t = r("wkspipfont"),
l = r("wkspipfont2"),
s = r("wkspipfsize"),
a = r("wkspipfweight"),
i = r("wkspipletterspacing"),
n = r("wkspipwordspacing"),
x = r("wkspiplinespacing"),
c = r("wkspiplineheight"),
o = r("wkspipcustomstyle");
if ("STYLE" == arguments[0].tagName) {
r("wklrctrans") && (e += ".container>.line>.compare{display:none}");
let d = [];
t && d.push(`"${t.replace(/"/g, '\\"')}"`),
l && d.push(`"${l.replace(/"/g, '\\"')}"`),
d.length > 0 &&
(e += `.container{font-family:${d.join(",")} !important}`),
a &&
!isNaN(+a) &&
(e += `.container,.container *{font-weight:${+a} !important}`),
s &&
!isNaN(+s) &&
(e += `.container>.line>.compare,.container>.line>.origin{font-size:${+s}px !important}`),
i &&
!isNaN(+i) &&
(e += `.container,.container *{letter-spacing:${+i}px !important}`),
n &&
!isNaN(+n) &&
(e += `.container,.container *{word-spacing:${+n}px !important}`),
x &&
!isNaN(+x) &&
(e += `.container>.line{padding:${+x}px 0 !important}`),
c &&
!isNaN(+c) &&
(e += `.container>.line{line-height:${+c}px !important}`),
e &&
(this.appendChildHost.call(
this,
document.createElement("style")
).innerHTML = e),
o &&
(this.appendChildHost.call(
this,
document.createElement("style")
).innerHTML = o);
}
if (!r("wksplayinguiani") || "g_playlist" != arguments[0].id)
return this.appendChildHost.call(this, ...arguments);
arguments[0].classList.add("hidden"),
document.body.classList.remove("wk-playlist-showing");
}),
(Element.prototype.appendChildHost = Element.prototype.appendChild),
(Element.prototype.appendChild = function () {
return (
r("wksplayinguiani") &&
"g_playlist" == arguments[0].id &&
(arguments[0].classList.remove("hidden"),
document.body.classList.add("wk-playlist-showing")),
r("wksplayinguiani") &&
arguments[0].classList &&
arguments[0].classList.contains("m-layer") &&
arguments[0].dataset &&
setTimeout((e) => {
arguments[0].dataset.wkAdvisedSize = arguments[0].clientHeight;
}, 50),
r("wklrctrans") && "g_playlist" == arguments[0].id && setTimeout(w, 50),
this.appendChildHost.call(this, ...arguments)
);
}),
((e) => {
if (r("wklistdisd") && !e) return;
let t = x("wkhi-c"),
l = x("wkhi-d");
if (!t || !l) return;
(t = t.split("|")), (l = l.split("|"));
let s = e ? 31536e5 : 1,
a = (t, l) => {
let a =
`${t};path=${l};max-age=${s}` +
(e ? "" : `;expires=${new Date(70).toGMTString()}`);
document.cookie = a;
};
for (let e = 0; e < t.length; e++)
for (let s = 0; s < l.length; s++) a(t[e], l[s]);
c("wklistdisd", e ? 0 : 1);
})(!!r("wksfullpl")),
r("wkslowcontrast") &&
Object.is(window.self, window.top) &&
(document.documentElement.style.filter = "contrast(.8)"),
r("wkslowbrightness") &&
Object.is(window.self, window.top) &&
(document.documentElement.style.filter =
document.documentElement.style.filter + " brightness(.5)");
let g = {
kw7: (e) => {
!isNaN(+e) &&
+e > 99999 &&
+e < 1e6 &&
alert(
((e) => {
let t = "" + e,
l = 0,
s = t.length;
for (let e = 0; e < s; e++) {
let a = (
t[e].codePointAt() * (s - e) * (e + 1) +
1 +
e
).toString(26);
l += a
.substr(a.length - 1, 1)
.toUpperCase()
.codePointAt();
}
let a = ((9301 * l + 49297) % 233280) / 233280;
return Math.round(1e5 + 899999 * a);
})(e)
);
},
},
y = (e) => {
if (
(r("wklrctrans") && w(),
r("wkshiresimages") &&
((e) => {
let t = document.querySelectorAll("img[data-src]");
for (let e = 0; e < t; e++)
t[e].dataset.src &&
"" == t[e].src &&
(t[e].src = t[e].dataset.src);
let l = document.querySelectorAll('img[src*="param="]');
for (let e = 0; e < l.length; e++) {
let t = l[e].src.split("?")[0];
if (l[e].src != t) {
let s = new Image(),
a = (i) => {
l[e] &&
(l[e].src.split("?")[0] == t &&
((l[e].src = t), l[e].classList.add("wk-hires-loaded")),
s.removeEventListener("load", a, !1));
};
s.addEventListener("load", a, !1),
l[e].classList.remove("wk-hires-loaded"),
(s.src = t);
}
}
})(),
r("wksemojisym") &&
((e) => {
let t = document.querySelectorAll(`img[src*="${n}"]`);
for (let e = 0; e < t.length; e++) {
let l = t[e].src.split(n)[1];
l &&
((l = l.split(".")[0]),
!isNaN(+l) &&
i[+l] &&
(t[e].src =
"data:image/svg+xml;charset=utf-8," +
encodeURIComponent(
[
"<svg",
'xmlns="http://www.w3.org/2000/svg"',
'width="21"',
'height="21"><text',
'x="10.5"',
'y="12.4"',
"style=\"text-anchor:middle;dominant-baseline:middle;font-size:14px;font-family:'Apple",
"Color",
"Emoji','Noto",
"Color",
"Emoji','Segoe",
"UI",
`Emoji'">&#x${i[+l]};</text></svg>`,
].join(" ")
)));
}
})(),
r("wksadptbg") &&
Object.is(window.self, window.top) &&
((e) => {
let t = document.querySelector(".m-playbar .head img"),
l = document.querySelector(".m-playbar");
if (t && l && t.src && t.src != m) {
l.classList.add("wksplybrbg");
let e = t.src;
e.indexOf("?") < 0 && (e += "?param=34y34"),
(l.style.cssText = `--a_plybarimgsrc:url(${e})`),
(m = t.src);
}
})(),
r("wksimprovedlook"))
) {
if ("user" == location.pathname.substring(1).split("/")[0]) {
let e = document.querySelector(".m-proifo dt img"),
t = document.querySelector(".g-bd");
e &&
e.src &&
t &&
(document.documentElement.classList.add("has-upb"),
(t.style.cssText = `--upb:url("${e.src}")`));
let l = document.querySelector(".m-proifo .name .tit"),
s = document.querySelector(".m-proifo .name #j-name-wrap");
l &&
s &&
((s.dataset.wkUsernameFull = s.title = l.innerText),
s.classList.add("wk-full-username"));
}
let e = document.querySelector(".g-wrap>.m-info .cover img"),
t = document.querySelector(".g-wrap>.m-info");
e &&
t &&
(document.documentElement.classList.add("has-mib"),
(t.style.cssText = `--mib:url("${e.src}")`));
}
let t =
location.hash &&
("video" == location.hash.substring(2).split("?")[0].split("/")[0] ||
"mv" == location.hash.substring(2).split("?")[0].split("/")[0]),
l = "/" == location.pathname,
a =
"video" == location.pathname.substring(1).split("/")[0] ||
"mv" == location.pathname.substring(1).split("/")[0];
if (
r("wksmusicsessionmeta") &&
"mediaSession" in navigator &&
(a || (l && !t))
) {
let t = document.querySelector(
a ? ".n-mv .title h2" : ".m-playbar .words .name"
),
l = document.querySelector(
a ? ".n-mv .title .name" : ".m-playbar .words .by"
),
i = document.querySelector(
a ? ".m-ctvideo .poster .pic" : ".m-playbar .head img"
),
n = [],
x =
(document.querySelector(a ? null : ".m-playbar .btns .prv"),
document.querySelector(
a
? ".m-ctvideo.z-play .controls .wrap .play"
: ".m-playbar .btns .ply"
),
document.querySelector(a ? null : ".m-playbar .btns .nxt"),
document.querySelector(a ? ".m-ctvideo" : ".m-playbar .btns .ply"));
(x = x
? x.classList.contains(a ? "z-play" : "pas")
? "playing"
: x.classList.contains(a ? "z-pause" : "ply")
? "paused"
: "none"
: "none"),
i &&
i.src &&
(n = [
{
src: i.src.split("?")[0] + "?param=96y96",
sizes: "96x96",
type: "image/jpeg",
},
{
src: i.src.split("?")[0] + "?param=128y128",
sizes: "128x128",
type: "image/jpeg",
},
{
src: i.src.split("?")[0] + "?param=192y192",
sizes: "192x192",
type: "image/jpeg",
},
{
src: i.src.split("?")[0] + "?param=256y256",
sizes: "256x256",
type: "image/jpeg",
},
{
src: i.src.split("?")[0] + "?param=384y384",
sizes: "384x384",
type: "image/jpeg",
},
{
src: i.src.split("?")[0] + "?param=512y512",
sizes: "512x512",
type: "image/jpeg",
},
{ src: i.src.split("?")[0], sizes: "any", type: "image/jpeg" },
]);
try {
let e = {
title: t ? t.innerText : document.title,
artist: l ? l.innerText : "",
album: l ? l.innerText : "",
artwork: n,
};
!((e, t) => {
if ("object" == typeof e)
try {
e = JSON.stringify(e);
} catch (e) {}
if ("object" == typeof t)
try {
t = JSON.stringify(t);
} catch (e) {}
return e == t;
})(e, s) &&
a &&
((s = e), (navigator.mediaSession.metadata = new MediaMetadata(s)));
} catch (e) {}
}
};
y(),
window.setInterval(y, 500),
d &&
(function () {
if ("/user/update" == location.pathname) {
let t = (t) => {
let l = document.querySelector("#baseBox");
if (l) {
((e = 0, t = 0) => {
let l = ("" + e).split("."),
s = ("" + t).split(".");
for (let e = 0; e < Math.max(l.length, s.length); e++) {
let t = u(l[e] ? s[e] : 0),
a = u(s[e] ? s[e] : 0);
if (t > a) return !1;
if (t < a) return !0;
}
})(e.split("-")[1], o);
let t = `<div class="item"><h3><span class="f-fs1">辅助脚本设置</span><span class="sub s-fc3">辅助脚本版本:${e}</span><span class="sub s-fc3">样式表版本:${o}</span></h3><ul class="n-plist n-plist-1" data-prompt-prefix="请输入">{1}</ul></div>`,
s =
'<li><label><input type="checkbox" class="f-rdi" {2}>{1}</label></li>',
a =
'<li class="wk-settings-button-line"><a class="u-btn2 u-btn2-2 u-btn2-w2" href="javascript:;" {2}><i>{3}</i></a> <label>{1}</label></li>',
i = [
{
label:
"样式表增强外观",
lsm: "wksimprovedlook",
},
{
label:
"显示歌单内全部音乐",
lsm: "wksfullpl",
},
{
label: "显示高清图片",
lsm: "wkshiresimages",
},
{
label:
"视频页面媒体信息显示支持",
lsm: "wksmusicsessionmeta",
test: "'mediaSession' in navigator",
},
{
label:
"顶栏动态固定 (忽略顶栏滚动状态设置)",
lsm: "wksdscrolling",
},
{
label:
"表情图片以系统 Emoji 表情显示",
lsm: "wksemojisym",
},
{
label:
"正在播放歌单界面和窗口的增强动画 (刷新页面应用更改)",
lsm: "wksplayinguiani",
},
{
label:
"排行榜页面的收藏按钮跳转到对应歌单",
lsm: "wkstoplistjump",
},
{
label:
"我的音乐中歌单的收藏按钮跳转到对应歌单",
lsm: "wksmylistjump",
},
{
label:
"隐藏正在播放界面和画中画歌词翻译",
lsm: "wklrctrans",
},
{
label:
"降低页面亮度 (刷新页面应用更改)",
lsm: "wkslowbrightness",
},
{
label:
"降低页面对比度 (刷新页面应用更改)",
lsm: "wkslowcontrast",
},
{
label:
"播放底栏和歌词动态背景 (Beta)",
lsm: "wksadptbg",
},
{
label:
"画中画显示首选字体名称 (换歌应用更改)",
lsm: "wkspipfont",
t: "t",
},
{
label:
"画中画显示备选字体名称 (换歌应用更改)",
lsm: "wkspipfont2",
t: "t",
},
{
label:
"画中画显示字体粗细 (范围 100-900, 换歌应用更改)",
lsm: "wkspipfweight",
t: "n",
},
{
label:
"画中画歌词字体大小 (像素,换歌应用更改)",
lsm: "wkspipfsize",
t: "n",
},
{
label:
"画中画歌词行间距 (像素,换歌应用更改)",
lsm: "wkspiplinespacing",
t: "n",
},
{
label:
"画中画歌词行高 (像素,换歌应用更改)",
lsm: "wkspiplineheight",
t: "n",
},
{
label:
"画中画显示字间距 (像素,换歌应用更改)",
lsm: "wkspipletterspacing",
t: "n",
},
{
label:
"画中画显示词间距 (像素,换歌应用更改)",
lsm: "wkspipwordspacing",
t: "n",
},
{
label:
"自定义画中画样式 (换歌应用更改)",
lsm: "wkspipcustomstyle",
t: "t",
},
],
n = "";
for (let e = 0; e < i.length; e++) {
if (i[e].roi && !p) continue;
let t = !0;
if (i[e].test) {
t = !1;
try {
t = !!window.eval(i[e].test);
} catch (e) {}
}
if (!t) continue;
let l = r(i[e].lsm);
"n" == i[e].t || "t" == i[e].t || "p" == i[e].t
? (n += f(
a,
i[e].label,
`data-wk-lsm="${i[e].lsm}" data-wk-t="${i[e].t}" data-wk-l="${i[e].label}"`,
"p" == i[e].t ? "开始" : "修改"
))
: (n += f(
s,
i[e].label,
`${l ? "checked " : ""}data-wk-lsm="${i[e].lsm}"`
));
}
n = f(t, n);
let x = document.createElement("div");
(x.className = "n-priv f-cb flatnmusic-settings"),
(x.style.display = "none"),
(x.innerHTML = n),
x.addEventListener("change", (e) => {
let t = e.target.closest("[data-wk-lsm]");
if (!t || !t.dataset) return;
let l = t.dataset.wkLsm;
t &&
l &&
("checkbox" == t.type
? c(l, t.checked ? "1" : "")
: c(l, t.value));
}),
l.appendChild(x),
x.addEventListener("click", (e) => {
let t = e.target.closest("[data-wk-t]");
if (!t || !t.dataset) return;
let l = t.dataset.wkLsm,
s = t.dataset.wkT,
a = t.dataset.wkL,
i = r(l),
n = t.closest("[data-prompt-prefix]");
if (((n = n ? n.dataset.promptPrefix : ""), t && l)) {
let e = n + a;
"p" == s && (e = n);
let t = window.prompt(e, i || ""),
x = ((e) => {
let t = 0,
l = "" + e,
s = l.length;
for (let e = 0; e < s; e++) t += l[e].codePointAt();
return t.toString(36) + s;
})(l);
if ("n" == s && isNaN(+t) && "" != t)
return void alert(
((e) => {
let t = "无效的值",
l = t.match(/\&#x[a-fA-F0-9]+;/g);
if (l)
for (let e = 0; e < l.length; e++) {
let s = l[e].substring(3, l[e].length - 1);
try {
s = JSON.parse(`"\\u${s.padStart(4, 0)}"`);
} catch (e) {}
t = t.replace(l[e], s);
}
return t;
})()
);
null != t && "p" != s
? c(l, t || "")
: "p" == s &&
g[x] &&
"function" == typeof g[x] &&
g[x](t);
}
});
}
};
window.addEventListener("load", t);
}
})();
})();