Skip to content

Commit

Permalink
Don't mess with greek letter words unless the title is detected as greek
Browse files Browse the repository at this point in the history
Should help with math in titles

Fix ajayyy#111
  • Loading branch information
ajayyy committed Jul 27, 2023
1 parent 8bd611e commit 4f7dfdb
Show file tree
Hide file tree
Showing 6 changed files with 114 additions and 57 deletions.
19 changes: 15 additions & 4 deletions src/options/ChannelOverridesComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { SelectOptionComponent } from "../popup/SelectOptionComponent";
import Config, { ConfigurationID, CustomConfiguration } from "../config/config";
import { generateUserID } from "../maze-utils/setup";
import { ToggleOptionComponent } from "../popup/ToggleOptionComponent";
import { toSentenceCase } from "../titles/titleFormatter";
import { toFirstLetterUppercase, toLowerCase, toSentenceCase } from "../titles/titleFormatter";

let forceUpdateConfigurationsTimeout: NodeJS.Timeout | null = null;
let forceUpdateOverridesTimeout: NodeJS.Timeout | null = null;
Expand Down Expand Up @@ -42,6 +42,17 @@ export const ChannelOverridesComponent = () => {
updateChannelList(setChannelListText, selectedConfigurationID!);
}, [selectedConfigurationID]);

const [sentenceCaseText, setSentenceCaseText] = React.useState(chrome.i18n.getMessage("SentenceCase"));
const [lowerCaseText, setLowerCaseText] = React.useState(chrome.i18n.getMessage("LowerCase"));
const [firstLetterUppercaseText, setFirstLetterUppercaseText] = React.useState(chrome.i18n.getMessage("FirstLetterUppercase"));
React.useEffect(() => {
(async () => {
setSentenceCaseText(await toSentenceCase(chrome.i18n.getMessage("SentenceCase"), false));
setLowerCaseText(await toLowerCase(chrome.i18n.getMessage("LowerCase")));
setFirstLetterUppercaseText(await toFirstLetterUppercase(chrome.i18n.getMessage("FirstLetterUppercase")));
})();
}, []);

