From 01b61f6192276f0bca3b175dd0109783fb73d8cb Mon Sep 17 00:00:00 2001 From: Ajay Ramachandran Date: Wed, 17 Jul 2019 19:42:13 -0400 Subject: [PATCH 01/13] Made it possible for multiple notices to appear, added an animation for it. --- content.css | 22 +++++++++--- content.js | 97 ++++++++++++++++++++++++++++++++++------------------- 2 files changed, 80 insertions(+), 39 deletions(-) diff --git a/content.css b/content.css index 1a85c3ac..3c5bfbda 100644 --- a/content.css +++ b/content.css @@ -2,7 +2,7 @@ font-family: 'Source Sans Pro', sans-serif; } -#sponsorSkipLogo { +.sponsorSkipLogo { height: 64px; position: absolute; top: 0; @@ -11,7 +11,12 @@ margin-left: 10px; } -#sponsorSkipNotice { +@keyframes fadeIn { + from { opacity: 0; } + to { opacity: 1; } +} + +.sponsorSkipNotice { min-height: 165px; min-width: 400px; background-color: rgba(255, 217, 217, 0.8); @@ -19,9 +24,18 @@ z-index: 1; border: 3px solid rgba(0, 0, 0, 0.8); margin-top: -50px; + + animation: fadeIn 0.5s; } -#sponsorSkipMessage { +/* if two are very close to eachother */ +.secondSkipNotice { + margin-left: 500px; + + transition: margin-left 0.2s; +} + +.sponsorSkipMessage { font-size: 18px; color: #000000; text-align: center; @@ -30,7 +44,7 @@ margin-top: 4px; } -#sponsorSkipInfo { +.sponsorSkipInfo { font-size: 10px; color: #000000; text-align: center; diff --git a/content.js b/content.js index 91e217f6..b5e2fc4c 100644 --- a/content.js +++ b/content.js @@ -148,24 +148,26 @@ function sponsorCheck(sponsorTimes) { // Video skipping v.currentTime = sponsorTimes[i][1]; lastSponsorTimeSkipped = sponsorTimes[i][0]; - lastSponsorTimeSkippedUUID = UUIDs[i]; + + let currentUUID = UUIDs[i]; + lastSponsorTimeSkippedUUID = currentUUID; //send out the message saying that a sponsor message was skipped openSkipNotice(); - setTimeout(closeSkipNotice, 7000); + setTimeout(() => closeSkipNotice(currentUUID), 7000); } lastTime = v.currentTime; } } -function goBackToPreviousTime() { - if (lastSponsorTimeSkipped != null) { +function goBackToPreviousTime(UUID) { + if (sponsorTimes != undefined) { //add a tiny bit of time to make sure it is not skipped again - v.currentTime = lastSponsorTimeSkipped + 0.001; + v.currentTime = sponsorTimes[UUIDs.indexOf(UUID)][0] + 0.001; - closeSkipNotice(); + closeSkipNotice(UUID); } } @@ -239,40 +241,57 @@ function openSkipNotice(){ return; } + let amountOfPreviousNotices = document.getElementsByClassName("sponsorSkipNotice").length; + + if (amountOfPreviousNotices > 0) { + //already exists + + let previousNotice = document.getElementsByClassName("sponsorSkipNotice")[0]; + previousNotice.classList.add("secondSkipNotice") + } + + let UUID = lastSponsorTimeSkippedUUID; + let noticeElement = document.createElement("div"); - noticeElement.id = "sponsorSkipNotice"; - noticeElement.className = "sponsorSkipObject"; + //what sponsor time this is about + noticeElement.id = "sponsorSkipNotice" + lastSponsorTimeSkippedUUID; + noticeElement.classList.add("sponsorSkipObject"); + noticeElement.classList.add("sponsorSkipNotice"); + noticeElement.style.zIndex = 1 + amountOfPreviousNotices; let logoElement = document.createElement("img"); - logoElement.id = "sponsorSkipLogo"; + logoElement.id = "sponsorSkipLogo" + lastSponsorTimeSkippedUUID; + logoElement.className = "sponsorSkipLogo"; logoElement.src = chrome.extension.getURL("icons/LogoSponsorBlocker256px.png"); let noticeMessage = document.createElement("div"); - noticeMessage.id = "sponsorSkipMessage"; - noticeMessage.className = "sponsorSkipObject"; + noticeMessage.id = "sponsorSkipMessage" + lastSponsorTimeSkippedUUID; + noticeMessage.classList.add("sponsorSkipMessage"); + noticeMessage.classList.add("sponsorSkipObject"); noticeMessage.innerText = "Hey, you just skipped a sponsor!"; let noticeInfo = document.createElement("p"); - noticeInfo.id = "sponsorSkipInfo"; - noticeInfo.className = "sponsorSkipObject"; + noticeInfo.id = "sponsorSkipInfo" + lastSponsorTimeSkippedUUID; + noticeInfo.classList.add("sponsorSkipInfo"); + noticeInfo.classList.add("sponsorSkipObject"); noticeInfo.innerText = "This message will disapear in 7 seconds"; //thumbs up and down buttons let voteButtonsContainer = document.createElement("div"); - voteButtonsContainer.id = "sponsorTimesVoteButtonsContainer"; + voteButtonsContainer.id = "sponsorTimesVoteButtonsContainer" + lastSponsorTimeSkippedUUID; voteButtonsContainer.setAttribute("align", "center"); let upvoteButton = document.createElement("img"); - upvoteButton.id = "sponsorTimesUpvoteButtonsContainer" + upvoteButton.id = "sponsorTimesUpvoteButtonsContainer" + lastSponsorTimeSkippedUUID; upvoteButton.className = "sponsorSkipObject voteButton"; upvoteButton.src = chrome.extension.getURL("icons/upvote.png"); - upvoteButton.addEventListener("click", upvote); + upvoteButton.addEventListener("click", () => upvote(UUID)); let downvoteButton = document.createElement("img"); - downvoteButton.id = "sponsorTimesDownvoteButtonsContainer" + downvoteButton.id = "sponsorTimesDownvoteButtonsContainer" + lastSponsorTimeSkippedUUID; downvoteButton.className = "sponsorSkipObject voteButton"; downvoteButton.src = chrome.extension.getURL("icons/downvote.png"); - downvoteButton.addEventListener("click", downvote); + downvoteButton.addEventListener("click", () => downvote(UUID)); //add thumbs up and down buttons to the container voteButtonsContainer.appendChild(upvoteButton); @@ -284,12 +303,12 @@ function openSkipNotice(){ let goBackButton = document.createElement("button"); goBackButton.innerText = "Go back"; goBackButton.className = "sponsorSkipButton"; - goBackButton.addEventListener("click", goBackToPreviousTime); + goBackButton.addEventListener("click", () => goBackToPreviousTime(UUID)); let hideButton = document.createElement("button"); hideButton.innerText = "Dismiss"; hideButton.className = "sponsorSkipButton"; - hideButton.addEventListener("click", closeSkipNotice); + hideButton.addEventListener("click", () => closeSkipNotice(UUID)); let dontShowAgainButton = document.createElement("button"); dontShowAgainButton.innerText = "Don't Show This Again"; @@ -316,19 +335,19 @@ function openSkipNotice(){ referenceNode.prepend(noticeElement); } -function upvote() { - vote(1); +function upvote(UUID) { + vote(1, UUID); - closeSkipNotice(); + closeSkipNotice(UUID); } -function downvote() { - vote(0); +function downvote(UUID) { + vote(0, UUID); //change text to say thanks for voting //remove buttons - document.getElementById("sponsorTimesVoteButtonsContainer").removeChild(document.getElementById("sponsorTimesUpvoteButtonsContainer")); - document.getElementById("sponsorTimesVoteButtonsContainer").removeChild(document.getElementById("sponsorTimesDownvoteButtonsContainer")); + document.getElementById("sponsorTimesVoteButtonsContainer" + UUID).removeChild(document.getElementById("sponsorTimesUpvoteButtonsContainer" + UUID)); + document.getElementById("sponsorTimesVoteButtonsContainer" + UUID).removeChild(document.getElementById("sponsorTimesDownvoteButtonsContainer" + UUID)); //add thanks for voting text let thanksForVotingText = document.createElement("p"); @@ -341,32 +360,40 @@ function downvote() { thanksForVotingInfoText.innerText = "Hit go back to get to where you came from." //add element to div - document.getElementById("sponsorTimesVoteButtonsContainer").appendChild(thanksForVotingText); - document.getElementById("sponsorTimesVoteButtonsContainer").appendChild(thanksForVotingInfoText); + document.getElementById("sponsorTimesVoteButtonsContainer" + UUID).appendChild(thanksForVotingText); + document.getElementById("sponsorTimesVoteButtonsContainer" + UUID).appendChild(thanksForVotingInfoText); } -function vote(type) { +function vote(type, UUID) { chrome.runtime.sendMessage({ message: "submitVote", type: type, - UUID: lastSponsorTimeSkippedUUID + UUID: UUID }); } -//Closes the notice that tells the user that a sponsor was just skipped -function closeSkipNotice(){ - let notice = document.getElementById("sponsorSkipNotice"); +//Closes the notice that tells the user that a sponsor was just skipped for this UUID +function closeSkipNotice(UUID){ + let notice = document.getElementById("sponsorSkipNotice" + UUID); if (notice != null) { notice.remove(); } } +//Closes all notices that tell the user that a sponsor was just skipped +function closeAllSkipNotices(){ + let notices = document.getElementsByClassName("sponsorSkipNotice"); + for (let i = 0; i < notices.length; i++) { + notices[i].remove(); + } +} + function dontShowNoticeAgain() { chrome.storage.local.set({"dontShowNoticeAgain": true}); dontShowNotice = true; - closeSkipNotice(); + closeAllSkipNotices(); } function sponsorMessageStarted() { From 888a03a708246ac2ba04874737359aa1b7ff5cfd Mon Sep 17 00:00:00 2001 From: Ajay Ramachandran Date: Wed, 17 Jul 2019 22:53:42 -0400 Subject: [PATCH 02/13] Added button to popup to allow you to vote from the popup. --- content.js | 3 ++- popup.css | 9 +++++++ popup.html | 16 ++++++++++- popup.js | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 104 insertions(+), 2 deletions(-) diff --git a/content.js b/content.js index b5e2fc4c..83d4735b 100644 --- a/content.js +++ b/content.js @@ -59,7 +59,8 @@ chrome.runtime.onMessage.addListener( // Detect URL Changes //send the sponsor times along with if it's found sendResponse({ found: sponsorDataFound, - sponsorTimes: sponsorTimes + sponsorTimes: sponsorTimes, + UUIDs: UUIDs }) } diff --git a/popup.css b/popup.css index 64ae0a17..36e2fb25 100644 --- a/popup.css +++ b/popup.css @@ -12,6 +12,15 @@ body { background-color: #ffd9d9; } +.voteButton { + height: 32px; + margin-right: 15px; + cursor: pointer; +} +.voteButton:hover { + filter: brightness(80%); +} + .greenButton { background-color:#ec1c1c; -moz-border-radius:28px; diff --git a/popup.html b/popup.html index 79b7adde..d34d9a76 100644 --- a/popup.html +++ b/popup.html @@ -24,7 +24,21 @@
- + +
+ + + + +

