Skip to content

Commit

Permalink
Add auto warnings
Browse files Browse the repository at this point in the history
  • Loading branch information
ajayyy committed Oct 18, 2024
1 parent 81ee8b3 commit 35d8e9c
Show file tree
Hide file tree
Showing 6 changed files with 222 additions and 7 deletions.
2 changes: 1 addition & 1 deletion public/_locales
Submodule _locales updated 1 files
+36 −1 en/messages.json
4 changes: 4 additions & 0 deletions public/content.css
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,10 @@ ytd-compact-playlist-renderer .ytd-compact-playlist-renderer #video-title:not(.c
vertical-align: middle;
}

.cbTitle {
position: relative;
}

.cbTitle:not(.cbTitleSelected, .cbTitlePreview) {
cursor: pointer !important;
}
Expand Down
18 changes: 12 additions & 6 deletions src/submission/SubmissionComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { Tooltip } from "../utils/tooltip";
import { LicenseComponent } from "../license/LicenseComponent";
import { ToggleOptionComponent } from "../popup/ToggleOptionComponent";
import { FormattedText } from "../popup/FormattedTextComponent";
import { isAutoWarningShown } from "./autoWarning";

export interface SubmissionComponentProps {
videoID: VideoID;
Expand All @@ -33,7 +34,7 @@ export interface SubmissionComponentProps {
submitClicked: (title: TitleSubmission | null, thumbnail: ThumbnailSubmission | null, actAsVip: boolean) => Promise<boolean>;
}

interface ChatDisplayName {
export interface ChatDisplayName {
publicUserID: string;
username: string | null;
}
Expand All @@ -51,10 +52,10 @@ export const SubmissionComponent = (props: SubmissionComponentProps) => {
setChatDisplayName(displayName);

const values = ["userName", "deArrowWarningReason"];
const result = await sendRequestToServer("GET", "/api/userInfo", {
publicUserID: publicUserID,
values
});
const result = await sendRequestToServer("GET", "/api/userInfo", {
publicUserID: publicUserID,
values
});

if (result.ok) {
const userInfo = JSON.parse(result.responseText);
Expand Down Expand Up @@ -341,6 +342,11 @@ export const SubmissionComponent = (props: SubmissionComponentProps) => {
|| (!selectedThumbnail.current && !selectedTitle)
|| (!!selectedTitle && selectedTitle.title.toLowerCase() === chrome.i18n.getMessage("OriginalTitle").toLowerCase())}
onClick={async () => {
if (isAutoWarningShown()) {
alert(chrome.i18n.getMessage("resolveWarningFirst"));
return;
}

setCurrentlySubmitting(true);

props.submitClicked(selectedTitle ? {
Expand Down Expand Up @@ -479,7 +485,7 @@ function updateUnsubmitted(unsubmitted: UnsubmittedSubmission,
}
}

function getChatDisplayName(chatDisplayName: ChatDisplayName | null): string {
export function getChatDisplayName(chatDisplayName: ChatDisplayName | null): string {
if (chatDisplayName) {
if (chatDisplayName.username && chatDisplayName.username !== chatDisplayName.publicUserID) {
return `${chatDisplayName.username} - ${chatDisplayName.publicUserID}`;
Expand Down
3 changes: 3 additions & 0 deletions src/submission/TitleComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { submitVideoBrandingAndHandleErrors } from "../dataFetching";
import { AnimationUtils } from "../../maze-utils/src/animationUtils";
import { VideoID } from "../../maze-utils/src/video";
import { shouldStoreVotes } from "../utils/configUtils";
import { showAutoWarningIfRequired } from "./autoWarning";

export interface TitleComponentProps {
submission: RenderedTitleSubmission;
Expand Down Expand Up @@ -84,6 +85,8 @@ export const TitleComponent = (props: TitleComponentProps) => {

setTitleChanged(newTitle !== props.submission.title);
setFocused(true);

showAutoWarningIfRequired(newTitle, e.target as HTMLElement);
}
}}
onKeyDown={(e) => {
Expand Down
199 changes: 199 additions & 0 deletions src/submission/autoWarning.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
import { objectToURI } from "../../maze-utils/src";
import { getHash } from "../../maze-utils/src/hash";
import Config from "../config/config";
import { getCurrentPageTitle } from "../titles/titleData";
import { cleanEmojis, cleanFancyText, cleanPunctuation } from "../titles/titleFormatter";
import { sendRequestToServer } from "../utils/requests";
import { Tooltip } from "../utils/tooltip";
import { ChatDisplayName, getChatDisplayName } from "./SubmissionComponent";

interface AutoWarningCheck {
check: (title: string, originalTitle: string) => {
found: boolean;
match?: string | null;
};
error: string;
id: string;
}

let activeTooltip: Tooltip | null = null;
let currentWarningId: string | null = null;
let timeout: NodeJS.Timeout | null = null;

const shownWarnings: string[] = [];
const autoWarningChecks: AutoWarningCheck[] = [
{
error: chrome.i18n.getMessage("DeArrowDiscussingWarning"),
check: (title) => {
const match = title.match(/^(discussing|explaining|talking about|summarizing) .\S+ .\S+/i)?.[1];
return {
found: !!match,
match,
};
},
id: "discussing"
}, {
error: chrome.i18n.getMessage("DeArrowStartLowerCaseWarning"),
check: (title) => {
return {
found: !!title.match(/^\p{Ll}\S+ \S+ \S+/u)
};
},
id: "startLowerCase"
}, {
error: chrome.i18n.getMessage("DeArrowEndWithPeriodWarning"),
check: (title) => {
return {
found: !!title.match(/\.$/u)
};
},
id: "endWithPeriod"
}, {
error: chrome.i18n.getMessage("DeArrowAddingAnswerWarning"),
check: (title, originalTitle) => {
// Only if ends with ? or ... and then optionally more symbols
return {
found: title.toLowerCase().startsWith(cleanPunctuation(cleanFancyText(cleanEmojis(originalTitle.toLowerCase()))))
&& !!originalTitle.match(/(\?|\.\.\.)[^\p{L}]*$/u)
};
},
id: "addingAnswer"
}, {
error: chrome.i18n.getMessage("DeArrowClickbaitWarning"),
check: (title, originalTitle) => {
const regex = /clickbait|fake news|fake video|boring|yapping|yap|worth your time/i;
const match = title.match(regex)?.[0];
const found = !!title.match(regex) && !originalTitle.match(regex);

return {
found,
match: found ? match : null,
};
},
id: "clickbait"
}, {
error: chrome.i18n.getMessage("DeArrowKeepingBadOriginalWarning"),
check: (title, originalTitle) => {
const regex = /massive problem|you need|insane|crazy|wild|you won't believe this/i;
const match = title.match(regex)?.[0];
const found = !!title.match(regex) && !!originalTitle.match(regex);

return {
found,
match: found ? match : null,
};
},
id: "keepingBadOriginal"
}, {
error: chrome.i18n.getMessage("DeArrowEmojiWarning"),
check: (title) => {
return {
found: cleanEmojis(title) !== title.trim()
};
},
id: "emoji"
}
];

function getAutoWarning(title: string, originalTitle: string): { id: string; text: string } | null {
for (const check of autoWarningChecks) {
const { found, match } = check.check(title, originalTitle);
if (found && !shownWarnings.includes(check.id)) {
return {
id: check.id,
text: check.error + (match ? `\n\n${chrome.i18n.getMessage("DetectedWord")}${match}` : "")
};
}
}

return null;
}

export function showAutoWarningIfRequired(title: string, element: HTMLElement): void {
// Wait until some time after typing stops
if (timeout) {
clearTimeout(timeout);
}

timeout = setTimeout(() => {
showAutoWarningIfRequiredInternal(title, element);
}, 500)
}

function showAutoWarningIfRequiredInternal(title: string, element: HTMLElement): void {
timeout = null;

const originalTitle = getCurrentPageTitle() || "";
console.log(originalTitle)
const warning = getAutoWarning(title, originalTitle);
if (warning && warning.id !== currentWarningId) {
activeTooltip?.close();

currentWarningId = warning.id;
activeTooltip = new Tooltip({
textBoxes: warning.text.split("\n"),
referenceNode: element.parentElement!,
prependElement: element,
positionRealtive: false,
containerAbsolute: true,
bottomOffset: "35px",
rightOffset: "0",
leftOffset: "0",
displayTriangle: true,
extraClass: "centeredSBTriangle",
center: true,
showGotIt: false,
buttonsAtBottom: true,
textBoxMaxHeight: "350px",
opacity: 1,
buttons: [{
name: chrome.i18n.getMessage("GotIt"),
listener: () => {
shownWarnings.push(warning.id);
activeTooltip?.close();
activeTooltip = null;
currentWarningId = null;
}
}, {
name: chrome.i18n.getMessage("questionButton"),
// eslint-disable-next-line @typescript-eslint/no-misused-promises
listener: async () => {
const publicUserID = await getHash(Config.config!.userID!);

const values = ["userName"];
const result = await sendRequestToServer("GET", "/api/userInfo", {
publicUserID: publicUserID,
values
});

let name: ChatDisplayName | null = null;

if (result.ok) {
const userInfo = JSON.parse(result.responseText);
name = {
publicUserID,
username: userInfo.userName
};
}

window.open(`https://chat.sponsor.ajay.app/#${objectToURI("", {
displayName: getChatDisplayName(name),
customDescription: `${chrome.i18n.getMessage("chatboxDescription")}\n\nhttps://discord.gg/SponsorBlock\nhttps://matrix.to/#/#sponsor:ajay.app?via=matrix.org`,
bigDescription: true
}, false)}`);
}
}],
});
}
}

export function resetShownWarnings(): void {
shownWarnings.length = 0;
activeTooltip?.close();
activeTooltip = null;
currentWarningId = null;
}

export function isAutoWarningShown(): boolean {
return !!activeTooltip;
}
3 changes: 3 additions & 0 deletions src/video.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { listenForBadges, listenForMiniPlayerTitleChange, listenForTitleChange }
import { getPlaybackFormats } from "./thumbnails/thumbnailData";
import { replaceVideoPlayerSuggestionsBranding, setupMobileAutoplayHandler } from "./videoBranding/watchPageBrandingHandler";
import { onMobile } from "../maze-utils/src/pageInfo";
import { resetShownWarnings } from "./submission/autoWarning";

export const submitButton = new SubmitButton();

Expand Down Expand Up @@ -48,6 +49,8 @@ function resetValues() {
submitButton.close();

clearVideoBrandingInstances();

resetShownWarnings();
}

// eslint-disable-next-line @typescript-eslint/no-empty-function, @typescript-eslint/no-unused-vars
Expand Down

0 comments on commit 35d8e9c

Please sign in to comment.