Skip to content

Commit

Permalink
Merge branch 'master' of https://github.com/ajayyy/ClickbaitExtension
Browse files Browse the repository at this point in the history
…into pr/jgoedde/244
  • Loading branch information
ajayyy committed May 16, 2024
2 parents e18f8ff + f3e9fb9 commit 3b41339
Show file tree
Hide file tree
Showing 15 changed files with 274 additions and 46 deletions.
4 changes: 4 additions & 0 deletions public/content.css
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,10 @@ ytd-compact-playlist-renderer .ytd-compact-playlist-renderer #video-title:not(.c
cursor: pointer;
}

.cbButton path {
transition: fill 0.5s;
}

.cbButton img {
height: 60%;
top: 0;
Expand Down
18 changes: 18 additions & 0 deletions public/options/options.html
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@
__MSG_ChannelAllowlist__
</div>

<div class="tab-heading" data-for="keybinds">
__MSG_optionsTabKeyBinds__
</div>

<div class="tab-heading" data-for="import">
__MSG_optionsTabBackup__
</div>
Expand Down Expand Up @@ -338,6 +342,20 @@

</div>

<div id="keybinds" class="option-group hidden">

<div data-type="keybind-change" data-sync="enableExtensionKey">
<label class="optionLabel">__MSG_enableDeArrowKey__:</label>
<div class="inline"></div>
</div>

<div data-type="keybind-change" data-sync="openMenuKey">
<label class="optionLabel">__MSG_openDeArrowMenu__:</label>
<div class="inline"></div>
</div>

</div>

<div id="import" class="option-group hidden">

<div data-type="private-text-change" data-sync="userID" data-confirm-message="userIDChangeWarning">
Expand Down
6 changes: 5 additions & 1 deletion src/config/config.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ProtoConfig } from "../../maze-utils/src/config";
import { Keybind, ProtoConfig } from "../../maze-utils/src/config";
import { VideoID } from "../../maze-utils/src/video";
import { ThumbnailSubmission } from "../thumbnails/thumbnailData";
import { logError } from "../utils/logger";
Expand Down Expand Up @@ -124,6 +124,8 @@ interface SBConfig {
firefoxOldContentScriptRegistration: boolean;
lastIncognitoStatus: boolean;
showActivatedMessage: boolean;
openMenuKey: Keybind;
enableExtensionKey: Keybind;
}

interface SBStorage {
Expand Down Expand Up @@ -209,6 +211,8 @@ const syncDefaults = {
firefoxOldContentScriptRegistration: false,
lastIncognitoStatus: false,
showActivatedMessage: false,
openMenuKey: { key: "d", shift: true },
enableExtensionKey: { key: "e", shift: true }
};

const localDefaults = {
Expand Down
2 changes: 2 additions & 0 deletions src/content.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { runCompatibilityFunctions } from "./utils/extensionCompatibility";
import { cleanPage } from "./utils/pageCleaner";
import { setupPageTitleHandler } from "./titles/pageTitleHandler";
import { setupWatchPageBrandingCleanup } from "./videoBranding/watchPageBrandingHandler";
import { addHotkeyListener } from "./utils/keybinds";

cleanPage();
addCssToPage();
Expand All @@ -19,6 +20,7 @@ listenForMiniPlayerTitleChange().catch(logError);
addTitleChangeListener(() => void replaceCurrentVideoBranding().catch(logError));
setupOptionChangeListener();
setupPageTitleHandler();
addHotkeyListener();

setupTitlebarCleanup();
setupWatchPageBrandingCleanup();
Expand Down
45 changes: 43 additions & 2 deletions src/submission/SubmissionComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ export const SubmissionComponent = (props: SubmissionComponentProps) => {
const originalTitle = await toSentenceCase(getCurrentPageTitle() || chrome.i18n.getMessage("OriginalTitle"), false);
setOriginalTitle(originalTitle);

setTitles([{
const newTitles = [{
title: originalTitle,
original: true,
votable: true,
Expand All @@ -98,7 +98,12 @@ export const SubmissionComponent = (props: SubmissionComponentProps) => {
original: s.original,
votable: true,
locked: s.locked
}))]);
}))];

setTitles(newTitles);

const unsubmitted = Config.local!.unsubmitted[props.videoID];
updateUnsubmitted(unsubmitted, setExtraUnsubmittedThumbnails, setExtraUnsubmittedTitles, thumbnails, newTitles);
})();
}, []);

