From abe7bba1517d9f7ffd52f9cdeb66b6add253f0bd Mon Sep 17 00:00:00 2001 From: jsh9 <25124332+jsh9@users.noreply.github.com> Date: Sun, 30 Apr 2023 23:23:05 -0700 Subject: [PATCH] Add code, icon, and config --- README.md | 56 ++++++++++++++++++++++++++++++- background.js | 6 ++++ content.js | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++ icon.png | Bin 0 -> 8058 bytes manifest.json | 27 +++++++++++++++ 5 files changed, 179 insertions(+), 1 deletion(-) create mode 100644 background.js create mode 100644 content.js create mode 100644 icon.png create mode 100644 manifest.json diff --git a/README.md b/README.md index a3d7fe3..2c56da9 100644 --- a/README.md +++ b/README.md @@ -1 +1,55 @@ -# chrome-media-controller \ No newline at end of file +# chrome-media-controller + + +A Chrome or Edge extension to use keyboard to control webpage media (video and audio). + +## 1. Installation + +(To be published onto the Chrome Web Store...) + + +## 2. How to use + +| Key | Function | +|-----|----------| +| `k` | Play/pause | +| `j` | Seek backward 10 seconds | +| `l` | Seek forward 10 seconds | +| `m` | Mute/unmute sound | +| `w` | Increase volume | +| `s` | Decrease volume | +| `<` (Shift+`,`) | Slow down media playback speed | +| `>` (Shift+`.`) | Speed up media playback speed | + +## 3. Which websites does this extension work on + +I have tested this extension on the following websites. Websites outside of this list may still work. + +### Fully compatible: + +* YouTube +* HBO Max +* Amazon Prime Video +* Hulu +* Paramount+ +* Disney+ +* Google Podcasts + +### Partially compatible: + +* Netflix + - `j` and `l` can cause the Netflix webpage to shut down, so they are disabled + - Please use ← and → (Netflix's default) to seek backward and forward + +### Not compatible at all: + +* [YouTube Music](https://music.youtube.com/) + - YouTube music has its [unofficial shortcuts](https://support.google.com/youtubemusic/thread/180145/keyboard-shortcuts-web-player-cheat-sheet?hl=en) which are very different from this extension + - Therfore, I have disabled this extension on YouTube Music +* [Vimeo](https://vimeo.com/) + - This extension does not work on Vimeo at all + - [Here](https://help.vimeo.com/hc/en-us/articles/12425998125073-What-are-player-keyboard-shortcuts-) are Vimeo's official keyboard shortcuts, which unfortunately don't always work +* Spotify + - This extension does not work on Spotify at all +* Amazon Prime Music + - This extension does not work on Spotify at all diff --git a/background.js b/background.js new file mode 100644 index 0000000..af5098b --- /dev/null +++ b/background.js @@ -0,0 +1,6 @@ +chrome.action.onClicked.addListener((tab) => { + chrome.scripting.executeScript({ + target: { tabId: tab.id }, + files: ['content.js'] + }); +}); diff --git a/content.js b/content.js new file mode 100644 index 0000000..1ff4832 --- /dev/null +++ b/content.js @@ -0,0 +1,91 @@ +document.addEventListener('keydown', handleKeyDown); + + +function handleKeyDown(event) { + if ( // k, j, l, m, <, > are already defined in YouTube + window.location.hostname.includes('youtube.com') + && ['k', 'j', 'l', 'm', '<', '>'].includes(event.key) + ) { + return; + } + + if ( // j & l cause issues on Netflix + window.location.hostname.includes('netflix.com') + && ['j', 'l'].includes(event.key) + ) { + return; + } + + const mediaElements = Array.from(document.querySelectorAll('video, audio')); + + mediaElements.forEach((media) => { + const volumeStep = 0.05; + const playbackRateStep = 0.1; + + switch (event.key) { + case 'k': + if (media.paused) media.play(); + else media.pause(); + break; + case 'j': + media.currentTime = Math.max(media.currentTime - 10, 0); + break; + case 'l': + media.currentTime = Math.min(media.currentTime + 10, media.duration); + break; + case 'm': + media.muted = !media.muted; + break; + case 's': + newVolume = Math.max(media.volume - volumeStep, 0); + media.volume = newVolume; + showStatusPrompt(newVolume, 'Volume'); + break; + case 'w': + newVolume = Math.min(media.volume + volumeStep, 1); + media.volume = newVolume; + showStatusPrompt(newVolume, 'Volume'); + break; + case '<': + newPlaybackRate = Math.max(media.playbackRate - playbackRateStep, 0.5); + media.playbackRate = newPlaybackRate; + showStatusPrompt(newPlaybackRate, 'Speed'); + break; + case '>': + newPlaybackRate = Math.min(media.playbackRate + 0.1, 2); + media.playbackRate = newPlaybackRate; + showStatusPrompt(newPlaybackRate, 'Speed'); + break; + } + }); +} + + +function showStatusPrompt(status, name) { + let statusPrompt = document.getElementById('status-prompt'); + + if (!statusPrompt) { + statusPrompt = document.createElement('div'); + statusPrompt.id = 'status-prompt'; + statusPrompt.style.position = 'fixed'; + statusPrompt.style.top = '10%'; + statusPrompt.style.left = '50%'; + statusPrompt.style.transform = 'translate(-50%, -50%)'; + statusPrompt.style.padding = '10px'; + statusPrompt.style.borderRadius = '5px'; + statusPrompt.style.backgroundColor = 'rgba(0, 0, 0, 0.5)'; + statusPrompt.style.color = 'white'; + statusPrompt.style.fontSize = '18px'; + statusPrompt.style.fontWeight = 'regular'; + statusPrompt.style.zIndex = '9999'; + document.body.appendChild(statusPrompt); + } + + statusPrompt.textContent = `${name}: ${(status * 100).toFixed(0)}%`; + statusPrompt.style.display = 'block'; + + clearTimeout(statusPrompt.timeout); + statusPrompt.timeout = setTimeout(() => { + statusPrompt.style.display = 'none'; + }, 1000); +} diff --git a/icon.png b/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..722aa2d94977cf7529f2311148cc75497227ace1 GIT binary patch literal 8058 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 literal 0 HcmV?d00001 diff --git a/manifest.json b/manifest.json new file mode 100644 index 0000000..0b29f10 --- /dev/null +++ b/manifest.json @@ -0,0 +1,27 @@ +{ + "manifest_version": 3, + "name": "Media Controller", + "description": "Control video/audio in the webpage with keyboard shortcuts", + "version": "0.0.1", + "icons": { + "48": "icon.png" + }, + "permissions": [ + "activeTab" + ], + "action": { + "default_popup": "", + "default_icon": { + "48": "icon.png" + } + }, + "background": { + "service_worker": "background.js" + }, + "content_scripts": [ + { + "matches": [""], + "js": ["content.js"] + } + ] +}