Skip to content

Commit b37e956

Browse files
authored
feat: Adds custom sound effects in Chrome extension (closes #2) (#6)
* added chrome extension & mariokart music * removed music and updated icon * remove music controls from content.js * Added options page to select sounds (including default free-to-use royalty-free sounds). Added background page to open options on install & click. Styled in a peaches and cream way * updated options for "none" option * finished song selection with iframe workaround * remove upload button * feat: add default sound list so you can select any for any sound * fix how defaults work * added trademark symbol & disclaimer * added trailing newlines to files without them * preload all audio * add "thanks for installing" * feat: upload sounds, switched from sync to local * added helpful comment about deleting sound * fix: changed reveal to hider * fix: more missing trademark symbols * fix: set local save to false after importing
1 parent c018df0 commit b37e956

File tree

9 files changed

+534
-4
lines changed

9 files changed

+534
-4
lines changed

chrome-extension/background.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Event listener for extension installation
2+
chrome.runtime.onInstalled.addListener(function (details) {
3+
if (details.reason === "install") {
4+
// Open options/index.html file in a new tab
5+
chrome.tabs.create({ url: "options/index.html?justInstalled=true" });
6+
}
7+
});
8+
9+
// Event listener for extension icon click
10+
chrome.action.onClicked.addListener(function () {
11+
// Open options/index.html file in a new tab
12+
chrome.tabs.create({ url: "options/index.html" });
13+
});

chrome-extension/confetti.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -631,4 +631,4 @@
631631
// end source content
632632

633633
window.confetti = module.exports;
634-
}(window, {}));
634+
}(window, {}));

