Skip to content

Commit abe7bba

Browse files
committed
Add code, icon, and config
1 parent fc3b432 commit abe7bba

File tree

5 files changed

+179
-1
lines changed

5 files changed

+179
-1
lines changed

README.md

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,55 @@
1-
# chrome-media-controller
1+
# chrome-media-controller
2+
3+
4+
A Chrome or Edge extension to use keyboard to control webpage media (video and audio).
5+
6+
## 1. Installation
7+
8+
(To be published onto the Chrome Web Store...)
9+
10+
11+
## 2. How to use
12+
13+
| Key | Function |
14+
|-----|----------|
15+
| `k` | Play/pause |
16+
| `j` | Seek backward 10 seconds |
17+
| `l` | Seek forward 10 seconds |
18+
| `m` | Mute/unmute sound |
19+
| `w` | Increase volume |
20+
| `s` | Decrease volume |
21+
| `<` (Shift+`,`) | Slow down media playback speed |
22+
| `>` (Shift+`.`) | Speed up media playback speed |
23+
24+
## 3. Which websites does this extension work on
25+
26+
I have tested this extension on the following websites. Websites outside of this list may still work.
27+
28+
### Fully compatible:
29+
30+
* YouTube
31+
* HBO Max
32+
* Amazon Prime Video
33+
* Hulu
34+
* Paramount+
35+
* Disney+
36+
* Google Podcasts
37+
38+
### Partially compatible:
39+
40+
* Netflix
41+
- `j` and `l` can cause the Netflix webpage to shut down, so they are disabled
42+
- Please use ← and → (Netflix's default) to seek backward and forward
43+
44+
### Not compatible at all:
45+
46+
* [YouTube Music](https://music.youtube.com/)
47+
- 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
48+
- Therfore, I have disabled this extension on YouTube Music
49+
* [Vimeo](https://vimeo.com/)
50+
- This extension does not work on Vimeo at all
51+
- [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
52+
* Spotify
53+
- This extension does not work on Spotify at all
54+
* Amazon Prime Music
55+
- This extension does not work on Spotify at all

background.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
chrome.action.onClicked.addListener((tab) => {
2+
chrome.scripting.executeScript({
3+
target: { tabId: tab.id },
4+
files: ['content.js']
5+
});
6+
});

content.js

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
document.addEventListener('keydown', handleKeyDown);
2+
3+
4+
function handleKeyDown(event) {
5+
if ( // k, j, l, m, <, > are already defined in YouTube
6+
window.location.hostname.includes('youtube.com')
7+
&& ['k', 'j', 'l', 'm', '<', '>'].includes(event.key)
8+
) {
9+
return;
10+
}
11+
12+
if ( // j & l cause issues on Netflix
13+
window.location.hostname.includes('netflix.com')
14+
&& ['j', 'l'].includes(event.key)
15+
) {
16+
return;
17+
}
18+
19+
const mediaElements = Array.from(document.querySelectorAll('video, audio'));
20+
21+
mediaElements.forEach((media) => {
22+
const volumeStep = 0.05;
23+
const playbackRateStep = 0.1;
24+
25+
switch (event.key) {
26+
case 'k':
27+
if (media.paused) media.play();
28+
else media.pause();
29+
break;
30+
case 'j':
31+
media.currentTime = Math.max(media.currentTime - 10, 0);
32+
break;
33+
case 'l':
34+
media.currentTime = Math.min(media.currentTime + 10, media.duration);
35+
break;
36+
case 'm':
37+
media.muted = !media.muted;
38+
break;
39+
case 's':
40+
newVolume = Math.max(media.volume - volumeStep, 0);
41+
media.volume = newVolume;
42+
showStatusPrompt(newVolume, 'Volume');
43+
break;
44+
case 'w':
45+
newVolume = Math.min(media.volume + volumeStep, 1);
46+
media.volume = newVolume;
47+
showStatusPrompt(newVolume, 'Volume');
48+
break;
49+
case '<':
50+
newPlaybackRate = Math.max(media.playbackRate - playbackRateStep, 0.5);
51+
media.playbackRate = newPlaybackRate;
52+
showStatusPrompt(newPlaybackRate, 'Speed');
53+
break;
54+
case '>':
55+
newPlaybackRate = Math.min(media.playbackRate + 0.1, 2);
56+
media.playbackRate = newPlaybackRate;
57+
showStatusPrompt(newPlaybackRate, 'Speed');
58+
break;
59+
}
60+
});
61+
}
62+
63+
64+
function showStatusPrompt(status, name) {
65+
let statusPrompt = document.getElementById('status-prompt');
66+
67+
if (!statusPrompt) {
68+
statusPrompt = document.createElement('div');
69+
statusPrompt.id = 'status-prompt';
70+
statusPrompt.style.position = 'fixed';
71+
statusPrompt.style.top = '10%';
72+
statusPrompt.style.left = '50%';
73+
statusPrompt.style.transform = 'translate(-50%, -50%)';
74+
statusPrompt.style.padding = '10px';
75+
statusPrompt.style.borderRadius = '5px';
76+
statusPrompt.style.backgroundColor = 'rgba(0, 0, 0, 0.5)';
77+
statusPrompt.style.color = 'white';
78+
statusPrompt.style.fontSize = '18px';
79+
statusPrompt.style.fontWeight = 'regular';
80+
statusPrompt.style.zIndex = '9999';
81+
document.body.appendChild(statusPrompt);
82+
}
83+
84+
statusPrompt.textContent = `${name}: ${(status * 100).toFixed(0)}%`;
85+
statusPrompt.style.display = 'block';
86+
87+
clearTimeout(statusPrompt.timeout);
88+
statusPrompt.timeout = setTimeout(() => {
89+
statusPrompt.style.display = 'none';
90+
}, 1000);
91+
}

icon.png

7.87 KB
Loading

manifest.json

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{
2+
"manifest_version": 3,
3+
"name": "Media Controller",
4+
"description": "Control video/audio in the webpage with keyboard shortcuts",
5+
"version": "0.0.1",
6+
"icons": {
7+
"48": "icon.png"
8+
},
9+
"permissions": [
10+
"activeTab"
11+
],
12+
"action": {
13+
"default_popup": "",
14+
"default_icon": {
15+
"48": "icon.png"
16+
}
17+
},
18+
"background": {
19+
"service_worker": "background.js"
20+
},
21+
"content_scripts": [
22+
{
23+
"matches": ["<all_urls>"],
24+
"js": ["content.js"]
25+
}
26+
]
27+
}

0 commit comments

Comments
 (0)