Skip to content

Commit

Permalink
Impl replace lang string way
Browse files Browse the repository at this point in the history
  • Loading branch information
biplobsd committed Jan 17, 2025
1 parent 1316c09 commit f7d9341
Show file tree
Hide file tree
Showing 7 changed files with 128 additions and 22 deletions.
45 changes: 45 additions & 0 deletions data/xpaths/v1.8.5.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
{
"SUBSCRIPTIONS_SECTION": "//*[contains(normalize-space(), '{{subscriptions}}')]/following-sibling::div[@id='items']",
"SUB_CHANNELS_EXPENDED_ITEMS": "//*[contains(normalize-space(), '{{subscriptions}}')]/following-sibling::div[@id='items']/ytd-guide-collapsible-entry-renderer/div/div/ytd-guide-entry-renderer",
"IS_EXPENDEDABLE": "//*[contains(normalize-space(), '{{subscriptions}}')]/following-sibling::div[@id='items']/ytd-guide-collapsible-entry-renderer",
"IS_EXPENDEDABLE_EXPENDED": "//*[contains(normalize-space(), '{{subscriptions}}')]/following-sibling::div[@id='items']/ytd-guide-collapsible-entry-renderer[@expanded]",
"IS_EXPENDEDABLE_EXPENDED_BUTTON": "//*[contains(normalize-space(), '{{subscriptions}}')]/following-sibling::div[@id='items']/ytd-guide-collapsible-entry-renderer/ytd-guide-entry-renderer",
"THREE_LINES": "//yt-icon-button[@id='guide-button']",
"DRAWER_OPENED": "//div[@id='contentContainer' and @opened]",
"ALREADY_SUBSCRIBE": "//*[translate(.,'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz')='{{channelID}}' and @id='subscribers']/ancestor::div[@id='info-section']//div[@id='notification-preference-button' and not(@invisible)]//span[text()='{{subscribed}}']",
"SUBSCRIBE_BTN": "//*[translate(.,'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz')='{{channelID}}' and @id='subscribers']/ancestor::div[@id='info-section']//div[@id='subscribe-button']//span[text()=\"{{subscribe}}\"]/ancestor::button",
"UNSUB1": "//yt-formatted-string[text()='{{unsubscribe}}']",
"UNSUB2": "//button[@aria-label='{{unsubscribe}}']",
"SEARCH_INPUT_QUERY": "//input[@name='search_query' and not(contains(@id, 'search'))]",
"NAVIGATION_PROGRESS": "//yt-page-navigation-progress[not(@hidden)]",
"ALL_SUBSCRIPTIONS_BTN": "//*[contains(normalize-space(), '{{allSubscriptions}}') and @id='endpoint']",
"ALL_SUBSCRIPTIONS_ITEMS": "//div[@id='notification-preference-button' and not(@invisible)]//span[text()='{{subscribed}}']/ancestor::ytd-channel-renderer//a[@href and @id='main-link']",
"XPATH_ENABLE": true,
"API_ENABLE": true,
"EXPIRE_DATE": 1738345140000,
"SUPPORTED_LANGS": {
"en": {
"subscriptions": "Subscriptions",
"unsubscribe": "Unsubscribe",
"allSubscriptions": "All subscriptions",
"subscribed": "Subscribed",
"subscribe": "Subscribe"
},
"en-IN": {
"__same__": "en"
},
"en-GB": {
"__same__": "en"
},
"fr-FR": {
"subscriptions": "Abonnements",
"unsubscribe": "Se désabonner",
"allSubscriptions": "Tous les abonnements",
"subscribed": "Abonné",
"subscribe": "S'abonner"
},
"fr-CA": {
"__same__": "fr-FR"
}
}
}
27 changes: 13 additions & 14 deletions data/xpaths/v1.8.json
Original file line number Diff line number Diff line change
@@ -1,21 +1,20 @@
{
"SUBSCRIPTIONS_SECTION": "//*[contains(normalize-space(), 'Subscriptions') or contains(normalize-space(), 'Abonnements')]/following-sibling::div[@id='items']",
"SUB_CHANNELS_EXPENDED_ITEMS": "//*[contains(normalize-space(), 'Subscriptions') or contains(normalize-space(), 'Abonnements')]/following-sibling::div[@id='items']/ytd-guide-collapsible-entry-renderer/div/div/ytd-guide-entry-renderer",
"IS_EXPENDEDABLE": "//*[contains(normalize-space(), 'Subscriptions') or contains(normalize-space(), 'Abonnements')]/following-sibling::div[@id='items']/ytd-guide-collapsible-entry-renderer",
"IS_EXPENDEDABLE_EXPENDED": "//*[contains(normalize-space(), 'Subscriptions') or contains(normalize-space(), 'Abonnements')]/following-sibling::div[@id='items']/ytd-guide-collapsible-entry-renderer[@expanded]",
"IS_EXPENDEDABLE_EXPENDED_BUTTON": "//*[contains(normalize-space(), 'Subscriptions') or contains(normalize-space(), 'Abonnements')]/following-sibling::div[@id='items']/ytd-guide-collapsible-entry-renderer/ytd-guide-entry-renderer",
"SUBSCRIPTIONS_SECTION": "//*[contains(normalize-space(), 'Subscriptions')]/following-sibling::div[@id='items']",
"SUB_CHANNELS_EXPENDED_ITEMS": "//*[contains(normalize-space(), 'Subscriptions')]/following-sibling::div[@id='items']/ytd-guide-collapsible-entry-renderer/div/div/ytd-guide-entry-renderer",
"IS_EXPENDEDABLE": "//*[contains(normalize-space(), 'Subscriptions')]/following-sibling::div[@id='items']/ytd-guide-collapsible-entry-renderer",
"IS_EXPENDEDABLE_EXPENDED": "//*[contains(normalize-space(), 'Subscriptions')]/following-sibling::div[@id='items']/ytd-guide-collapsible-entry-renderer[@expanded]",
"IS_EXPENDEDABLE_EXPENDED_BUTTON": "//*[contains(normalize-space(), 'Subscriptions')]/following-sibling::div[@id='items']/ytd-guide-collapsible-entry-renderer/ytd-guide-entry-renderer",
"THREE_LINES": "//yt-icon-button[@id='guide-button']",
"DRAWER_OPENED": "//div[@id='contentContainer' and @opened]",
"ALREADY_SUBSCRIBE": "//*[translate(.,'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz')='{{channelID}}' and @id='subscribers']/ancestor::div[@id='info-section']//div[@id='notification-preference-button' and not(@invisible)]//span[text()='Subscribed' or text()='Abonné']",
"SUBSCRIBE_BTN": "//*[translate(.,'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz')='{{channelID}}' and @id='subscribers']/ancestor::div[@id='info-section']//div[@id='subscribe-button']//span[text()='Subscribe' or text()=\"S'abonner\"]/ancestor::button",
"UNSUB1": "//yt-formatted-string[text()='Unsubscribe' or text()='Se désabonner']",
"UNSUB2": "//button[@aria-label='Unsubscribe' or @aria-label='Se désabonner']",
"ALREADY_SUBSCRIBE": "//*[translate(.,'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz')='{{channelID}}' and @id='subscribers']/ancestor::div[@id='info-section']//div[@id='notification-preference-button' and not(@invisible)]//span[text()='Subscribed']",
"SUBSCRIBE_BTN": "//*[translate(.,'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz')='{{channelID}}' and @id='subscribers']/ancestor::div[@id='info-section']//div[@id='subscribe-button']//span[text()='Subscribe']/ancestor::button",
"UNSUB1": "//yt-formatted-string[text()='Unsubscribe']",
"UNSUB2": "//button[@aria-label='Unsubscribe']",
"SEARCH_INPUT_QUERY": "//input[@name='search_query' and not(contains(@id, 'search'))]",
"NAVIGATION_PROGRESS": "//yt-page-navigation-progress[not(@hidden)]",
"ALL_SUBSCRIPTIONS_BTN": "//*[(contains(normalize-space(), 'All subscriptions') or contains(normalize-space(), 'Tous les abonnements')) and @id='endpoint']",
"ALL_SUBSCRIPTIONS_ITEMS": "//div[@id='notification-preference-button' and not(@invisible)]//span[text()='Subscribed' or text()='Abonné']/ancestor::ytd-channel-renderer//a[@href and @id='main-link']",
"ALL_SUBSCRIPTIONS_BTN": "//*[contains(normalize-space(), 'All subscriptions') and @id='endpoint']",
"ALL_SUBSCRIPTIONS_ITEMS": "//div[@id='notification-preference-button' and not(@invisible)]//span[text()='Subscribed']/ancestor::ytd-channel-renderer//a[@href and @id='main-link']",
"XPATH_ENABLE": true,
"API_ENABLE": true,
"EXPIRE_DATE": 1738345140000,
"SUPPORTED_LANGS": ["en","en-IN", "en-GB", "fr-FR", "fr-CA"]
}
"EXPIRE_DATE": 1738345140000
}
27 changes: 24 additions & 3 deletions src/content/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
getXpathFromElement,
getXpathFromElements,
isXPathExpressionExists,
replaceLangKeys, type SupportedLangs
} from "src/utils/helper";
import log from "src/utils/logger";
import type { XPathModel } from "src/utils/xpaths";
Expand All @@ -12,6 +13,7 @@ let isRunning: boolean = false;
let stop: boolean = false;
let xpathValues: XPathModel;
let isNotTabRegister = true;
let lang = "en";

