Skip to content

Commit

Permalink
Init: clone from private repo
Browse files Browse the repository at this point in the history
  • Loading branch information
letwebdev committed Mar 8, 2024
0 parents commit 4edfb73
Show file tree
Hide file tree
Showing 22 changed files with 2,841 additions and 0 deletions.
17 changes: 17 additions & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"env": {
"browser": true,
"es2021": true
},
"extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended"],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": "latest"
},
"plugins": ["@typescript-eslint"],
"rules": {
"no-extra-semi": "off",
"@typescript-eslint/no-extra-semi": "off",
"no-inner-declarations": "off"
}
}
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/node_modules/*
5 changes: 5 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"trailingComma": "es5",
"semi": false,
"printWidth": 100
}
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Scripts for TamperMonkey

## Zhihu tweaker

- 移除生成的关键词搜索链接蓝字高亮
- 移除重定向
- 回答显示创建时间和最后修改时间
- 首页-关注页面 `header` 显示 "我的收藏" 和 "我关注的问题"
- 问题页面 显示 "查看问题日志" 按钮, 提问者, 问题创建时间和最后修改时间
- 咨询页面 显示 "打开对话页面" 按钮

## PlaybackRate Controller

目前仅支持B站

-`s`调整基础播放速度为1或2(默认为1)
-`1-9`调整播放速度为相应倍速,再按一次恢复为基础播放速度
- 按住`r`调整为4倍播放速度, 松开恢复为基础播放速度
96 changes: 96 additions & 0 deletions dist/playbackRateController_bundled.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
"use strict"
/**
* Promise-based `setTimeout`
*/
async function wait(time) {
function execute(resolve) {
setTimeout(resolve, time);
}
return new Promise(execute);
}

async function selectElementAsync(querySelector, options = {
intervalOfRetry: 1000,
parent: document,
}) {
const intervalOfRetry = options.intervalOfRetry || 1000;
const parent = options.parent || document;
const element = parent.querySelector(querySelector);
if (element === null) {
await wait(intervalOfRetry);
return selectElementAsync(querySelector, options);
}
else {
return element;
}
}