Expand Down Expand Up @@ -130,7 +135,31 @@ export const SubmissionComponent = (props: SubmissionComponentProps) => {
const [selectedTitle, setSelectedTitle] = React.useState<RenderedTitleSubmission | null>(null);
const selectedThumbnail = React.useRef<ThumbnailSubmission | null>(null);
const [selectedTitleIndex, setSelectedTitleIndex] = React.useState(-1);
const [upvotedTitleIndex, setUpvotedTitleIndex] = React.useState(-1);
const [selectedThumbnailIndex, setSelectedThumbnailIndex] = React.useState(-1);
const [upvotedThumbnailIndex, setUpvotedThumbnailIndex] = React.useState(-1);

React.useEffect(() => {
const unsubmitted = Config.local!.unsubmitted[props.videoID];
if (unsubmitted) {
const upvotedTitle = unsubmitted.titles.find((t) => t.selected);
if (upvotedTitle) {
const upvotedTitleIndex = titles.findIndex((t) => t.title === upvotedTitle.title);
if (upvotedTitleIndex !== -1) {
setUpvotedTitleIndex(upvotedTitleIndex);
}
}

const upvotedThumbnail = unsubmitted.thumbnails.find((t) => t.selected);
if (upvotedThumbnail) {
const upvotedThumbnailIndex = thumbnails.findIndex((t) => (t.type === ThumbnailType.Original && upvotedThumbnail.original)
|| (t.type === ThumbnailType.SpecifiedTime && !upvotedThumbnail.original && t.timestamp === upvotedThumbnail.timestamp));
if (upvotedThumbnailIndex !== -1) {
setUpvotedThumbnailIndex(upvotedThumbnailIndex);
}
}
}
}, [titles]);

// Load existing unsubmitted thumbnails whenever a videoID change happens
const [extraUnsubmittedThumbnails, setExtraUnsubmittedThumbnails] = React.useState<RenderedThumbnailSubmission[]>([]);
Expand Down Expand Up @@ -185,6 +214,7 @@ export const SubmissionComponent = (props: SubmissionComponentProps) => {
videoId={props.videoID}
existingSubmissions={thumbnailSubmissions}
selectedThumbnailIndex={selectedThumbnailIndex}
upvotedThumbnailIndex={upvotedThumbnailIndex}
actAsVip={actAsVip}
onSelect={(t, i) => {
let selectedIndex = i;
Expand Down Expand Up @@ -230,12 +260,16 @@ export const SubmissionComponent = (props: SubmissionComponentProps) => {

setSelectedThumbnailIndex(selectedIndex);
selectedThumbnail.current = t;
}}
onUpvote={(index) => {
setUpvotedThumbnailIndex(index);
}}></ThumbnailDrawerComponent>
</div>

<div>
<TitleDrawerComponent existingSubmissions={[...titles, ...extraUnsubmittedTitles]}
selectedTitleIndex={selectedTitleIndex}
upvotedTitleIndex={upvotedTitleIndex}
actAsVip={actAsVip}
videoID={props.videoID}
onDeselect={() => {
Expand Down Expand Up @@ -274,8 +308,15 @@ export const SubmissionComponent = (props: SubmissionComponentProps) => {
}
}

if (unsubmitted.titles.length === 0 && unsubmitted.thumbnails.length === 0) {
delete Config.local!.unsubmitted[props.videoID];
}

Config.forceLocalUpdate("unsubmitted");
}
}}
onUpvote={(index) => {
setUpvotedTitleIndex(index);
}}></TitleDrawerComponent>
</div>

Expand Down
6 changes: 6 additions & 0 deletions src/submission/ThumbnailDrawerComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ export interface ThumbnailDrawerComponentProps {
videoId: VideoID;
existingSubmissions: RenderedThumbnailSubmission[];
selectedThumbnailIndex: number;
upvotedThumbnailIndex: number;
onSelect: (submission: ThumbnailSubmission, index: number) => void;
onUpvote: (index: number) => void;
actAsVip: boolean;
}

Expand Down Expand Up @@ -47,9 +49,13 @@ function getThumbnails(props: ThumbnailDrawerComponentProps,
<ThumbnailSelectionComponent
video={props.video}
selected={selectedThumbnail === i}
upvoted={props.upvotedThumbnailIndex === i}
onClick={(submission) => {
props.onSelect(submission, i);
}}
onUpvote={() => {
props.onUpvote(i);
}}
type={props.existingSubmissions[i].type}
videoID={props.videoId}
time={time}
Expand Down
54 changes: 45 additions & 9 deletions src/submission/ThumbnailSelectionComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,14 @@ import { submitVideoBrandingAndHandleErrors } from "../dataFetching";
import { AnimationUtils } from "../../maze-utils/src/animationUtils";
import Config from "../config/config";
import { FormattedText } from "../popup/FormattedTextComponent";
import { shouldStoreVotes } from "../utils/configUtils";

export interface ThumbnailSelectionComponentProps {
video: HTMLVideoElement;
selected?: boolean;
upvoted?: boolean;
onClick?: (thumbnail: ThumbnailSubmission) => void;
onUpvote?: () => void;
type: ThumbnailType;
videoID: VideoID;
hideTime?: boolean;
Expand All @@ -31,6 +34,7 @@ export interface ThumbnailSelectionComponentProps {
*/
export const ThumbnailSelectionComponent = (props: ThumbnailSelectionComponentProps) => {
const [error, setError] = React.useState("");
const [downvoted, setDownvoted] = React.useState(false);

function createThumbnailSubmission(): ThumbnailSubmission | null {
return props.type === ThumbnailType.Original ? {
Expand Down Expand Up @@ -82,19 +86,43 @@ export const ThumbnailSelectionComponent = (props: ThumbnailSelectionComponentPr
e.stopPropagation();

const stopAnimation = AnimationUtils.applyLoadingAnimation(e.currentTarget, 0.3);
submitVideoBrandingAndHandleErrors(null, createThumbnailSubmission(), false, props.actAsVip!).then(stopAnimation);
submitVideoBrandingAndHandleErrors(null, createThumbnailSubmission(), false, props.actAsVip!).then(() => {
stopAnimation();
setDownvoted(false);

const unsubmitted = Config.local!.unsubmitted[props.videoID];
if (unsubmitted) {
const unsubmittedThumbnail = unsubmitted.thumbnails.find((t) => !t.original && t.timestamp === props.time);
props.onUpvote?.();
});

if (shouldStoreVotes()) {
const unsubmitted = Config.local!.unsubmitted[props.videoID] ??= {
thumbnails: [],
titles: []
};
unsubmitted.thumbnails.forEach((t) => t.selected = false);

const unsubmittedThumbnail = unsubmitted.thumbnails.find((t) =>(t.original && props.type === ThumbnailType.Original)
|| (!t.original && t.timestamp === props.time));
if (unsubmittedThumbnail) {
unsubmitted.thumbnails.forEach((t) => t.selected = false);
unsubmittedThumbnail.selected = true;
Config.forceLocalUpdate("unsubmitted");
} else {
if (props.type === ThumbnailType.Original) {
unsubmitted.thumbnails.push({
original: true,
selected: true
});
} else {
unsubmitted.thumbnails.push({
original: false,
timestamp: props.time!,
selected: true
});
}
}

Config.forceLocalUpdate("unsubmitted");
}
}}>
<UpvoteIcon/>
<UpvoteIcon selected={props.upvoted}/>
</button>

<button className="cbButton"
Expand All @@ -103,18 +131,26 @@ export const ThumbnailSelectionComponent = (props: ThumbnailSelectionComponentPr
e.stopPropagation();

const stopAnimation = AnimationUtils.applyLoadingAnimation(e.currentTarget, 0.3);
submitVideoBrandingAndHandleErrors(null, createThumbnailSubmission(), true, props.actAsVip!).then(stopAnimation);
submitVideoBrandingAndHandleErrors(null, createThumbnailSubmission(), true, props.actAsVip!).then(() => {
stopAnimation();
setDownvoted(true);
});

const unsubmitted = Config.local!.unsubmitted[props.videoID];
if (unsubmitted) {
const unsubmittedThumbnail = unsubmitted.thumbnails.find((t) => !t.original && t.timestamp === props.time);
if (unsubmittedThumbnail) {
unsubmitted.thumbnails.splice(unsubmitted.thumbnails.indexOf(unsubmittedThumbnail), 1);

if (unsubmitted.titles.length === 0 && unsubmitted.thumbnails.length === 0) {
delete Config.local!.unsubmitted[props.videoID];
}

Config.forceLocalUpdate("unsubmitted");
}
}
}}>
<DownvoteIcon locked={ Config.config!.vip && props.locked }/>
<DownvoteIcon selected={downvoted} locked={ Config.config!.vip && props.locked }/>
</button>
</div>
: null
Expand Down
43 changes: 35 additions & 8 deletions src/submission/TitleComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,14 @@ import DownvoteIcon from "../svgIcons/downvoteIcon";
import { submitVideoBrandingAndHandleErrors } from "../dataFetching";
import { AnimationUtils } from "../../maze-utils/src/animationUtils";
import { VideoID } from "../../maze-utils/src/video";
import { shouldStoreVotes } from "../utils/configUtils";

export interface TitleComponentProps {
submission: RenderedTitleSubmission;
selected: boolean;
upvoted: boolean;
onSelectOrUpdate: (title: string, oldTitle: string) => void;
onUpvote: () => void;
onDeselect: () => void;
actAsVip: boolean;
videoID: VideoID;
Expand All @@ -24,6 +27,7 @@ export const TitleComponent = (props: TitleComponentProps) => {
const title = React.useRef(props.submission.title);
const [titleChanged, setTitleChanged] = React.useState(false);
const [focused, setFocused] = React.useState(false);
const [downvoted, setDownvoted] = React.useState(false);

React.useEffect(() => {
if (focused && title.current === "") {
Expand Down Expand Up @@ -109,19 +113,34 @@ export const TitleComponent = (props: TitleComponentProps) => {
e.stopPropagation();

const stopAnimation = AnimationUtils.applyLoadingAnimation(e.currentTarget, 0.3);
submitVideoBrandingAndHandleErrors(props.submission, null, false, props.actAsVip).then(stopAnimation);
submitVideoBrandingAndHandleErrors(props.submission, null, false, props.actAsVip).then(() => {
stopAnimation();
setDownvoted(false);

props.onUpvote();
});

if (shouldStoreVotes()) {
const unsubmitted = Config.local!.unsubmitted[props.videoID] ??= {
thumbnails: [],
titles: []
};
unsubmitted.titles.forEach((t) => t.selected = false);

const unsubmitted = Config.local!.unsubmitted[props.videoID];
if (unsubmitted) {
const unsubmittedTitle = unsubmitted.titles.find((t) => t.title === props.submission.title);
if (unsubmittedTitle) {
unsubmitted.titles.forEach((t) => t.selected = false);
unsubmittedTitle.selected = true;
Config.forceLocalUpdate("unsubmitted");
} else {
unsubmitted.titles.push({
title: props.submission.title,
selected: true
})
}

Config.forceLocalUpdate("unsubmitted");
}
}}>
<UpvoteIcon/>
<UpvoteIcon selected={props.upvoted} />
</button>

<button className="cbButton"
Expand All @@ -130,18 +149,26 @@ export const TitleComponent = (props: TitleComponentProps) => {
e.stopPropagation();

const stopAnimation = AnimationUtils.applyLoadingAnimation(e.currentTarget, 0.3);
submitVideoBrandingAndHandleErrors(props.submission, null, true, props.actAsVip).then(stopAnimation);
submitVideoBrandingAndHandleErrors(props.submission, null, true, props.actAsVip).then(() => {
stopAnimation();
setDownvoted(true);
});

const unsubmitted = Config.local!.unsubmitted[props.videoID];
if (unsubmitted) {
const unsubmittedTitle = unsubmitted.titles.find((t) => t.title === props.submission.title);
if (unsubmittedTitle) {
unsubmitted.titles.splice(unsubmitted.titles.indexOf(unsubmittedTitle), 1);

if (unsubmitted.titles.length === 0 && unsubmitted.thumbnails.length === 0) {
delete Config.local!.unsubmitted[props.videoID];
}

Config.forceLocalUpdate("unsubmitted");
}
}
}}>
<DownvoteIcon locked={ Config.config!.vip && props.submission.locked }/>
<DownvoteIcon selected={downvoted} locked={ Config.config!.vip && props.submission.locked }/>
</button>
</div>

Expand Down
Loading

0 comments on commit 3b41339

Please sign in to comment.