return (
<div className="channelOverrides">

Expand Down Expand Up @@ -212,9 +223,9 @@ export const ChannelOverridesComponent = () => {
options={[
{ value: "-1", label: chrome.i18n.getMessage("Disabled") },
{ value: "1", label: chrome.i18n.getMessage("TitleCase") },
{ value: "2", label: toSentenceCase(chrome.i18n.getMessage("SentenceCase"), false) },
{ value: "3", label: chrome.i18n.getMessage("LowerCase") },
{ value: "4", label: chrome.i18n.getMessage("FirstLetterUppercase") },
{ value: "2", label: sentenceCaseText },
{ value: "3", label: lowerCaseText },
{ value: "4", label: firstLetterUppercaseText },
{ value: "0", label: chrome.i18n.getMessage("CapitalizeWords") },
]}
showResetButton={shouldShowResetButton(titleFormatting)}
Expand Down
17 changes: 14 additions & 3 deletions src/popup/FormattingOptionsComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,17 @@ export const FormattingOptionsComponent = () => {
const [shouldCleanEmojis, setShouldCleanEmojis] = React.useState(Config.config!.shouldCleanEmojis);
const [thumbnailFallback, setThumbnailFallback] = React.useState(String(Config.config!.thumbnailFallback));

const [sentenceCaseText, setSentenceCaseText] = React.useState(chrome.i18n.getMessage("SentenceCase"));
const [lowerCaseText, setLowerCaseText] = React.useState(chrome.i18n.getMessage("LowerCase"));
const [firstLetterUppercaseText, setFirstLetterUppercaseText] = React.useState(chrome.i18n.getMessage("FirstLetterUppercase"));
React.useEffect(() => {
(async () => {
setSentenceCaseText(await toSentenceCase(chrome.i18n.getMessage("SentenceCase"), false));
setLowerCaseText(await toLowerCase(chrome.i18n.getMessage("LowerCase")));
setFirstLetterUppercaseText(await toFirstLetterUppercase(chrome.i18n.getMessage("FirstLetterUppercase")));
})();
}, []);

return (
<>
{/* Title Reformatting Option */}
Expand All @@ -26,9 +37,9 @@ export const FormattingOptionsComponent = () => {
options={[
{ value: "-1", label: chrome.i18n.getMessage("Disabled") },
{ value: "1", label: chrome.i18n.getMessage("TitleCase") },
{ value: "2", label: toSentenceCase(chrome.i18n.getMessage("SentenceCase"), false) },
{ value: "3", label: toLowerCase(chrome.i18n.getMessage("LowerCase")) },
{ value: "4", label: toFirstLetterUppercase(chrome.i18n.getMessage("FirstLetterUppercase")) },
{ value: "2", label: sentenceCaseText },
{ value: "3", label: lowerCaseText },
{ value: "4", label: firstLetterUppercaseText },
{ value: "0", label: chrome.i18n.getMessage("CapitalizeWords") },
]}
/>
Expand Down
21 changes: 13 additions & 8 deletions src/submission/BrandingPreviewComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,21 @@ export interface BrandingPreviewComponentComponentProps {
}

export const BrandingPreviewComponent = (props: BrandingPreviewComponentComponentProps) => {
const [displayedTitle, setDisplayedTitle] = React.useState(getDefaultTitle(props.submissions, props.titles));
const [displayedTitle, setDisplayedTitle] = React.useState("");
const [displayedThumbnail, setDisplayedThumbnail] = React.useState(getDefaultThumbnail(props.submissions, props.thumbnails));

React.useEffect(() => {
if (props.selectedTitle?.title) {
setDisplayedTitle(props.selectedTitle);
} else {
setDisplayedTitle(getDefaultTitle(props.submissions, props.titles));
}
}, [props.selectedTitle]);
(async () => {
if (props.selectedTitle?.title) {
setDisplayedTitle(await formatTitleDefaultSettings(props.selectedTitle.title, true));
} else {
const defaultTitle = getDefaultTitle(props.submissions, props.titles);
if (defaultTitle) {
setDisplayedTitle(await formatTitleDefaultSettings(defaultTitle.title, true));
}
}
})();
}, [props.selectedTitle, props.submissions, props.titles]);

React.useEffect(() => {
if (props.selectedThumbnail) {
Expand All @@ -51,7 +56,7 @@ export const BrandingPreviewComponent = (props: BrandingPreviewComponentCompone
></ThumbnailSelectionComponent>

<div className="cbTitle cbTitlePreview">
{formatTitleDefaultSettings(displayedTitle.title, true)}
{displayedTitle}
</div>
</div>
);
Expand Down
32 changes: 20 additions & 12 deletions src/submission/SubmissionComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,16 +71,24 @@ export const SubmissionComponent = (props: SubmissionComponentProps) => {

const [currentlySubmitting, setCurrentlySubmitting] = React.useState(false);

const originalTitle = toSentenceCase(getCurrentPageTitle() || chrome.i18n.getMessage("OriginalTitle"), false);
const titles: RenderedTitleSubmission[] = [{
title: originalTitle
}, {
title: ""
}, ...props.submissions.titles
.filter((s) => s.title !== originalTitle)
.map((s) => ({
title: s.title
}))];
const [originalTitle, setOriginalTitle] = React.useState("");
const [titles, setTitles] = React.useState<RenderedTitleSubmission[]>([]);
React.useEffect(() => {
(async () => {
const originalTitle = await toSentenceCase(getCurrentPageTitle() || chrome.i18n.getMessage("OriginalTitle"), false);
setOriginalTitle(originalTitle);

setTitles([{
title: originalTitle
}, {
title: ""
}, ...props.submissions.titles
.filter((s) => s.title !== originalTitle)
.map((s) => ({
title: s.title
}))]);
})();
}, []);

const defaultThumbnails: RenderedThumbnailSubmission[] = [{
type: ThumbnailType.Original
Expand Down Expand Up @@ -227,13 +235,13 @@ export const SubmissionComponent = (props: SubmissionComponentProps) => {
disabled={currentlySubmitting
|| (!selectedThumbnail.current && !selectedTitle)
|| (!!selectedTitle && selectedTitle.title === chrome.i18n.getMessage("OriginalTitle"))}
onClick={() => {
onClick={async () => {
setCurrentlySubmitting(true);

props.submitClicked(selectedTitle ? {
...selectedTitle,
original: selectedTitle.title === getCurrentPageTitle()
|| (!!getCurrentPageTitle() && selectedTitle.title === toSentenceCase(getCurrentPageTitle()!, false))
|| (!!getCurrentPageTitle() && selectedTitle.title === await toSentenceCase(getCurrentPageTitle()!, false))
} : null, selectedThumbnail.current).then((success) => {
if (!success) {
setCurrentlySubmitting(false);
Expand Down
58 changes: 40 additions & 18 deletions src/titles/titleFormatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,38 +15,38 @@ export async function formatTitle(title: string, isCustom: boolean, videoID: Vid
return formatTitleInternal(title, isCustom, await getTitleFormatting(videoID), await shouldCleanEmojis(videoID));
}

export function formatTitleDefaultSettings(title: string, isCustom: boolean): string {
return formatTitleInternal(title, isCustom, Config.config!.titleFormatting, Config.config!.shouldCleanEmojis);
export async function formatTitleDefaultSettings(title: string, isCustom: boolean): Promise<string> {
return await formatTitleInternal(title, isCustom, Config.config!.titleFormatting, Config.config!.shouldCleanEmojis);
}

export function formatTitleInternal(title: string, isCustom: boolean, titleFormatting: TitleFormatting, shouldCleanEmojis: boolean): string {
export async function formatTitleInternal(title: string, isCustom: boolean, titleFormatting: TitleFormatting, shouldCleanEmojis: boolean): Promise<string> {
if (shouldCleanEmojis) {
title = cleanEmojis(title);
}

switch (titleFormatting) {
case TitleFormatting.CapitalizeWords:
return toCapitalizeCase(title, isCustom);
return await toCapitalizeCase(title, isCustom);
case TitleFormatting.TitleCase:
return toTitleCase(title, isCustom);
return await toTitleCase(title, isCustom);
case TitleFormatting.SentenceCase:
return toSentenceCase(title, isCustom);
return await toSentenceCase(title, isCustom);
case TitleFormatting.LowerCase:
return toLowerCase(title);
return await toLowerCase(title);
case TitleFormatting.FirstLetterUppercase:
return toFirstLetterUppercase(title);
return await toFirstLetterUppercase(title);
default: {
return cleanUnformattedTitle(title);
}
}
}

export function toLowerCase(str: string): string {
export async function toLowerCase(str: string): Promise<string> {
const words = str.split(" ");

let result = "";
for (const word of words) {
if (forceKeepFormatting(word)) {
if (forceKeepFormatting(word) || await greekLetterAllowed(word, str)) {
result += word + " ";
} else {
result += word.toLowerCase() + " ";
Expand All @@ -56,13 +56,13 @@ export function toLowerCase(str: string): string {
return cleanResultingTitle(result);
}

export function toFirstLetterUppercase(str: string): string {
export async function toFirstLetterUppercase(str: string): Promise<string> {
const words = str.split(" ");

let result = "";
let index = 0;
for (const word of words) {
if (forceKeepFormatting(word)) {
if (forceKeepFormatting(word) || await greekLetterAllowed(word, str)) {
result += word + " ";
} else if (startOfSentence(index, words) && !isNumberThenLetter(word)) {
result += capitalizeFirstLetter(word) + " ";
Expand All @@ -76,7 +76,7 @@ export function toFirstLetterUppercase(str: string): string {
return cleanResultingTitle(result);
}

export function toSentenceCase(str: string, isCustom: boolean): string {
export async function toSentenceCase(str: string, isCustom: boolean): Promise<string> {
const words = str.split(" ");
const inTitleCase = isInTitleCase(words);
const mostlyAllCaps = isMostlyAllCaps(words);
Expand All @@ -93,7 +93,8 @@ export function toSentenceCase(str: string, isCustom: boolean): string {
|| ((!inTitleCase || !isWordCapitalCase(word)) && trustCaps && isAcronym(word))
|| (!inTitleCase && isWordCapitalCase(word))
|| (isCustom && isWordCustomCapitalization(word))
|| (!isAllCaps(word) && isWordCustomCapitalization(word))) {
|| (!isAllCaps(word) && isWordCustomCapitalization(word))
|| await greekLetterAllowed(word, str)) {
// For custom titles, allow any not just first capital
// For non-custom, allow any that isn't all caps
// Trust it with capitalization
Expand All @@ -116,7 +117,7 @@ export function toSentenceCase(str: string, isCustom: boolean): string {
return cleanResultingTitle(result);
}

export function toTitleCase(str: string, isCustom: boolean): string {
export async function toTitleCase(str: string, isCustom: boolean): Promise<string> {
const words = str.split(" ");
const mostlyAllCaps = isMostlyAllCaps(words);

Expand All @@ -128,7 +129,8 @@ export function toTitleCase(str: string, isCustom: boolean): string {
if (forceKeepFormatting(word)
|| (isCustom && isWordCustomCapitalization(word))
|| (!isAllCaps(word) && (isWordCustomCapitalization(word) || isNumberThenLetter(word)))
|| isYear(word)) {
|| isYear(word)
|| await greekLetterAllowed(word, str)) {
// For custom titles, allow any not just first capital
// For non-custom, allow any that isn't all caps
result += word + " ";
Expand All @@ -149,7 +151,7 @@ export function toTitleCase(str: string, isCustom: boolean): string {
return cleanResultingTitle(result);
}

export function toCapitalizeCase(str: string, isCustom: boolean): string {
export async function toCapitalizeCase(str: string, isCustom: boolean): Promise<string> {
const words = str.split(" ");
const mostlyAllCaps = isMostlyAllCaps(words);

Expand All @@ -160,7 +162,8 @@ export function toCapitalizeCase(str: string, isCustom: boolean): string {
|| (!isAllCaps(word) && isWordCustomCapitalization(word))
|| (isFirstLetterCapital(word) &&
((!mostlyAllCaps && isAcronym(word)) || isAcronymStrict(word)))
|| isYear(word)) {
|| isYear(word)
|| await greekLetterAllowed(word, str)) {
// For custom titles, allow any not just first capital
// For non-custom, allow any that isn't all caps
// Trust it with capitalization
Expand Down Expand Up @@ -291,6 +294,25 @@ function forceKeepFormatting(word: string, ignorePunctuation = true): boolean {
return result;
}

/**
* Allow mathematical greek symbols without breaking greek
*/
async function greekLetterAllowed(word: string, title: string): Promise<boolean> {
if (word.match(/[Ͱ-Ͽ]/)) {
return !await checkLanguage(title, "el")
}

return false;
}

async function checkLanguage(title: string, language: string): Promise<boolean> {
if (typeof chrome === "undefined" || !("detectLanguage" in chrome.i18n)) return false;

const detectedLanguages = await chrome.i18n.detectLanguage(title);
const detectedLanguage = detectedLanguages.languages.find((l) => l.language === language);
return !!detectedLanguage && detectedLanguage.percentage > 30;
}

export function isAcronym(word: string): boolean {
// 2 - 3 chars, or has dots after each letter except last word
// U.S.A allowed
Expand Down
24 changes: 12 additions & 12 deletions test/titleFormatter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,8 @@ describe("toCapitalizeCase", () => {
];
for (const testCase of capitalizeCases) {
const [input, expected] = testCase;
it(input, () => {
expect(toCapitalizeCase(input, false)).toBe(expected);
it(input, async () => {
expect(await toCapitalizeCase(input, false)).toBe(expected);
});
}
});
Expand Down Expand Up @@ -125,8 +125,8 @@ describe("toTitleCase", () => {
];
for (const testCase of titleCases) {
const [input, expected] = testCase;
it(input, () => {
expect(toTitleCase(input, false)).toBe(expected);
it(input, async () => {
expect(await toTitleCase(input, false)).toBe(expected);
});
}
});
Expand All @@ -144,8 +144,8 @@ describe("toTitleCase cleanEmojis", () => {
];
for (const testCase of titleCases) {
const [input, expected] = testCase;
it(input, () => {
expect(formatTitleInternal(input, false, TitleFormatting.TitleCase, true)).toBe(expected);
it(input, async () => {
expect(await formatTitleInternal(input, false, TitleFormatting.TitleCase, true)).toBe(expected);
});
}
});
Expand Down Expand Up @@ -190,8 +190,8 @@ describe("toSentenceCase", () => {
];
for (const testCase of sentenceCases) {
const [input, expected] = testCase;
it(input, () => {
expect(toSentenceCase(input, false)).toBe(expected);
it(input, async () => {
expect(await toSentenceCase(input, false)).toBe(expected);
});
}
});
Expand Down Expand Up @@ -239,11 +239,11 @@ describe("titleFormatter custom cases", () => {
];
for (const testCase of customTitles) {
const [input, title, sentence] = testCase;
it(`toTitleCase "${input}"`, () => {
expect(toTitleCase(input, true)).toBe(title);
it(`toTitleCase "${input}"`, async () => {
expect(await toTitleCase(input, true)).toBe(title);
});
it(`toSentenceCase "${input}"`, () => {
expect(toSentenceCase(input, true)).toBe(sentence);
it(`toSentenceCase "${input}"`, async () => {
expect(await toSentenceCase(input, true)).toBe(sentence);
});
}
});
Expand Down

0 comments on commit 4f7dfdb

Please sign in to comment.