// ==UserScript==
// @name 百度网盘浏览记录
// @namespace https://greasyfork.org
// @match https://pan.baidu.com/*
// @exclude https://pan.baidu.com/aipan/search
// @grant unsafeWindow
// @grant GM_addStyle
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_openInTab
// @require https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.min.js
// @run-at document-body
// @homepageURL https://greasyfork.org/zh-CN/scripts/485074-%E7%99%BE%E5%BA%A6%E7%BD%91%E7%9B%98%E6%B5%8F%E8%A7%88%E8%AE%B0%E5%BD%95
// @version 1.0.1
// @author Gwen
// @license MIT
// @description 2024/1/17 20:01:55
// ==/UserScript==
!(function() {
'use strict';
GM_addStyle('.bdh-button{z-index:10000;width:30px;height:30px;line-height:30px;text-align:center;color:#f5f5f5;border-radius:50%;position:absolute;left:calc(50vw - 15px);top:0;animation:colorChange 4s infinite linear;cursor:pointer}@keyframes colorChange{0%{background-color:red}25%{background-color:#00f}50%{background-color:green}75%{background-color:brown}to{background-color:red}}.bdh-panel{z-index:10000;background:white;position:fixed;left:20px;top:20px;width:390px;border:1px solid #000}.bdh-header{position:relative;height:30px;background:rgb(250, 250, 250);cursor:move}.bdh-close{position:absolute;right:10px;top:0;font-size:19px;cursor:pointer}.bdh-body{min-height:200px;max-height:500px;overflow-y:auto;overflow-x:hidden}.bdh-group{padding:10px;border-bottom:1px solid #d3d3d3}.bdh-group-header{color:gray;font-size:14px;margin-bottom:5px}.bdh-group-item{position:relative;width:100%;height:80px;padding:5px;box-sizing:border-box;border-bottom:1px solid #d3d3d3;cursor:pointer;display:flex}.bdh-group-item.picture{display:inline-block;border-bottom:none;width:80px}.bdh-group-item:nth-last-child(1){border-bottom:none}.bdh-group-item-image{width:70px;height:70px;object-fit:cover;display:inline-block;margin-right:5px}.bdh-group-item-image.video{width:90px}.bdh-group-item-video{position:absolute;left:5px;top:5px;width:90px;height:70px;background-color:rgba(0,0,0,.4)}.bdh-group-item-video-play{position:absolute;top:18px;left:35px;border-width:17px;border-style:solid;border-color:transparent transparent transparent #fff}.bdh-group-item-info{display:inline-block;max-width:280px;min-width:280px;height:70px;position:relative}.bdh-group-item-info.video{display:inline-block;max-width:260px;height:70px;position:relative}.bdh-group-item-info.picture{display:none}.bdh-group-item-title{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;word-break:break-all}.bdh-group-item-record{position:absolute;left:0;bottom:0;font-size:14px;color:gray}')
const bd_history_store = {}
function createElement(type, className) {
let d = document.createElement(type)
d.className = className
return d;
}
function initPanel() {
let panel = createElement('div', 'bdh-panel')
let header = createElement('div', 'bdh-header')
let close = createElement('div', 'bdh-close')
close.innerText = '×'
let body = createElement('div', 'bdh-body')
header.appendChild(close)
panel.appendChild(header)
panel.appendChild(body)
document.body.appendChild(panel)
let lastX = GM_getValue('box_last_x', 100)
let lastY = GM_getValue('box_last_y', 100)
panel.style.left = lastX + 'px'
panel.style.top = lastY + 'px'
panel.style.display = 'none'
header.addEventListener('mousedown', makeDraggableFunction(panel, false, null, () => {
GM_setValue('box_last_x', parseInt(panel.style.left))
GM_setValue('box_last_y', parseInt(panel.style.top))
}), false)
let showButton = createElement('span', 'bdh-button')
showButton.innerText = '史'
document.body.appendChild(showButton)
showButton.addEventListener('click', e => {
showButton.style.display = 'none'
panel.style.display = 'block'
body.innerHTML = ''
getHistory()
})
close.addEventListener('click', e => {
panel.style.display = 'none'
showButton.style.display = 'block'
})
}
function makeDraggableFunction(elem, allowMoveOut, exec, callback) {
let handleMouseDown = function (event) {
let offsetX = parseInt(elem.style.left)
let offsetY = parseInt(elem.style.top)
let innerX = event.clientX - offsetX
let innerY = event.clientY - offsetY
if (!!exec) {
exec()
}
document.onmousemove = function (event) {
elem.style.left = event.clientX - innerX + 'px'
elem.style.top = event.clientY - innerY + 'px'
if (!allowMoveOut) {
if (parseInt(elem.style.left) <= 0) {
elem.style.left = '0px'
}
if (parseInt(elem.style.top) <= 0) {
elem.style.top = '0px'
}
if (
parseInt(elem.style.left) >=
window.innerWidth - parseInt(elem.style.width)
) {
elem.style.left =
window.innerWidth - parseInt(elem.style.width) + 'px'
}
if (
parseInt(elem.style.top) >=
window.innerHeight - parseInt(elem.style.height)
) {
elem.style.top = window.innerHeight - parseInt(elem.style.height) + 'px'
}
}
}
document.onmouseup = function () {
document.onmousemove = null
document.onmouseup = null
if (!!callback) {
callback()
}
}
}
return handleMouseDown
}
function getHistory() {
let url = "https://pan.baidu.com/recent/list?"
let params = {
"app_id": "250528",
"vip": "2",
"version": "11.14.0",
"queryfree": "0",
"channel": "iPhone_14.4.2_iPhone11ProMax_chunlei_1099a_wifi",
"apn_id": "1_0",
"network_type": "wifi",
"freeisp": "0",
"activestatus": "0",
"time": new Date().getTime(),
"clienttype": "1",
"bgstatus": "1",
"need_detail": "1"
}
Object.keys(params).forEach(k => {
console.log(k)
url += k + '=' + params[k] + '&'
})
fetch(url, {
method: 'GET',
credentials: 'include',
headers: {
'Content-Type': 'application/json;charset=UTF-8'
},
}).then(res => {
return res.json()
}).then(res => {
console.log('res: ', res)
resolveHistory(res.list)
})
}
async function download(fsid) {
//get template variales
let url = await fetch('https://pan.baidu.com/api/gettemplatevariable?clienttype=0&app_id=250528&web=1&fields=[%22sign1%22,%22sign2%22,%22sign3%22,%22timestamp%22]').then(res => {
return res.json()
}).then(a => {
console.log(a)
a = a.result
let s = a.sign1, r = a.sign2 , c = a.sign3 , l = a.timestamp
let u = new Function("return " + a.sign2)()
let sign = btoa(u(c, s))
let url = `https://pan.baidu.com/api/download?clienttype=0&app_id=250528&web=1
&fidlist=[${fsid}]&type=dlink&vip=2&sign=${encodeURIComponent(sign)}×tamp=${l}`
return fetch(url).then(res => res.json()).then(res => {
console.log('下载链接:' + res.dlink[0].dlink)
GM_openInTab(res.dlink[0].dlink)
})
})
}
function resolveHistory(list) {
let bdhBody = $('.bdh-body')
for (let group of list) {
console.log(group)
let groupElem = $('<div class="bdh-group"></div>')
groupElem.append(`<div class="bdh-group-header">
${formatTime(group.smtime)} ${group.clienttype}查看
</div>`)
let count = 0
for (let item of group.detail) {
let tag = item.category==1 ? ' video' : item.category==3 ? ' picture' : ''
let itemElem = $(`<div class="bdh-group-item${tag}">
<img class="bdh-group-item-image${tag}" src="${item.thumbs?item.thumbs.url3:''}" alt="无图片">
${item.category==1?'<div class="bdh-group-item-video"><div class="bdh-group-item-video-play"></div></div>':''}
<div class="bdh-group-item-info${tag}">
<div class="bdh-group-item-title" title="${item.server_filename}">${item.server_filename}</div>
${(item.category==1&&group.view_time)?('<div class="bdh-group-item-record">播放至 '+formatViewTime(group.view_time[count])+'/'+formatViewTime(item.duration)+'</div>'):''}
</div>
</div>`)
itemElem.attr('count', count)
groupElem.append(itemElem)
itemElem.click(function(e) {
let url = ''
let category = item.category
if (category == 1) { //视频
url = 'https://pan.baidu.com/pfile/video?path=' + encodeURIComponent(item.path)
GM_openInTab(url)
} else if (category == 2) { //音频
console.log(this.getAttribute('count'))
download(group.fsids[this.getAttribute('count')])
} else if (category == 3) { //图片
//url = item.thumbs.url3
//GM_openInTab(url)
download(group.fsids[this.getAttribute('count')])
} else if (category == 4) { //文档
url = 'https://pan.baidu.com/pfile/docview?path=' + encodeURIComponent(item.path)
GM_openInTab(url)
} else if (category == 5) { //转存
}
//GM_openInTab(url)
})
count++
}
bdhBody.append(groupElem)
}
}
function formatTime(timestamp) {
let now = new Date()
let nowTime = now.getTime()
nowTime /= 1000
if (nowTime - timestamp < 60) {
return '刚刚'
} else if (nowTime - timestamp < 60 * 60) {
return Math.floor((nowTime - timestamp) / 60) + '分钟前'
} else if (nowTime - timestamp < 24 * 60 * 60) {
return Math.floor((nowTime - timestamp) / 60 / 24) + '小时前'
} else {
let result = ''
let date = new Date(timestamp * 1000)
if (date.getFullYear() != now.getFullYear()) {
result += date.getFullYear() + '-'
}
let M = date.getMonth() + 1
let d = date.getDate()
let h = date.getHours() < 10 ? ('0' + date.getHours()) : date.getHours()
let m = date.getMinutes() < 10 ? ('0' + date.getMinutes()) : date.getMinutes()
let s = date.getSeconds() < 10 ? ('0' + date.getSeconds()) : date.getSeconds()
result += M + '-' + d + ' ' + h + ':' + m + ':' + s
return result
}
}
function formatViewTime(time) {
let h = Math.floor(time / 60 / 24)
h = h < 10 ? '0' + h : h
let m = Math.floor(time / 60 % 24)
m = m < 10 ? '0' + m : m
let s = Math.floor(time % 60)
s = s < 10 ? '0' + s : s
return h + ':' + m + ':' + s
}
initPanel()
//getHistory()
})()