您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Adds keyboard shortcuts [ and ] for liking and disliking videos, B and R to Back up and Restore position, H to use picture-in-picture, { and } to change playback speed.
当前为
// ==UserScript== // @name Youtube Keyboard Shortcuts: like/dislike, backup/restore position, change speed, picture-in-picture // @match https://www.youtube.com/* // @description Adds keyboard shortcuts [ and ] for liking and disliking videos, B and R to Back up and Restore position, H to use picture-in-picture, { and } to change playback speed. // @author https://gf.qytechs.cn/en/users/728793-keyboard-shortcuts // @namespace http://tampermonkey.net/ // @version 1.2 // @grant none // @license MIT // @icon https://t1.gstatic.com/faviconV2?client=SOCIAL&type=FAVICON&fallback_opts=TYPE,SIZE,URL&url=http://youtube.com&size=128 // ==/UserScript== /* jshint esversion: 6 */ /** * Keyboard shortcuts: * [ to like a video * ] to dislike it * h to enable/disable Picture-in-Picture (PiP) * b to back up the current time (where you are in the video) * r to jump back to the backed up time * shift-] – or "}" – to increase playback speed * shift-[ – or "{" – to decrease playback speed */ /****************************************************************************************************/ /* */ /* Change these constants to configure the script */ const PLAYBACK_RATE_STEP = 0.05; // change playback rate by 5% when pressing the shortcut keys const SHOW_NOTIFICATIONS = true; const NOTIFICATIONS_INCLUDE_EMOJIS = true; const NOTIFICATION_DURATION_MILLIS = 2000; // how long – in milliseconds – to keep a like/dislike notification visible. const REMOVE_FEEDBACK_SHARED_WITH_CREATOR = true; // if true, remove the notification on dislike that says "feedback shared with the creator" /****************************************************************************************************/ var lastToastElement = null; function showNotification(message) { if (!SHOW_NOTIFICATIONS) { return; } if (lastToastElement !== null) { // delete if still visible lastToastElement.remove(); lastToastElement = null; } const toast = document.createElement('tp-yt-paper-toast'); toast.innerText = message; toast.classList.add('toast-open'); const styleProps = { outline: 'none', position: 'fixed', left: '0', bottom: '12px', maxWidth: '297.547px', maxHeight: '48px', zIndex: '2202', opacity: '1', }; for (const prop in styleProps) { toast.style[prop] = styleProps[prop]; } document.body.appendChild(toast); lastToastElement = toast; // needed otherwise the notification won't show setTimeout(() => { toast.style.display = 'block'; }, 0); // preserves the animation setTimeout(() => { toast.style.transform = 'none'; }, 10); setTimeout(() => { toast.style.transform = 'translateY(200%)'; }, Math.max(0, NOTIFICATION_DURATION_MILLIS)); } function removeBuiltInFeedbackShared(feedbackSharedStartTime) { const now = Date.now(); for (const toastElement of Array.from(document.querySelectorAll('tp-yt-paper-toast'))) { if (toastElement.textContent.toLowerCase().includes('feedback shared with the creator')) { toastElement.remove(); return; } } if (now - feedbackSharedStartTime < 1000) { const intervalMs = (now - feedbackSharedStartTime < 100) ? 10 : 50; // faster at first setTimeout(() => removeBuiltInFeedbackShared(feedbackSharedStartTime), intervalMs); } } function getVideoId() { const url = new URL(location.href); return url.searchParams.get('v'); } function pageIsYouTubeShortsViewer() { return /^\/(shorts)/.test(location.pathname); } function pageIsRegularWatchViewer() { return /^\/(watch)/.test(location.pathname); } function findLikeDislikeButtonsShorts() { const likeButtonRenderer = document.querySelector('div#like-button ytd-like-button-renderer'); var like = null, dislike = null; if (likeButtonRenderer) { like = likeButtonRenderer.querySelector('#like-button'); dislike = likeButtonRenderer.querySelector('#dislike-button'); } return {like, dislike}; } function findLikeDislikeButtons() { if (pageIsYouTubeShortsViewer()) { return findLikeDislikeButtonsShorts(); } else if (!pageIsRegularWatchViewer()) { return { like: null, dislike: null }; } const infoRenderer = document.getElementsByTagName('ytd-video-primary-info-renderer'); var like = null, dislike = null; if (infoRenderer.length == 1) { const buttons = Array.from(infoRenderer[0].getElementsByTagName('button')); for (var b of buttons) { if (b.hasAttribute('aria-label')) { if (b.getAttribute('aria-label').toLowerCase().indexOf('dislike this') !== -1) { dislike = b; } else if (b.getAttribute('aria-label').toLowerCase().indexOf('like this') !== -1) { like = b; } } } if (!like) { like = buttons[4]; } if (!dislike) { dislike = buttons[5]; } } return {like, dislike}; } function applyScrubSeconds(event, delta) { const video = getVideoElement(); if (video) { video.currentTime += delta; event.preventDefault(); } } function getPressedAttribute(button) { return button.hasAttribute('aria-pressed') ? button.getAttribute('aria-pressed') : null; } function formatTime(timeSec) { const hours = Math.floor(timeSec / 3600.0); const minutes = Math.floor((timeSec % 3600) / 60); const seconds = Math.floor((timeSec % 60)); return (hours > 0 ? (('' + hours).padStart(2, '0') + ':') : '') + ('' + minutes).padStart(2, '0') + ':' + ('' + seconds).padStart(2, '0'); } function formatPlaybackRate(rate) { if (rate == Math.floor(rate)) { // integer return rate + 'x'; } else if (rate.toFixed(2).endsWith('0')) { // float, 1 decimal place return rate.toFixed(1) + 'x'; } else { // float, 2 decimal places max return rate.toFixed(2) + 'x'; } } function maybePrefixWithEmoji(emoji, message) { return NOTIFICATIONS_INCLUDE_EMOJIS ? emoji + ' ' + message : message; } function getVideoElement() { const videos = Array.from(document.querySelectorAll('video')).filter(v => ! isNaN(v.duration)); // filter the invalid ones return videos.length === 0 ? null : videos[0]; } var pipEnabled = false; // initial value const observer = new MutationObserver(findLikeDislikeButtons); // find buttons on DOM changes observer.observe(document.documentElement, { childList: true, subtree: true }); var savedPosition = {}; // add keybindings addEventListener('keypress', function (e) { const tag = e.target.tagName.toLowerCase(); if (e.target.getAttribute('contenteditable') == 'true' || tag == 'input' || tag == 'textarea') { return; } const player = document.getElementById('movie_player'); const buttons = findLikeDislikeButtons(); if (e.code == 'BracketLeft' && (!e.ctrlKey) && (!e.shiftKey) && buttons.like) { const likePressed = getPressedAttribute(buttons.like); if (likePressed === 'true') { showNotification(maybePrefixWithEmoji('😭', 'Removed like from video')); } else if (likePressed === 'false') { showNotification(maybePrefixWithEmoji('❤️', 'Liked video')); } buttons.like.click(); } else if (e.code == 'BracketRight' && (!e.ctrlKey) && (!e.shiftKey) && buttons.dislike) { const dislikePressed = getPressedAttribute(buttons.dislike); if (dislikePressed === 'true') { showNotification(maybePrefixWithEmoji('😐', 'Removed dislike from video')); } else if (dislikePressed === 'false') { showNotification(maybePrefixWithEmoji('💔', 'Disliked video')); if (REMOVE_FEEDBACK_SHARED_WITH_CREATOR) { removeBuiltInFeedbackShared(Date.now()); } } buttons.dislike.click(); } else if (e.code == 'KeyH') { if (pipEnabled) { document.exitPictureInPicture(); } else { const video = getVideoElement(); video && video.requestPictureInPicture(); } pipEnabled = !pipEnabled; } else if (e.code == 'KeyB') { // back up current position const video = getVideoElement(); if (video) { const videoId = getVideoId(); savedPosition = { videoId: videoId, time: video.currentTime }; showNotification('Saved position: ' + formatTime(savedPosition.time)); } } else if (e.code == 'KeyR') { // restore saved position const video = getVideoElement(); if (video) { const videoId = getVideoId(); if (videoId && savedPosition.videoId && savedPosition.videoId === videoId) { video.currentTime = savedPosition.time; } else { showNotification('No saved timestamp found'); } } } else if (player && e.shiftKey && e.code === 'BracketRight') { player.setPlaybackRate(player.getPlaybackRate() + PLAYBACK_RATE_STEP); showNotification('Playback rate:' + formatPlaybackRate(player.getPlaybackRate())); } else if (player && e.shiftKey && e.code === 'BracketLeft') { player.setPlaybackRate(player.getPlaybackRate() - PLAYBACK_RATE_STEP); showNotification('Playback rate:' + formatPlaybackRate(player.getPlaybackRate())); } });
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址