Skip to content

Commit

Permalink
Application now downloads from reddit
Browse files Browse the repository at this point in the history
  • Loading branch information
lirannl committed May 26, 2021
1 parent 77f798c commit d345e8c
Show file tree
Hide file tree
Showing 8 changed files with 851 additions and 0 deletions.
23 changes: 23 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Deno: Run",
"request": "launch",
"type": "pwa-node",
"program": "main.ts",
"cwd": "${workspaceFolder}",
"runtimeExecutable": "deno",
"outputCapture": "std",
"runtimeArgs": [
"run",
"--inspect",
"--allow-all"
],
"attachSimplePort": 9229
}
]
}
4 changes: 4 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"deno.enable": true,
"deno.path": "C:\\Users\\Liran\\Downloads\\deno\\deno.exe"
}
84 changes: 84 additions & 0 deletions config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import * as path from 'https://deno.land/std/path/mod.ts';
import { safeParse } from "./utils.ts";

const { configFilePath, appFolder } = (() => {
const dataFolder = Deno.env.get("HOME")?.concat("/.config") || path.normalize(Deno.env.get("LOCALAPPDATA")!);
const appFolder = path.join(dataFolder, "reddwp");
const configFilePath = path.join(appFolder, "config.json");
return { configFilePath, appFolder };
})();

type stringStringMapping = { [variable: string]: string };

export const fileExists = (path: string) => {
try {
Deno.statSync(path);
return true;
}
catch (e) {
if (e.name != "NotFound") throw e;
return false;
}
}

if (!fileExists(appFolder))
// Appdata folder generation
await Deno.mkdir(appFolder, { recursive: true });

if (!fileExists(path.join(appFolder, "config.json"))) {
const defaults = {
targetFolder: path.join(appFolder, "Downloads"),
sources: ["r/wallpapers"],
interval: 20,
filterNsfw: true,
maxFolderSize: 500,
minimumSize: 1,
};
// Write defaults as config.json
await Deno.writeFile(path.join(appFolder, "config.json"), new TextEncoder().encode(
// Convert object to pretty string
JSON.stringify(defaults, null, 2)
));
}

const configFileVars: stringStringMapping = await (async () => {
const configFilePath = path.join(appFolder, "config.json");
const configFileString = new TextDecoder().decode(await Deno.readFile(configFilePath));
return JSON.parse(configFileString);
})();

interface appConfig {
readonly configFilePath: string;
readonly appFolder: string;
targetFolder: string;
interval /* Hours */: number;
sources: string[];
filterNsfw?: true;
maxFolderSize /* Megabytes */: number;
minimumSize? /* Megabytes */: number;
}

const config = new Proxy<appConfig>({ configFilePath, appFolder } as unknown as appConfig, {
// Either read from environment, or from config
get(target, variable: string) {
return Deno.env.get(variable) ?
safeParse(Deno.env.get(variable)!) || Deno.env.get(variable)
:
(target as any)[variable] || configFileVars[variable];
},
// Always write to config
set(target, variable: string, value) {
// readonlies
if (variable == "configFilePath" || variable == "appFolder") return false;

// Write new config to file
(target as any)[variable] = value;
Deno.writeFileSync(configFilePath, new TextEncoder().encode(
JSON.stringify(target, null, 2)
));

return true;
}
});

export default config;
47 changes: 47 additions & 0 deletions extensions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
enum AsyncMode {
Sequential, Parellel
}

declare global {
interface Array<T> {
asyncFind(predicate: (this: void, item: T, index: number, obj: T[]) => Promise<any>, mode?: AsyncMode): Promise<T | undefined>
}
}

Array.prototype.asyncFind = async function <T>(
predicate: (this: void, item: T, index: number, obj: T[]) => Promise<any>,
// asyncFind is sequential by default
mode = AsyncMode.Sequential) {
const arr = this as T[];
switch (mode) {
// Avoids flooding the system with requests - minimises resource load
case AsyncMode.Sequential:
{
let index = 0;
for (const item of arr) {
// Fire only the promise in question
if (await predicate(item, index, arr))
return item;
else index++;
}
}
break;

// Doesn't wait for each predicate to resolve - can be much faster
case AsyncMode.Parellel:
{
let index = 0;
// Fire off all promises immediately
const promises = arr.map(predicate);
// One by one, wait for each predicate to be determined
for await (const result of promises) {
// Stop as soon as one matches
if (result) return arr[index];
else index++;
}
}
break;
}
}

export { AsyncMode };
22 changes: 22 additions & 0 deletions main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { AsyncMode } from './extensions.ts';
import config, { fileExists } from './config.ts';
import * as path from 'https://deno.land/std/path/mod.ts';
import retriever from './retriever.ts';

// Create target folder if it doesn't exist already
if (!fileExists(config.targetFolder))
await Deno.mkdir(config.targetFolder, { recursive: true });

// Get downloads
async function getDownloaded(): Promise<(Deno.FileInfo & { name: string })[]> {
const downloaded: (Deno.FileInfo & { name: string })[] = [];
for (const { name, isDirectory } of Deno.readDirSync(config.targetFolder)) if (!isDirectory) {
const file = Deno.statSync(path.join(config.targetFolder, name));
downloaded.push({ ...file, name });
}
return downloaded;
};

export { AsyncMode, getDownloaded };

retriever();
Loading

0 comments on commit d345e8c

Please sign in to comment.