mirror of
https://github.com/ajayyy/SponsorBlock.git
synced 2024-11-10 09:07:45 +01:00
Merge pull request #862 from ajayyy/warning-chat
Add chat box when getting a warning
This commit is contained in:
commit
2373b34067
7 changed files with 115 additions and 19 deletions
|
@ -675,5 +675,11 @@
|
|||
},
|
||||
"hideForever": {
|
||||
"message": "Hide forever"
|
||||
},
|
||||
"warningChatInfo": {
|
||||
"message": "You got a warning and cannot submit segments temporarily. This means that we noticed you were making some common mistakes that are not malicious, and we just want to clarify the rules. You can also join this chat using discord.gg/SponsorBlock or matrix.to/#/+sponsor:ajay.app"
|
||||
},
|
||||
"voteRejectedWarning": {
|
||||
"message": "Vote rejected due to a warning. Click to open a chat to resolve it, or come back later when you have time."
|
||||
}
|
||||
}
|
||||
|
|
|
@ -121,8 +121,19 @@
|
|||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.sbChatNotice {
|
||||
min-width: 350px;
|
||||
height: 70%;
|
||||
|
||||
position: absolute;
|
||||
right: 5px;
|
||||
bottom: 100px;
|
||||
right: 10px;
|
||||
}
|
||||
|
||||
.sponsorSkipNotice {
|
||||
min-width: 350px;
|
||||
max-width: 50%;
|
||||
background-color: rgba(28, 28, 28, 0.9);
|
||||
position: absolute;
|
||||
right: 5px;
|
||||
|
@ -445,4 +456,15 @@ input::-webkit-inner-spin-button {
|
|||
}
|
||||
.helpButton:hover {
|
||||
filter: brightness(80%);
|
||||
}
|
||||
|
||||
.sbChatNotice iframe {
|
||||
height: 32px;
|
||||
cursor: pointer;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.sbChatClose {
|
||||
height: 14px;
|
||||
cursor: pointer;
|
||||
}
|
|
@ -164,11 +164,7 @@ async function asyncRequestToServer(type: string, address: string, data = {}) {
|
|||
async function sendRequestToCustomServer(type: string, url: string, data = {}) {
|
||||
// If GET, convert JSON to parameters
|
||||
if (type.toLowerCase() === "get") {
|
||||
for (const key in data) {
|
||||
const seperator = url.includes("?") ? "&" : "?";
|
||||
const value = (typeof(data[key]) === "string") ? data[key]: JSON.stringify(data[key]);
|
||||
url += seperator + key + "=" + value;
|
||||
}
|
||||
url = utils.objectToURI(url, data, true);
|
||||
|
||||
data = null;
|
||||
}
|
||||
|
|
|
@ -313,11 +313,15 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
|
|||
|
||||
for (let i = 0; i < this.state.messages.length; i++) {
|
||||
elements.push(
|
||||
<NoticeTextSelectionComponent idSuffix={this.idSuffix}
|
||||
text={this.state.messages[i]}
|
||||
onClick={this.state.messageOnClick}
|
||||
key={i}>
|
||||
</NoticeTextSelectionComponent>
|
||||
<tr>
|
||||
<td>
|
||||
<NoticeTextSelectionComponent idSuffix={this.idSuffix}
|
||||
text={this.state.messages[i]}
|
||||
onClick={this.state.messageOnClick}
|
||||
key={i + "_messageBox"}>
|
||||
</NoticeTextSelectionComponent>
|
||||
</td>
|
||||
</tr>
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ import SkipNotice from "./render/SkipNotice";
|
|||
import SkipNoticeComponent from "./components/SkipNoticeComponent";
|
||||
import SubmissionNotice from "./render/SubmissionNotice";
|
||||
import { Message, MessageResponse } from "./messageTypes";
|
||||
import GenericNotice from "./render/GenericNotice";
|
||||
import * as Chat from "./js-components/chat";
|
||||
|
||||
// Hack to get the CSS loaded on permission-based sites (Invidious)
|
||||
utils.wait(() => Config.config !== null, 5000, 10).then(addCSS);
|
||||
|
@ -1458,7 +1458,15 @@ function vote(type: number, UUID: string, category?: string, skipNotice?: SkipNo
|
|||
//success (treat rate limits as a success)
|
||||
skipNotice.afterVote.bind(skipNotice)(utils.getSponsorTimeFromUUID(sponsorTimes, UUID), type, category);
|
||||
} else if (response.successType == -1) {
|
||||
skipNotice.setNoticeInfoMessage.bind(skipNotice)(utils.getErrorMessage(response.statusCode, response.responseText))
|
||||
if (response.statusCode === 403 && response.responseText.startsWith("Vote rejected due to a warning from a moderator.")) {
|
||||
skipNotice.setNoticeInfoMessageWithOnClick.bind(skipNotice)(() => {
|
||||
Chat.openWarningChat(response.responseText);
|
||||
skipNotice.closeListener.call(skipNotice);
|
||||
}, chrome.i18n.getMessage("voteRejectedWarning"));
|
||||
} else {
|
||||
skipNotice.setNoticeInfoMessage.bind(skipNotice)(utils.getErrorMessage(response.statusCode, response.responseText))
|
||||
}
|
||||
|
||||
skipNotice.resetVoteButtonInfo.bind(skipNotice)();
|
||||
}
|
||||
}
|
||||
|
@ -1567,7 +1575,11 @@ async function sendSubmitMessage() {
|
|||
playerButtons.submit.button.style.animation = "unset";
|
||||
playerButtons.submit.image.src = chrome.extension.getURL("icons/PlayerUploadFailedIconSponsorBlocker.svg");
|
||||
|
||||
alert(utils.getErrorMessage(response.status, response.responseText));
|
||||
if (response.status === 403 && response.responseText.startsWith("Submission rejected due to a warning from a moderator.")) {
|
||||
Chat.openWarningChat(response.responseText);
|
||||
} else {
|
||||
alert(utils.getErrorMessage(response.status, response.responseText));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
44
src/js-components/chat.ts
Normal file
44
src/js-components/chat.ts
Normal file
|
@ -0,0 +1,44 @@
|
|||
import Config from "../config";
|
||||
import Utils from "../utils";
|
||||
const utils = new Utils();
|
||||
|
||||
export interface ChatConfig {
|
||||
displayName: string,
|
||||
composerInitialValue?: string,
|
||||
customDescription?: string
|
||||
}
|
||||
|
||||
export function openChat(config: ChatConfig): void {
|
||||
const chat = document.createElement("div");
|
||||
chat.classList.add("sbChatNotice");
|
||||
chat.style.zIndex = "2000";
|
||||
|
||||
const iframe= document.createElement("iframe");
|
||||
iframe.src = "https://chat.sponsor.ajay.app/#" + utils.objectToURI("", config, false);
|
||||
chat.appendChild(iframe);
|
||||
|
||||
const closeButton = document.createElement("img");
|
||||
closeButton.classList.add("sbChatClose");
|
||||
closeButton.src = chrome.extension.getURL("icons/close.png");
|
||||
closeButton.addEventListener("click", () => {
|
||||
chat.remove();
|
||||
closeButton.remove();
|
||||
});
|
||||
chat.appendChild(closeButton);
|
||||
|
||||
const referenceNode = utils.findReferenceNode();
|
||||
referenceNode.prepend(chat);
|
||||
}
|
||||
|
||||
export async function openWarningChat(warningMessage: string): Promise<void> {
|
||||
const userNameData = await utils.asyncRequestToServer("GET", "/api/getUsername?userID=" + Config.config.userID);
|
||||
const userName = userNameData.ok ? JSON.parse(userNameData.responseText).userName : "";
|
||||
const publicUserID = await utils.getHash(Config.config.userID);
|
||||
|
||||
openChat({
|
||||
displayName: `${userName ? `${userName} | `: ``}${userName !== publicUserID ? publicUserID : ``}`,
|
||||
composerInitialValue: `I got a warning and want to know what I need to do to improve. ` +
|
||||
`Warning reason: ${warningMessage.match(/Warning reason: '(.+)'/)[1]}`,
|
||||
customDescription: chrome.i18n.getMessage("warningChatInfo")
|
||||
});
|
||||
}
|
24
src/utils.ts
24
src/utils.ts
|
@ -415,6 +415,19 @@ export default class Utils {
|
|||
return referenceNode;
|
||||
}
|
||||
|
||||
objectToURI<T>(url: string, data: T, includeQuestionMark: boolean): string {
|
||||
let counter = 0;
|
||||
for (const key in data) {
|
||||
const seperator = (url.includes("?") || counter > 0) ? "&" : (includeQuestionMark ? "?" : "");
|
||||
const value = (typeof(data[key]) === "string") ? data[key] as unknown as string : JSON.stringify(data[key]);
|
||||
url += seperator + encodeURIComponent(key) + "=" + encodeURIComponent(value);
|
||||
|
||||
counter++;
|
||||
}
|
||||
|
||||
return url;
|
||||
}
|
||||
|
||||
getFormattedTime(seconds: number, precise?: boolean): string {
|
||||
const hours = Math.floor(seconds / 60 / 60);
|
||||
const minutes = Math.floor(seconds / 60) % 60;
|
||||
|
@ -479,14 +492,13 @@ export default class Utils {
|
|||
async getHash(value: string, times = 5000): Promise<string> {
|
||||
if (times <= 0) return "";
|
||||
|
||||
let hashBuffer = new TextEncoder().encode(value).buffer;
|
||||
|
||||
let hashHex = value;
|
||||
for (let i = 0; i < times; i++) {
|
||||
hashBuffer = await crypto.subtle.digest('SHA-256', hashBuffer);
|
||||
}
|
||||
const hashBuffer = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(hashHex).buffer);
|
||||
|
||||
const hashArray = Array.from(new Uint8Array(hashBuffer));
|
||||
const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
|
||||
const hashArray = Array.from(new Uint8Array(hashBuffer));
|
||||
hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
|
||||
}
|
||||
|
||||
return hashHex;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue