mirror of
https://github.com/LuanRT/YouTube.js.git
synced 2026-06-24 07:11:48 +00:00
refactor!: cleanup platform support (#306)
* refactor!: cleanup platform support * chore: lint * fix: web platform * feat: provide UniversalCache Provide UniversalCache as a wrapper around Platform.shim.Cache. * fix: invalid import * refactor: remove isolated-vm support * fix: type info * refactor: cleanup exports * fix: mark jintr as external dependency In the bundled CJS node build, mark jintr as external. * chore: add additional exports web exports provide a way to select web implementation manually without relying on the bundler to select it correctly from the "exports" field web points to src/platform/web.js web.bundle points to bundle/browser.js web.bundle.browser points to bundle/browser.min.js agnostic exports provide users of the library to provide their own platform implementation without first importing the default one. agnostic points to src/platform/lib.ts * fix: toDash on web * revert: eval is synchronous * fix: use serializeDOM in FormatUtils * ci: automate releases with `release-please` * chore: clean up workflow files * ci: fix NPM publish action --------- Co-authored-by: LuanRT <luan.lrt4@gmail.com>
This commit is contained in:
@@ -1,238 +1,21 @@
|
||||
import { getRuntime } from './Utils';
|
||||
import { ICache } from '../types/Cache.js';
|
||||
import { Platform } from './Utils.js';
|
||||
|
||||
// Browser Cache is based off:
|
||||
// https://github.com/elias551/simple-kvs/blob/master/src/index.ts
|
||||
|
||||
export default class UniversalCache {
|
||||
#persistent_directory: string;
|
||||
#persistent: boolean;
|
||||
|
||||
constructor(persistent = false, persistent_directory?: string) {
|
||||
this.#persistent_directory = persistent_directory || UniversalCache.default_persistent_directory;
|
||||
this.#persistent = persistent;
|
||||
export default class UniversalCache implements ICache {
|
||||
#cache: ICache;
|
||||
constructor(persistent: boolean, persistent_directory?: string) {
|
||||
this.#cache = new Platform.shim.Cache(persistent, persistent_directory);
|
||||
}
|
||||
|
||||
static get temp_directory() {
|
||||
switch (getRuntime()) {
|
||||
case 'deno':
|
||||
const Deno: any = Reflect.get(globalThis, 'Deno');
|
||||
return `${Deno.env.get('TMPDIR') || Deno.env.get('TMP') || Deno.env.get('TEMP') || '/tmp'}/youtubei.js`;
|
||||
case 'node':
|
||||
return `${Reflect.get(module, 'require')('os').tmpdir()}/youtubei.js`;
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
static get default_persistent_directory() {
|
||||
switch (getRuntime()) {
|
||||
case 'deno':
|
||||
const Deno: any = Reflect.get(globalThis, 'Deno');
|
||||
return `${Deno.cwd()}/.cache/youtubei.js`;
|
||||
case 'node':
|
||||
return Reflect.get(module, 'require')('path').resolve(__dirname, '..', '..', '.cache', 'youtubei.js');
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
get cache_dir() {
|
||||
return this.#persistent ? this.#persistent_directory : UniversalCache.temp_directory;
|
||||
return this.#cache.cache_dir;
|
||||
}
|
||||
|
||||
async #createCache() {
|
||||
const dir = this.cache_dir;
|
||||
switch (getRuntime()) {
|
||||
case 'deno':
|
||||
const Deno: any = Reflect.get(globalThis, 'Deno');
|
||||
try {
|
||||
const cwd = await Deno.stat(dir);
|
||||
if (!cwd.isDirectory)
|
||||
throw new Error('An unexpected file was found in place of the cache directory');
|
||||
} catch (e) {
|
||||
if (e instanceof Deno.errors.NotFound)
|
||||
await Deno.mkdir(dir, { recursive: true });
|
||||
else
|
||||
throw e;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'node':
|
||||
const fs = Reflect.get(module, 'require')('fs/promises');
|
||||
try {
|
||||
const cwd = await fs.stat(dir);
|
||||
if (!cwd.isDirectory())
|
||||
throw new Error('An unexpected file was found in place of the cache directory');
|
||||
} catch (e: any) {
|
||||
if (e?.code === 'ENOENT')
|
||||
await fs.mkdir(dir, { recursive: true });
|
||||
else
|
||||
throw e;
|
||||
}
|
||||
break;
|
||||
}
|
||||
get(key: string) {
|
||||
return this.#cache.get(key);
|
||||
}
|
||||
|
||||
#getBrowserDB() {
|
||||
const indexedDB: IDBFactory = Reflect.get(globalThis, 'indexedDB') || Reflect.get(globalThis, 'webkitIndexedDB') || Reflect.get(globalThis, 'mozIndexedDB') || Reflect.get(globalThis, 'msIndexedDB');
|
||||
|
||||
if (!indexedDB) return console.log('IndexedDB is not supported. No cache will be used.');
|
||||
|
||||
return new Promise<IDBDatabase>((resolve, reject) => {
|
||||
const request = indexedDB.open('youtubei.js', 1);
|
||||
request.onsuccess = function () {
|
||||
resolve(this.result);
|
||||
};
|
||||
|
||||
request.onerror = function (event) {
|
||||
reject('indexedDB request error');
|
||||
console.error(event);
|
||||
};
|
||||
|
||||
request.onupgradeneeded = function () {
|
||||
const store = this.result.createObjectStore('kv-store', {
|
||||
keyPath: 'k'
|
||||
});
|
||||
|
||||
store.transaction.oncomplete = function () {
|
||||
resolve(this.db);
|
||||
};
|
||||
};
|
||||
});
|
||||
set(key: string, value: ArrayBuffer) {
|
||||
return this.#cache.set(key, value);
|
||||
}
|
||||
|
||||
async get(key: string) {
|
||||
await this.#createCache();
|
||||
switch (getRuntime()) {
|
||||
case 'deno':
|
||||
{
|
||||
const file = `${this.cache_dir}/${key}`;
|
||||
const Deno: any = Reflect.get(globalThis, 'Deno');
|
||||
try {
|
||||
const stat = await Deno.stat(file);
|
||||
if (stat.isFile) {
|
||||
const data: Uint8Array = await Deno.readFile(file);
|
||||
return data.buffer;
|
||||
}
|
||||
throw new Error('An unexpected file was found in place of the cache key');
|
||||
|
||||
} catch (e) {
|
||||
if (e instanceof Deno.errors.NotFound)
|
||||
return undefined;
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
case 'node':
|
||||
{
|
||||
const fs = Reflect.get(module, 'require')('fs/promises');
|
||||
const file = Reflect.get(module, 'require')('path').resolve(this.cache_dir, key);
|
||||
try {
|
||||
const stat = await fs.stat(file);
|
||||
if (stat.isFile()) {
|
||||
const data: Buffer = await fs.readFile(file);
|
||||
return data.buffer;
|
||||
}
|
||||
throw new Error('An unexpected file was found in place of the cache key');
|
||||
|
||||
} catch (e: any) {
|
||||
if (e?.code === 'ENOENT')
|
||||
return undefined;
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
case 'browser':
|
||||
{
|
||||
const db = await this.#getBrowserDB();
|
||||
if (!db) return;
|
||||
|
||||
return new Promise<ArrayBuffer | undefined>((resolve, reject) => {
|
||||
const request = db.transaction('kv-store', 'readonly').objectStore('kv-store').get(key);
|
||||
request.onerror = reject;
|
||||
request.onsuccess = function () {
|
||||
const result: Uint8Array | undefined = this.result?.v;
|
||||
resolve(result ? result.buffer : undefined);
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async set(key: string, value: ArrayBuffer) {
|
||||
await this.#createCache();
|
||||
switch (getRuntime()) {
|
||||
case 'deno':
|
||||
{
|
||||
const Deno: any = Reflect.get(globalThis, 'Deno');
|
||||
const file = `${this.cache_dir}/${key}`;
|
||||
await Deno.writeFile(file, new Uint8Array(value));
|
||||
}
|
||||
break;
|
||||
|
||||
case 'node':
|
||||
{
|
||||
const fs = Reflect.get(module, 'require')('fs/promises');
|
||||
const file = Reflect.get(module, 'require')('path').resolve(this.cache_dir, key);
|
||||
await fs.writeFile(file, new Uint8Array(value));
|
||||
}
|
||||
break;
|
||||
|
||||
case 'browser':
|
||||
{
|
||||
const db = await this.#getBrowserDB();
|
||||
if (!db) return;
|
||||
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
const request = db.transaction('kv-store', 'readwrite').objectStore('kv-store').put({ k: key, v: value });
|
||||
request.onerror = reject;
|
||||
request.onsuccess = () => resolve();
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
async remove(key: string) {
|
||||
await this.#createCache();
|
||||
switch (getRuntime()) {
|
||||
case 'deno':
|
||||
{
|
||||
const file = `${this.cache_dir}/${key}`;
|
||||
const Deno: any = Reflect.get(globalThis, 'Deno');
|
||||
try {
|
||||
await Deno.remove(file);
|
||||
} catch (e) {
|
||||
if (e instanceof Deno.errors.NotFound) return undefined;
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'node':
|
||||
{
|
||||
const fs = Reflect.get(module, 'require')('fs/promises');
|
||||
const file = Reflect.get(module, 'require')('path').resolve(this.cache_dir, key);
|
||||
try {
|
||||
await fs.unlink(file);
|
||||
} catch (e: any) {
|
||||
if (e?.code === 'ENOENT') return;
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'browser':
|
||||
{
|
||||
const db = await this.#getBrowserDB();
|
||||
if (!db) return;
|
||||
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
const request = db.transaction('kv-store', 'readwrite').objectStore('kv-store').delete(key);
|
||||
request.onerror = reject;
|
||||
request.onsuccess = () => resolve();
|
||||
});
|
||||
}
|
||||
}
|
||||
remove(key: string) {
|
||||
return this.#cache.remove(key);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user