chrome-extension/content.js

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,53 @@
1414
(async function () {
1515
"use strict";
1616

17+
function loadAudioInIframe(soundObj) { // weird thing to get around college board not allowing external audio sources to be played
18+
let iframe = document.createElement('iframe')
19+
iframe.id = "audioIframe"
20+
iframe.src = chrome.runtime.getURL('/iframe/audioPlayerIframe.html');
21+
iframe.allow = "autoplay"
22+
iframe.style = `
23+
position: fixed;
24+
top: 0;
25+
left: 0;
26+
width: 0;
27+
height: 0;
28+
`;
29+
iframe.frameBorder = 0;
30+
iframe.scrolling = 'no';
31+
32+
iframe.addEventListener('load', () => {
33+
iframe.contentWindow.postMessage({sounds: soundObj, message: "setup"}, '*');
34+
});
35+
36+
document.body.appendChild(iframe);
37+
}
38+
39+
function playSoundInFrame(score){
40+
let iframe = document.getElementById("audioIframe")
41+
iframe.contentWindow.postMessage({message: "score", score: score}, "*")
42+
}
43+
44+
function getObjWithId(array, id){
45+
for (let obj of array){
46+
if (obj.id === id){
47+
return obj
48+
}
49+
}
50+
}
51+
52+
const selectSoundsObj = await chrome.storage.local.get("selectedSounds") // get the response from storage
53+
const selectedSounds = selectSoundsObj.selectedSounds
54+
const soundStorage = await chrome.storage.local.get("sounds") // get the response from storage
55+
const soundArray = soundStorage.sounds
56+
let sounds = {}
57+
58+
for (let score in selectedSounds) { // basically transfering this new format to the old format
59+
sounds[score] = getObjWithId(soundArray, selectedSounds[score]).URL
60+
}
61+
console.log(sounds)
62+
loadAudioInIframe(sounds)
63+
1764
// Grab all of the boxes that contain scores
1865
document.body.style.opacity = "0%"; // Hide the entire page until we can hide the scores themselves
1966
let ccontainers = [];
@@ -39,11 +86,12 @@
3986
ccontainer.parentNode.parentNode.style.cursor = "pointer"; // Makes the mouse display a pointer when you hover over the place the score should be
4087
ccontainer.parentNode.children[1].style.pointerEvents = "none"; // Make the sidebar not clickable
4188

42-
const clickListener = (e) => {
89+
const clickListener = (e) => {
4390
e.stopPropagation();
4491
const container = ccontainer.querySelector(".apscores-badge.apscores-badge-score"); // Have to do this again because reference gets messed
4592
const scoreNode = container.childNodes[1]; // Grab the text box that holds the score number
4693
const score = parseInt(scoreNode.nodeValue); // Get the score as a number (not a string)
94+
playSoundInFrame(score)
4795
if (score >= 3) {
4896
const { left, top } = ccontainer.getBoundingClientRect();
4997

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<title>Audio player iframe</title>
6+
</head>
7+
<body>
8+
<script src="iframeAudio.js"></script>
9+
</body>
10+
</html>
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
let sounds = {};
2+
window.addEventListener('message', (event) => {
3+
if (event.data.message === "setup"){
4+
const soundUrls = event.data.sounds
5+
for (const score in soundUrls) {
6+
sounds[score] = {score: score, audio: new Audio(soundUrls[score])}
7+
}
8+
console.log(sounds)
9+
}
10+
else if (event.data.message === "score"){
11+
pauseSounds()
12+
let score = event.data.score;
13+
sounds[score].audio.play()
14+
}
15+
});
16+
17+
function pauseSounds(){
18+
for (const score in sounds){
19+
sounds[score].audio.pause()
20+
}
21+
}

chrome-extension/manifest.json

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@
33
"name": "AP® Score Hider",
44
"version": "1.0.0",
55
"description": "Hides AP® Exam scores on the College Board website until you click on them, and displays confetti if they're passing.",
6-
"permissions": [],
6+
"permissions": ["storage", "unlimitedStorage"],
7+
"background": {
8+
"service_worker": "background.js"
9+
},
710
"content_scripts": [
811
{
912
"matches": ["https://apstudents.collegeboard.org/view-scores*"],
@@ -14,5 +17,16 @@
1417
"48": "icons/48.png",
1518
"128": "icons/128.png",
1619
"512": "icons/512.png"
17-
}
20+
},
21+
"action": {},
22+
"options_ui" : {
23+
"page": "options/index.html",
24+
"open_in_tab": true
25+
},
26+
"web_accessible_resources": [
27+
{
28+
"resources": ["iframe/*"],
29+
"matches": ["https://apstudents.collegeboard.org/*"]
30+
}
31+
]
1832
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<title>AP® Score Hider Settings</title>
6+
7+
<link rel="stylesheet" href="styles.css">
8+
</head>
9+
<body>
10+
<h1>AP® Score Hider Settings</h1>
11+
<h2 id="installThanks" style="display:none">Thank you for installing!</h2>
12+
<h4>Choose what sounds you want to play when you get your AP® Score!</h4>
13+
<br>
14+
<h4>Import sounds (use a direct .mp3 link or upload)</h4>
15+
<table>
16+
<tr>
17+
<th>Sound Title</th>
18+
<th>Direct link to sound file</th>
19+
</tr>
20+
<tr>
21+
<td><input type="text" id=""></td>
22+
<td><input type="url" id="sound-url"> or &nbsp; <label id="upload-label" for="audioFile"><input accept="audio/*" type="file" id="audioFile">Upload Sound</label></td>
23+
</tr>
24+
</table>
25+
<button id="import-btn">Import sound</button>
26+
<br>
27+
<div id="tables">
28+
<div>
29+
<h4>Choose Sounds</h4>
30+
<table>
31+
<tr>
32+
<th>Score</th>
33+
<th>Sound Effect</th>
34+
<th>Play Sound</th> <!-- New column for play sound button -->
35+
</tr>
36+
<tr>
37+
<td><label for="1">1</label></td>
38+
<td><select class="song-select" id="1"></select></td>
39+
<td><button class="play-button">&#128266;</button></td>
40+
</tr>
41+
<tr>
42+
<td><label for="2">2</label></td>
43+
<td><select class="song-select" id="2"></select></td>
44+
<td><button class="play-button">&#128266;</button></td>
45+
</tr>
46+
<tr>
47+
<td><label for="3">3</label></td>
48+
<td><select class="song-select" id="3"></select></td>
49+
<td><button class="play-button">&#128266;</button></td>
50+
</tr>
51+
<tr>
52+
<td><label for="4">4</label></td>
53+
<td><select class="song-select" id="4"></select></td>
54+
<td><button class="play-button">&#128266;</button></td>
55+
</tr>
56+
<tr>
57+
<td><label for="5">5</label></td>
58+
<td><select class="song-select" id="5"></select></td>
59+
<td><button class="play-button">&#128266;</button></td>
60+
</tr>
61+
</table>
62+
</div>
63+
<div id="delete-div" style="display: none">
64+
<h4>Delete Imported Sounds</h4>
65+
<table id="deleteSounds">
66+
<tr>
67+
<th>Sound</th>
68+
<th>Delete</th>
69+
</tr>
70+
</table>
71+
</div>
72+
</div>
73+
<h4><a href="https://account.collegeboard.org/login/login?appId=287&idp=ECL&DURL=https%3A//apstudents.collegeboard.org/view-scores" target="_blank">View your AP® scores</a></h4>
74+
<p><em>AP® is a trademark registered by the College Board, which is not affiliated with, and does not endorse, this product.</em></p>
75+
<script src="options.js"></script>
76+
</body>
77+
</html>

0 commit comments

Comments
 (0)