Skip to content

Commit

Permalink
Merge branch 'search-switch'
Browse files Browse the repository at this point in the history
  • Loading branch information
biplobsd committed Nov 4, 2023
2 parents bd370ef + 8e9eab7 commit 4e03edf
Show file tree
Hide file tree
Showing 17 changed files with 163 additions and 30 deletions.
17 changes: 17 additions & 0 deletions data/xpaths/v1.6.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"SUBSCRIPTIONS_SECTION": "//*[contains(normalize-space(), 'Subscriptions')]/following-sibling::div[@id='items']",
"GET_CHANNELS_WITHOUT_EXPEND": "//*[contains(normalize-space(), 'Subscriptions')]/following-sibling::div[@id='items']/ytd-guide-entry-renderer/a[@href]",
"SUB_CHANNELS_EXPENDED_ITEMS": "//*[contains(normalize-space(), 'Subscriptions')]/following-sibling::div[@id='items']/ytd-guide-collapsible-entry-renderer/div/div/ytd-guide-entry-renderer",
"GET_CHANNELS_IN_EXPEND": "//*[contains(normalize-space(), 'Subscriptions')]/following-sibling::div[@id='items']/ytd-guide-collapsible-entry-renderer/div/div/ytd-guide-entry-renderer/a[@href]",
"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": "//span[translate(.,'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz')='{{channelID}}']/ancestor::div[@id='info-section']//div[@id='notification-preference-button' and not(@invisible)]//span[text()='Subscribed']",
"SUBSCRIBE_BTN": "//span[translate(.,'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz')='{{channelID}}']/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": "//input[@id='search']",
"NAVIGATION_PROGRESS": "//yt-page-navigation-progress[not(@hidden)]"
}
2 changes: 1 addition & 1 deletion manifest.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "Youtube Subscriptions Transfer",
"description": "Transferring subscriptions from one YouTube account to another",
"version": "1.5",
"version": "1.6",
"manifest_version": 3,
"icons": {
"16": "src/assets/icons/icon16.png",
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "youtube-subscriptions-transfer",
"version": "1.5",
"version": "1.6",
"type": "module",
"repository": {
"type": "git",
Expand Down
10 changes: 10 additions & 0 deletions src/components/Docs_Link.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<script lang="ts">
import QuestionCircleIcon from "./icons/Question_circle_Icon.svelte";
export let href: string;
</script>

<span class="tooltip tooltip-right" data-tip="Read docs">
<a class="link-hover" target="_blank" rel="noreferrer" {href}>
<QuestionCircleIcon />
</a>
</span>
3 changes: 2 additions & 1 deletion src/components/Footer.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import { onMount } from "svelte";
import GithubMark from "src/assets/icons/github-mark.png";
import GithubMarkWhite from "src/assets/icons/github-mark-white.png";
import { docs } from "src/utils/docs";
let isLight = false;
Expand All @@ -20,7 +21,7 @@
class="btn btn-xs normal-case"
target="_blank"
rel="noreferrer"
href={REPO_URL}
href={docs.README}
>
<img
class="w-4 h-4"
Expand Down
6 changes: 5 additions & 1 deletion src/components/api/Select_Account.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
import Item from "./Item.svelte";
import axios from "axios";
import type { PrimaryChannel } from "src/utils/types";
import DocsLink from "../Docs_Link.svelte";
import { docs } from "src/utils/docs";
export let primaryChannel: PrimaryChannel;
export let isRunning: boolean;
Expand Down Expand Up @@ -136,7 +138,9 @@
}
</script>

<div class="font-bold">Account</div>
<div class="font-bold flex items-center gap-1">
Account <DocsLink href={docs.connectAccount} />
</div>
<div
class="collapse collapse-arrow border border-base-300 bg-base-100 rounded-box"
>
Expand Down
6 changes: 5 additions & 1 deletion src/components/data/Zip_Reader.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
import { ChannelRawSchema } from "src/utils/schema";
import qs from "qs";
import toast from "svelte-french-toast";
import DocsLink from "../Docs_Link.svelte";
import { docs } from "src/utils/docs";
export let channelsIdsTakeoutSave: (channelIDs: string[]) => void;
let files: FileList | null = null;
Expand Down Expand Up @@ -121,7 +123,9 @@
</script>

<div class="space-y-2 my-2 form-control">
<div class="font-bold text-sm">Takeout import</div>
<div class="font-bold text-sm flex items-center gap-1">
Takeout import <DocsLink href={docs.googleTakeout} />
</div>
<div class="relative w-full h-full">
{#if isLoading}
<div
Expand Down
14 changes: 14 additions & 0 deletions src/components/icons/Question_circle_Icon.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="w-4 h-4"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M9.879 7.519c1.171-1.025 3.071-1.025 4.242 0 1.172 1.025 1.172 2.687 0 3.712-.203.179-.43.326-.67.442-.745.361-1.45.999-1.45 1.827v.75M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9 5.25h.008v.008H12v-.008z"
/>
</svg>
10 changes: 8 additions & 2 deletions src/components/pages/Home.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
import Timer from "../Timer.svelte";
import { channelPathsSchema } from "src/utils/schema";
import ZipReader from "../data/Zip_Reader.svelte";
import DocsLink from "../Docs_Link.svelte";
import { docs } from "src/utils/docs";
let channelPaths: string[] = [];
let xpathValues: XPathModel | undefined = undefined;
Expand Down Expand Up @@ -437,7 +439,9 @@

{#if isRightSiteNow}
<div class="space-y-2">
<div class="font-bold">Data</div>
<div class="font-bold flex gap-1 items-center">
Data <DocsLink href={docs.dataSection} />
</div>
<div
class="collapse collapse-arrow border border-base-300 bg-base-100 rounded-box"
>
Expand Down Expand Up @@ -585,7 +589,9 @@
</div>
<div class="w-[17rem] space-y-2">
<div class="capitalize flex justify-between">
<div class="font-bold">Actions</div>
<div class="font-bold flex items-center gap-1">
Actions <DocsLink href={docs.action} />
</div>
{#if actionName !== ""}
<div
transition:blur
Expand Down
8 changes: 6 additions & 2 deletions src/components/setting/Mode_Switch.svelte
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
<script lang="ts">
import { MODE_DEFAULT } from "src/utils/default";
import { docs } from "src/utils/docs";
import { modeWritable, type MODE } from "src/utils/storage";
import { onMount } from "svelte";
import DocsLink from "../Docs_Link.svelte";
let localMode: MODE = MODE_DEFAULT;
Expand All @@ -12,8 +14,10 @@
});
</script>

<div class="capitalize font-bold tracking-wider text-base !mt-0">
Select Mode
<div
class="capitalize font-bold tracking-wider text-base !mt-0 flex items-center gap-1"
>
Select Mode <DocsLink href={docs.selectMode} />
</div>
<div class="form-control !py-1 !my-0 hover:bg-base-200 rounded-md">
<label class="label !py-0 cursor-pointer">
Expand Down
7 changes: 6 additions & 1 deletion src/components/setting/api/API_Delay.svelte
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<script lang="ts">
import DocsLink from "src/components/Docs_Link.svelte";
import { API_REQ_DELAY_DEFAULT, MODE_DEFAULT } from "src/utils/default";
import { docs } from "src/utils/docs";
import { apiReqDelayWritable } from "src/utils/storage";
import { modeWritable, type MODE } from "src/utils/storage";
import { onMount } from "svelte";
Expand All @@ -19,7 +21,10 @@

<div class="form-control w-full max-w-xs !my-0">
<label class="label">
<span class="label-text">API delay per request</span>
<p class="flex items-center gap-1">
<span class="label-text">API delay per request</span>
<DocsLink href={docs.apiDelay} />
</p>
<input
disabled={localMode !== "api"}
type="number"
Expand Down
6 changes: 5 additions & 1 deletion src/components/setting/xpath/Update_Xpath.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
import log from "src/utils/logger";
import toast from "svelte-french-toast";
import { fetchXPathUpdate } from "src/popup/helper";
import DocsLink from "src/components/Docs_Link.svelte";
import { docs } from "src/utils/docs";
let xpathValuesString: string = "";
let isLoadingSave = false;
let isErrorSave = false;
Expand Down Expand Up @@ -101,7 +103,9 @@
{/if}
<div class="form-control">
<div class="label">
<span class="label-text">All XPath</span>
<span class="label-text flex items-center gap-1"
>All XPath <DocsLink href={docs.updateXPathValue} /></span
>
</div>
<textarea
bind:value={xpathValuesString}
Expand Down
70 changes: 57 additions & 13 deletions src/content/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,53 @@ import type { XPathModel } from "src/utils/xpaths";
let isRunning: boolean = false;
let stop: boolean = false;
let xpathValues: XPathModel;
let isNotTabRegister = true;

function getAlreadySubscribeXpath(channelID: string) {
return xpathValues.ALREADY_SUBSCRIBE.replace("{{channelID}}", channelID);
}

function getSubscribeButton(channelID: string) {
return xpathValues.SUBSCRIBE_BTN.replace("{{channelID}}", channelID);
}

async function searchChannel(channelID: string) {
const search = getXpathFromElement(
xpathValues.SEARCH_INPUT
) as HTMLInputElement;
if (search) {
if (isNotTabRegister) {
search.dispatchEvent(new KeyboardEvent("keypress", { key: "Tab" }));
await delay(100);
}
search.value = channelID;
search.dispatchEvent(new KeyboardEvent("keydown", { keyCode: 13 }));
return true;
}
return false;
}

async function switchChannel(channelID: string) {
if (await searchChannel(channelID)) {
if (await waitingForProgressEnd()) {
await readySignalSend();
}
}
}

async function waitingForProgressEnd() {
await delay(100);
for (let index = 0; index < 50; index++) {
if (!isXPathExpressionExists(xpathValues.NAVIGATION_PROGRESS)) {
return true;
}
if (isNotTabRegister) {
isNotTabRegister = false;
}
await delay(500);
}
return false;
}

function isDrawerOpened() {
if (!isXPathExpressionExists(xpathValues.DRAWER_OPENED)) {
Expand Down Expand Up @@ -257,13 +304,9 @@ async function acceptSignalSend() {
});
}

function newPage(path: string) {
window.location.href = "https://youtube.com/" + path;
}

async function isAlreadySubscribe() {
async function isAlreadySubscribe(channelID: string) {
for (let index = 0; index < 2; index++) {
if (isXPathExpressionExists(xpathValues.ALREADY_SUBSCRIBE)) {
if (isXPathExpressionExists(getAlreadySubscribeXpath(channelID))) {
return true;
}
await delay(500);
Expand All @@ -272,7 +315,7 @@ async function isAlreadySubscribe() {
}

async function subSubNow(channelID: string) {
if (await isAlreadySubscribe()) {
if (await isAlreadySubscribe(channelID)) {
await runtime.send({
type: "statusOption",
status: {
Expand All @@ -284,15 +327,15 @@ async function subSubNow(channelID: string) {
}

for (let index = 0; index < 2; index++) {
const subButton = getXpathFromElement(xpathValues.SUBSCRIBE_BTN);
const subButton = getXpathFromElement(getSubscribeButton(channelID));
if (subButton) {
subButton.click();
break;
}
await delay(500);
}

if (await isAlreadySubscribe()) {
if (await isAlreadySubscribe(channelID)) {
await runtime.send({
type: "statusOption",
status: {
Expand Down Expand Up @@ -321,7 +364,7 @@ async function unSubSubNow(channelID: string) {
},
};

if (isXPathExpressionExists(xpathValues.SUBSCRIBE_BTN)) {
if (isXPathExpressionExists(getSubscribeButton(channelID))) {
await runtime.send({
type: "statusOption",
status: {
Expand All @@ -332,7 +375,7 @@ async function unSubSubNow(channelID: string) {
return;
}

const unSubButton = getXpathFromElement(xpathValues.ALREADY_SUBSCRIBE);
const unSubButton = getXpathFromElement(getAlreadySubscribeXpath(channelID));
if (unSubButton) {
unSubButton.click();
await delay(50);
Expand All @@ -345,7 +388,8 @@ async function unSubSubNow(channelID: string) {
const unSub2 = getXpathFromElement(xpathValues.UNSUB2);
if (unSub2) {
unSub2.click();
if (isXPathExpressionExists(xpathValues.SUBSCRIBE_BTN)) {
await delay(50);
if (isXPathExpressionExists(getSubscribeButton(channelID))) {
await runtime.send({
type: "statusOption",
status: {
Expand Down Expand Up @@ -400,7 +444,7 @@ export async function parseData(dataLocal: RuntimeMessage) {
);
return;
}
newPage(status.msg);
await switchChannel(status.msg);
break;
case "subscribe":
if (isRunning) {
Expand Down
5 changes: 2 additions & 3 deletions src/utils/constants.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
export const STORIES_URL = ["https://www.youtube.com/"];
export const DEFAULT_STATUS_MSG = "Ready for request";
export const APP_NAME = "Youtube Subscriptions Transfer";
export const VERSION = "v1.5";
export const VERSION = "v1.6";

export const REPO_URL = "https://github.com/biplobsd/yst";
export const XPATH_URL =
"https://raw.githubusercontent.com/biplobsd/yst/main/data/xpath.json";
export const XPATH_URL = `https://raw.githubusercontent.com/biplobsd/yst/main/data/xpaths/${VERSION}.json`;

export const CHANNEL_PATHS_KEY = "channelPaths";
export const XPATH_VALUES_KEY = "xpathValues";
Expand Down
15 changes: 15 additions & 0 deletions src/utils/docs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
export const docs = {
README: "https://github.com/biplobsd/yst/blob/main/README.md",
dataSection:
"https://github.com/biplobsd/yst/blob/main/README.md#data-section",
googleTakeout:
"https://github.com/biplobsd/yst/blob/main/README.md#google-takeout",
action: "https://github.com/biplobsd/yst/blob/main/README.md#actions",
updateXPathValue:
"https://github.com/biplobsd/yst/blob/main/README.md#update-xpath-value",
selectMode: "https://github.com/biplobsd/yst/blob/main/README.md#select-mode",
apiDelay:
"https://github.com/biplobsd/yst/blob/main/README.md#api-delay-per-request",
connectAccount:
"https://github.com/biplobsd/yst/blob/main/README.md#connect-your-account",
};
8 changes: 6 additions & 2 deletions src/utils/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,16 @@ export const ChannelRawSchema = z
items: z
.object({
snippet: z.object({
customUrl: z.string(),
customUrl: z.string().optional(),
}),
})
.array(),
})
.transform((x) => x.items.map((y) => y.snippet.customUrl));
.transform((x) =>
x.items
.filter((y) => y.snippet.customUrl !== undefined)
.map((y) => y.snippet.customUrl!)
);

export const SubscriptionsListSchema = z
.object({
Expand Down
Loading

0 comments on commit 4e03edf

Please sign in to comment.