Add download limit bar on file viewer

This commit is contained in:
2022-12-24 11:37:02 +01:00
parent 5729bb81f6
commit 34ede38889
13 changed files with 196 additions and 142 deletions

View File

@@ -106,9 +106,9 @@
"dev": true "dev": true
}, },
"node_modules/@jridgewell/trace-mapping": { "node_modules/@jridgewell/trace-mapping": {
"version": "0.3.16", "version": "0.3.17",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.16.tgz", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz",
"integrity": "sha512-LCQ+NeThyJ4k1W2d+vIKdxuSt9R3pQSZ4P92m7EakaYuXcVWbHuT5bjNcqLd4Rdgi6xYWYDvBJZJLZSLanjDcA==", "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@jridgewell/resolve-uri": "3.1.0", "@jridgewell/resolve-uri": "3.1.0",
@@ -187,9 +187,9 @@
"dev": true "dev": true
}, },
"node_modules/@types/node": { "node_modules/@types/node": {
"version": "18.8.4", "version": "18.11.17",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.8.4.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.17.tgz",
"integrity": "sha512-WdlVphvfR/GJCLEMbNA8lJ0lhFNBj4SW3O+O5/cEGw9oYrv0al9zTwuQsq+myDUXgNx2jgBynoVgZ2MMJ6pbow==", "integrity": "sha512-HJSUJmni4BeDHhfzn6nF0sVmd1SMezP7/4F0Lq+aXzmp2xm9O7WXrUtHW/CHlYVtZUbByEvWidHqRtcJXGF2Ng==",
"dev": true "dev": true
}, },
"node_modules/@types/resolve": { "node_modules/@types/resolve": {
@@ -202,9 +202,9 @@
} }
}, },
"node_modules/acorn": { "node_modules/acorn": {
"version": "8.8.0", "version": "8.8.1",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz",
"integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==",
"dev": true, "dev": true,
"bin": { "bin": {
"acorn": "bin/acorn" "acorn": "bin/acorn"
@@ -226,9 +226,9 @@
} }
}, },
"node_modules/anymatch": { "node_modules/anymatch": {
"version": "3.1.2", "version": "3.1.3",
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
"integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"normalize-path": "^3.0.0", "normalize-path": "^3.0.0",
@@ -527,9 +527,9 @@
} }
}, },
"node_modules/is-core-module": { "node_modules/is-core-module": {
"version": "2.10.0", "version": "2.11.0",
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz",
"integrity": "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==", "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"has": "^1.0.3" "has": "^1.0.3"
@@ -816,6 +816,7 @@
"version": "7.0.2", "version": "7.0.2",
"resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz", "resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz",
"integrity": "sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==", "integrity": "sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==",
"deprecated": "This package has been deprecated and is no longer maintained. Please use @rollup/plugin-terser",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@babel/code-frame": "^7.10.4", "@babel/code-frame": "^7.10.4",
@@ -894,6 +895,7 @@
"version": "1.4.8", "version": "1.4.8",
"resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz",
"integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==",
"deprecated": "Please use @jridgewell/sourcemap-codec instead",
"dev": true "dev": true
}, },
"node_modules/supports-color": { "node_modules/supports-color": {
@@ -921,18 +923,18 @@
} }
}, },
"node_modules/svelte": { "node_modules/svelte": {
"version": "3.51.0", "version": "3.55.0",
"resolved": "https://registry.npmjs.org/svelte/-/svelte-3.51.0.tgz", "resolved": "https://registry.npmjs.org/svelte/-/svelte-3.55.0.tgz",
"integrity": "sha512-PBITYIrsNOuW+Dtds00gSY68raNZQn7i59Dg/fjgf6WwyawPKeBwle692coO7ILZqSO+UJe9899aDn9sMdeOHA==", "integrity": "sha512-uGu2FVMlOuey4JoKHKrpZFkoYyj0VLjJdz47zX5+gVK5odxHM40RVhar9/iK2YFRVxvfg9FkhfVlR0sjeIrOiA==",
"dev": true, "dev": true,
"engines": { "engines": {
"node": ">= 8" "node": ">= 8"
} }
}, },
"node_modules/terser": { "node_modules/terser": {
"version": "5.15.1", "version": "5.16.1",
"resolved": "https://registry.npmjs.org/terser/-/terser-5.15.1.tgz", "resolved": "https://registry.npmjs.org/terser/-/terser-5.16.1.tgz",
"integrity": "sha512-K1faMUvpm/FBxjBXud0LWVAGxmvoPbZbfTCYbSgaaYQaIXI3/TdI7a7ZGA73Zrou6Q8Zmz3oeUTsp/dj+ag2Xw==", "integrity": "sha512-xvQfyfA1ayT0qdK47zskQgRZeWLoOQ8JQ6mIgRGVNwZKdQMU+5FkCBjmv4QjcrTzyZquRw2FVtlJSRUmMKQslw==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@jridgewell/source-map": "^0.3.2", "@jridgewell/source-map": "^0.3.2",
@@ -1054,9 +1056,9 @@
"dev": true "dev": true
}, },
"@jridgewell/trace-mapping": { "@jridgewell/trace-mapping": {
"version": "0.3.16", "version": "0.3.17",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.16.tgz", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz",
"integrity": "sha512-LCQ+NeThyJ4k1W2d+vIKdxuSt9R3pQSZ4P92m7EakaYuXcVWbHuT5bjNcqLd4Rdgi6xYWYDvBJZJLZSLanjDcA==", "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==",
"dev": true, "dev": true,
"requires": { "requires": {
"@jridgewell/resolve-uri": "3.1.0", "@jridgewell/resolve-uri": "3.1.0",
@@ -1117,9 +1119,9 @@
"dev": true "dev": true
}, },
"@types/node": { "@types/node": {
"version": "18.8.4", "version": "18.11.17",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.8.4.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.17.tgz",
"integrity": "sha512-WdlVphvfR/GJCLEMbNA8lJ0lhFNBj4SW3O+O5/cEGw9oYrv0al9zTwuQsq+myDUXgNx2jgBynoVgZ2MMJ6pbow==", "integrity": "sha512-HJSUJmni4BeDHhfzn6nF0sVmd1SMezP7/4F0Lq+aXzmp2xm9O7WXrUtHW/CHlYVtZUbByEvWidHqRtcJXGF2Ng==",
"dev": true "dev": true
}, },
"@types/resolve": { "@types/resolve": {
@@ -1132,9 +1134,9 @@
} }
}, },
"acorn": { "acorn": {
"version": "8.8.0", "version": "8.8.1",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz",
"integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==",
"dev": true "dev": true
}, },
"ansi-styles": { "ansi-styles": {
@@ -1147,9 +1149,9 @@
} }
}, },
"anymatch": { "anymatch": {
"version": "3.1.2", "version": "3.1.3",
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
"integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
"dev": true, "dev": true,
"requires": { "requires": {
"normalize-path": "^3.0.0", "normalize-path": "^3.0.0",
@@ -1385,9 +1387,9 @@
} }
}, },
"is-core-module": { "is-core-module": {
"version": "2.10.0", "version": "2.11.0",
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz",
"integrity": "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==", "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==",
"dev": true, "dev": true,
"requires": { "requires": {
"has": "^1.0.3" "has": "^1.0.3"
@@ -1690,15 +1692,15 @@
"dev": true "dev": true
}, },
"svelte": { "svelte": {
"version": "3.51.0", "version": "3.55.0",
"resolved": "https://registry.npmjs.org/svelte/-/svelte-3.51.0.tgz", "resolved": "https://registry.npmjs.org/svelte/-/svelte-3.55.0.tgz",
"integrity": "sha512-PBITYIrsNOuW+Dtds00gSY68raNZQn7i59Dg/fjgf6WwyawPKeBwle692coO7ILZqSO+UJe9899aDn9sMdeOHA==", "integrity": "sha512-uGu2FVMlOuey4JoKHKrpZFkoYyj0VLjJdz47zX5+gVK5odxHM40RVhar9/iK2YFRVxvfg9FkhfVlR0sjeIrOiA==",
"dev": true "dev": true
}, },
"terser": { "terser": {
"version": "5.15.1", "version": "5.16.1",
"resolved": "https://registry.npmjs.org/terser/-/terser-5.15.1.tgz", "resolved": "https://registry.npmjs.org/terser/-/terser-5.16.1.tgz",
"integrity": "sha512-K1faMUvpm/FBxjBXud0LWVAGxmvoPbZbfTCYbSgaaYQaIXI3/TdI7a7ZGA73Zrou6Q8Zmz3oeUTsp/dj+ag2Xw==", "integrity": "sha512-xvQfyfA1ayT0qdK47zskQgRZeWLoOQ8JQ6mIgRGVNwZKdQMU+5FkCBjmv4QjcrTzyZquRw2FVtlJSRUmMKQslw==",
"dev": true, "dev": true,
"requires": { "requires": {
"@jridgewell/source-map": "^0.3.2", "@jridgewell/source-map": "^0.3.2",

View File

@@ -0,0 +1,62 @@
import { readable } from 'svelte/store';
let limits = {
download_limit: 0,
download_limit_used: 0,
transfer_limit: 0,
transfer_limit_used: 0,
ipv6_bonus: 0,
loaded: false,
}
export const download_limits = readable(
limits,
function start(set) {
set_func = set;
loop();
return function stop() {
clearTimeout(timeout_ref);
};
}
);
let set_func;
let timeout_ref = 0;
let timeout_ms = 10000;
const loop = async () => {
let new_limits;
try {
let resp = await fetch(window.api_endpoint + "/misc/rate_limits")
if (resp.status >= 400) {
throw new Error(await resp.text())
}
new_limits = await resp.json()
new_limits.loaded = true
} catch (err) {
console.error("Failed to get rate limits: " + err)
timeout_ref = setTimeout(loop, 30000)
return
}
// If the usage has not changed we increase the timeout with one second. If
// it did change we halve the timeout
if (new_limits.transfer_limit_used === limits.transfer_limit_used) {
timeout_ms += 1000
if (timeout_ms > 60000) {
timeout_ms = 60000
}
} else {
timeout_ms /= 2
if (timeout_ms < 5000) {
timeout_ms = 5000
}
limits = new_limits
set_func(new_limits)
}
console.debug("Sleep", timeout_ms / 1000, "seconds")
timeout_ref = setTimeout(loop, timeout_ms)
}

View File

@@ -20,6 +20,7 @@ import GalleryView from "./GalleryView.svelte";
import Downloader from "./Downloader.svelte"; import Downloader from "./Downloader.svelte";
import CustomBanner from "./CustomBanner.svelte"; import CustomBanner from "./CustomBanner.svelte";
import LoadingIndicator from "../util/LoadingIndicator.svelte"; import LoadingIndicator from "../util/LoadingIndicator.svelte";
import TransferLimit from "./TransferLimit.svelte";
let loading = true let loading = true
let embedded = false let embedded = false
@@ -389,7 +390,7 @@ const keyboard_event = evt => {
{#if file.name !== ""}{file.name}{/if} {#if file.name !== ""}{file.name}{/if}
</div> </div>
{#if embedded} {#if embedded}
<a href={window.location.pathname} target="_blank" class="button round" title="Open this page in a new tab"> <a href={window.location.pathname} target="_blank" class="button round" title="Open this page in a new tab" rel="noreferrer">
<i class="icon" id="btn_fullscreen_icon">open_in_new</i> <i class="icon" id="btn_fullscreen_icon">open_in_new</i>
</a> </a>
{/if} {/if}
@@ -581,6 +582,8 @@ const keyboard_event = evt => {
<CustomBanner src={custom_footer} link={custom_footer_link}></CustomBanner> <CustomBanner src={custom_footer} link={custom_footer_link}></CustomBanner>
{/if} {/if}
<TransferLimit/>
<Modal bind:this={details_window} on:is_visible={e => {details_visible = e.detail}} title="File details" width="1000px"> <Modal bind:this={details_window} on:is_visible={e => {details_visible = e.detail}} title="File details" width="1000px">
<DetailsWindow file={file}></DetailsWindow> <DetailsWindow file={file}></DetailsWindow>
</Modal> </Modal>

View File

@@ -70,7 +70,7 @@ const add_files = async files => {
} }
const delete_file = async index => { const delete_file = async index => {
const list_files = list.files let list_files = list.files
list_files.splice(index, 1) list_files.splice(index, 1)
await update_list(list_files) await update_list(list_files)
list.files = list_files list.files = list_files
@@ -80,7 +80,7 @@ const move_left = async index => {
if (index === 0) { if (index === 0) {
return; return;
} }
const f = list.files; let f = list.files;
[f[index], f[index-1]] = [f[index-1], f[index]]; [f[index], f[index-1]] = [f[index-1], f[index]];
await update_list(f) await update_list(f)
list.files = f list.files = f
@@ -89,7 +89,7 @@ const move_right = async index => {
if (index >= list.files.length-1) { if (index >= list.files.length-1) {
return; return;
} }
const f = list.files; let f = list.files;
[f[index], f[index+1]] = [f[index+1], f[index]]; [f[index], f[index+1]] = [f[index+1], f[index]];
await update_list(f) await update_list(f)
list.files = f list.files = f

View File

@@ -0,0 +1,45 @@
<script>
import { formatDataVolume } from "../util/Formatting.svelte";
import { download_limits } from "./DownloadLimitStore.js"
let percent = 0
let title = ""
$: {
if ($download_limits.transfer_limit === 0) {
percent = 0 // Avoid division by 0
}else if ($download_limits.transfer_limit_used / $download_limits.transfer_limit > 1) {
percent = 100
} else {
percent = ($download_limits.transfer_limit_used / $download_limits.transfer_limit) * 100
}
title = "Transfer limit used: " +
formatDataVolume($download_limits.transfer_limit_used, 3) +
" of " +
formatDataVolume($download_limits.transfer_limit, 3);
}
</script>
{#if $download_limits.loaded}
<div class="progress_bar_outer" title="{title}">
<div class="progress_bar_inner" style="width: {percent}%;">
</div>
</div>
{/if}
<style>
.progress_bar_outer {
display: block;
width: 100%;
height: 6px;
overflow: hidden;
}
.progress_bar_inner {
background: var(--highlight_background);
height: 100%;
width: 0;
border-top-right-radius: 6px;
border-bottom-right-radius: 6px;
transition: width 5s linear;
}
</style>

View File

@@ -1,50 +1,17 @@
<script> <script>
import { createEventDispatcher, onMount } from "svelte";
import { formatDataVolume } from "../../util/Formatting.svelte"; import { formatDataVolume } from "../../util/Formatting.svelte";
import TextBlock from "./TextBlock.svelte"; import TextBlock from "./TextBlock.svelte";
import ProgressBar from "../../util/ProgressBar.svelte"; import ProgressBar from "../../util/ProgressBar.svelte";
import { download_limits } from "../DownloadLimitStore";
let dispatch = createEventDispatcher()
export let file = { export let file = {
size: 0, size: 0,
} }
let loaded = false $: transfer_left = download_limits.transfer_limit = download_limits.transfer_limit_used
let limits = {
download_limit: 0,
download_limit_used: 0,
transfer_limit: 0,
transfer_limit_used: 0,
}
let transfer_left = 0
const update = async () => {
try {
let resp = await fetch(window.api_endpoint+"/misc/rate_limits")
if(resp.status >= 400) {
throw new Error(await resp.text())
}
limits = await resp.json()
transfer_left = limits.transfer_limit - limits.transfer_limit_used
loaded = true
if (limits.transfer_limit_used > limits.transfer_limit) {
dispatch("reload")
}
} catch (err) {
console.error("Failed to get rate limits: "+err)
}
}
onMount(() => {
update()
let interval = setInterval(update, 30e3)
return () => clearInterval(interval)
})
</script> </script>
{#if loaded} {#if $download_limits.loaded}
<TextBlock width="700px" center={true}> <TextBlock width="700px" center={true}>
{#if file.size > transfer_left} {#if file.size > transfer_left}
<div class="highlight_yellow"> <div class="highlight_yellow">
@@ -57,21 +24,21 @@ onMount(() => {
{/if} {/if}
<p> <p>
You have used {formatDataVolume(limits.transfer_limit_used, 3)} of You have used {formatDataVolume($download_limits.transfer_limit_used, 3)} of
your weekly {formatDataVolume(limits.transfer_limit, 3)} transfer your weekly {formatDataVolume($download_limits.transfer_limit, 3)} transfer
limit. When the transfer limit is exceeded your download speed will limit. When the transfer limit is exceeded your download speed will
be reduced. be reduced.
</p> </p>
<p> <p>
<strong> <strong>
<a href="https://www.patreon.com/join/pixeldrain" target="_blank" class="button button_highlight"> <a href="https://www.patreon.com/join/pixeldrain" target="_blank" class="button button_highlight" rel="noreferrer">
<i class="icon">bolt</i> Support Pixeldrain on Patreon <i class="icon">bolt</i> Support Pixeldrain on Patreon
</a> </a>
to disable the transfer limit to disable the transfer limit
</strong> </strong>
</p> </p>
<ProgressBar total={limits.transfer_limit} used={limits.transfer_limit_used}></ProgressBar> <ProgressBar total={$download_limits.transfer_limit} used={$download_limits.transfer_limit_used}></ProgressBar>
</TextBlock> </TextBlock>
{/if} {/if}

View File

@@ -18,7 +18,7 @@ let file = {
<h1>{file.name}</h1> <h1>{file.name}</h1>
<img src={file.icon_href} alt="File icon" class="icon"> <img src={file.icon_href} alt="File icon" class="icon">
<TextBlock> <TextBlock width="600px">
Type: {file.mime_type}<br/> Type: {file.mime_type}<br/>
No preview is available for this file type. Download to view it locally. No preview is available for this file type. Download to view it locally.
<br/> <br/>

View File

@@ -12,10 +12,12 @@ import { file_type } from "../FileUtilities.svelte";
import RateLimit from "./RateLimit.svelte"; import RateLimit from "./RateLimit.svelte";
import Torrent from "./Torrent.svelte"; import Torrent from "./Torrent.svelte";
import SpeedLimit from "./SpeedLimit.svelte"; import SpeedLimit from "./SpeedLimit.svelte";
import { download_limits } from "../DownloadLimitStore";
let viewer let viewer
let viewer_type = "loading" let viewer_type = "loading"
export let is_list = false export let is_list = false
let current_file
export const set_file = async file => { export const set_file = async file => {
if (file.id === "") { if (file.id === "") {
@@ -35,14 +37,19 @@ export const set_file = async file => {
} }
console.log("opening file", file) console.log("opening file", file)
current_file = file
// Render the viewer component and set the file type // Render the viewer component and set the file type
await tick() await tick()
if (viewer) {
viewer.set_file(file) viewer.set_file(file)
} }
}
</script> </script>
{#if viewer_type === "loading"} {#if $download_limits.transfer_limit_used > $download_limits.transfer_limit}
<SpeedLimit file={current_file} on:download></SpeedLimit>
{:else if viewer_type === "loading"}
<div class="center"> <div class="center">
<Spinner></Spinner> <Spinner></Spinner>
</div> </div>
@@ -50,8 +57,6 @@ export const set_file = async file => {
<Abuse bind:this={viewer}></Abuse> <Abuse bind:this={viewer}></Abuse>
{:else if viewer_type === "rate_limit"} {:else if viewer_type === "rate_limit"}
<RateLimit bind:this={viewer} on:download></RateLimit> <RateLimit bind:this={viewer} on:download></RateLimit>
{:else if viewer_type === "speed_limit"}
<SpeedLimit bind:this={viewer} on:download></SpeedLimit>
{:else if viewer_type === "image"} {:else if viewer_type === "image"}
<Image bind:this={viewer} on:loading></Image> <Image bind:this={viewer} on:loading></Image>
{:else if viewer_type === "video"} {:else if viewer_type === "video"}

View File

@@ -1,6 +1,7 @@
<script> <script>
import { createEventDispatcher, onMount } from "svelte"; import { createEventDispatcher, onMount } from "svelte";
import { formatDataVolume } from "../../util/Formatting.svelte"; import { formatDataVolume } from "../../util/Formatting.svelte";
import { download_limits } from "../DownloadLimitStore";
import TextBlock from "./TextBlock.svelte"; import TextBlock from "./TextBlock.svelte";
let dispatch = createEventDispatcher() let dispatch = createEventDispatcher()
@@ -10,24 +11,6 @@ let file = {
mime_type: "", mime_type: "",
availability: "", availability: "",
} }
let limits = {
download_limit: 1000,
download_limit_used: 0,
transfer_limit: 50e9,
transfer_limit_used: 0,
}
onMount(async () => {
try {
let resp = await fetch(window.api_endpoint+"/misc/rate_limits")
if(resp.status >= 400) {
throw new Error(await resp.text())
}
limits = await resp.json()
} catch (err) {
alert("Failed to get rate limits: "+err)
}
})
</script> </script>
<br/> <br/>
@@ -53,15 +36,15 @@ onMount(async () => {
</h1> </h1>
<p> <p>
You have reached your download limit for today. Without a pixeldrain You have reached your download limit for today. Without a pixeldrain
account you are limited to downloading {limits.download_limit} files account you are limited to downloading {$download_limits.download_limit} files
or {formatDataVolume(limits.transfer_limit, 3)} per 48 hours. This limit or {formatDataVolume($download_limits.transfer_limit, 3)} per 48 hours. This limit
is counted per IP address, so if you're on a shared network it's is counted per IP address, so if you're on a shared network it's
possible that others have also contributed to this limit. possible that others have also contributed to this limit.
</p> </p>
<p> <p>
In the last 24 hours you have downloaded In the last 24 hours you have downloaded
{limits.download_limit_used} files and used {$download_limits.download_limit_used} files and used
{formatDataVolume(limits.transfer_limit_used, 3)} bandwidth. {formatDataVolume($download_limits.transfer_limit_used, 3)} bandwidth.
</p> </p>
{/if} {/if}
<p> <p>
@@ -89,7 +72,7 @@ onMount(async () => {
<button on:click={() => {dispatch("download")}}> <button on:click={() => {dispatch("download")}}>
<i class="icon">download</i> Download <i class="icon">download</i> Download
</button> </button>
<a href="https://www.patreon.com/join/pixeldrain" target="_blank" class="button button_highlight"> <a href="https://www.patreon.com/join/pixeldrain" target="_blank" class="button button_highlight" rel="noreferrer">
<i class="icon">bolt</i> Support Pixeldrain on Patreon <i class="icon">bolt</i> Support Pixeldrain on Patreon
</a> </a>
</div> </div>

View File

@@ -1,33 +1,17 @@
<script> <script>
import { createEventDispatcher, onMount } from "svelte"; import { createEventDispatcher, onMount } from "svelte";
import { formatDataVolume, formatDuration } from "../../util/Formatting.svelte"; import { formatDataVolume, formatDuration } from "../../util/Formatting.svelte";
import { download_limits } from "../DownloadLimitStore";
import TextBlock from "./TextBlock.svelte"; import TextBlock from "./TextBlock.svelte";
let dispatch = createEventDispatcher() let dispatch = createEventDispatcher()
export const set_file = f => file = f export let file = {
let file = {
name: "", name: "",
mime_type: "", mime_type: "",
availability: "", availability: "",
size: 0,
download_speed_limit: 0,
} }
let limits = {
download_limit: 1000,
download_limit_used: 0,
transfer_limit: 10e9,
transfer_limit_used: 0,
}
onMount(async () => {
try {
let resp = await fetch(window.api_endpoint+"/misc/rate_limits")
if(resp.status >= 400) {
throw new Error(await resp.text())
}
limits = await resp.json()
} catch (err) {
alert("Failed to get rate limits: "+err)
}
})
</script> </script>
<br/> <br/>
@@ -36,10 +20,10 @@ onMount(async () => {
<p> <p>
Pixeldrain's free tier is supported by advertisements. There's only so Pixeldrain's free tier is supported by advertisements. There's only so
much that you can do with the budget those ads provide (spoiler: it's much that you can do with the budget those ads provide (spoiler: it's
not a lot). {formatDataVolume(limits.transfer_limit, 3)} per week is not a lot). {formatDataVolume($download_limits.transfer_limit, 3)} per week is
about the most I can give away for free, and according to our records about the most I can give away for free, and according to our records
you have already downloaded you have already downloaded
{formatDataVolume(limits.transfer_limit_used, 3)}. {formatDataVolume($download_limits.transfer_limit_used, 3)}.
</p> </p>
<p> <p>
It's not that I want to withold this file from you, it's just that I It's not that I want to withold this file from you, it's just that I
@@ -57,7 +41,7 @@ onMount(async () => {
{formatDuration((file.size/file.download_speed_limit)*1000)} {formatDuration((file.size/file.download_speed_limit)*1000)}
</li> </li>
<li> <li>
<a href="https://www.patreon.com/join/pixeldrain" target="_blank" class="button button_highlight"> <a href="https://www.patreon.com/join/pixeldrain" target="_blank" class="button button_highlight" rel="noreferrer">
<i class="icon">bolt</i> Support Pixeldrain on Patreon <i class="icon">bolt</i> Support Pixeldrain on Patreon
</a> </a>
and earn my eternal gratitude and earn my eternal gratitude

View File

@@ -155,7 +155,7 @@ const fullscreen = () => {
{:else} {:else}
<h1>{file.name}</h1> <h1>{file.name}</h1>
<img src={file.icon_href} class="video_icon" alt="Video icon"> <img src={file.icon_href} class="video_icon" alt="Video icon">
<TextBlock width="650px"> <TextBlock width="600px">
The online video player on pixeldrain is only available for registered The online video player on pixeldrain is only available for registered
users, or when the uploader of the video has a Pro account. You can users, or when the uploader of the video has a Pro account. You can
still download the video and watch it locally on your computer without still download the video and watch it locally on your computer without
@@ -167,7 +167,7 @@ const fullscreen = () => {
<a href="/register" class="button"> <a href="/register" class="button">
<i class="icon">how_to_reg</i> Sign up <i class="icon">how_to_reg</i> Sign up
</a> </a>
<a href="https://www.patreon.com/join/pixeldrain" target="_blank" class="button button_highlight"> <a href="https://www.patreon.com/join/pixeldrain" target="_blank" class="button button_highlight" rel="noreferrer">
<i class="icon">bolt</i> Get Pixeldrain Pro <i class="icon">bolt</i> Get Pixeldrain Pro
</a> </a>
</TextBlock> </TextBlock>

View File

@@ -47,9 +47,9 @@ const keydown = e => {
<svelte:window on:keydown={keydown}/> <svelte:window on:keydown={keydown}/>
{#if visible} {#if visible}
<div class="background" use:load_bg on:click={hide} transition:fade={{duration: 200}}> <div class="background" use:load_bg on:click={hide} transition:fade={{duration: 200}} on:keydown={keydown}>
<div class="top_padding"></div> <div class="top_padding"></div>
<div class="window" use:load_modal on:click|stopPropagation role="dialog" aria-modal="true"> <div class="window" use:load_modal on:click|stopPropagation role="dialog" aria-modal="true" on:keydown={keydown}>
<div class="header"> <div class="header">
<slot name="title"> <slot name="title">
<div class="title">{title}</div> <div class="title">{title}</div>

View File

@@ -20,7 +20,10 @@ $: {
</script> </script>
<div class="progress_bar_outer"> <div class="progress_bar_outer">
<div class="progress_bar_inner" style="width: {percent}%; transition-timing-function: {animation}; transition-duration: {speed}ms;"></div> <div
class="progress_bar_inner"
style="width: {percent}%; transition-timing-function: {animation}; transition-duration: {speed}ms;">
</div>
</div> </div>
<style> <style>