大体完成
剩下有个问题是排序之后,点击其他part跳转的问题,在156-159行
需要先研究一下b站原来是如何实现的
篡改猴脚本
// ==UserScript==
// @name B站视频合集排序
// @namespace http://tampermonkey.net/
// @version 1.4
// @description 对B站视频合集重新排序
// @author 武幻空
// @match https://www.bilibili.com/video/*
// @icon https://www.bilibili.com/favicon.ico?v=1
// @grant none
// ==/UserScript==
(function () {
'use strict';
const checkEpisodes = () => {
return new Promise((resolve, reject) => {
let attempts = 0;
const maxAttempts = 120;
const interval = setInterval(() => {
attempts++;
if (window.__INITIAL_STATE__?.videoData?.ugc_season?.sections[0]?.episodes?.length) {
clearInterval(interval);
resolve(window.__INITIAL_STATE__.videoData.ugc_season.sections[0].episodes);
} else if (attempts >= maxAttempts) {
clearInterval(interval);
reject(new Error("检测超时:未找到视频列表"));
}
}, 1000);
});
};
const addButtonContainer = () => {
return new Promise((resolve, reject) => {
let attempts = 0;
const maxAttempts = 120;
const interval = setInterval(() => {
attempts++;
const targetContainer = document.getElementsByClassName("video-pod video-pod")[0];
if (targetContainer) {
clearInterval(interval);
resolve(targetContainer);
} else if (attempts >= maxAttempts) {
clearInterval(interval);
reject(new Error("检测超时:未找到插入按钮的位置"));
}
}, 1000);
});
};
function applyStyles(element) {
element.style.padding = '14px 0px 12px';
//element.style.border = '0px 0px 1px solid #E3E5E7';
element.style.borderRadius = '6px';
element.style.fontWeight = 'bold';
element.style.fontSize = '14px';
element.style.display = 'flex';
element.style.flexDirection = 'column';
element.style.alignItems = 'flex-start';
}
function createSortContainer(episodes) {
const container = document.createElement("div");
container.id = "sort-statistics";
container.innerHTML = "<strong>视频集合排序</strong>";
applyStyles(container);
const controlRow = document.createElement('div');
controlRow.style.display = 'flex';
controlRow.style.alignItems = 'center';
controlRow.style.marginTop = '10px';
const sortSelect = document.createElement('select');
sortSelect.style.padding = '5px 8px';
sortSelect.style.borderRadius = '4px';
sortSelect.style.border = '1px solid #dcdcdc';
sortSelect.style.backgroundColor = '#fff';
sortSelect.style.marginRight = '10px';
sortSelect.innerHTML = `
<option value="id">按 ID 排序</option>
<option value="ctime">按发布时间排序</option>
<option value="title">按标题排序</option>
`;
controlRow.appendChild(sortSelect);
const orderButton = document.createElement('button');
orderButton.innerText = '升序';
orderButton.style.padding = '5px 10px';
orderButton.style.border = 'none';
orderButton.style.borderRadius = '4px';
orderButton.style.backgroundColor = '#409eff';
orderButton.style.color = '#fff';
orderButton.style.cursor = 'pointer';
orderButton.style.fontSize = '14px';
orderButton.style.marginRight = '10px';
let isAscending = true;
orderButton.onclick = () => {
isAscending = !isAscending;
orderButton.innerText = isAscending ? '升序' : '降序';
};
controlRow.appendChild(orderButton);
const sortButton = document.createElement('button');
sortButton.innerText = '确认排序';
sortButton.style.padding = '5px 10px';
sortButton.style.border = 'none';
sortButton.style.borderRadius = '4px';
sortButton.style.backgroundColor = '#67c23a';
sortButton.style.color = '#fff';
sortButton.style.cursor = 'pointer';
sortButton.style.fontSize = '14px';
sortButton.onclick = () => {
const sortBy = sortSelect.value;
sortEpisodes(sortBy, isAscending, episodes);
};
controlRow.appendChild(sortButton);
container.appendChild(controlRow);
return container;
}
function sortEpisodes(sortMode, isAscending, episodes) {
const currentScrolledElement = document.querySelector('.video-pod__item[data-scrolled="true"]');
const currentScrolledKey = currentScrolledElement ? currentScrolledElement.getAttribute('data-key') : null;
episodes.sort((a, b) => {
let compareA, compareB;
if (sortMode === 'id') {
compareA = a.id;
compareB = b.id;
return isAscending ? compareA - compareB : compareB - compareA;
} else if (sortMode === 'ctime') {
compareA = a.arc.ctime;
compareB = b.arc.ctime;
return isAscending ? compareA - compareB : compareB - compareA;
} else if (sortMode === 'title') {
compareA = a.arc.title;
compareB = b.arc.title;
return isAscending ? compareA.localeCompare(compareB) : compareB.localeCompare(compareA);
}
});
const videoListContainer = document.querySelector('.video-pod__list.section');
if (videoListContainer) {
videoListContainer.innerHTML = '';
episodes.forEach((episode) => {
const videoItem = document.createElement('div');
videoItem.className = 'pod-item video-pod__item simple';
videoItem.dataset.key = episode.bvid;
// 添加点击事件
videoItem.onclick = () => {
window.location.href = `https://www.bilibili.com/video/${episode.bvid}`;
};
if (episode.bvid === currentScrolledKey) {
videoItem.setAttribute('data-scrolled', 'true');
videoItem.innerHTML = `
<div class="single-p">
<div class="simple-base-item active normal">
<div title="${episode.title}" class="title">
<div class="playing-gif" style="display:;"></div>
<div class="title-txt">${episode.title}</div>
</div>
<div class="stats">
<div class="stat-item duration">
${(episode.arc.duration / 60).toFixed(0)}:${(episode.arc.duration % 60).toString().padStart(2, '0')}
</div>
</div>
</div>
</div>
`;
} else {
videoItem.innerHTML = `
<div class="single-p">
<div class="simple-base-item normal">
<div title="${episode.title}" class="title">
<div class="playing-gif" style="display:none;"></div>
<div class="title-txt">${episode.title}</div>
</div>
<div class="stats">
<div class="stat-item duration">
${(episode.arc.duration / 60).toFixed(0)}:${(episode.arc.duration % 60).toString().padStart(2, '0')}
</div>
</div>
</div>
</div>
`;
}
videoListContainer.appendChild(videoItem);
});
// 在这里添加滚动逻辑
if (currentScrolledElement) {
const newScrolledElement = videoListContainer.querySelector(`.pod-item[data-key="${currentScrolledKey}"]`);
if (newScrolledElement) {
newScrolledElement.scrollIntoView({ behavior: 'smooth', block: 'center' });
}
}
} else {
console.error("未找到视频展示容器");
}
}
async function main() {
try {
const episodes = await checkEpisodes();
const targetContainer = await addButtonContainer();
const sortContainer = createSortContainer(episodes);
targetContainer.insertBefore(sortContainer, targetContainer.firstChild);
} catch (error) {
console.error(error.message);
}
}
main();
})();