Implemented importing subs via different file types

This commit is contained in:
WardPearce
2026-03-06 23:38:58 +13:00
parent 73e1e609c8
commit 13b5d87c9d
3 changed files with 84 additions and 4 deletions
+20 -2
View File
@@ -1,12 +1,12 @@
{
"name": "materialious",
"version": "1.16.8",
"version": "1.16.12",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "materialious",
"version": "1.16.8",
"version": "1.16.12",
"hasInstallScript": true,
"dependencies": {
"@capacitor-community/electron": "^5.0.1",
@@ -47,6 +47,7 @@
"melt": "^0.44.0",
"mousetrap": "^1.6.5",
"mysql2": "^3.18.2",
"papaparse": "^5.5.3",
"pg": "^8.19.0",
"pg-hstore": "^2.3.4",
"safe-regex2": "^5.0.0",
@@ -76,6 +77,7 @@
"@types/human-number": "^1.0.2",
"@types/jsdom": "^28.0.0",
"@types/mousetrap": "^1.6.15",
"@types/papaparse": "^5.5.2",
"@vite-pwa/sveltekit": "^1.0.0",
"eslint": "^10.0.2",
"eslint-config-prettier": "^10.1.8",
@@ -6125,6 +6127,16 @@
"dev": true,
"license": "MIT"
},
"node_modules/@types/papaparse": {
"version": "5.5.2",
"resolved": "https://registry.npmjs.org/@types/papaparse/-/papaparse-5.5.2.tgz",
"integrity": "sha512-gFnFp/JMzLHCwRf7tQHrNnfhN4eYBVYYI897CGX4MY1tzY9l2aLkVyx2IlKZ/SAqDbB3I1AOZW5gTMGGsqWliA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/node": "*"
}
},
"node_modules/@types/phoenix": {
"version": "1.6.7",
"resolved": "https://registry.npmjs.org/@types/phoenix/-/phoenix-1.6.7.tgz",
@@ -14525,6 +14537,12 @@
"integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==",
"license": "BlueOak-1.0.0"
},
"node_modules/papaparse": {
"version": "5.5.3",
"resolved": "https://registry.npmjs.org/papaparse/-/papaparse-5.5.3.tgz",
"integrity": "sha512-5QvjGxYVjxO59MGU2lHVYpRWBBtKHnlIAcSe1uNFCkkptUh63NFRj0FJQm7nR67puEruUci/ZkjmEFrjCAyP4A==",
"license": "MIT"
},
"node_modules/parse-json": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
+3 -1
View File
@@ -30,6 +30,7 @@
"@types/human-number": "^1.0.2",
"@types/jsdom": "^28.0.0",
"@types/mousetrap": "^1.6.15",
"@types/papaparse": "^5.5.2",
"@vite-pwa/sveltekit": "^1.0.0",
"eslint": "^10.0.2",
"eslint-config-prettier": "^10.1.8",
@@ -85,6 +86,7 @@
"melt": "^0.44.0",
"mousetrap": "^1.6.5",
"mysql2": "^3.18.2",
"papaparse": "^5.5.3",
"pg": "^8.19.0",
"pg-hstore": "^2.3.4",
"safe-regex2": "^5.0.0",
@@ -99,4 +101,4 @@
"youtubei.js": "^16.0.1",
"zod": "^4.3.6"
}
}
}
+61 -1
View File
@@ -1,6 +1,7 @@
import z from 'zod';
import type { Subscription } from './api/model';
import { getChannel, postSubscribe } from './api';
import Papa from 'papaparse';
const zInvidiousSubs = z.object({
subscriptions: z.array(z.string())
@@ -16,6 +17,32 @@ const zFreetubeSubs = z.object({
)
});
const zNewPipeSubs = z.object({
subscriptions: z.array(
z.object({
service_id: z.number(),
url: z.url(),
name: z.string()
})
)
});
const zYouTubeSubs = z.array(
z.object({
snippet: z.object({
channelId: z.string(),
title: z.string()
})
})
);
const zYouTubeCsvSubs = z.array(
z.object({
'Channel ID': z.string(),
'Channel title': z.string()
})
);
export async function importSubscriptions(subscriptions: Subscription[]) {
const subPromises: Promise<void>[] = [];
for (const sub of subscriptions) {
@@ -64,7 +91,7 @@ export async function importSubscriptionsFromFile(file: File) {
authorId: channelId
});
}
} else {
} else if (file.name.endsWith('.json')) {
let fileJson: Record<any, any> | undefined;
try {
fileJson = JSON.parse(fileContents);
@@ -75,6 +102,8 @@ export async function importSubscriptionsFromFile(file: File) {
if (fileJson) {
const invidiousSubs = zInvidiousSubs.safeParse(fileJson);
const freetubeSubs = zFreetubeSubs.safeParse(fileJson);
const newPipeSubs = zNewPipeSubs.safeParse(fileJson);
const youtubeSubs = zYouTubeSubs.safeParse(fileJson);
if (invidiousSubs.success) {
for (const authorId of invidiousSubs.data.subscriptions) {
@@ -95,6 +124,37 @@ export async function importSubscriptionsFromFile(file: File) {
authorId: sub.id
});
}
} else if (newPipeSubs.success) {
for (const sub of newPipeSubs.data.subscriptions) {
const authorId = sub.url.split('/')[4];
if (typeof authorId !== 'string') continue;
subsToImport.push({
author: sub.name,
authorId
});
}
} else if (youtubeSubs.success) {
for (const sub of youtubeSubs.data) {
subsToImport.push({
author: sub.snippet.title,
authorId: sub.snippet.channelId
});
}
}
}
} else if (file.name.endsWith('.csv')) {
const csv = Papa.parse(fileContents, { header: true, skipEmptyLines: true });
if (csv.data.length > 0) {
const youtubeSubs = zYouTubeCsvSubs.safeParse(csv.data);
if (youtubeSubs.success) {
for (const sub of youtubeSubs.data) {
subsToImport.push({
author: sub['Channel title'],
authorId: sub['Channel ID']
});
}
}
}
}