// ==UserScript==
// @name Playback rate controller
// @namespace http://tampermonkey.net/
// @version 0.0.2
// @description try to take over the world!
// @author You
// @match https://www.bilibili.com/video/*
// @match https://www.bilibili.com/bangumi/play/*
// @grant none
// ==/UserScript==
(async function () {
const videoElement = (await selectElementAsync(".bpx-player-video-wrap video"));
const video = {
get playbackRate() {
return videoElement.playbackRate;
},
set playbackRate(rate) {
videoElement.playbackRate = rate;
},
togglePlayBackRate(rate1, rate2) {
videoElement.playbackRate = videoElement.playbackRate === rate1 ? rate2 : rate1;
},
basePlaybackRate: videoElement.playbackRate,
toggleBasePlayBackRate(rate1, rate2) {
this.basePlaybackRate = this.basePlaybackRate === rate1 ? rate2 : rate1;
},
};
enableTogglingPlaybackRate();
enableHoldingDownToControlPlaybackRate();
function enableTogglingPlaybackRate() {
const presetOfRates = ["1", "2", "3", "4", "5", "6", "7", "8", "9"];
window.addEventListener("keydown", (event) => {
if (presetOfRates.includes(event.key)) {
video.togglePlayBackRate(Number(event.key), video.basePlaybackRate);
return;
}
switch (event.key) {
case "s": {
video.toggleBasePlayBackRate(1, 2);
break;
}
default:
return;
}
}, true);
}
function enableHoldingDownToControlPlaybackRate() {
window.addEventListener("keydown", (event) => {
switch (event.key) {
case "r": {
video.playbackRate = 4;
break;
}
default:
return;
}
}, true);
window.addEventListener("keyup", (event) => {
switch (event.key) {
case "r":
video.playbackRate = video.basePlaybackRate;
break;
default:
return;
}
}, true);
}
//
})();
209 changes: 209 additions & 0 deletions dist/zhihuTweaker_bundled.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
"use strict"
function supplementFooterOfQuestionHeader() {
const footer = document.querySelector(".QuestionHeader-footer-main");
const buttonForViewingLogBeingAppended = footer.querySelector(".buttonForViewingLogBeingAppended");
if (buttonForViewingLogBeingAppended) {
return;
}
else {
appendButtonForViewingLog(footer);
appendTimeGroups(footer);
function appendButtonForViewingLog(target) {
const linkToLog = document.createElement("a");
linkToLog.textContent = "查看问题日志";
linkToLog.classList.add("Button--grey", "Button", "buttonForViewingLogBeingAppended");
linkToLog.href = getUrlToLog();
target.append(linkToLog);
}
}
async function appendTimeGroups(target) {
const logHtml = await fetch(getUrlToLog(), {
headers: {
"Content-Type": "text/html",
},
}).then((response) => {
return response.text();
});
const sectionOfLog = document.createElement("section");
sectionOfLog.innerHTML = logHtml;
const logList = sectionOfLog.querySelector("#zh-question-log-list-wrap");
const logListItems = logList.querySelectorAll("div.zm-item");
const timeLastModified = logListItems[0].querySelector("time");
const earliestLogListItem = [...logListItems].at(-1);
const timeCreated = earliestLogListItem.querySelector("time");
const questioner = earliestLogListItem.querySelector("& > div:nth-child(1) a");
target.append(questioner, timeCreated, timeLastModified);
}
function getUrlToLog() {
const currentUrl = window.location.href;
const validUrlInfixOfLinkToLog = new RegExp("/question/\\d+");
const urlInfixOfLinkToLog = currentUrl.match(validUrlInfixOfLinkToLog)[0];
return `${urlInfixOfLinkToLog}/log`;
}
}

function removeAutoGenerantedKeywordLinks() {
const autoGeneratedKeywordLinks = document.querySelectorAll("a.RichContent-EntityWord:not(.autoGeneratedKeywordLinksRemoved)");
autoGeneratedKeywordLinks.forEach((anchor) => {
anchor.style.display = "none";
const container = anchor.parentElement;
const newSpan = document.createTextNode(anchor.textContent);
container.append(newSpan);
anchor.classList.add("autoGeneratedKeywordLinksRemoved");
/**
* Can't replace(delete) children(`a` included), which will cause React(zhihu) to throw errors
* @deprecated
*/
// container.replaceChildren(anchor.textContent as string)
});
}
function substituteRedirectionLinks() {
const linksToRemoveRedirection = document.querySelectorAll("a[href^='https://link.zhihu.com/?target='], a[href^='link.zhihu.com/?target=']");
linksToRemoveRedirection.forEach((linkToRemoveRedirection) => {
const urlWithRedirection = linkToRemoveRedirection.href;
linkToRemoveRedirection.href = removeRedirection(urlWithRedirection);
});
function removeRedirection(url) {
const urlRemovingRedirection = url
.replace("https://link.zhihu.com/?target=", "")
.replace("link.zhihu.com/?target=", "");
return decodeURIComponent(urlRemovingRedirection);
}
}

/**
* Promise-based `setTimeout`
*/
async function wait(time) {
function execute(resolve) {
setTimeout(resolve, time);
}
return new Promise(execute);
}

async function selectElementAsync(querySelector, options = {
intervalOfRetry: 1000,
parent: document,
}) {
const intervalOfRetry = options.intervalOfRetry || 1000;
const parent = options.parent || document;
const element = parent.querySelector(querySelector);
if (element === null) {
await wait(intervalOfRetry);
return selectElementAsync(querySelector, options);
}
else {
return element;
}
}