function getAlreadySubscribeXpath(channelID: string) {
return xpathValues.ALREADY_SUBSCRIBE.replace("{{channelID}}", channelID);
Expand All @@ -21,6 +23,25 @@ function getSubscribeButton(channelID: string) {
return xpathValues.SUBSCRIBE_BTN.replace("{{channelID}}", channelID);
}

function replaceLang(str: string, supportedLangs: SupportedLangs) {
lang = document.documentElement.lang;
return replaceLangKeys(supportedLangs, lang, str);
}

function replaceAllLangKeysFlat(xpathValues: XPathModel): XPathModel {
const updatedValues: Record<string, any> = {};

for (const [key, value] of Object.entries(xpathValues)) {
if (typeof value === "string") {
updatedValues[key] = replaceLang(value, xpathValues.SUPPORTED_LANGS);
} else {
updatedValues[key] = value;
}
}

return updatedValues as XPathModel;
}

async function searchChannel(channelID: string) {
const search = getXpathFromElement(
xpathValues.SEARCH_INPUT_QUERY,
Expand Down Expand Up @@ -421,8 +442,8 @@ async function unSubSubNow(channelID: string) {
}

async function isInSupportedLanguage() {
const lang = document.documentElement.lang;
return xpathValues.SUPPORTED_LANGS.includes(lang);
lang = document.documentElement.lang;
return lang in xpathValues.SUPPORTED_LANGS;
}

export async function parseData({ status, to: type }: RuntimeMessage) {
Expand Down Expand Up @@ -485,7 +506,7 @@ export async function parseData({ status, to: type }: RuntimeMessage) {
await readySignalSend();
break;
case "xpathValues":
xpathValues = status.xpathValues;
xpathValues = replaceAllLangKeysFlat(status.xpathValues);
if (!(await isInSupportedLanguage())) {
await runtime.send({
to: "option",
Expand Down
2 changes: 1 addition & 1 deletion src/utils/constants.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export const STORIES_URL = ["https://www.youtube.com/"];
export const REPO_URL = "github.com/biplobsd/yst";
export const XPATH_URL = `https://raw.githubusercontent.com/biplobsd/yst/main/data/xpaths/v1.8.json`;
export const XPATH_URL = `https://raw.githubusercontent.com/biplobsd/yst/main/data/xpaths/v1.8.5.json`;
export const AUTH_URL = "https://accounts.google.com/o/oauth2/auth";
export const REDIRECT_URI =
"https://" + chrome.runtime.id + ".chromiumapp.org/provider_cb";
Expand Down
2 changes: 1 addition & 1 deletion src/utils/default.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { Settings } from "./schema";
import xpathJson from "../../data/xpaths/v1.8.json";
import xpathJson from "../../data/xpaths/v1.8.5.json";

export const SETTINGS_DEFAULT: Settings = {
themeMode: "dark",
Expand Down
30 changes: 30 additions & 0 deletions src/utils/helper.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { STORIES_URL as SELECTED_URLS } from "./constants";
import { type XPathModel } from "./xpaths";

export type SupportedLangs = Record<string, Record<string, string> | { __same__: string | null }>;

export function isXPathExpressionExists(expression: string): boolean {
const result = document.evaluate(
expression,
Expand Down Expand Up @@ -110,3 +112,31 @@ export async function promisedStringifyJSON(value: any) {
}
});
}

export function replaceLangKeys(
supportedLangs: SupportedLangs,
lang: string,
str: string
): string {
const resolveLang = (language: string): Record<string, string> | null => {
const entry = supportedLangs[language];
if (!entry) return null; // Language not found.

if (typeof entry === "object" && "__same__" in entry) {
const sameLang = entry.__same__;
return sameLang ? resolveLang(sameLang) : null; // Resolve the referenced language.
}

return entry as Record<string, string>;
};

const resolvedLang = resolveLang(lang);
if (!resolvedLang) {
console.warn(`Language "${lang}" not found or could not be resolved.`);
return str;
}

return str.replace(/\{\{(.*?)\}\}/g, (match, key) => {
return resolvedLang[key] || match;
});
}
17 changes: 14 additions & 3 deletions src/utils/xpaths.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
import xpathJson from "../../data/xpaths/v1.8.json";
import xpathJson from "../../data/xpaths/v1.8.5.json";
import { z } from "zod";

const LanguageSchema = z.record(z.string());

const SameAsSchema = z.object({
__same__: z.string().nullable(),
});

const SupportedLangsSchema = z.record(
z.string(),
z.union([LanguageSchema, SameAsSchema])
);

export const XPathModelSchema = z.object({
SUBSCRIPTIONS_SECTION: z.string().default(xpathJson.SUBSCRIPTIONS_SECTION),
SUB_CHANNELS_EXPENDED_ITEMS: z
Expand All @@ -20,7 +31,7 @@ export const XPathModelSchema = z.object({
UNSUB1: z.string().default(xpathJson.UNSUB1),
UNSUB2: z.string().default(xpathJson.UNSUB2),
UPDATE_DATE: z.string().optional(),
REMOTE_DISABLE: z.boolean().optional().default(false),
REMOTE_DISABLE: z.boolean().default(false).optional(),
SEARCH_INPUT_QUERY: z.string().default(xpathJson.SEARCH_INPUT_QUERY),
NAVIGATION_PROGRESS: z.string().default(xpathJson.NAVIGATION_PROGRESS),
ALL_SUBSCRIPTIONS_BTN: z.string().default(xpathJson.ALL_SUBSCRIPTIONS_BTN),
Expand All @@ -30,7 +41,7 @@ export const XPathModelSchema = z.object({
XPATH_ENABLE: z.boolean().default(xpathJson.XPATH_ENABLE),
API_ENABLE: z.boolean().default(xpathJson.API_ENABLE),
EXPIRE_DATE: z.number().default(xpathJson.EXPIRE_DATE),
SUPPORTED_LANGS: z.array(z.string()).default(xpathJson.SUPPORTED_LANGS)
SUPPORTED_LANGS: SupportedLangsSchema.default(xpathJson.SUPPORTED_LANGS)
});

export type XPathModel = z.infer<typeof XPathModelSchema>;
Expand Down

0 comments on commit f7d9341

Please sign in to comment.