Record the times of a sponsorship

diff --git a/popup.js b/popup.js index d5b984f0..29deaf66 100644 --- a/popup.js +++ b/popup.js @@ -6,6 +6,7 @@ document.getElementById("showNoticeAgain").addEventListener("click", showNoticeA document.getElementById("hideVideoPlayerControls").addEventListener("click", hideVideoPlayerControls); document.getElementById("showVideoPlayerControls").addEventListener("click", showVideoPlayerControls); document.getElementById("optionsButton").addEventListener("click", openOptions); +document.getElementById("reportAnIssue").addEventListener("click", reportAnIssue); //if true, the button now selects the end time var startTimeChosen = false; @@ -164,6 +165,56 @@ function displayDownloadedSponsorTimes(request) { if (request.sponsorTimes != undefined) { //set it to the message document.getElementById("downloadedSponsorMessageTimes").innerHTML = getSponsorTimesMessage(request.sponsorTimes); + + //add them as buttons to the issue reporting container + let container = document.getElementById("issueReporterTimeButtons"); + for (let i = 0; i < request.sponsorTimes.length; i++) { + let sponsorTimeButton = document.createElement("button"); + sponsorTimeButton.className = "warningButton"; + sponsorTimeButton.innerText = getFormattedTime(request.sponsorTimes[i][0]) + " to " + getFormattedTime(request.sponsorTimes[i][1]); + + let votingButtons = document.createElement("div"); + + let UUID = request.UUIDs[i]; + + //thumbs up and down buttons + let voteButtonsContainer = document.createElement("div"); + voteButtonsContainer.id = "sponsorTimesVoteButtonsContainer" + UUID; + voteButtonsContainer.setAttribute("align", "center"); + voteButtonsContainer.style.display = "none" + + let upvoteButton = document.createElement("img"); + upvoteButton.id = "sponsorTimesUpvoteButtonsContainer" + UUID; + upvoteButton.className = "voteButton"; + upvoteButton.src = chrome.extension.getURL("icons/upvote.png"); + upvoteButton.addEventListener("click", () => vote(1, UUID)); + + let downvoteButton = document.createElement("img"); + downvoteButton.id = "sponsorTimesDownvoteButtonsContainer" + UUID; + downvoteButton.className = "voteButton"; + downvoteButton.src = chrome.extension.getURL("icons/downvote.png"); + downvoteButton.addEventListener("click", () => vote(0, UUID)); + + //add thumbs up and down buttons to the container + voteButtonsContainer.appendChild(document.createElement("br")); + voteButtonsContainer.appendChild(document.createElement("br")); + voteButtonsContainer.appendChild(upvoteButton); + voteButtonsContainer.appendChild(downvoteButton); + + //add click listener to open up vote panel + sponsorTimeButton.addEventListener("click", function() { + voteButtonsContainer.style.display = "unset"; + }); + + container.appendChild(sponsorTimeButton); + container.appendChild(voteButtonsContainer); + + //if it is not the last iteration + if (i != request.sponsorTimes.length - 1) { + container.appendChild(document.createElement("br")); + container.appendChild(document.createElement("br")); + } + } } } @@ -314,6 +365,33 @@ function displayNoVideo() { "If you know this is a YouTube tab, close this popup and open it again."; } +function reportAnIssue() { + document.getElementById("issueReporterContainer").style.display = "unset"; + document.getElementById("reportAnIssue").style.display = "none"; +} + +function vote(type, UUID) { + let container = document.getElementById("sponsorTimesVoteButtonsContainer" + UUID); + //remove all children + while (container.firstChild) { + container.removeChild(container.firstChild); + } + + let thanksForVotingText = document.createElement("h2"); + thanksForVotingText.innerText = "Thanks for voting!"; + //there are already breaks there + thanksForVotingText.style.marginBottom = "0px"; + + container.appendChild(thanksForVotingText); + + //send the vote message to the tab + chrome.runtime.sendMessage({ + message: "submitVote", + type: type, + UUID: UUID + }); +} + //converts time in seconds to minutes:seconds function getFormattedTime(seconds) { let minutes = Math.floor(seconds / 60); From b319729da8a0e4bf3d4871dda70fde894e74439c Mon Sep 17 00:00:00 2001 From: Ajay Ramachandran Date: Fri, 19 Jul 2019 22:24:59 -0400 Subject: [PATCH 03/13] Added error message for a duplicate vote. --- background.js | 39 ++++++++++++++++++++++++++++++--------- content.css | 7 +++++++ content.js | 44 +++++++++++++++++++++++++++++++++----------- popup.js | 17 +++++++++++++++-- 4 files changed, 85 insertions(+), 22 deletions(-) diff --git a/background.js b/background.js index c619bcbb..ec126b20 100644 --- a/background.js +++ b/background.js @@ -42,7 +42,10 @@ chrome.runtime.onMessage.addListener(function (request, sender, callback) { //this allows the callback to be called later return true; } else if (request.message == "submitVote") { - submitVote(request.type, request.UUID) + submitVote(request.type, request.UUID, callback); + + //this allows the callback to be called later + return true; } }); @@ -81,16 +84,21 @@ function addSponsorTime(time) { }); } -function submitVote(type, UUID) { - let xmlhttp = new XMLHttpRequest(); - +function submitVote(type, UUID, callback) { getUserID(function(userID) { //publish this vote - console.log(serverAddress + "/api/voteOnSponsorTime?UUID=" + UUID + "&userID=" + userID + "&type=" + type); - xmlhttp.open('GET', serverAddress + "/api/voteOnSponsorTime?UUID=" + UUID + "&userID=" + userID + "&type=" + type, true); - - //submit this vote - xmlhttp.send(); + sendRequestToUser('GET', "/api/voteOnSponsorTime?UUID=" + UUID + "&userID=" + userID + "&type=" + type, function(xmlhttp) { + if (xmlhttp.readyState == 4 && xmlhttp.status == 200) { + callback({ + successType: 1 + }); + } else if (xmlhttp.readyState == 4 && xmlhttp.status == 405) { + //duplicate vote + callback({ + successType: 0 + }); + } + }) }) } @@ -166,6 +174,19 @@ function getUserID(callback) { }); } +function sendRequestToUser(type, address, callback) { + let xmlhttp = new XMLHttpRequest(); + + xmlhttp.open(type, serverAddress + address, true); + + xmlhttp.onreadystatechange = function () { + callback(xmlhttp); + }; + + //submit this request + xmlhttp.send(); +} + function getYouTubeVideoID(url) { // Return video id or false var regExp = /^.*((youtu.be\/)|(v\/)|(\/u\/\w\/)|(embed\/)|(watch\?))\??v?=?([^#\&\?]*).*/; var match = url.match(regExp); diff --git a/content.css b/content.css index 3c5bfbda..763213ba 100644 --- a/content.css +++ b/content.css @@ -58,6 +58,13 @@ text-align: center; } +#sponsorTimesErrorMessage { + font-size: 15px; + font-weight: bold; + color: #000000; + text-align: center; +} + #sponsorTimesThanksForVotingInfoText { font-size: 12px; font-weight: bold; diff --git a/content.js b/content.js index 83d4735b..2bea7df8 100644 --- a/content.js +++ b/content.js @@ -286,13 +286,13 @@ function openSkipNotice(){ upvoteButton.id = "sponsorTimesUpvoteButtonsContainer" + lastSponsorTimeSkippedUUID; upvoteButton.className = "sponsorSkipObject voteButton"; upvoteButton.src = chrome.extension.getURL("icons/upvote.png"); - upvoteButton.addEventListener("click", () => upvote(UUID)); + upvoteButton.addEventListener("click", () => vote(1, UUID)); let downvoteButton = document.createElement("img"); downvoteButton.id = "sponsorTimesDownvoteButtonsContainer" + lastSponsorTimeSkippedUUID; downvoteButton.className = "sponsorSkipObject voteButton"; downvoteButton.src = chrome.extension.getURL("icons/downvote.png"); - downvoteButton.addEventListener("click", () => downvote(UUID)); + downvoteButton.addEventListener("click", () => vote(0, UUID)); //add thumbs up and down buttons to the container voteButtonsContainer.appendChild(upvoteButton); @@ -336,15 +336,7 @@ function openSkipNotice(){ referenceNode.prepend(noticeElement); } -function upvote(UUID) { - vote(1, UUID); - - closeSkipNotice(UUID); -} - -function downvote(UUID) { - vote(0, UUID); - +function afterDownvote(UUID) { //change text to say thanks for voting //remove buttons document.getElementById("sponsorTimesVoteButtonsContainer" + UUID).removeChild(document.getElementById("sponsorTimesUpvoteButtonsContainer" + UUID)); @@ -365,11 +357,41 @@ function downvote(UUID) { document.getElementById("sponsorTimesVoteButtonsContainer" + UUID).appendChild(thanksForVotingInfoText); } +function votingError(message, UUID) { + //change text to say thanks for voting + //remove buttons + document.getElementById("sponsorTimesVoteButtonsContainer" + UUID).removeChild(document.getElementById("sponsorTimesUpvoteButtonsContainer" + UUID)); + document.getElementById("sponsorTimesVoteButtonsContainer" + UUID).removeChild(document.getElementById("sponsorTimesDownvoteButtonsContainer" + UUID)); + + //add thanks for voting text + let thanksForVotingText = document.createElement("p"); + thanksForVotingText.id = "sponsorTimesErrorMessage"; + thanksForVotingText.innerText = message; + + //add element to div + document.getElementById("sponsorTimesVoteButtonsContainer" + UUID).appendChild(thanksForVotingText); +} + function vote(type, UUID) { chrome.runtime.sendMessage({ message: "submitVote", type: type, UUID: UUID + }, function(response) { + if (response != undefined) { + //see if it was a success or failure + if (response.successType == 1) { + //success + if (type == 0) { + afterDownvote(UUID); + } else if (type == 1) { + closeSkipNotice(UUID); + } + } else if (response.successType == 0) { + //failure: duplicate vote + votingError("It seems you've already voted before", UUID) + } + } }); } diff --git a/popup.js b/popup.js index 29deaf66..cf4d54cf 100644 --- a/popup.js +++ b/popup.js @@ -370,7 +370,7 @@ function reportAnIssue() { document.getElementById("reportAnIssue").style.display = "none"; } -function vote(type, UUID) { +function addVoteMessage(message, UUID) { let container = document.getElementById("sponsorTimesVoteButtonsContainer" + UUID); //remove all children while (container.firstChild) { @@ -378,17 +378,30 @@ function vote(type, UUID) { } let thanksForVotingText = document.createElement("h2"); - thanksForVotingText.innerText = "Thanks for voting!"; + thanksForVotingText.innerText = message; //there are already breaks there thanksForVotingText.style.marginBottom = "0px"; container.appendChild(thanksForVotingText); +} +function vote(type, UUID) { //send the vote message to the tab chrome.runtime.sendMessage({ message: "submitVote", type: type, UUID: UUID + }, function(response) { + if (response != undefined) { + //see if it was a success or failure + if (response.successType == 1) { + //success + addVoteMessage("Thanks for voting!", UUID) + } else if (response.successType == 0) { + //failure: duplicate vote + addVoteMessage("You have already voted this way before.", UUID) + } + } }); } From 4bb6cd0dcfb1677346c66df16627b497b7b24ff8 Mon Sep 17 00:00:00 2001 From: Ajay Ramachandran Date: Sat, 20 Jul 2019 13:26:55 -0400 Subject: [PATCH 04/13] Add message when connection failed when trying to vote. --- background.js | 13 +++++++++++-- content.js | 3 +++ popup.js | 3 +++ 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/background.js b/background.js index ec126b20..4feb48bd 100644 --- a/background.js +++ b/background.js @@ -87,7 +87,7 @@ function addSponsorTime(time) { function submitVote(type, UUID, callback) { getUserID(function(userID) { //publish this vote - sendRequestToUser('GET', "/api/voteOnSponsorTime?UUID=" + UUID + "&userID=" + userID + "&type=" + type, function(xmlhttp) { + sendRequestToUser('GET', "/api/voteOnSponsorTime?UUID=" + UUID + "&userID=" + userID + "&type=" + type, function(xmlhttp, error) { if (xmlhttp.readyState == 4 && xmlhttp.status == 200) { callback({ successType: 1 @@ -97,6 +97,11 @@ function submitVote(type, UUID, callback) { callback({ successType: 0 }); + } else if (error) { + //error while connect + callback({ + successType: -1 + }); } }) }) @@ -180,7 +185,11 @@ function sendRequestToUser(type, address, callback) { xmlhttp.open(type, serverAddress + address, true); xmlhttp.onreadystatechange = function () { - callback(xmlhttp); + callback(xmlhttp, false); + }; + + xmlhttp.onerror = function(ev) { + callback(xmlhttp, true); }; //submit this request diff --git a/content.js b/content.js index 2bea7df8..b6f3ed9f 100644 --- a/content.js +++ b/content.js @@ -390,6 +390,9 @@ function vote(type, UUID) { } else if (response.successType == 0) { //failure: duplicate vote votingError("It seems you've already voted before", UUID) + } else if (response.successType == -1) { + //failure: duplicate vote + votingError("A connection error has occured.", UUID) } } }); diff --git a/popup.js b/popup.js index cf4d54cf..fdf23dc9 100644 --- a/popup.js +++ b/popup.js @@ -400,6 +400,9 @@ function vote(type, UUID) { } else if (response.successType == 0) { //failure: duplicate vote addVoteMessage("You have already voted this way before.", UUID) + } else if (response.successType == -1) { + //failure: duplicate vote + addVoteMessage("A connection error has occured.", UUID) } } }); From 4cc44258e8c4c76322d7f9c981222f0e49839395 Mon Sep 17 00:00:00 2001 From: Ajay Ramachandran Date: Sat, 20 Jul 2019 13:41:13 -0400 Subject: [PATCH 05/13] Added a loading indicator when voting. --- content.css | 17 ++++++++++------- content.js | 46 +++++++++++++++++++++++++++++++++++++--------- popup.js | 3 +++ 3 files changed, 50 insertions(+), 16 deletions(-) diff --git a/content.css b/content.css index 763213ba..6ff83351 100644 --- a/content.css +++ b/content.css @@ -56,13 +56,8 @@ font-weight: bold; color: #000000; text-align: center; -} - -#sponsorTimesErrorMessage { - font-size: 15px; - font-weight: bold; - color: #000000; - text-align: center; + margin-top: 0px; + margin-bottom: 0px; } #sponsorTimesThanksForVotingInfoText { @@ -70,6 +65,14 @@ font-weight: bold; color: #000000; text-align: center; + margin-top: 0px; +} + +.sponsorTimesInfoMessage { + font-size: 15px; + font-weight: bold; + color: #000000; + text-align: center; } .voteButton { diff --git a/content.js b/content.js index b6f3ed9f..9203acc6 100644 --- a/content.js +++ b/content.js @@ -339,8 +339,20 @@ function openSkipNotice(){ function afterDownvote(UUID) { //change text to say thanks for voting //remove buttons - document.getElementById("sponsorTimesVoteButtonsContainer" + UUID).removeChild(document.getElementById("sponsorTimesUpvoteButtonsContainer" + UUID)); - document.getElementById("sponsorTimesVoteButtonsContainer" + UUID).removeChild(document.getElementById("sponsorTimesDownvoteButtonsContainer" + UUID)); + let upvoteButton = document.getElementById("sponsorTimesUpvoteButtonsContainer" + UUID); + let downvoteButton = document.getElementById("sponsorTimesDownvoteButtonsContainer" + UUID); + if (upvoteButton != null) { + document.getElementById("sponsorTimesVoteButtonsContainer" + UUID).removeChild(upvoteButton); + } + if (downvoteButton != null) { + document.getElementById("sponsorTimesVoteButtonsContainer" + UUID).removeChild(downvoteButton); + } + + let previousInfoMessage = document.getElementById("sponsorTimesInfoMessage" + UUID); + if (previousInfoMessage != null) { + //remove it + document.getElementById("sponsorTimesVoteButtonsContainer" + UUID).removeChild(previousInfoMessage); + } //add thanks for voting text let thanksForVotingText = document.createElement("p"); @@ -357,15 +369,28 @@ function afterDownvote(UUID) { document.getElementById("sponsorTimesVoteButtonsContainer" + UUID).appendChild(thanksForVotingInfoText); } -function votingError(message, UUID) { - //change text to say thanks for voting +function addLoadingInfo(message, UUID) { + //change text to say thanks for message //remove buttons - document.getElementById("sponsorTimesVoteButtonsContainer" + UUID).removeChild(document.getElementById("sponsorTimesUpvoteButtonsContainer" + UUID)); - document.getElementById("sponsorTimesVoteButtonsContainer" + UUID).removeChild(document.getElementById("sponsorTimesDownvoteButtonsContainer" + UUID)); + let upvoteButton = document.getElementById("sponsorTimesUpvoteButtonsContainer" + UUID); + let downvoteButton = document.getElementById("sponsorTimesDownvoteButtonsContainer" + UUID); + if (upvoteButton != null) { + document.getElementById("sponsorTimesVoteButtonsContainer" + UUID).removeChild(upvoteButton); + } + if (downvoteButton != null) { + document.getElementById("sponsorTimesVoteButtonsContainer" + UUID).removeChild(downvoteButton); + } + + let previousInfoMessage = document.getElementById("sponsorTimesInfoMessage" + UUID); + if (previousInfoMessage != null) { + //remove it + document.getElementById("sponsorTimesVoteButtonsContainer" + UUID).removeChild(previousInfoMessage); + } //add thanks for voting text let thanksForVotingText = document.createElement("p"); - thanksForVotingText.id = "sponsorTimesErrorMessage"; + thanksForVotingText.id = "sponsorTimesInfoMessage" + UUID; + thanksForVotingText.className = "sponsorTimesInfoMessage"; thanksForVotingText.innerText = message; //add element to div @@ -373,6 +398,9 @@ function votingError(message, UUID) { } function vote(type, UUID) { + //add loading info + addLoadingInfo("Loading...", UUID) + chrome.runtime.sendMessage({ message: "submitVote", type: type, @@ -389,10 +417,10 @@ function vote(type, UUID) { } } else if (response.successType == 0) { //failure: duplicate vote - votingError("It seems you've already voted before", UUID) + addLoadingInfo("It seems you've already voted before", UUID) } else if (response.successType == -1) { //failure: duplicate vote - votingError("A connection error has occured.", UUID) + addLoadingInfo("A connection error has occured.", UUID) } } }); diff --git a/popup.js b/popup.js index fdf23dc9..29157379 100644 --- a/popup.js +++ b/popup.js @@ -386,6 +386,9 @@ function addVoteMessage(message, UUID) { } function vote(type, UUID) { + //add loading info + addVoteMessage("Loading...", UUID) + //send the vote message to the tab chrome.runtime.sendMessage({ message: "submitVote", From 91f0b65d0633e3b34272d715475c273802df471b Mon Sep 17 00:00:00 2001 From: Ajay Ramachandran Date: Sat, 20 Jul 2019 15:33:52 -0400 Subject: [PATCH 06/13] Switched all xmlhttp requests to use new dedicated function. --- background.js | 29 ++++++++++++++--------------- content.js | 48 ++++++++++++++++++++++++++++++++---------------- 2 files changed, 46 insertions(+), 31 deletions(-) diff --git a/background.js b/background.js index 4feb48bd..c7bf572b 100644 --- a/background.js +++ b/background.js @@ -87,7 +87,7 @@ function addSponsorTime(time) { function submitVote(type, UUID, callback) { getUserID(function(userID) { //publish this vote - sendRequestToUser('GET', "/api/voteOnSponsorTime?UUID=" + UUID + "&userID=" + userID + "&type=" + type, function(xmlhttp, error) { + sendRequestToServer('GET', "/api/voteOnSponsorTime?UUID=" + UUID + "&userID=" + userID + "&type=" + type, function(xmlhttp, error) { if (xmlhttp.readyState == 4 && xmlhttp.status == 200) { callback({ successType: 1 @@ -116,13 +116,10 @@ function submitTimes(videoID) { if (sponsorTimes != undefined && sponsorTimes.length > 0) { //submit these times for (let i = 0; i < sponsorTimes.length; i++) { - let xmlhttp = new XMLHttpRequest(); - - let userIDStorage = getUserID(function(userIDStorage) { + getUserID(function(userIDStorage) { //submit the sponsorTime - xmlhttp.open('GET', serverAddress + "/api/postVideoSponsorTimes?videoID=" + videoID + "&startTime=" + sponsorTimes[i][0] + "&endTime=" + sponsorTimes[i][1] - + "&userID=" + userIDStorage, true); - xmlhttp.send(); + sendRequestToServer('GET', "/api/postVideoSponsorTimes?videoID=" + videoID + "&startTime=" + sponsorTimes[i][0] + "&endTime=" + sponsorTimes[i][1] + + "&userID=" + userIDStorage); }); } } @@ -179,18 +176,20 @@ function getUserID(callback) { }); } -function sendRequestToUser(type, address, callback) { +function sendRequestToServer(type, address, callback) { let xmlhttp = new XMLHttpRequest(); xmlhttp.open(type, serverAddress + address, true); - xmlhttp.onreadystatechange = function () { - callback(xmlhttp, false); - }; - - xmlhttp.onerror = function(ev) { - callback(xmlhttp, true); - }; + if (callback != undefined) { + xmlhttp.onreadystatechange = function () { + callback(xmlhttp, false); + }; + + xmlhttp.onerror = function(ev) { + callback(xmlhttp, true); + }; + } //submit this request xmlhttp.send(); diff --git a/content.js b/content.js index 9203acc6..cafd9db7 100644 --- a/content.js +++ b/content.js @@ -118,24 +118,21 @@ function sponsorsLookup(id) { let xmlhttp = new XMLHttpRequest(); //check database for sponsor times - xmlhttp.open('GET', serverAddress + "/api/getVideoSponsorTimes?videoID=" + id, true); + sendRequestToServer('GET', "/api/getVideoSponsorTimes?videoID=" + id, function(xmlhttp) { + if (xmlhttp.readyState == 4 && xmlhttp.status == 200) { + sponsorDataFound = true; - xmlhttp.onreadystatechange = function () { - if (xmlhttp.readyState == 4 && xmlhttp.status == 200) { - sponsorDataFound = true; + sponsorTimes = JSON.parse(xmlhttp.responseText).sponsorTimes; + UUIDs = JSON.parse(xmlhttp.responseText).UUIDs; - sponsorTimes = JSON.parse(xmlhttp.responseText).sponsorTimes; - UUIDs = JSON.parse(xmlhttp.responseText).UUIDs; - - // If the sponsor data exists, add the event to run on the videos "ontimeupdate" - v.ontimeupdate = function () { - sponsorCheck(sponsorTimes); - }; - } else { - sponsorDataFound = false; - } - }; - xmlhttp.send(null); + // If the sponsor data exists, add the event to run on the videos "ontimeupdate" + v.ontimeupdate = function () { + sponsorCheck(sponsorTimes); + }; + } else { + sponsorDataFound = false; + } + }); } function sponsorCheck(sponsorTimes) { // Video skipping @@ -463,6 +460,25 @@ function sponsorMessageStarted() { toggleStartSponsorButton(); } +function sendRequestToServer(type, address, callback) { + let xmlhttp = new XMLHttpRequest(); + + xmlhttp.open(type, serverAddress + address, true); + + if (callback != undefined) { + xmlhttp.onreadystatechange = function () { + callback(xmlhttp, false); + }; + + xmlhttp.onerror = function(ev) { + callback(xmlhttp, true); + }; + } + + //submit this request + xmlhttp.send(); +} + function getYouTubeVideoID(url) { // Returns with video id else returns false var regExp = /^.*((youtu.be\/)|(v\/)|(\/u\/\w\/)|(embed\/)|(watch\?))\??v?=?([^#\&\?]*).*/; var match = url.match(regExp); From a7a4642920e046a21a9ce101d6064b1c430fff95 Mon Sep 17 00:00:00 2001 From: Ajay Ramachandran Date: Sat, 20 Jul 2019 16:03:42 -0400 Subject: [PATCH 07/13] Sponsor time submission now has proper error messages. --- background.js | 21 +++++++++++++++------ popup.html | 12 +++++++++++- popup.js | 33 +++++++++++++++++++++++++++++---- 3 files changed, 55 insertions(+), 11 deletions(-) diff --git a/background.js b/background.js index c7bf572b..026b83f8 100644 --- a/background.js +++ b/background.js @@ -21,11 +21,10 @@ chrome.tabs.onUpdated.addListener( // On tab update chrome.runtime.onMessage.addListener(function (request, sender, callback) { if (request.message == "submitTimes") { - submitTimes(request.videoID); + submitTimes(request.videoID, callback); - callback({ - success: true - }); + //this allows the callback to be called later by the submitTimes function + return true; } else if (request.message == "ytvideoid") { if (previousVideoID != request.videoID) { videoIDChange(request.videoID); @@ -107,7 +106,7 @@ function submitVote(type, UUID, callback) { }) } -function submitTimes(videoID) { +function submitTimes(videoID, callback) { //get the video times from storage let sponsorTimeKey = 'sponsorTimes' + videoID; chrome.storage.local.get([sponsorTimeKey], function(result) { @@ -119,7 +118,17 @@ function submitTimes(videoID) { getUserID(function(userIDStorage) { //submit the sponsorTime sendRequestToServer('GET', "/api/postVideoSponsorTimes?videoID=" + videoID + "&startTime=" + sponsorTimes[i][0] + "&endTime=" + sponsorTimes[i][1] - + "&userID=" + userIDStorage); + + "&userID=" + userIDStorage, function(xmlhttp, error) { + if (xmlhttp.readyState == 4 && !error) { + callback({ + statusCode: xmlhttp.status + }); + } else if (error) { + callback({ + statusCode: -1 + }); + } + }); }); } } diff --git a/popup.html b/popup.html index d34d9a76..f77a6a02 100644 --- a/popup.html +++ b/popup.html @@ -62,8 +62,18 @@

+ +

-
diff --git a/popup.js b/popup.js index 29157379..d60bba61 100644 --- a/popup.js +++ b/popup.js @@ -268,12 +268,35 @@ function clearTimes() { } function submitTimes() { + //make info message say loading + document.getElementById("submitTimesInfoMessage").innerText = "Loading..."; + document.getElementById("submitTimesInfoMessageContainer").style.display = "unset"; + if (sponsorTimes.length > 0) { chrome.runtime.sendMessage({ message: "submitTimes", videoID: currentVideoID - }, function(request) { - clearTimes(); + }, function(response) { + if (response != undefined) { + if (response.statusCode == 200) { + //hide loading message + document.getElementById("submitTimesInfoMessageContainer").style.display = "none"; + + clearTimes(); + } else if(response.statusCode == 400) { + document.getElementById("submitTimesInfoMessage").innerText = "Server said this request was invalid"; + document.getElementById("submitTimesInfoMessageContainer").style.display = "unset"; + } else if(response.statusCode == 429) { + document.getElementById("submitTimesInfoMessage").innerText = "You have submitted too many sponsor times for this one video, are you sure there are this many?"; + document.getElementById("submitTimesInfoMessageContainer").style.display = "unset"; + } else if(response.statusCode == 409) { + document.getElementById("submitTimesInfoMessage").innerText = "This has already been submitted before"; + document.getElementById("submitTimesInfoMessageContainer").style.display = "unset"; + } else { + document.getElementById("submitTimesInfoMessage").innerText = "There was an error submitting your sponsor times, please try again later"; + document.getElementById("submitTimesInfoMessageContainer").style.display = "unset"; + } + } }); } } @@ -343,13 +366,15 @@ function resetStartTimeChosen() { document.getElementById("sponsorStart").innerHTML = "Sponsorship Starts Now"; } +//hides and shows the submit times button when needed function showSubmitTimesIfNecessary() { //check if an end time has been specified for the latest sponsor time if (sponsorTimes.length > 0 && sponsorTimes[sponsorTimes.length - 1].length > 1) { //show submit times button - document.getElementById("submitTimes").style.display = "unset"; + document.getElementById("submitTimesContainer").style.display = "unset"; } else { - document.getElementById("submitTimes").style.display = "none"; + //hide submit times button + document.getElementById("submitTimesContainer").style.display = "none"; } } From 2d00cfffdfac4a5e30fcef55c576ceec650de28a Mon Sep 17 00:00:00 2001 From: Ajay Ramachandran Date: Sun, 21 Jul 2019 18:19:56 -0400 Subject: [PATCH 08/13] Added submit button on the video player. --- content.css | 44 ++++++++ content.js | 98 +++++++++++++++--- ...yerUploadFailedIconSponsorBlocker256px.png | Bin 0 -> 11695 bytes icons/PlayerUploadIconSponsorBlocker256px.png | Bin 0 -> 11934 bytes manifest.json | 2 + popup.js | 9 +- 6 files changed, 137 insertions(+), 16 deletions(-) create mode 100644 icons/PlayerUploadFailedIconSponsorBlocker256px.png create mode 100644 icons/PlayerUploadIconSponsorBlocker256px.png diff --git a/content.css b/content.css index 6ff83351..6126768a 100644 --- a/content.css +++ b/content.css @@ -1,3 +1,11 @@ +.playerButton { + height: 60%; + top: 0; + bottom: 0; + display: block; + margin: auto; +} + .sponsorSkipObject { font-family: 'Source Sans Pro', sans-serif; } @@ -84,6 +92,42 @@ filter: brightness(80%); } +.submitButton { + background-color:#ec1c1c; + -moz-border-radius:28px; + -webkit-border-radius:28px; + border-radius:28px; + border:1px solid #d31919; + display:inline-block; + cursor:pointer; + color:#ffffff; + font-size:14px; + padding:4px 15px; + text-decoration:none; + text-shadow:0px 0px 0px #662727; + + margin-top: 5px; + margin-right: 15px; +} +.submitButton:hover { + background-color:#bf2a2a; +} + +.submitButton:focus { + outline: none; + background-color:#bf2a2a; +} + +.submitButton:active { + position:relative; + top:1px; +} + +@keyframes rotate { + from { transform: rotate(0deg); } + to { transform: rotate(360deg); } +} + .sponsorSkipButton { background-color:#ec1c1c; -moz-border-radius:28px; diff --git a/content.js b/content.js index cafd9db7..f27120c5 100644 --- a/content.js +++ b/content.js @@ -74,8 +74,8 @@ chrome.runtime.onMessage.addListener( // Detect URL Changes dontShowNotice = false; } - if (request.message == "toggleStartSponsorButton") { - toggleStartSponsorButton(); + if (request.message == "changeStartSponsorButton") { + changeStartSponsorButton(request.visibility, request.uploadButtonVisible); } if (request.message == "changeVideoPlayerControlsVisibility") { @@ -97,7 +97,9 @@ function videoIDChange(id) { }, function(response) { if (response != undefined) { let sponsorTimes = response.sponsorTimes; - if (sponsorTimes != undefined && sponsorTimes.length > 0 && sponsorTimes[sponsorTimes.length - 1].length < 2) { + if (sponsorTimes != undefined && sponsorTimes.length > 0 && sponsorTimes[sponsorTimes.length - 1].length >= 2) { + document.getElementById("submitButton").style.display = "unset"; + } else if (sponsorTimes != undefined && sponsorTimes.length > 0 && sponsorTimes[sponsorTimes.length - 1].length < 2) { toggleStartSponsorButton(); } } @@ -184,11 +186,7 @@ function addPlayerControlsButton() { let startSponsorImage = document.createElement("img"); startSponsorImage.id = "startSponsorImage"; - startSponsorImage.style.height = "60%"; - startSponsorImage.style.top = "0"; - startSponsorImage.style.bottom = "0"; - startSponsorImage.style.display = "block"; - startSponsorImage.style.margin = "auto"; + startSponsorImage.className = "playerButton"; startSponsorImage.src = chrome.extension.getURL("icons/PlayerStartIconSponsorBlocker256px.png"); //add the image to the button @@ -201,6 +199,7 @@ function addPlayerControlsButton() { function removePlayerControlsButton() { document.getElementById("startSponsorButton").style.display = "none"; + document.getElementById("submitButton").style.display = "none"; } //adds or removes the player controls button to what it should be @@ -209,6 +208,7 @@ function updateVisibilityOfPlayerControlsButton() { removePlayerControlsButton(); } else { addPlayerControlsButton(); + addSubmitButton(); } } @@ -222,16 +222,58 @@ function startSponsorClicked() { }); } -function toggleStartSponsorButton() { - if (showingStartSponsor) { - showingStartSponsor = false; - document.getElementById("startSponsorImage").src = chrome.extension.getURL("icons/PlayerStopIconSponsorBlocker256px.png"); - } else { +function changeStartSponsorButton(visibility, uploadButtonVisible) { + if (visibility) { showingStartSponsor = true; document.getElementById("startSponsorImage").src = chrome.extension.getURL("icons/PlayerStartIconSponsorBlocker256px.png"); + + if (document.getElementById("startSponsorImage").style.display != "none" && uploadButtonVisible) { + document.getElementById("submitButton").style.display = "unset"; + } else if (!uploadButtonVisible) { + //disable submit button + document.getElementById("submitButton").style.display = "none"; + } + } else { + showingStartSponsor = false; + document.getElementById("startSponsorImage").src = chrome.extension.getURL("icons/PlayerStopIconSponsorBlocker256px.png"); + + //disable submit button + document.getElementById("submitButton").style.display = "none"; } } +function toggleStartSponsorButton() { + changeStartSponsorButton(!showingStartSponsor, true); +} + +//shows the submit button on the video player +function addSubmitButton() { + if (document.getElementById("submitButton") != null) { + //it's already added + return; + } + + //make a submit button + let submitButton = document.createElement("button"); + submitButton.id = "submitButton"; + submitButton.className = "ytp-button"; + submitButton.setAttribute("title", "Submit Sponsor Times"); + submitButton.addEventListener("click", submitSponsorTimes); + //hide it at the start + submitButton.style.display = "none"; + + let submitImage = document.createElement("img"); + submitImage.id = "submitButtonImage"; + submitImage.className = "playerButton"; + submitImage.src = chrome.extension.getURL("icons/PlayerUploadIconSponsorBlocker256px.png"); + + //add the image to the button + submitButton.appendChild(submitImage); + + let referenceNode = document.getElementsByClassName("ytp-right-controls")[0]; + referenceNode.prepend(submitButton); +} + //Opens the notice that tells the user that a sponsor was just skipped function openSkipNotice(){ if (dontShowNotice) { @@ -460,6 +502,36 @@ function sponsorMessageStarted() { toggleStartSponsorButton(); } +function submitSponsorTimes() { + //add loading animation + document.getElementById("submitButtonImage").src = chrome.extension.getURL("icons/PlayerUploadIconSponsorBlocker256px.png"); + document.getElementById("submitButton").style.animation = "rotate 1s 0s infinite"; + + let currentVideoID = getYouTubeVideoID(document.URL); + + chrome.runtime.sendMessage({ + message: "submitTimes", + videoID: currentVideoID + }, function(response) { + if (response != undefined) { + if (response.statusCode == 200) { + //hide loading message + document.getElementById("submitButton").style.animation = "unset"; + document.getElementById("submitButton").style.display = "none"; + + //clear the sponsor times + let sponsorTimeKey = "sponsorTimes" + currentVideoID; + chrome.storage.local.set({[sponsorTimeKey]: []}); + } else { + //for a more detailed error message, they should check the popup + //show that the upload failed + document.getElementById("submitButton").style.animation = "unset"; + document.getElementById("submitButtonImage").src = chrome.extension.getURL("icons/PlayerUploadFailedIconSponsorBlocker256px.png"); + } + } + }); +} + function sendRequestToServer(type, address, callback) { let xmlhttp = new XMLHttpRequest(); diff --git a/icons/PlayerUploadFailedIconSponsorBlocker256px.png b/icons/PlayerUploadFailedIconSponsorBlocker256px.png new file mode 100644 index 0000000000000000000000000000000000000000..57c808389bde93fd20adf3347c9dc413d455e559 GIT binary patch literal 11695 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 literal 0 HcmV?d00001 diff --git a/icons/PlayerUploadIconSponsorBlocker256px.png b/icons/PlayerUploadIconSponsorBlocker256px.png new file mode 100644 index 0000000000000000000000000000000000000000..5be42678007d146cb3ccf0481e48a914804d5a5d GIT binary patch literal 11934 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 ZCc|lDCf=v%1nwyZR1`H8YUQjV{|{J6vWox! literal 0 HcmV?d00001 diff --git a/manifest.json b/manifest.json index c742d16d..f0a4ba7b 100644 --- a/manifest.json +++ b/manifest.json @@ -22,6 +22,8 @@ "icons/IconSponsorBlocker256px.png", "icons/PlayerStartIconSponsorBlocker256px.png", "icons/PlayerStopIconSponsorBlocker256px.png", + "icons/PlayerUploadIconSponsorBlocker256px.png", + "icons/PlayerUploadFailedIconSponsorBlocker256px.png", "icons/upvote.png", "icons/downvote.png" ], diff --git a/popup.js b/popup.js index d60bba61..3490297a 100644 --- a/popup.js +++ b/popup.js @@ -241,14 +241,17 @@ function getSponsorTimesMessage(sponsorTimes) { } function clearTimes() { - //check if the player controls should be toggled - if (sponsorTimes.length > 0 && sponsorTimes[sponsorTimes.length - 1].length < 2) { + //send new sponsor time state to tab + if (sponsorTimes.length > 0) { + let visibility = sponsorTimes[sponsorTimes.length - 1].length >= 2; chrome.tabs.query({ active: true, currentWindow: true }, function(tabs) { chrome.tabs.sendMessage(tabs[0].id, { - message: "toggleStartSponsorButton" + message: "changeStartSponsorButton", + visibility: visibility, + uploadButtonVisible: false }); }); } From 52ec50a13262d9a2b00c2249e151a1f7d2f085ce Mon Sep 17 00:00:00 2001 From: Ajay Ramachandran Date: Sun, 21 Jul 2019 21:08:23 -0400 Subject: [PATCH 09/13] Made it keep checking for submitted sponsor times every 10 seconds on recent videos. --- README.md | 2 ++ content.js | 34 +++++++++++++++++++++++++++++++++- 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 70756792..72e4bb2e 100644 --- a/README.md +++ b/README.md @@ -29,4 +29,6 @@ None at the moment # Credit +The awesome [Invidious API](https://github.com/omarroth/invidious/wiki/API) is used to grab the time the video was published. + Some i made by Gregor Cresnar from www.flaticon.com and are licensed by CC 3.0 BY \ No newline at end of file diff --git a/content.js b/content.js index f27120c5..eba49faf 100644 --- a/content.js +++ b/content.js @@ -131,8 +131,21 @@ function sponsorsLookup(id) { v.ontimeupdate = function () { sponsorCheck(sponsorTimes); }; - } else { + } else if (xmlhttp.readyState == 4) { sponsorDataFound = false; + + //check if this video was uploaded recently + //use the invidious api to get the time published + sendRequestToCustomServer('GET', "https://invidio.us/api/v1/videos/" + id, function(xmlhttp, error) { + if (xmlhttp.readyState == 4 && xmlhttp.status == 200) { + let unixTimePublished = JSON.parse(xmlhttp.responseText).published; + + //if less than 3 days old + if ((Date.now() / 1000) - unixTimePublished < 259200) { + setTimeout(() => sponsorsLookup(id), 10000); + } + } + }); } }); } @@ -551,6 +564,25 @@ function sendRequestToServer(type, address, callback) { xmlhttp.send(); } +function sendRequestToCustomServer(type, fullAddress, callback) { + let xmlhttp = new XMLHttpRequest(); + + xmlhttp.open(type, fullAddress, true); + + if (callback != undefined) { + xmlhttp.onreadystatechange = function () { + callback(xmlhttp, false); + }; + + xmlhttp.onerror = function(ev) { + callback(xmlhttp, true); + }; + } + + //submit this request + xmlhttp.send(); +} + function getYouTubeVideoID(url) { // Returns with video id else returns false var regExp = /^.*((youtu.be\/)|(v\/)|(\/u\/\w\/)|(embed\/)|(watch\?))\??v?=?([^#\&\?]*).*/; var match = url.match(regExp); From 14121af9005d5664503ac75861379cddf4afb562 Mon Sep 17 00:00:00 2001 From: Ajay Ramachandran Date: Mon, 22 Jul 2019 15:59:21 -0400 Subject: [PATCH 10/13] Made it finish the current animation on the submit button before hiding it. --- content.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/content.js b/content.js index eba49faf..969bf7c8 100644 --- a/content.js +++ b/content.js @@ -529,8 +529,14 @@ function submitSponsorTimes() { if (response != undefined) { if (response.statusCode == 200) { //hide loading message - document.getElementById("submitButton").style.animation = "unset"; - document.getElementById("submitButton").style.display = "none"; + let submitButton = document.getElementById("submitButton"); + //finish this animation + submitButton.style.animation = "rotate 1s"; + //when the animation is over, hide the button + submitButton.addEventListener("animationend", function() { + submitButton.style.animation = "unset"; + submitButton.style.display = "none"; + }); //clear the sponsor times let sponsorTimeKey = "sponsorTimes" + currentVideoID; From baefc5995461f38beaed5759928ff6bbf27f923d Mon Sep 17 00:00:00 2001 From: Ajay Ramachandran Date: Mon, 22 Jul 2019 16:42:57 -0400 Subject: [PATCH 11/13] Switched it from using local storage to synced storage. --- background.js | 12 ++++++------ content.js | 8 ++++---- popup.js | 16 ++++++++-------- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/background.js b/background.js index 026b83f8..1c1c3ad6 100644 --- a/background.js +++ b/background.js @@ -53,7 +53,7 @@ chrome.runtime.onMessage.addListener(function (request, sender, callback) { function getSponsorTimes(videoID, callback) { let sponsorTimes = []; let sponsorTimeKey = "sponsorTimes" + videoID; - chrome.storage.local.get([sponsorTimeKey], function(result) { + chrome.storage.sync.get([sponsorTimeKey], function(result) { let sponsorTimesStorage = result[sponsorTimeKey]; if (sponsorTimesStorage != undefined && sponsorTimesStorage.length > 0) { sponsorTimes = sponsorTimesStorage; @@ -79,7 +79,7 @@ function addSponsorTime(time) { //save this info let sponsorTimeKey = "sponsorTimes" + previousVideoID; - chrome.storage.local.set({[sponsorTimeKey]: sponsorTimes}); + chrome.storage.sync.set({[sponsorTimeKey]: sponsorTimes}); }); } @@ -109,7 +109,7 @@ function submitVote(type, UUID, callback) { function submitTimes(videoID, callback) { //get the video times from storage let sponsorTimeKey = 'sponsorTimes' + videoID; - chrome.storage.local.get([sponsorTimeKey], function(result) { + chrome.storage.sync.get([sponsorTimeKey], function(result) { let sponsorTimes = result[sponsorTimeKey]; if (sponsorTimes != undefined && sponsorTimes.length > 0) { @@ -140,7 +140,7 @@ function videoIDChange(currentVideoID) { if (previousVideoID != null) { //get the sponsor times from storage let sponsorTimeKey = 'sponsorTimes' + previousVideoID; - chrome.storage.local.get([sponsorTimeKey], function(result) { + chrome.storage.sync.get([sponsorTimeKey], function(result) { let sponsorTimes = result[sponsorTimeKey]; if (sponsorTimes != undefined && sponsorTimes.length > 0) { @@ -168,7 +168,7 @@ function getUserID(callback) { } //if it is not cached yet, grab it from storage - chrome.storage.local.get(["userID"], function(result) { + chrome.storage.sync.get(["userID"], function(result) { let userIDStorage = result.userID; if (userIDStorage != undefined) { userID = userIDStorage; @@ -178,7 +178,7 @@ function getUserID(callback) { userID = generateUUID(); //save this UUID - chrome.storage.local.set({"userID": userID}); + chrome.storage.sync.set({"userID": userID}); callback(userID); } diff --git a/content.js b/content.js index 969bf7c8..2e2310fe 100644 --- a/content.js +++ b/content.js @@ -36,7 +36,7 @@ var hideVideoPlayerControls = false; //if the notice should not be shown //happens when the user click's the "Don't show notice again" button var dontShowNotice = false; -chrome.storage.local.get(["dontShowNoticeAgain"], function(result) { +chrome.storage.sync.get(["dontShowNoticeAgain"], function(result) { let dontShowNoticeAgain = result.dontShowNoticeAgain; if (dontShowNoticeAgain != undefined) { dontShowNotice = dontShowNoticeAgain; @@ -106,7 +106,7 @@ function videoIDChange(id) { }); //see if video control buttons should be added - chrome.storage.local.get(["hideVideoPlayerControls"], function(result) { + chrome.storage.sync.get(["hideVideoPlayerControls"], function(result) { if (result.hideVideoPlayerControls != undefined) { hideVideoPlayerControls = result.hideVideoPlayerControls; } @@ -495,7 +495,7 @@ function closeAllSkipNotices(){ } function dontShowNoticeAgain() { - chrome.storage.local.set({"dontShowNoticeAgain": true}); + chrome.storage.sync.set({"dontShowNoticeAgain": true}); dontShowNotice = true; @@ -540,7 +540,7 @@ function submitSponsorTimes() { //clear the sponsor times let sponsorTimeKey = "sponsorTimes" + currentVideoID; - chrome.storage.local.set({[sponsorTimeKey]: []}); + chrome.storage.sync.set({[sponsorTimeKey]: []}); } else { //for a more detailed error message, they should check the popup //show that the upload failed diff --git a/popup.js b/popup.js index 3490297a..561a273e 100644 --- a/popup.js +++ b/popup.js @@ -22,7 +22,7 @@ var isYouTubeTab = false; //if the don't show notice again variable is true, an option to // disable should be available -chrome.storage.local.get(["dontShowNoticeAgain"], function(result) { +chrome.storage.sync.get(["dontShowNoticeAgain"], function(result) { let dontShowNoticeAgain = result.dontShowNoticeAgain; if (dontShowNoticeAgain != undefined && dontShowNoticeAgain) { document.getElementById("showNoticeAgain").style.display = "unset"; @@ -30,7 +30,7 @@ chrome.storage.local.get(["dontShowNoticeAgain"], function(result) { }); //show proper video player controls option -chrome.storage.local.get(["hideVideoPlayerControls"], function(result) { +chrome.storage.sync.get(["hideVideoPlayerControls"], function(result) { let hideVideoPlayerControls = result.hideVideoPlayerControls; if (hideVideoPlayerControls != undefined && hideVideoPlayerControls) { document.getElementById("hideVideoPlayerControls").style.display = "none"; @@ -55,7 +55,7 @@ function loadTabData(tabs) { //load video times for this video let sponsorTimeKey = "sponsorTimes" + currentVideoID; - chrome.storage.local.get([sponsorTimeKey], function(result) { + chrome.storage.sync.get([sponsorTimeKey], function(result) { let sponsorTimesStorage = result[sponsorTimeKey]; if (sponsorTimesStorage != undefined && sponsorTimesStorage.length > 0) { if (sponsorTimesStorage[sponsorTimesStorage.length - 1] != undefined && sponsorTimesStorage[sponsorTimesStorage.length - 1].length < 2) { @@ -140,7 +140,7 @@ chrome.runtime.onMessage.addListener(function (request, sender, callback) { sponsorTimes[sponsorTimesIndex][startTimeChosen ? 1 : 0] = request.time; let sponsorTimeKey = "sponsorTimes" + currentVideoID; - chrome.storage.local.set({[sponsorTimeKey]: sponsorTimes}); + chrome.storage.sync.set({[sponsorTimeKey]: sponsorTimes}); updateStartTimeChosen(); @@ -260,7 +260,7 @@ function clearTimes() { sponsorTimes = []; let sponsorTimeKey = "sponsorTimes" + currentVideoID; - chrome.storage.local.set({[sponsorTimeKey]: sponsorTimes}); + chrome.storage.sync.set({[sponsorTimeKey]: sponsorTimes}); displaySponsorTimes(); @@ -305,7 +305,7 @@ function submitTimes() { } function showNoticeAgain() { - chrome.storage.local.set({"dontShowNoticeAgain": false}); + chrome.storage.sync.set({"dontShowNoticeAgain": false}); chrome.tabs.query({ active: true, @@ -320,7 +320,7 @@ function showNoticeAgain() { } function hideVideoPlayerControls() { - chrome.storage.local.set({"hideVideoPlayerControls": true}); + chrome.storage.sync.set({"hideVideoPlayerControls": true}); chrome.tabs.query({ active: true, @@ -337,7 +337,7 @@ function hideVideoPlayerControls() { } function showVideoPlayerControls() { - chrome.storage.local.set({"hideVideoPlayerControls": false}); + chrome.storage.sync.set({"hideVideoPlayerControls": false}); chrome.tabs.query({ active: true, From b7a35f0823d399d5538f40c80fcf414f33ad0d40 Mon Sep 17 00:00:00 2001 From: Ajay Ramachandran Date: Mon, 22 Jul 2019 16:46:50 -0400 Subject: [PATCH 12/13] Fixed clear times button having incorrect behavior. --- content.js | 6 +++--- popup.js | 3 +-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/content.js b/content.js index 2e2310fe..1fdccecc 100644 --- a/content.js +++ b/content.js @@ -75,7 +75,7 @@ chrome.runtime.onMessage.addListener( // Detect URL Changes } if (request.message == "changeStartSponsorButton") { - changeStartSponsorButton(request.visibility, request.uploadButtonVisible); + changeStartSponsorButton(request.showStartSponsor, request.uploadButtonVisible); } if (request.message == "changeVideoPlayerControlsVisibility") { @@ -235,8 +235,8 @@ function startSponsorClicked() { }); } -function changeStartSponsorButton(visibility, uploadButtonVisible) { - if (visibility) { +function changeStartSponsorButton(showStartSponsor, uploadButtonVisible) { + if (showStartSponsor) { showingStartSponsor = true; document.getElementById("startSponsorImage").src = chrome.extension.getURL("icons/PlayerStartIconSponsorBlocker256px.png"); diff --git a/popup.js b/popup.js index 561a273e..6445a3bf 100644 --- a/popup.js +++ b/popup.js @@ -243,14 +243,13 @@ function getSponsorTimesMessage(sponsorTimes) { function clearTimes() { //send new sponsor time state to tab if (sponsorTimes.length > 0) { - let visibility = sponsorTimes[sponsorTimes.length - 1].length >= 2; chrome.tabs.query({ active: true, currentWindow: true }, function(tabs) { chrome.tabs.sendMessage(tabs[0].id, { message: "changeStartSponsorButton", - visibility: visibility, + showStartSponsor: true, uploadButtonVisible: false }); }); From 1040868ebb1c28da539d4821510fad33e69aa5b1 Mon Sep 17 00:00:00 2001 From: Ajay Ramachandran Date: Mon, 22 Jul 2019 19:08:21 -0400 Subject: [PATCH 13/13] Added small notice of how many submissions this user has made. --- background.js | 12 ++++++++++++ popup.css | 4 ++++ popup.html | 6 +++++- popup.js | 14 ++++++++++++++ 4 files changed, 35 insertions(+), 1 deletion(-) diff --git a/background.js b/background.js index 1c1c3ad6..07743435 100644 --- a/background.js +++ b/background.js @@ -131,6 +131,18 @@ function submitTimes(videoID, callback) { }); }); } + + //add these to the storage log + chrome.storage.sync.get(["sponsorTimesContributed"], function(result) { + let currentContributionAmount = 0; + if (result.sponsorTimesContributed != undefined) { + //current contribution amount is known + currentContributionAmount = result.sponsorTimesContributed; + } + + //save the amount contributed + chrome.storage.sync.set({"sponsorTimesContributed": currentContributionAmount + sponsorTimes.length}); + }); } }); } diff --git a/popup.css b/popup.css index 36e2fb25..ec2f1d59 100644 --- a/popup.css +++ b/popup.css @@ -12,6 +12,10 @@ body { background-color: #ffd9d9; } +.recordingSubtitle { + margin-bottom: 10px; +} + .voteButton { height: 32px; margin-right: 15px; diff --git a/popup.html b/popup.html index f77a6a02..b180d788 100644 --- a/popup.html +++ b/popup.html @@ -39,7 +39,11 @@
-

Record the times of a sponsorship

+

Record the times of a sponsorship

+ +

Click the button below when the sponsorship starts and ends to record and diff --git a/popup.js b/popup.js index 6445a3bf..36f6e2d2 100644 --- a/popup.js +++ b/popup.js @@ -38,6 +38,20 @@ chrome.storage.sync.get(["hideVideoPlayerControls"], function(result) { } }); +//get the amount of times this user has contributed and display it to thank them +chrome.storage.sync.get(["sponsorTimesContributed"], function(result) { + if (result.sponsorTimesContributed != undefined) { + let sponsorTimesContributionsDisplay = document.getElementById("sponsorTimesContributionsDisplay"); + + if (result.sponsorTimesContributed > 1) { + sponsorTimesContributionsDisplay.innerText = "So far, you've submitted " + result.sponsorTimesContributed + " sponsor times."; + } else { + sponsorTimesContributionsDisplay.innerText = "So far, you've submitted " + result.sponsorTimesContributed + " sponsor time."; + } + sponsorTimesContributionsDisplay.style.display = "unset"; + } +}); + chrome.tabs.query({ active: true, currentWindow: true