function supplementItemTime() {
const itemsToPendTime = document.querySelectorAll(".AnswerItem .RichContent:not(.itemTimeAlreadySupplemented)");
pendTimeToItems(itemsToPendTime);
}
function pendTimeToItems(items) {
items.forEach(async (item) => {
item.classList.add("itemTimeAlreadySupplemented");
const containerOfTime = await selectElementAsync(".ContentItem-time", { parent: item });
pendTime(item, containerOfTime);
});
}
function pendTime(target, containerOfTime) {
const spanWithtimeOfItem = containerOfTime.querySelector("span[data-tooltip]");
if (itemWasEdited(spanWithtimeOfItem)) {
const containerOfTimeEdited = containerOfTime.cloneNode(true);
target.prepend(containerOfTimeEdited);
const containerOfTimeCreated = containerOfTime.cloneNode(true);
const timeCreated = spanWithtimeOfItem.dataset.tooltip;
containerOfTimeCreated.textContent = timeCreated;
target.prepend(containerOfTimeCreated);
const containerOfTimeCreatedToAppend = containerOfTimeCreated.cloneNode(true);
target.append(containerOfTimeCreatedToAppend);
}
else {
const containerOfTimeCreated = containerOfTime.cloneNode(true);
target.prepend(containerOfTimeCreated);
}
}
function itemWasEdited(spanWithtimeOfItem) {
return spanWithtimeOfItem.textContent.includes("编辑于");
}

function supplementHeader() {
const header = document.querySelector(".AppHeader-userInfo");
const favorites = document.querySelector(".GlobalSideBar-starItem");
const followingQuestions = document.querySelector(".GlobalSideBar-questionListItem");
const ul = document.createElement("ul");
ul.style.display = "flex";
ul.append(favorites, followingQuestions);
header.append(ul);
}

async function supplementConsultPage() {
repeatlyAppendAnchors();
const buttonForShowingMore = (await selectElementAsync(".PublicConsultation-layerContent"));
buttonForShowingMore.addEventListener("click", repeatlyAppendAnchors);
}
function repeatlyAppendAnchors() {
appendAnchors();
setTimeout(appendAnchors, 200);
setTimeout(appendAnchors, 500);
}
function appendAnchors() {
const consultCards = document.querySelectorAll(".ConsultCard:not(.linkToConversationAppended)");
consultCards.forEach((consultCard) => {
appendAnchor(consultCard);
consultCard.classList.add("linkToConversationAppended");
});
}
function appendAnchor(target) {
const linkToConversation = document.createElement("a");
const relativeUrlToConversation = target.dataset.to;
linkToConversation.href = relativeUrlToConversation;
linkToConversation.textContent = "打开对话页面";
linkToConversation.classList.add("Button");
target.append(linkToConversation);
}

// ==UserScript==
// @name Zhihu tweaker
// @namespace http://tampermonkey.net/
// @version 0.1.2
// @description tweak zhihu functionalities.
// @author You
// @match *://*.zhihu.com/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=zhihu.com
// @grant none
// ==/UserScript==
(async function () {
const currentUrl = window.location.href;
const validFollowUrl = new RegExp("https://www.zhihu.com/follow*");
const validQuestionUrl = new RegExp("https://www.zhihu.com/question(?!.*/log$).*");
// const validPeoPleUrl = new RegExp("https://www.zhihu.com/people/*")
// const validArticleUrl = new RegExp("https://zhuanlan.zhihu.com/p/*")
const validConsultUrl = new RegExp("https://www.zhihu.com/consult/people/*");
setInterval(() => {
supplementItemTime();
removeAutoGenerantedKeywordLinks();
substituteRedirectionLinks();
}, 2000);
switch (true) {
case inUrl(validFollowUrl): {
supplementHeader();
break;
}
case inUrl(validQuestionUrl): {
setInterval(() => {
supplementFooterOfQuestionHeader();
}, 2000);
break;
}
case inUrl(validConsultUrl): {
supplementConsultPage();
break;
}
}
function inUrl(type) {
return type.test(currentUrl);
}
})();
Loading

0 comments on commit 4edfb73

Please sign in to comment.