// ==UserScript==
// @name hifini音乐播放管理
// @namespace http://tampermonkey.net/
// @version 0.4.4
// @description 在HiFiNi网站自动播放歌曲,可以自定义播放列表
// @author zs
// @license MIT
// @match https://www.hifini.com/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=hifini.com
// @grant none
// ==/UserScript==
(function () {
'use strict';
insetPanel();
// 初始化 判断url是否有thread字符串,有的话是播放音乐页面,则自动播放
// 没有的话是外层音乐列表页面,则在每个记录上insert'添加到播放列表按钮'
init();
})();
function insetPanel() {
// 播放音乐页面
// if (location.href.indexOf('thread') !== -1) return;
const body = document.getElementById('body');
const panel = `
<div id="play-list-panel-zs" style="position: fixed;top: 100px;left: 0;width: 240px;background: #b1cde4;border-bottom-right-radius: 5px;border-top-right-radius: 5px; padding: 6px 8px;font-size: 12px;z-index: 1001;transition: width 2s, height 2s;">
<div style="display: flex;align-items: center;justify-content: space-between;width: 100%;height: 30px;border-bottom: 1px solid #333;">
<span id="start-auto-play-zs" style="color: #333;cursor: pointer;">开始自动播放</span>
<span style="width: 1px;height: 8px;background: #333;"></span>
<span id="clear-play-list-zs" style="color: #333;cursor: pointer;">清空播放列表</span>
</div>
<div style="display: flex;align-items: center;flex-wrap: wrap;width: 100%;height: 30px;border-bottom: 1px solid #333;">
<span id="order-play-zs" style="margin-right: 8px;cursor: pointer;">顺序播放</span>
<span style="cursor: pointer;">
<input id="play-end-remove-zs" type="checkbox" id="vehicle1" name="vehicle1" value="remove">
<label style="margin-bottom: 0;" for="vehicle1">播放完成在列表移除</label>
</span>
</div>
<div id="diy-play-list" style="display: flex;flex-direction: column;max-height: 500px;">
<span style="color: #000;">播放列表</span>
<span style="color: #333;">播放列表暂无添加音乐</span>
</div>
<div id="tips-zs" style="color: #008cff;cursor: pointer;">
关于进入音乐播放页面无法自动播放问题
</div>
<div style="
position: absolute;
top: 50%;
right: -14px;
width: 14px;
margin-top: -20px;
background: #b1cde4;
cursor: pointer;
display: flex;
justify-content: center;
height: 40px;
writing-mode: vertical-rl;
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
"
id="fold-zs"
>
收起
</div>
</div>
`;
body ? body.insertAdjacentHTML('beforeend', panel) : '';
setPlayList(getPlayList());
setTimeout(() => {
// 点击开始自动播放
document.getElementById('start-auto-play-zs').addEventListener('click', () => {
const data = getPlayList();
if (Array.isArray(data) && data.length) {
window.open(data[0].href);
localStorage.setItem('play-list-index-zs', '0');
} else {
alert('请先去音乐列表添加音乐到播放列表');
location.href = 'https://www.hifini.com';
}
})
// 点击清空播放列表
document.getElementById('clear-play-list-zs').addEventListener('click', () => {
setPlayList([]);
})
// 点击关于进入音乐播放页面无法自动播放问题
document.getElementById('tips-zs').addEventListener('click', () => {
alert(`由于浏览器策略不同,可能不允许脚本驱动媒体播放,可以手动点击播放音乐按钮,次数多了浏览器会记住你的选择,则脚本驱动媒体播放不会再失败。
您也可以手动开启浏览器对声音的设置,将该网站设置为允许播放声音。`);
})
// 点击顺序播放、随机播放
document.getElementById('order-play-zs').addEventListener('click', (e) => {
const text = e.target.innerText;
if (text === '顺序播放') {
document.getElementById('order-play-zs').innerText = '随机播放';
localStorage.setItem('play-order-zs', 'random');
}
if (text === '随机播放') {
document.getElementById('order-play-zs').innerText = '顺序播放';
localStorage.setItem('play-order-zs', 'order');
}
})
// 勾选、取消勾选 播放完成在列表移除
document.getElementById('play-end-remove-zs').addEventListener('change', (e) => {
const checked = e.target.checked;
localStorage.setItem('play-end-remove-result', `${checked}`);
})
// 点击收起按钮
document.getElementById('fold-zs').addEventListener('click', (e) => {
const panelELe = document.getElementById('play-list-panel-zs');
panelELe.style.overflow = 'hidden';
panelELe.style.width = '0px';
setTimeout(() => {
panelELe.style.display = 'none';
initFoldPanel();
}, 800)
})
const localOrder = localStorage.getItem('play-order-zs');
const checked = localStorage.getItem('play-end-remove-result');
if (localOrder === 'random') {
document.getElementById('order-play-zs').innerText = '随机播放';
}
if (`${checked}` === 'true') {
document.getElementById('play-end-remove-zs').checked = true;
}
}, 400)
}
// 初始化收起后的面板
function initFoldPanel() {
const foldEle = document.getElementById('fold-panel-zs');
if (foldEle) {
foldEle.style.display = 'block';
foldEle.addEventListener('click', () => {
foldEle.style.display = 'none';
document.getElementById('play-list-panel-zs').style.overflow = 'inherit';
document.getElementById('play-list-panel-zs').style.display = 'block';
document.getElementById('play-list-panel-zs').style.width = '240px';
})
} else {
const body = document.getElementById('body');
const divDom = document.createElement('div');
divDom.setAttribute('id', 'fold-panel-zs');
divDom.style = 'position: fixed;top: 100px;left: 0;width: 40px;height: 40px;border-radius: 50%;background: #b1cde4;font-size: 12px;z-index: 1001;cursor: pointer;text-align: center;line-height: 40px;';
divDom.innerText = '展开';
divDom.addEventListener('click', () => {
divDom.style.display = 'none';
document.getElementById('play-list-panel-zs').style.overflow = 'inherit';
document.getElementById('play-list-panel-zs').style.display = 'block';
document.getElementById('play-list-panel-zs').style.width = '240px';
})
body ? body.appendChild(divDom) : '';
}
}
function init() {
// 播放音乐页面
if (location.href.indexOf('thread') !== -1) {
setTimeout(() => {
if (!document.querySelector('.aplayer-icon-play')) {
next();
return;
}
const playerEle = document.getElementById('player4');
playerEle.style.position = 'relative';
const btnEle = document.createElement('button');
btnEle.style = 'position: absolute;top: 14px;right: 7px;cursor: pointer;';
btnEle.innerHTML = '下一首';
btnEle.addEventListener('click', (e) => {
e.stopPropagation();
next();
})
playerEle.appendChild(btnEle);
document.querySelector('.aplayer-icon-play').click();
watchPlayEnd();
const alreadyPlayList = localStorage.getItem('already-play-list');
if (alreadyPlayList) {
try {
const list = JSON.parse(alreadyPlayList);
list.push({
pathname: location.pathname,
timeStamp: new Date().getTime()
});
const _list = list.filter(i => {
return (new Date().getTime() - i.timeStamp) < 60 * 30 * 1000;
});
console.log('有已播放列表,收录,且过滤列表中超过半小时的项', _list);
localStorage.setItem('already-play-list', JSON.stringify(_list));
} catch (err) {
console.log(err.message);
}
} else {
console.log('无已播放列表,收录第一首');
localStorage.setItem('already-play-list', JSON.stringify([{ pathname: location.pathname, timeStamp: new Date().getTime() }]));
}
}, 1000);
} else { // 外层音乐列表页面
try {
let ulEle = Array.from(document.querySelector('.card-body').children[0].children).filter(i => i.tagName === 'LI');
if (location.href.indexOf('search') !== -1) {
ulEle = Array.from(document.querySelector('.search .card-body').children[0].children).filter(i => i.tagName === 'LI');
}
ulEle.forEach(it => {
const mediaEle = getNodeByClassName(it.children, 'media-body');
const subjectEle = getNodeByClassName(mediaEle.children, 'subject');
const btnEle = document.createElement('button');
btnEle.style = 'margin-left: 20px;cursor: pointer;';
btnEle.innerHTML = '添加到播放列表';
btnEle.setAttribute('data-href', subjectEle.children[0].href || '');
btnEle.setAttribute('data-name', subjectEle.children[0].innerText || '');
btnEle.addEventListener('click', (e) => {
e.stopPropagation();
const href = e.target.dataset.href;
const name = e.target.dataset.name;
const playList = getPlayList();
if (playList.find(i => i.href === href)) return;
playList.push({
name,
href
})
setPlayList(playList);
})
subjectEle.appendChild(btnEle);
})
} catch (error) {
console.log("插入'添加到播放列表'按钮失败:", error);
alert("插入'添加到播放列表'按钮失败");
}
}
}
// 获取播放列表
function getPlayList() {
const data = localStorage.getItem('hifini_play_list');
try {
return data ? JSON.parse(data) : [];
} catch (error) {
return [];
}
}
// 设置播放列表并且重新渲染
function setPlayList(data) {
localStorage.setItem('hifini_play_list', JSON.stringify(data));
if (Array.isArray(data)) {
const ele = document.getElementById('diy-play-list');
ele.innerHTML = '<span style="color: #000;">播放列表</span>';
const divEle = document.createElement('div');
divEle.style = 'width: 100%;overflow-y: scroll;overflow-x: hidden;';
let html = '';
const index = localStorage.getItem('play-list-index-zs');
data.forEach((it, idx) => {
html += `<div style="display: flex;height: 24px;align-items: center;">
<span
data-href="${it.href}"
data-type="play"
data-index="${idx}"
style="overflow: hidden;width: 160px;word-break: break-all;white-space: nowrap;text-overflow: ellipsis;cursor: pointer;color: ${index && +index === idx ? 'blue' : '#212529'};"
>
${it.name}
</span>
<span data-href="${it.href}" data-type="del" data-index="${idx}" style="white-space: nowrap;color: #9a2121;cursor: pointer;margin-left: 4px;">删除</span>
<span data-href="${it.href}" data-type="move-up" data-index="${idx}" style="white-space: nowrap;color: #9a2121;cursor: pointer;margin-left: 4px;">上移</span>
<span data-href="${it.href}" data-type="move-down" data-index="${idx}" style="white-space: nowrap;color: #9a2121;cursor: pointer;margin-left: 4px;">下移</span>
</div>
`;
})
divEle.innerHTML = html;
divEle.addEventListener('click', e => {
const { type, href, index } = e.target.dataset;
const list = getPlayList();
if (type === 'play') { // 播放
location.href = href;
localStorage.setItem('play-list-index-zs', index);
} else if (type === 'del') { // 删除
list.splice(+index, 1);
setPlayList(list);
} else if (type === 'move-up') { // 上移
if (+index) {
const snap = list[+index];
list[+index] = list[+index - 1];
list[+index - 1] = snap;
setPlayList(list);
}
} else if (type === 'move-down') { // 下移
if (+index < list.length - 1) {
const snap = list[+index];
list[+index] = list[+index + 1];
list[+index + 1] = snap;
setPlayList(list);
}
}
})
ele.appendChild(divEle);
}
if (Array.isArray(data) && !data.length) {
const ele = document.getElementById('diy-play-list');
ele.innerHTML = '<span style="color: #000;">播放列表</span><span style="color: #333;">播放列表暂无添加音乐</span>';
}
}
// 通过判断className获取节点
function getNodeByClassName(node, name) {
for (let i = 0; i < node.length; i++) {
if (node[i].className.split(' ').includes(name)) {
return node[i];
}
}
}
// 监听播放完毕
function watchPlayEnd() {
const url = location.href;
const timer = setInterval(() => {
if (url !== location.href) {
clearInterval(timer);
}
try {
const dtime = document.querySelector('.aplayer-dtime').innerText;
const ptime = document.querySelector('.aplayer-ptime').innerText;
if (dtime === '00:00' && ptime === '00:00') {
console.log('00:00');
return;
}
const end = computedTime(dtime);
const start = computedTime(ptime);
if (start === end || start === (end - 1)) {
clearInterval(timer);
document.querySelector('.aplayer-icon-pause').click()
next();
}
} catch (error) {
clearInterval(timer);
}
}, 1000)
}
// 下一首
function next() {
let index = localStorage.getItem('play-list-index-zs');
if (index) {
const data = getPlayList();
const localOrder = localStorage.getItem('play-order-zs');
const checked = localStorage.getItem('play-end-remove-result');
if (`${checked}` === 'true') {
data.splice(+index, 1);
index = index - 1;
localStorage.setItem('hifini_play_list', JSON.stringify(data));
}
// 随机播放
if (localOrder === 'random') {
let sindex = Random(1, data.length);
console.log('随机生成 ', sindex);
const alreadyPlayList = localStorage.getItem('already-play-list');
if (alreadyPlayList) {
try {
const list = JSON.parse(alreadyPlayList);
let count = 0;
while (list.find(i => data[sindex - 1].href.includes(i.pathname)) && count <= 5) {
sindex = Random(1, data.length);
console.log('重新随机生成 ', sindex);
count++;
}
} catch (err) {
console.log(err.message);
}
}
console.log('最终随机播放url:', sindex, data[sindex - 1].href);
location.href = data[sindex - 1].href;
localStorage.setItem('play-list-index-zs', sindex - 1);
} else { // 顺序播放
if (data.length === +index + 1) {
location.href = data[0].href;
localStorage.setItem('play-list-index-zs', '0');
return;
}
location.href = data[+index + 1].href;
localStorage.setItem('play-list-index-zs', +index + 1);
}
}
}
// 计算04:22 格式时长
function computedTime(time) {
let result = 0;
const arr = time.split(':');
result += Number(arr[0]) * 60;
result += Number(arr[1]);
return result;
}
// 生成指定范围随机数
function Random(min, max) {
return Math.round(Math.random() * (max - min)) + min;
}