// ==UserScript==
// @name Cubox助手
// @author 岚浅浅
// @description 在 Cubox 左上角添加一个随机漫游的按钮(也可使用 Ctrl+R 触发),支持在指定的收藏夹内随机漫游
// @namespace http://tampermonkey.net/
// @homepageURL https://github.com/LanQianqian/greasyForkScripts
// @version 1.0.4
// @include *cubox.pro/*
// @grant GM_addStyle
// @license GPL-3.0 License
// @require http://libs.baidu.com/jquery/1.8.3/jquery.js
// @require http://libs.baidu.com/underscore/1.3.3/underscore-min.js
// @require https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js
// ==/UserScript==
// jshint esversion: 6
$(function () {
let TOOLBAR_HTML = `
<div id='toolbar' class="clickable" style="display:flex;flex-direction:column">
<div style="margin:2px auto">
<a id="start-btn" style="margin:auto">随机漫游</a>
</div>
</div>
`;
$('body').append(TOOLBAR_HTML);
$(document).on('click', '#start-btn', function () {
start();
});
// 禁用Crtrl+R刷新页面,而是执行随机漫游
document.addEventListener('keydown', function (event) {
if (event.ctrlKey && event.key === 'r') {
event.preventDefault();
start();
}
if (event.ctrlKey && ['1', '2', '3', '4'].includes(event.key)) {
event.preventDefault();
markCurrentCard(parseInt(event.key));
start();
}
});
let TOKEN = localStorage.getItem('token');
let currentUrl;
let isCardPage;
let cache = new Map();
refreshStyle();
if (currentUrl.endsWith('random')) {
start();
}
function refreshStyle() {
// 获取地址栏的URL
currentUrl = window.location.href;
isCardPage = extractCardId(currentUrl) !== null;
let toolbarTop = !isCardPage ? 25 : 15;
let toolbarLeft = !isCardPage ? 180 : 120;
let toolbarCss = `
#toolbar {
z-index: 999999;
position: fixed;
top: ${toolbarTop}px;
left: ${toolbarLeft}px;
width: 120px;
opacity: 0.6;
border: 1px solid #a38a54;
border-radius: 3px;
background-color: white
}
.clickable a {
cursor: pointer;
}
`;
GM_addStyle(toolbarCss);
}
function start() {
refreshStyle();
let randomPage;
let currentPage = 0;
let searchBase = function (response) {
let pageCount = response.pageCount;
randomPage = Math.floor(Math.random() * pageCount) + 1;
currentPage++;
if (currentPage === randomPage) {
viewRandomCard(response);
} else {
let cacheKey = `${searchBaseUrl}[${randomPage}]`;
let lastBookmarkId;
if (cache.get(cacheKey)) {
lastBookmarkId = cache.get(cacheKey);
currentPage = randomPage;
} else {
lastBookmarkId = response.data[response.data.length - 1].userSearchEngineID;
currentPage++;
}
getRequest(searchBaseUrl.replace('page=1', `page=${currentPage}`) + `&lastBookmarkId=${lastBookmarkId}`, searchRandomPage);
}
};
let searchRandomPage = function (response) {
if (currentPage === randomPage) {
viewRandomCard(response);
} else {
let cacheKey = `${searchBaseUrl}[${currentPage}]`;
let lastBookmarkId = response.data[response.data.length - 1].userSearchEngineID;
currentPage++;
cache.set(cacheKey, lastBookmarkId);
getRequest(searchBaseUrl.replace('page=1', `page=${currentPage}`) + `&lastBookmarkId=${lastBookmarkId}`, searchRandomPage);
}
};
let searchBaseUrl = localStorage.getItem('searchBaseUrl');
if (currentUrl.startsWith('https://www.cubox.pro/my/inbox')) {
searchBaseUrl = 'https://cubox.pro/c/api/v2/search_engine/inbox?asc=false&page=1&filters=&archiving=false';
} else if (currentUrl.startsWith('https://www.cubox.pro/my/all')) {
searchBaseUrl = 'https://cubox.pro/c/api/v2/search_engine/my?asc=false&page=1&filters=&archiving=false';
} else if (currentUrl.startsWith('https://www.cubox.pro/my/folder?id=')) {
let folderId = currentUrl.split("id=")[1].replace('&random', '');
searchBaseUrl = `https://cubox.pro/c/api/v2/search_engine/my?asc=false&page=1&filters=&groupId=${folderId}&archiving=false`;
} else {
popup('获取不到URL,如果当前位于快照页面,请将鼠标焦点移至页面右上角,而不是图片区域');
}
localStorage.setItem('searchBaseUrl', searchBaseUrl);
getRequest(searchBaseUrl, searchBase);
}
function getRequest(url, callback) {
$.ajax({
type: 'GET',
url: url,
headers: {
'Authorization': TOKEN
},
success: callback
});
}
function viewRandomCard(response) {
let cardIds = _.map(response.data, function (data) {
return data.userSearchEngineID
});
// 使用洗牌算法打乱cardIds的顺序
for (let i = cardIds.length - 1; i >= 0; i--) {
let randomIndex = Math.floor(Math.random() * (i + 1));
let itemAtIndex = cardIds[randomIndex];
cardIds[randomIndex] = cardIds[i];
cardIds[i] = itemAtIndex;
}
let latestCardIds = [];
let latestCardIdStr = localStorage.getItem('latestCardIds');
if (latestCardIdStr) {
latestCardIds = latestCardIdStr.split(',');
}
// 遍历cardIds,找到第一个未被标记的卡片
for (let i = 0; i < cardIds.length; i++) {
let cardId = cardIds[i];
const key = `card-${cardId}`;
let valueJson = localStorage.getItem(key);
if (!valueJson) {
if (openCard(cardId, latestCardIds)) {
return;
}
} else {
let value = JSON.parse(valueJson);
let due = window.moment(value.due, ['YYYY-MM-DD']);
if (due.isBefore(window.moment())) {
if (openCard(cardId, latestCardIds)) {
return;
}
}
}
}
}
function openCard(cardId, latestCardIds) {
if (latestCardIds.includes(cardId)) {
return false;
}
latestCardIds.push(cardId);
localStorage.setItem('latestCardIds', latestCardIds);
window.open(`https://www.cubox.pro/my/card?id=${cardId}`, '_self');
return true;
}
// 标记当前卡片
function markCurrentCard(response) {
let cardId = extractCardId(currentUrl);
if (!cardId) {
// 弹窗提示获取不到cardId
popup('获取不到卡片ID');
return;
}
const key = `card-${cardId}`;
let ease, interval, delayBeforeReview;
const now = Date.now();
let valueJson = localStorage.getItem(key);
if (!valueJson) {
ease = 250;
interval = 1;
delayBeforeReview = 0;
} else {
let value = JSON.parse(valueJson);
ease = value.ease;
interval = value.interval;
delayBeforeReview = now - window.moment(value.due, ['YYYY-MM-DD']).valueOf();
}
const schedObj = schedule(
response,
interval,
ease,
delayBeforeReview
);
interval = schedObj.interval;
ease = schedObj.ease;
const due = window.moment(now + interval * 24 * 3600 * 1e3);
const dueString = due.format("YYYY-MM-DD");
let value = {
'due': dueString,
'interval': interval,
'ease': ease
};
localStorage.setItem(key, JSON.stringify(value));
}
function schedule(response, interval, ease, delayBeforeReview) {
delayBeforeReview = Math.max(0, Math.floor(delayBeforeReview / (24 * 3600 * 1e3)));
if (response === 4 /* Very Easy */) {
ease += 20;
interval = (interval + delayBeforeReview) * ease / 100;
interval *= 4;
} if (response === 3 /* Easy */) {
ease += 20;
interval = (interval + delayBeforeReview) * ease / 100;
interval *= 1.3;
} else if (response === 2 /* Good */) {
interval = (interval + delayBeforeReview / 2) * ease / 100;
} else if (response === 1 /* Hard */) {
ease = Math.max(130, ease - 20);
interval = Math.max(
1,
(interval + delayBeforeReview / 4) * 50
);
}
interval = Math.min(interval, 365);
return { interval: Math.round(interval * 10) / 10, ease };
}
function extractCardId(url) {
// 正则提取 https://www.cubox.pro/my/card?id={cardId},如果提取不到,返回null
let regex = /.*cubox.pro\/my\/card\?id=(\d+)/;
let result = regex.exec(url);
if (result) {
return result[1];
} else {
return null;
}
}
// 浮动层提示用户
function popup(message) {
// 创建浮动层
var popup = document.createElement('div');
popup.textContent = message;
popup.style.position = 'fixed';
popup.style.top = '10%';
popup.style.left = '50%';
popup.style.transform = 'translate(-50%, -50%)';
popup.style.padding = '20px';
popup.style.backgroundColor = 'rgba(255, 255, 255, 0.8)';
popup.style.color = '#000';
popup.style.fontSize = '24px';
// 插入浮动层到页面中
document.body.appendChild(popup);
// 一定时间后隐藏浮动层
setTimeout(function () {
popup.style.display = 'none';
}, 3000);
}
});