Add free transfer limit to filesystem

This commit is contained in:
2024-09-05 17:28:31 +02:00
parent 04efcb6505
commit 51afa2615c
30 changed files with 125 additions and 64 deletions

View File

@@ -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",

View File

@@ -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"
}

View File

@@ -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

View File

@@ -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: "",

View File

@@ -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 = ""

View File

@@ -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()

View File

@@ -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

View File

@@ -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,

View File

@@ -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()

View File

@@ -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"}

View File

@@ -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 => {

View File

@@ -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

View File

@@ -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()

View File

@@ -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

View File

@@ -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()

View File

@@ -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)

View File

@@ -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) {

View File

@@ -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
// ==============

View File

@@ -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

View File

@@ -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

View File

@@ -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}/>

View File

@@ -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();

View File

@@ -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";

View File

@@ -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()

View File

@@ -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;
}

View File

@@ -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>