Add free transfer limit to filesystem
This commit is contained in:
7
svelte/package-lock.json
generated
7
svelte/package-lock.json
generated
@@ -11,6 +11,7 @@
|
||||
"behave-js": "^1.5.0",
|
||||
"chart.js": "^4.2.0",
|
||||
"pure-color": "^1.3.0",
|
||||
"rollup-plugin-includepaths": "^0.2.4",
|
||||
"svelte-preprocess": "^6.0.2",
|
||||
"tslib": "^2.7.0"
|
||||
},
|
||||
@@ -3460,6 +3461,12 @@
|
||||
"fsevents": "~2.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/rollup-plugin-includepaths": {
|
||||
"version": "0.2.4",
|
||||
"resolved": "https://registry.npmjs.org/rollup-plugin-includepaths/-/rollup-plugin-includepaths-0.2.4.tgz",
|
||||
"integrity": "sha512-iZen+XKVExeCzk7jeSZPJKL7B67slZNr8GXSC5ROBXtDGXDBH8wdjMfdNW5hf9kPt+tHyIvWh3wlE9bPrZL24g==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/rollup-plugin-livereload": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/rollup-plugin-livereload/-/rollup-plugin-livereload-2.0.5.tgz",
|
||||
|
@@ -24,6 +24,7 @@
|
||||
"behave-js": "^1.5.0",
|
||||
"chart.js": "^4.2.0",
|
||||
"pure-color": "^1.3.0",
|
||||
"rollup-plugin-includepaths": "^0.2.4",
|
||||
"svelte-preprocess": "^6.0.2",
|
||||
"tslib": "^2.7.0"
|
||||
}
|
||||
|
@@ -5,6 +5,7 @@ import livereload from 'rollup-plugin-livereload';
|
||||
import terser from '@rollup/plugin-terser';
|
||||
import babel from '@rollup/plugin-babel'
|
||||
import typescript from '@rollup/plugin-typescript'
|
||||
import includePaths from 'rollup-plugin-includepaths';
|
||||
import { sveltePreprocess } from 'svelte-preprocess';
|
||||
|
||||
const production = !process.env.ROLLUP_WATCH;
|
||||
@@ -39,7 +40,7 @@ export default [
|
||||
}),
|
||||
|
||||
babel({
|
||||
extensions: [".js", ".html", ".svelte"],
|
||||
extensions: [".js", ".ts", ".html", ".svelte"],
|
||||
babelHelpers: "bundled",
|
||||
}),
|
||||
|
||||
@@ -59,6 +60,9 @@ export default [
|
||||
compilerOptions: { lib: ["es2015", "dom"] },
|
||||
verbatimModuleSyntax: true,
|
||||
}),
|
||||
includePaths({
|
||||
paths: ["."],
|
||||
}),
|
||||
|
||||
// In dev mode, call `npm run start` once
|
||||
// the bundle has been generated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
<script>
|
||||
import { formatDataVolume, formatThousands } from "../util/Formatting.svelte"
|
||||
import { set_file, stats } from "./StatsSocket"
|
||||
import { set_file, stats } from "src/util/StatsSocket"
|
||||
|
||||
export let file = {
|
||||
id: "",
|
||||
|
@@ -1,6 +1,6 @@
|
||||
<script>
|
||||
import { formatDataVolume } from "../util/Formatting.svelte";
|
||||
import { stats } from "./StatsSocket.js"
|
||||
import { stats } from "src/util/StatsSocket.js"
|
||||
|
||||
let percent = 0
|
||||
let title = ""
|
||||
|
@@ -1,8 +1,8 @@
|
||||
<script>
|
||||
import { createEventDispatcher } from "svelte";
|
||||
import IconBlock from "./IconBlock.svelte"
|
||||
import TextBlock from "./TextBlock.svelte"
|
||||
import FileTitle from "./FileTitle.svelte";
|
||||
import IconBlock from "src/layout/IconBlock.svelte";
|
||||
import TextBlock from "src/layout/TextBlock.svelte"
|
||||
import FileTitle from "src/layout/FileTitle.svelte";
|
||||
|
||||
let dispatch = createEventDispatcher()
|
||||
|
||||
|
@@ -1,7 +1,7 @@
|
||||
<script>
|
||||
import { createEventDispatcher, tick } from "svelte";
|
||||
import BandwidthUsage from "./BandwidthUsage.svelte";
|
||||
import FileTitle from "./FileTitle.svelte";
|
||||
import FileTitle from "src/layout/FileTitle.svelte";
|
||||
let dispatch = createEventDispatcher()
|
||||
|
||||
export let is_list = false
|
||||
|
@@ -1,8 +1,8 @@
|
||||
<script>
|
||||
import { formatDataVolume } from "../../util/Formatting.svelte";
|
||||
import TextBlock from "./TextBlock.svelte";
|
||||
import TextBlock from "src/layout/TextBlock.svelte"
|
||||
import ProgressBar from "../../util/ProgressBar.svelte";
|
||||
import { stats } from "../StatsSocket"
|
||||
import { stats } from "src/util/StatsSocket.js"
|
||||
|
||||
export let file = {
|
||||
size: 0,
|
||||
|
@@ -1,8 +1,8 @@
|
||||
<script>
|
||||
import { createEventDispatcher } from "svelte";
|
||||
import BandwidthUsage from "./BandwidthUsage.svelte";
|
||||
import IconBlock from "./IconBlock.svelte";
|
||||
import FileTitle from "./FileTitle.svelte";
|
||||
import IconBlock from "src/layout/IconBlock.svelte";
|
||||
import FileTitle from "src/layout/FileTitle.svelte";
|
||||
import { formatDataVolume } from "../../util/Formatting.svelte";
|
||||
let dispatch = createEventDispatcher()
|
||||
|
||||
|
@@ -11,9 +11,9 @@ import Abuse from "./Abuse.svelte";
|
||||
import { file_type } from "../FileUtilities.svelte";
|
||||
import RateLimit from "./RateLimit.svelte";
|
||||
import Torrent from "./Torrent.svelte";
|
||||
import SpeedLimit from "./SpeedLimit.svelte";
|
||||
import { stats } from "../StatsSocket";
|
||||
import { stats } from "src/util/StatsSocket.js"
|
||||
import Zip from "./Zip.svelte";
|
||||
import SlowDown from "src/layout/SlowDown.svelte";
|
||||
|
||||
let viewer
|
||||
let viewer_type = "loading"
|
||||
@@ -66,7 +66,13 @@ export const seek = delta => {
|
||||
{:else if viewer_type === "abuse"}
|
||||
<Abuse bind:this={viewer} on:download></Abuse>
|
||||
{:else if !premium_download && $stats.limits.transfer_limit_used > $stats.limits.transfer_limit}
|
||||
<SpeedLimit file={current_file} on:download></SpeedLimit>
|
||||
<SlowDown
|
||||
on:download
|
||||
file_size={current_file.size}
|
||||
file_name={current_file.name}
|
||||
file_type={current_file.mime_type}
|
||||
icon_href={current_file.icon_href}
|
||||
/>
|
||||
{:else if viewer_type === "rate_limit"}
|
||||
<RateLimit bind:this={viewer} on:download></RateLimit>
|
||||
{:else if viewer_type === "image"}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
<script>
|
||||
import { createEventDispatcher } from "svelte"
|
||||
import { swipe_nav } from "./SwipeNavigate";
|
||||
import { swipe_nav } from "src/util/SwipeNavigate.ts";
|
||||
let dispatch = createEventDispatcher()
|
||||
|
||||
export const set_file = f => {
|
||||
|
@@ -1,9 +1,9 @@
|
||||
<script>
|
||||
import { createEventDispatcher } from "svelte";
|
||||
import { formatDataVolume } from "../../util/Formatting.svelte";
|
||||
import { stats } from "../StatsSocket";
|
||||
import IconBlock from "./IconBlock.svelte";
|
||||
import TextBlock from "./TextBlock.svelte";
|
||||
import { stats } from "src/util/StatsSocket.js"
|
||||
import IconBlock from "src/layout/IconBlock.svelte";
|
||||
import TextBlock from "src/layout/TextBlock.svelte"
|
||||
let dispatch = createEventDispatcher()
|
||||
|
||||
export const set_file = f => file = f
|
||||
|
@@ -1,12 +1,12 @@
|
||||
<script>
|
||||
import { createEventDispatcher } from "svelte";
|
||||
import Magnet from "../../icons/Magnet.svelte";
|
||||
import { formatDate } from "../../util/Formatting.svelte"
|
||||
import IconBlock from "./IconBlock.svelte";
|
||||
import TextBlock from "./TextBlock.svelte";
|
||||
import Magnet from "src/icons/Magnet.svelte";
|
||||
import { formatDate } from "src/util/Formatting.svelte"
|
||||
import IconBlock from "src/layout/IconBlock.svelte";
|
||||
import TextBlock from "src/layout/TextBlock.svelte";
|
||||
import TorrentItem from "./TorrentItem.svelte"
|
||||
import FileTitle from "./FileTitle.svelte";
|
||||
import CopyButton from "../../layout/CopyButton.svelte";
|
||||
import FileTitle from "src/layout/FileTitle.svelte";
|
||||
import CopyButton from "src/layout/CopyButton.svelte";
|
||||
|
||||
let dispatch = createEventDispatcher()
|
||||
|
||||
|
@@ -1,7 +1,7 @@
|
||||
<script>
|
||||
import { onMount, createEventDispatcher, tick } from "svelte";
|
||||
import BandwidthUsage from "./BandwidthUsage.svelte";
|
||||
import IconBlock from "./IconBlock.svelte";
|
||||
import IconBlock from "src/layout/IconBlock.svelte";
|
||||
let dispatch = createEventDispatcher()
|
||||
|
||||
export let is_list = false
|
||||
|
@@ -1,11 +1,11 @@
|
||||
<script>
|
||||
import { createEventDispatcher } from "svelte";
|
||||
import { formatDataVolume, formatDate } from "../../util/Formatting.svelte"
|
||||
import IconBlock from "./IconBlock.svelte";
|
||||
import TextBlock from "./TextBlock.svelte";
|
||||
import IconBlock from "src/layout/IconBlock.svelte";
|
||||
import TextBlock from "src/layout/TextBlock.svelte"
|
||||
import ZipItem from "./ZipItem.svelte";
|
||||
import BandwidthUsage from "./BandwidthUsage.svelte";
|
||||
import FileTitle from "./FileTitle.svelte";
|
||||
import FileTitle from "src/layout/FileTitle.svelte";
|
||||
|
||||
let dispatch = createEventDispatcher()
|
||||
|
||||
|
@@ -1,5 +1,6 @@
|
||||
import { fs_get_node, fs_encode_path, fs_split_path, type FSNode, type FSPath, type FSPermissions } from "./FilesystemAPI";
|
||||
import { type Writable } from "svelte/store"
|
||||
import { fs_get_node, fs_encode_path, fs_split_path } from "./FilesystemAPI";
|
||||
import type { FSNode, FSPath, FSPermissions, FSContext } from "./FilesystemAPI";
|
||||
import type { Writable } from "svelte/store"
|
||||
|
||||
export class FSNavigator {
|
||||
// Parts of the raw API response
|
||||
@@ -7,6 +8,7 @@ export class FSNavigator {
|
||||
base_index: number = 0
|
||||
children: Array<FSNode> = []
|
||||
permissions: FSPermissions = <FSPermissions>{}
|
||||
context: FSContext = <FSContext>{}
|
||||
|
||||
// base equals path[base_index]. It's updated every time the path updates
|
||||
base: FSNode = <FSNode>{}
|
||||
@@ -128,6 +130,7 @@ export class FSNavigator {
|
||||
this.base = node.path[node.base_index]
|
||||
this.children = node.children
|
||||
this.permissions = node.permissions
|
||||
this.context = node.context
|
||||
this.initialized = true
|
||||
|
||||
console.debug("Opened node", node)
|
||||
|
@@ -13,6 +13,8 @@ import { branding_from_path } from './edit_window/Branding.js'
|
||||
import Menu from './Menu.svelte';
|
||||
import { FSNavigator } from "./FSNavigator"
|
||||
import { writable } from 'svelte/store';
|
||||
import TransferLimit from '../file_viewer/TransferLimit.svelte';
|
||||
import { stats } from "src/util/StatsSocket.js"
|
||||
|
||||
let file_viewer
|
||||
let file_preview
|
||||
@@ -178,6 +180,21 @@ const search = async () => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{#if $nav.context.premium_transfer === false}
|
||||
<div class="download_limit">
|
||||
{#if $stats.limits.transfer_limit_used > $stats.limits.transfer_limit}
|
||||
<div class="highlight_yellow">
|
||||
Your free download limit has been used up and your download
|
||||
speed has been limited to 1 MiB/s. <a href="/#pro"
|
||||
target="_blank">Upgrade to premium</a> to continue fast
|
||||
downloading
|
||||
</div>
|
||||
{:else}
|
||||
<TransferLimit/>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<!-- This frame will load the download URL when a download button is pressed -->
|
||||
<iframe
|
||||
bind:this={download_frame}
|
||||
@@ -244,6 +261,15 @@ const search = async () => {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* Download limit gauge (row 3) */
|
||||
.download_limit {
|
||||
flex: 0 0 auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
background-color: var(--shaded_background);
|
||||
}
|
||||
|
||||
/* This max-width needs to be synced with the .toolbar max-width in
|
||||
Toolbar.svelte and the .label max-width in FileStats.svelte */
|
||||
@media (max-width: 800px) {
|
||||
|
@@ -11,6 +11,7 @@ export type FSPath = {
|
||||
base_index: number,
|
||||
children: Array<FSNode>,
|
||||
permissions: FSPermissions,
|
||||
context: FSContext,
|
||||
}
|
||||
|
||||
export type FSNode = {
|
||||
@@ -42,6 +43,10 @@ export type FSPermissions = {
|
||||
delete: boolean,
|
||||
}
|
||||
|
||||
export type FSContext = {
|
||||
premium_transfer: boolean,
|
||||
}
|
||||
|
||||
// API parameters
|
||||
// ==============
|
||||
|
||||
|
@@ -1,8 +1,8 @@
|
||||
<script>
|
||||
import { onMount } from 'svelte'
|
||||
import { fs_path_url, fs_encode_path, fs_node_icon } from "./../FilesystemAPI"
|
||||
import FileTitle from './../../file_viewer/viewers/FileTitle.svelte';
|
||||
import TextBlock from './../../file_viewer/viewers/TextBlock.svelte';
|
||||
import { fs_path_url, fs_encode_path, fs_node_icon } from "src/filesystem/FilesystemAPI.ts"
|
||||
import FileTitle from "src/layout/FileTitle.svelte";
|
||||
import TextBlock from "src/layout/TextBlock.svelte"
|
||||
|
||||
export let nav
|
||||
let player
|
||||
|
@@ -1,8 +1,8 @@
|
||||
<script>
|
||||
import { createEventDispatcher } from "svelte";
|
||||
import IconBlock from "../../file_viewer/viewers/IconBlock.svelte";
|
||||
import IconBlock from "src/layout/IconBlock.svelte";
|
||||
import { fs_thumbnail_url } from "../FilesystemAPI";
|
||||
import TextBlock from "../../file_viewer/viewers/TextBlock.svelte";
|
||||
import TextBlock from "src/layout/TextBlock.svelte"
|
||||
let dispatch = createEventDispatcher()
|
||||
|
||||
export let nav
|
||||
|
@@ -1,7 +1,7 @@
|
||||
<script>
|
||||
import { onMount, tick } from "svelte";
|
||||
import Spinner from "../../util/Spinner.svelte";
|
||||
import { fs_node_type } from "./../FilesystemAPI";
|
||||
import { fs_node_type, fs_thumbnail_url } from "./../FilesystemAPI";
|
||||
import FileManager from "../filemanager/FileManager.svelte";
|
||||
import Audio from "./Audio.svelte";
|
||||
import File from "./File.svelte";
|
||||
@@ -12,6 +12,8 @@ import Video from "./Video.svelte";
|
||||
import Torrent from "./Torrent.svelte";
|
||||
import Zip from "./Zip.svelte";
|
||||
import CustomBanner from "./CustomBanner.svelte";
|
||||
import { stats } from "src/util/StatsSocket.js"
|
||||
import SlowDown from "src/layout/SlowDown.svelte";
|
||||
|
||||
export let nav
|
||||
export let edit_window
|
||||
@@ -60,6 +62,14 @@ export const seek = delta => {
|
||||
<FileManager nav={nav} edit_window={edit_window} on:upload_picker>
|
||||
<CustomBanner path={$nav.path}/>
|
||||
</FileManager>
|
||||
{:else if $nav.context.premium_transfer === false && $stats.limits.transfer_limit_used > $stats.limits.transfer_limit}
|
||||
<SlowDown
|
||||
on:download
|
||||
file_size={$nav.base.file_size}
|
||||
file_name={$nav.base.name}
|
||||
file_type={$nav.base.file_type}
|
||||
icon_href={fs_thumbnail_url($nav.base.path, 256, 256)}
|
||||
/>
|
||||
{:else if viewer_type === "audio"}
|
||||
<Audio nav={nav} bind:this={viewer}>
|
||||
<CustomBanner path={$nav.path}/>
|
||||
|
@@ -1,6 +1,6 @@
|
||||
<script>
|
||||
import { createEventDispatcher } from "svelte";
|
||||
import { swipe_nav } from "./../../file_viewer/viewers/SwipeNavigate";
|
||||
import { swipe_nav } from "src/util/SwipeNavigate.ts";
|
||||
import { fs_path_url } from "./../FilesystemAPI";
|
||||
|
||||
let dispatch = createEventDispatcher();
|
||||
|
@@ -3,8 +3,8 @@ import { createEventDispatcher } from "svelte";
|
||||
import Magnet from "../../icons/Magnet.svelte";
|
||||
import { formatDate } from "../../util/Formatting.svelte"
|
||||
import TorrentItem from "./TorrentItem.svelte"
|
||||
import IconBlock from "../../file_viewer/viewers/IconBlock.svelte";
|
||||
import TextBlock from "../../file_viewer/viewers/TextBlock.svelte";
|
||||
import IconBlock from "src/layout/IconBlock.svelte";
|
||||
import TextBlock from "src/layout/TextBlock.svelte"
|
||||
import { fs_node_icon, fs_path_url } from "../FilesystemAPI";
|
||||
import CopyButton from "../../layout/CopyButton.svelte";
|
||||
|
||||
|
@@ -2,8 +2,8 @@
|
||||
import { createEventDispatcher } from "svelte";
|
||||
import { formatDataVolume, formatDate } from "../../util/Formatting.svelte"
|
||||
import ZipItem from "../../file_viewer/viewers/ZipItem.svelte";
|
||||
import IconBlock from "../../file_viewer/viewers/IconBlock.svelte";
|
||||
import TextBlock from "../../file_viewer/viewers/TextBlock.svelte";
|
||||
import IconBlock from "src/layout/IconBlock.svelte";
|
||||
import TextBlock from "src/layout/TextBlock.svelte"
|
||||
import { fs_node_icon, fs_path_url } from "../FilesystemAPI";
|
||||
|
||||
let dispatch = createEventDispatcher()
|
||||
|
@@ -16,7 +16,7 @@ export let width = "750px"
|
||||
flex-direction: row;
|
||||
margin: 8px auto;
|
||||
}
|
||||
@media(max-width: 500px) {
|
||||
@media(max-width: 400px) {
|
||||
.block {
|
||||
flex-direction: column;
|
||||
}
|
@@ -1,28 +1,25 @@
|
||||
<script>
|
||||
import { createEventDispatcher } from "svelte";
|
||||
import { formatDataVolume, formatDuration } from "../../util/Formatting.svelte";
|
||||
import { stats } from "../StatsSocket";
|
||||
import IconBlock from "./IconBlock.svelte";
|
||||
import TextBlock from "./TextBlock.svelte";
|
||||
import { formatDataVolume, formatDuration } from "../util/Formatting.svelte";
|
||||
import { stats } from "src/util/StatsSocket.js"
|
||||
import TextBlock from "src/layout/TextBlock.svelte"
|
||||
import IconBlock from "src/layout/IconBlock.svelte";
|
||||
let dispatch = createEventDispatcher()
|
||||
|
||||
export let file = {
|
||||
name: "",
|
||||
mime_type: "",
|
||||
availability: "",
|
||||
size: 0,
|
||||
download_speed_limit: 0,
|
||||
}
|
||||
export let file_size = 0
|
||||
export let file_name = ""
|
||||
export let file_type = ""
|
||||
export let icon_href = ""
|
||||
</script>
|
||||
|
||||
<TextBlock>
|
||||
<img src="/res/img/slow_down.webp" class="header_image" alt="Yea, I'm gonna need you to slow down a bit"/>
|
||||
<p>
|
||||
Pixeldrain's free tier is supported by my Patrons (be grateful). There's
|
||||
only so much that you can do with the budget they provide.
|
||||
{formatDataVolume($stats.limits.transfer_limit, 3)} per day is about
|
||||
the most I can give away for free while keeping it fair for everyone,
|
||||
and according to our records you have already downloaded
|
||||
Pixeldrain's free tier is supported by my Patrons. There's only so much
|
||||
that you can do with the budget they provide.
|
||||
{formatDataVolume($stats.limits.transfer_limit, 3)} per day is about the
|
||||
most I can give away for free while keeping it fair for everyone, and
|
||||
according to our records you have already downloaded
|
||||
{formatDataVolume($stats.limits.transfer_limit_used, 3)}.
|
||||
</p>
|
||||
<p>
|
||||
@@ -36,9 +33,8 @@ export let file = {
|
||||
Come back tomorrow when your free transfer limit resets
|
||||
</li>
|
||||
<li>
|
||||
Download the file at a rate of {file.download_speed_limit/(1<<10)}
|
||||
kiB/s. This will take at least
|
||||
{formatDuration((file.size/file.download_speed_limit)*1000)}
|
||||
Download the file at a limited rate of 1 MiB/s. This will take at
|
||||
least {formatDuration((file_size/(1<<20))*1000, 0)}
|
||||
</li>
|
||||
<li>
|
||||
<a href="/#pro" target="_blank" class="button button_highlight">
|
||||
@@ -53,9 +49,12 @@ export let file = {
|
||||
</ul>
|
||||
</TextBlock>
|
||||
|
||||
<IconBlock icon_href={file.icon_href}>
|
||||
Name: {file.name}<br/>
|
||||
Type: {file.mime_type}<br/>
|
||||
<IconBlock icon_href={icon_href}>
|
||||
<table>
|
||||
<tr><td colspan="2">{file_name}</td></tr>
|
||||
<tr><td>Type</td><td>{file_type}</td></tr>
|
||||
<tr><td>Size</td><td>{formatDataVolume(file_size, 3)}</td></tr>
|
||||
</table>
|
||||
<button on:click={() => {dispatch("download")}}>
|
||||
<i class="icon">download</i> Download
|
||||
</button>
|
Reference in New Issue
Block a user