// ==UserScript==
// @name PikPak 更多交互功能 新标签页打开 复制文件名 统计 More interactive function
// @namespace https://greasyfork.org/zh-CN/users/722555-vveishu
// @version 2.2.3
// @description PikePak 为导航和文件列表添加新标签页打开按钮、复制文件/文件夹名按钮 统计文件(夹)数 Open in new tab, Copy file/folder name
// @author vvei
// @match https://mypikpak.com/s/*
// @icon http://mypikpak.com/favicon.ico
// @grant none
// @require https://code.jquery.com/jquery-3.7.1.slim.min.js
// @run-at document-end
// ==/UserScript==
(function ($) {
'use strict';
// 添加 Material Symbols Outlined 样式表
$('head').append(
$('<link>', {
rel: 'stylesheet',
href: 'https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@24,400,0,0&icon_names=content_copy,open_in_new'
})
);
// 添加 CSS 样式
$('<style>').text(`
.folder-navigator{
>ul>li>.pp-link-button{
padding-right: 0;
}
.copy-name{
font-size: 1.5em;
}
.open_in_new{
font-size: 1.5em;
height: 36px;
min-width: 1em;
margin: 0 8px;
align-items: center;
line-height: 36px;
text-decoration: none;
}
}
.custom-alert {
position: fixed;
padding: 3px 0.5em;
background: #333C;
color: #fff;
border: 1px solid #5f5;
border-radius: 5px;
z-index: 9000;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
}
.grid-operation.folder-CM8m{
display:block!important;
>.pp-link-button>.pp-icon{
color: #000!important;
}
>.pp-link-button.pp-link-button.pp-link-button {
top: 40px;
background-color: #fff7;
}
>.open_in_new {
position: absolute;
min-width: 24px;
height: 24px;
top: 8px;
right: 8px;
}
}
#统计 {
position: fixed;
left: 500px;
padding: 0.5em;
background-color: #FFFD;
z-index: 1000;
.统计值 {
font-size: 2em;
font-weight: bold;
}
ul {
padding-inline-start: 0.5em;
}
li {
margin: 5px 0;
list-style-type: none;
}
}
`).appendTo('head');
// 获取当前页面 url
const $canonical = $('link[rel="canonical"]').attr('href');
// 执行时间逻辑
// 延迟1.5秒执行
setTimeout(() => {
// 初始化处理
const $navLis = $('.folder-navigator > ul').first().children('li')
const $grids = $('.file-list').first().children('.grid')
navCopys($navLis);
fileCopy($grids);
navAddLink($navLis);
fileListAddLink($grids);
统计div();
// 监听导航列表变化
new MutationObserver(mutations => {
mutations.forEach(m => {
m.addedNodes.forEach(node => {
navCopy($(node));
navAddLink($(node));
});
m.removedNodes.length && $('.folder-navigator > ul').first().children('li').last().find('.open_in_new').remove();
});
}).observe(document.querySelector('.folder-navigator > ul'), { childList: true });
// 间隔1秒循环执行3次 file-list 添加链接,之后再次 统计div 并开始监听 file-list
let checkCount = 0;
const fileListInterval = setInterval(() => {
fileListAddLink($grids);
if (++checkCount >= 3) {
clearInterval(fileListInterval);
统计div();
observeFileList();
}
}, 1000);
// 监听 file-list 变化的函数
function observeFileList() {
new MutationObserver(mutations => {
mutations.forEach(m => {
m.addedNodes.forEach(node => {
fileCopy($(node));
fileListAddLink($(node));
});
统计div();
});
}).observe(document.querySelector('.file-list'), { childList: true });
}
}, 1500);
// 导航添加复制文本按钮
function navCopys($navLis) {
// 排除第一个li
$navLis.slice(1).find('.pp-link-button').each(function () {
addCopy($(this), 'content_copy');
});
}
function navCopy($navLi) {
$navLi.find('.pp-link-button').each(function () {
addCopy($(this), 'content_copy');
});
}
// file-list 添加复制文本按钮
function fileCopy($grids) {
$grids.find('.name').each(function () {
const $ell = $(this).children('.ellipsis').first();
addCopy($ell, 'content_copy');
});
}
// 模块化添加复制文本按钮的功能
function addCopy($element, buttonText) {
$element.after(
$('<span>', {
class: 'copy-name material-symbols-outlined',
text: buttonText,
}).on('click', function (event) {
const textToCopy = $element.text();
navigator.clipboard.writeText(textToCopy).then(() => {
// 创建自定义的提示框
const alertBox = $('<div>', {
class: 'custom-alert',
text: '已复制文本: ' + textToCopy,
}).appendTo('body');
// 设置提示框的位置
alertBox.css({
top: event.pageY + parseFloat(getComputedStyle(document.body).fontSize) + 'px',
left: event.pageX + 'px'
});
// 3秒后自动关闭提示框
setTimeout(function () {
alertBox.remove();
}, 3000);
}).catch(err => console.error('复制失败: ', err)); // 复制失败后的处理,可选
})
);
}
// 导航添加新标签页打开链接
function navAddLink($navLis) {
$navLis.prev().each(function () {
const $li = $(this);
$li.append(
$('<a>', {
href: $li.children('.pp-link-button').first().attr('href'),
target: '_blank',
class: 'open_in_new material-symbols-outlined',
text: 'open_in_new'
})
);
});
}
// file-list 添加新标签页打开链接
function fileListAddLink($grids) {
$grids.each(function () {
const $grid = $(this);
// 判断 .folder-cover 存在
if ($grid.has('.folder-cover').length) {
// .pp-link-button 通过 css 下移
const $operation = $grid.find('.grid-operation').first();
$operation.hasClass('folder-CM8m') || $operation.addClass('folder-CM8m');
// 添加按钮
const $openInNew = $grid.find('.open_in_new').first();
if (!$openInNew.length) {
$operation.append(
$('<a>', { href: $canonical + '/' + $grid.attr('id'), target: '_blank', class: 'open_in_new' }).append(
$('<span>', { class: 'material-symbols-outlined', text: 'open_in_new' })
)
);
}
}
});
}
// 统计文件(夹)数量
function 统计div() {
const 总数 = $grids.length;
let 统计div;
if (document.querySelector('body > div#统计')) {
统计div = $('body>div#统计');
统计div.empty(); // 清空旧统计
} else {
统计div = $('<div>', { id: '统计' })
$('body').append(统计div);
}
// 输出统计
if (总数 === 0) 统计div.text('空文件夹')
else {
const 文件夹数 = $grids.has('.folder-cover').length;
const 文件组 = $grids.has('.file-cover');
const 文件数 = 文件组.length;
if (文件夹数 + 文件数 === 总数) {
统计div.append($('<p>').append('共', $('<span>', { class: '统计值' }).text(总数), '个'))
if (文件夹数 > 0) 统计div.append($('<p>').append('文件夹', $('<span>', { class: '统计值' }).text(文件夹数), '个'))
if (文件数 > 0) {
统计div.append($('<p>').append('文件', $('<span>', { class: '统计值' }).text(文件数), '个'))
let 加载完成 = true;
文件组.each(function () {
const 文件名 = $(this).attract('aria-label');
if (文件名 === '******') {
加载完成 = false;
return false;
}
});
function 分类统计(扩展名) {
let 计数 = 0;
文件组.each(function () {
const 文件名 = $(this).attract('aria-label');
文件名.endsWith(扩展名) && 计数++;
});
return 计数;
}
if (加载完成) {
const 视频扩展名 = ['mp4', '.webm', '.avi', '.mkv', '.wmv', '.flv', '.mov', '.mpg', '.mpeg', '.mpe', '.asf', '.qt', '.rm', '.m4v', '.ogv', '.ogg', '.ts', '.tsv'];
const 图片扩展名 = ['.png', '.jpg', '.webp', '.gif', '.jpeg', '.svg'];
const 音频扩展名 = ['.mp3', '.flac', '.ape', '.wma', '.ogg', '.wav', '.aac', '.m4a', '.oga', '.ac3', '.amr'];
const 视频数 = 分类统计(视频扩展名);
const 图片数 = 分类统计(图片扩展名);
const 音频数 = 分类统计(音频扩展名);
const 其他数 = 文件数 - 视频数 - 图片数 - 音频数;
return { 视频数, 图片数, 音频数, 其他数 };
}
if (加载完成) {
const 文件ul = $('<ul>');
统计div.append(文件ul);
if (视频数 > 0) 文件ul.append($('<li>').append('视频', $('<span>', { class: '统计值' }).text(视频数), '个'))
if (图片数 > 0) 文件ul.append($('<li>').append('图片', $('<span>', { class: '统计值' }).text(图片数), '个'))
if (音频数 > 0) 文件ul.append($('<li>').append('音频', $('<span>', { class: '统计值' }).text(音频数), '个'))
if (其他数 > 0) 文件ul.append($('<li>').append('其他', $('<span>', { class: '统计值' }).text(其他数), '个'))
}
}
} else 统计div.text('页面加载有缺漏<br>请刷新');
}
}
})(jQuery);