Subscription management and bandwidth accounting

This commit is contained in:
2021-11-22 21:34:14 +01:00
parent 1c75f68812
commit 206dc5e906
10 changed files with 216 additions and 156 deletions

View File

@@ -23,7 +23,7 @@
<a href="/api">API</a> <a href="/api">API</a>
<a href="/acknowledgements">Acknowledgements</a> <a href="/acknowledgements">Acknowledgements</a>
<a href="https://stats.uptimerobot.com/p9v2ktzyjm" target="_blank">Server Status</a> <a href="https://stats.uptimerobot.com/p9v2ktzyjm" target="_blank">Server Status</a>
{{if eq .User.Subscription.DisableAdDisplay false}} {{if eq .User.Subscription.ID ""}}
<a href="https://pixeldrain.com/vouchercodes">Shopping discounts</a> <a href="https://pixeldrain.com/vouchercodes">Shopping discounts</a>
{{end}} {{end}}
</div> </div>

View File

@@ -5,14 +5,14 @@ import Chart from "../util/Chart.svelte";
let graphViews let graphViews
let graphBandwidth let graphBandwidth
let graphHotlink let graphBandwidthPaid
let graphTimeout = null let graphTimeout = null
let start_time = "" let start_time = ""
let end_time = "" let end_time = ""
let total_bandwidth = 0 let total_bandwidth = 0
let total_views = 0 let total_views = 0
let total_hotlink = 0 let total_bandwidth_paid = 0
const loadGraph = (minutes, interval, live) => { const loadGraph = (minutes, interval, live) => {
if (graphTimeout !== null) { clearTimeout(graphTimeout) } if (graphTimeout !== null) { clearTimeout(graphTimeout) }
if (live) { if (live) {
@@ -44,17 +44,17 @@ const loadGraph = (minutes, interval, live) => {
graphViews.chart().data.datasets[0].data = resp.views.amounts; graphViews.chart().data.datasets[0].data = resp.views.amounts;
graphBandwidth.chart().data.labels = resp.views.timestamps; graphBandwidth.chart().data.labels = resp.views.timestamps;
graphBandwidth.chart().data.datasets[0].data = resp.bandwidth.amounts; graphBandwidth.chart().data.datasets[0].data = resp.bandwidth.amounts;
graphHotlink.chart().data.labels = resp.views.timestamps; graphBandwidthPaid.chart().data.labels = resp.views.timestamps;
graphHotlink.chart().data.datasets[0].data = resp.direct_link_bandwidth.amounts; graphBandwidthPaid.chart().data.datasets[0].data = resp.bandwidth_paid.amounts;
graphViews.update() graphViews.update()
graphBandwidth.update() graphBandwidth.update()
graphHotlink.update() graphBandwidthPaid.update()
start_time = resp.views.timestamps[0] start_time = resp.views.timestamps[0]
end_time = resp.views.timestamps.slice(-1)[0]; end_time = resp.views.timestamps.slice(-1)[0];
total_bandwidth = resp.bandwidth.amounts.reduce((acc, val) => acc + val) total_bandwidth = resp.bandwidth.amounts.reduce((acc, val) => acc + val)
total_views = resp.views.amounts.reduce((acc, val) => acc + val) total_views = resp.views.amounts.reduce((acc, val) => acc + val)
total_hotlink = resp.direct_link_bandwidth.amounts.reduce((acc, val) => acc + val) total_bandwidth_paid = resp.bandwidth_paid.amounts.reduce((acc, val) => acc + val)
}) })
} }
@@ -141,13 +141,13 @@ onDestroy(() => {
</div> </div>
<Chart bind:this={graphBandwidth} dataType="bytes" label="Bandwidth" /> <Chart bind:this={graphBandwidth} dataType="bytes" label="Bandwidth" />
<hr/> <hr/>
<Chart bind:this={graphHotlink} dataType="bytes" label="Hotlink bandwidth" /> <Chart bind:this={graphBandwidthPaid} dataType="bytes" label="Paid bandwidth" />
<hr/> <hr/>
<Chart bind:this={graphViews} dataType="number" label="Views" /> <Chart bind:this={graphViews} dataType="number" label="Views" />
<div class="highlight_dark"> <div class="highlight_dark">
Total usage from {start_time} to {end_time}<br/> Total usage from {start_time} to {end_time}<br/>
{formatDataVolume(total_bandwidth, 3)} bandwidth, {formatDataVolume(total_bandwidth, 3)} bandwidth,
{formatDataVolume(total_hotlink, 3)} hotlink bandwidth and {formatDataVolume(total_bandwidth_paid, 3)} paid bandwidth and
{formatThousands(total_views, 3)} views {formatThousands(total_views, 3)} views
</div> </div>

View File

@@ -45,6 +45,9 @@ let update_charts = () => {
resp.bandwidth.amounts.forEach((val, idx) => { resp.bandwidth.amounts.forEach((val, idx) => {
resp.bandwidth.amounts[idx] = Math.round(val / file.size); resp.bandwidth.amounts[idx] = Math.round(val / file.size);
}); });
resp.bandwidth_paid.amounts.forEach((val, idx) => {
resp.bandwidth.amounts[idx] += Math.round(val / file.size);
});
download_chart.chart().data.labels = resp.views.timestamps download_chart.chart().data.labels = resp.views.timestamps
view_chart.chart().data.labels = resp.views.timestamps view_chart.chart().data.labels = resp.views.timestamps
download_chart.chart().data.datasets[0].data = resp.bandwidth.amounts download_chart.chart().data.datasets[0].data = resp.bandwidth.amounts
@@ -78,8 +81,20 @@ let update_charts = () => {
<td>{formatDataVolume(file.size, 4)} ( {formatThousands(file.size)} B )</td> <td>{formatDataVolume(file.size, 4)} ( {formatThousands(file.size)} B )</td>
</tr> </tr>
<tr> <tr>
<td>Bandwidth</td> <td>Free bandwidth used</td>
<td>{formatDataVolume(file.bandwidth_used, 4)} ( {formatThousands(file.bandwidth_used)} B )</td> <td>
{formatDataVolume(file.bandwidth_used, 4)}
( {formatThousands(file.bandwidth_used)} B ),
{(file.bandwidth_used/file.size).toFixed(1)}x file size
</td>
</tr>
<tr>
<td>Premium bandwidth used</td>
<td>
{formatDataVolume(file.bandwidth_used_paid, 4)}
( {formatThousands(file.bandwidth_used_paid)} B ),
{(file.bandwidth_used_paid/file.size).toFixed(1)}x file size
</td>
</tr> </tr>
<tr style="border-bottom: none"> <tr style="border-bottom: none">
<td>Unique downloads</td> <td>Unique downloads</td>

View File

@@ -50,7 +50,7 @@ let update_stats = (id) => {
if (file.size === 0) { if (file.size === 0) {
downloads = j.downloads downloads = j.downloads
} else { } else {
downloads = Math.round(j.bandwidth / file.size) downloads = Math.round((j.bandwidth + j.bandwidth_paid) / file.size)
} }
} }
socket.onerror = err => { socket.onerror = err => {

View File

@@ -437,7 +437,7 @@ const keyboard_event = evt => {
</FilePreview> </FilePreview>
</div> </div>
{#if current_file.show_ads && window.viewer_data.user_ads_enabled} {#if current_file.show_ads}
<AdSkyscraper on:visibility={e => {skyscraper_visible = e.detail}}></AdSkyscraper> <AdSkyscraper on:visibility={e => {skyscraper_visible = e.detail}}></AdSkyscraper>
{/if} {/if}

View File

@@ -9,13 +9,13 @@ import Euro from "../util/Euro.svelte"
let graph_view = null let graph_view = null
let graph_download = null let graph_download = null
let graph_bandwidth = null let graph_bandwidth = null
let graph_direct_link = null let graph_transfer_paid = null
let time_start = "" let time_start = ""
let time_end = "" let time_end = ""
let total_views = 0 let total_views = 0
let total_downloads = 0 let total_downloads = 0
let total_bandwidth = 0 let total_bandwidth = 0
let total_direct_link = 0 let total_transfer_paid = 0
let load_graph = (graph, stat, minutes, interval) => { let load_graph = (graph, stat, minutes, interval) => {
let today = new Date() let today = new Date()
@@ -54,8 +54,8 @@ let load_graph = (graph, stat, minutes, interval) => {
total_downloads = total; total_downloads = total;
} else if (stat == "bandwidth") { } else if (stat == "bandwidth") {
total_bandwidth = total; total_bandwidth = total;
} else if (stat == "direct_bandwidth") { } else if (stat == "transfer_paid") {
total_direct_link = total; total_transfer_paid = total;
} }
}).catch(e => { }).catch(e => {
console.error("Error requesting time series: " + e); console.error("Error requesting time series: " + e);
@@ -75,11 +75,12 @@ let update_graphs = (minutes, interval, live) => {
load_graph(graph_view, "views", minutes, interval) load_graph(graph_view, "views", minutes, interval)
load_graph(graph_download, "downloads", minutes, interval) load_graph(graph_download, "downloads", minutes, interval)
load_graph(graph_bandwidth, "bandwidth", minutes, interval) load_graph(graph_bandwidth, "bandwidth", minutes, interval)
load_graph(graph_direct_link, "direct_bandwidth", minutes, interval) load_graph(graph_transfer_paid, "transfer_paid", minutes, interval)
load_direct_bw() load_direct_bw()
} }
let direct_link_bandwidth_used = 0 let transfer_cap = 0
let transfer_used = 0
let storage_space_used = 0 let storage_space_used = 0
let load_direct_bw = () => { let load_direct_bw = () => {
let today = new Date() let today = new Date()
@@ -87,7 +88,7 @@ let load_direct_bw = () => {
start.setDate(start.getDate() - 30) start.setDate(start.getDate() - 30)
fetch( fetch(
window.api_endpoint + "/user/time_series/direct_bandwidth" + window.api_endpoint + "/user/time_series/transfer_paid" +
"?start=" + start.toISOString() + "?start=" + start.toISOString() +
"&end=" + today.toISOString() + "&end=" + today.toISOString() +
"&interval=60" "&interval=60"
@@ -96,7 +97,7 @@ let load_direct_bw = () => {
return resp.json(); return resp.json();
}).then(resp => { }).then(resp => {
let total = resp.amounts.reduce((accum, val) => accum += val, 0); let total = resp.amounts.reduce((accum, val) => accum += val, 0);
direct_link_bandwidth_used = total transfer_used = total
storage_space_used = window.user.storage_space_used storage_space_used = window.user.storage_space_used
}).catch(e => { }).catch(e => {
console.error("Error requesting time series: " + e); console.error("Error requesting time series: " + e);
@@ -104,6 +105,14 @@ let load_direct_bw = () => {
} }
onMount(() => { onMount(() => {
if (window.user.subscription.monthly_transfer_cap > 0) {
transfer_cap = window.user.subscription.monthly_transfer_cap
} else if (window.user.monthly_transfer_cap > 0) {
transfer_cap = window.user.monthly_transfer_cap
} else {
transfer_cap = -1
}
update_graphs(1440, 1, true); update_graphs(1440, 1, true);
}) })
onDestroy(() => { onDestroy(() => {
@@ -128,14 +137,6 @@ onDestroy(() => {
<li> <li>
Max file size: {formatDataVolume(window.user.subscription.file_size_limit, 3)} Max file size: {formatDataVolume(window.user.subscription.file_size_limit, 3)}
</li> </li>
<li>
Advertisements when you view files:
{#if window.user.subscription.disable_ad_display}No{:else}Yes{/if}
</li>
<li>
Advertisements when others view your files:
{#if window.user.subscription.disable_ads_on_files}No{:else}Yes{/if}
</li>
{#if window.user.subscription.file_expiry_days > 0} {#if window.user.subscription.file_expiry_days > 0}
<li>Files expire after {window.user.subscription.file_expiry_days} days</li> <li>Files expire after {window.user.subscription.file_expiry_days} days</li>
{:else} {:else}
@@ -156,10 +157,10 @@ onDestroy(() => {
<StorageProgressBar used={storage_space_used} total={window.user.subscription.storage_space}></StorageProgressBar> <StorageProgressBar used={storage_space_used} total={window.user.subscription.storage_space}></StorageProgressBar>
{/if} {/if}
{#if window.user.subscription.direct_linking_bandwidth === -1} {#if transfer_cap === -1}
Hotlink bandwidth used in the last 30 days: {formatDataVolume(direct_link_bandwidth_used, 3)}<br/> Paid transfers in the last 30 days: {formatDataVolume(transfer_used, 3)}<br/>
{:else} {:else}
<HotlinkProgressBar used={direct_link_bandwidth_used} total={window.user.subscription.direct_linking_bandwidth}></HotlinkProgressBar> <HotlinkProgressBar used={transfer_used} total={transfer_cap}></HotlinkProgressBar>
{/if} {/if}
<h3>Exports</h3> <h3>Exports</h3>
@@ -224,8 +225,18 @@ onDestroy(() => {
{formatThousands(total_views)} views, {formatThousands(total_views)} views,
{formatThousands(total_downloads)} downloads, {formatThousands(total_downloads)} downloads,
{formatDataVolume(total_bandwidth, 3)} bandwidth and {formatDataVolume(total_bandwidth, 3)} bandwidth and
{formatDataVolume(total_direct_link, 3)} direct link bandwidth {formatDataVolume(total_transfer_paid, 3)} paid transfers
</div> </div>
<div class="limit_width">
<h3>Paid transfers</h3>
<p>
A paid transfer is when a file is downloaded using the data cap on
your subscription plan. These can be files you downloaded from other
people, or other people downloading your files if you have bandwidth
sharing enabled.
</p>
</div>
<Chart bind:this={graph_transfer_paid} dataType="bytes" label="Paid transfers" />
<div class="limit_width"> <div class="limit_width">
<h3>Views</h3> <h3>Views</h3>
<p> <p>
@@ -255,17 +266,4 @@ onDestroy(() => {
</p> </p>
</div> </div>
<Chart bind:this={graph_bandwidth} dataType="bytes" label="Bandwidth" /> <Chart bind:this={graph_bandwidth} dataType="bytes" label="Bandwidth" />
<div class="limit_width">
<h3>Hotlink bandwidth</h3>
<p>
When a file is downloaded without going through pixeldrain's
download page it counts as a hotlink. Because hotlinking costs us
bandwidth and doesn't generate any ad revenue we have to limit it.
When your hotlink bandwidth runs out people will be asked to do a
test before they can download your files. See our
<a href="/#pro">subscription options</a> to get more hotlink
bandwidth.
</p>
</div>
<Chart bind:this={graph_direct_link} dataType="bytes" label="Hotlink bandwidth" />
</div> </div>

View File

@@ -8,7 +8,7 @@ $: frac = used / total
</script> </script>
<div> <div>
Hotlink bandwidth: Paid transfers:
{formatDataVolume(used, 3)} {formatDataVolume(used, 3)}
out of out of
{formatDataVolume(total, 3)} {formatDataVolume(total, 3)}
@@ -20,10 +20,9 @@ $: frac = used / total
{#if frac > 0.99} {#if frac > 0.99}
<div class="highlight_red"> <div class="highlight_red">
You have used all of your hotlink bandwidth. Other people won't You have used all of your data cap. People can still download your
be able to download your files directly from the API anymore. files, but not directly from the API anymore. The file viewer shows
Downloads will have to go through the file viewer page. Please ads on your files and download speeds are limited.
upgrade to a higher support tier to continue hotlinking files:
<br/> <br/>
<a class="button button_highlight" href="https://www.patreon.com/join/pixeldrain"> <a class="button button_highlight" href="https://www.patreon.com/join/pixeldrain">
Upgrade options Upgrade options
@@ -31,12 +30,10 @@ $: frac = used / total
</div> </div>
{:else if frac > 0.8} {:else if frac > 0.8}
<div class="highlight_yellow"> <div class="highlight_yellow">
You have used {(frac*100).toFixed(0)}% of your You have used {(frac*100).toFixed(0)}% of your data cap. If your
hotlink bandwidth. If your hotlink bandwidth runs out people data runs out people won't be able to download your files directly
won't be able to download your files directly from the API from the API anymore, ads will be shown on the file viewer and
anymore. Downloads will have to go through the file viewer page. transfer rates will be limited.
Please upgrade to a higher support tier to continue hotlinking
files:
<br/> <br/>
<a class="button button_highlight" href="https://www.patreon.com/join/pixeldrain"> <a class="button button_highlight" href="https://www.patreon.com/join/pixeldrain">
Upgrade options Upgrade options

View File

@@ -55,6 +55,13 @@ onMount(() => {
<i class="icon">vpn_key</i> <i class="icon">vpn_key</i>
API keys API keys
</a> </a>
<a class="button"
href="/user/subscription"
class:button_highlight={page === "subscription"}
on:click|preventDefault={() => {navigate("subscription", "Subscription")}}>
<i class="icon">shopping_cart</i>
Subscription
</a>
{#if window.user.balance_micro_eur !== 0} {#if window.user.balance_micro_eur !== 0}
<a class="button" <a class="button"
href="/user/transactions" href="/user/transactions"
@@ -63,13 +70,6 @@ onMount(() => {
<i class="icon">receipt_long</i> <i class="icon">receipt_long</i>
Transactions Transactions
</a> </a>
<a class="button"
href="/user/subscription"
class:button_highlight={page === "subscription"}
on:click|preventDefault={() => {navigate("subscription", "Subscription")}}>
<i class="icon">shopping_cart</i>
Subscription
</a>
{/if} {/if}
</div> </div>

View File

@@ -3,15 +3,20 @@ import Spinner from "../util/Spinner.svelte";
import Euro from "../util/Euro.svelte" import Euro from "../util/Euro.svelte"
let loading = false let loading = false
let subscription = window.user.subscription.id
let hotlinking = window.user.hotlinking_enabled
let transfer_cap = window.user.monthly_transfer_cap / 1e12
let result = "" let result = ""
let result_success = false let result_success = false
const update_subscription = async name => { const update_subscription = async () => {
loading = true loading = true
const form = new FormData() const form = new FormData()
form.append("subscription", name) form.append("subscription", subscription)
form.append("hotlinking_enabled", hotlinking)
form.append("transfer_cap", transfer_cap*1e12)
try { try {
const resp = await fetch( const resp = await fetch(
window.api_endpoint+"/user/subscription", window.api_endpoint+"/user/subscription",
@@ -62,97 +67,135 @@ const update_subscription = async name => {
balance to activate the subscription again. balance to activate the subscription again.
</p> </p>
{#if result !== ""} <h3>Prepaid plans</h3>
<div class:highlight_green={result_success} class:highlight_red={!result_success}> {#if window.user.subscription.type === "patreon"}
{result} <p>Prepaid subscriptions are not available for Patreon supporters.</p>
{:else}
{#if result !== ""}
<div class:highlight_green={result_success} class:highlight_red={!result_success}>
{result}
</div>
{/if}
<div class="feat_table">
<div>
<div class="feat_label" class:feat_highlight={subscription === "prepaid"}>
Prepaid<br/>
{#if subscription === "prepaid"}
Currently active
{:else}
<button on:click={() => {subscription = "prepaid"; update_subscription()}}>
<i class="icon">attach_money</i>
Activate
</button>
{/if}
</div>
<div class="feat_normal round_tr">
<ul>
<li>Base price of €1 per month</li>
<li>€4 per TB per month for storage</li>
<li>€2 per TB for data transfer</li>
<li>Files never expire as long as subscription is active</li>
</ul>
</div>
</div>
<div>
<div class="feat_label" class:feat_highlight={subscription === "prepaid_temp_storage_120d"}>
120 days storage<br/>
{#if subscription === "prepaid_temp_storage_120d"}
Currently active
{:else}
<button on:click={() => {subscription = "prepaid_temp_storage_120d"; update_subscription()}}>
<i class="icon">attach_money</i>
Activate
</button>
{/if}
</div>
<div class="feat_normal">
<ul>
<li>Base price of €1 per month</li>
<li>€2 per TB per month for storage</li>
<li>€2 per TB for data transfer</li>
<li>Files expire 120 days after the last time they're viewed</li>
</ul>
</div>
</div>
<div>
<div class="feat_label" class:feat_highlight={subscription === "prepaid_temp_storage_60d"}>
60 days storage<br/>
{#if subscription === "prepaid_temp_storage_60d"}
Currently active
{:else}
<button on:click={() => {subscription = "prepaid_temp_storage_60d"; update_subscription()}}>
<i class="icon">attach_money</i>
Activate
</button>
{/if}
</div>
<div class="feat_normal">
<ul>
<li>Base price of €1 per month</li>
<li>€1 per TB per month for storage</li>
<li>€2 per TB for data transfer</li>
<li>Files expire 60 days after the last time they're viewed</li>
</ul>
</div>
</div>
<div>
<div class="feat_label" class:feat_highlight={subscription === ""}>
Free<br/>
{#if subscription === ""}
Currently active
{:else}
<button on:click={() => {subscription = ""; update_subscription()}}>
<i class="icon">money_off</i>
Activate
</button>
{/if}
</div>
<div class="feat_normal round_br">
<ul>
<li>Standard free plan, files expire after 30 days.</li>
</ul>
</div>
</div>
</div> </div>
{/if} {/if}
<div class="feat_table"> <h3>Bandwidth sharing</h3>
<div>
<div class="feat_label" class:feat_highlight={window.user.subscription.id === "prepaid"}> {#if hotlinking}
Prepaid<br/> <button on:click={() => { hotlinking = false; update_subscription() }}>
{#if window.user.subscription.id === "prepaid"} <i class="icon green">check</i> ON (click to turn off)
Currently active </button>
{:else} {:else}
<button on:click={() => {update_subscription("prepaid")}}> <button on:click={() => { hotlinking = true; update_subscription() }}>
<i class="icon">attach_money</i> <i class="icon red">close</i> OFF (click to turn on)
Activate </button>
</button> {/if}
{/if} <p>
</div> When bandwidth sharing is enabled all the bandwidth that your files
<div class="feat_normal round_tr"> use will be subtracted from your data cap. Advertisements will be
<ul> disabled on the download pages for your files and download speed
<li>Base price of €2 per month (includes all the benefits of the Pro plan)</li> will be unlimited. The rate limiting captcha for files is also
<li>€4 per TB per month for storage</li> disabled when bandwidth sharing is on. You can directly embed your
<li>€2 per TB for hotlink bandwidth</li> file's download link anywhere, you don't need to use the file viewer
<li>All advertisements disabled</li> page.
<li>No rate limit, your files will download at the highest speed possible</li> </p>
</ul>
</div> <h3>Bill shock limit</h3>
</div> Billshock limit in terabytes per month. Set to 0 to disable<br/>
<div> <input type="number" bind:value={transfer_cap}/> TB
<div class="feat_label" class:feat_highlight={window.user.subscription.id === "prepaid_storage"}> <button on:click={update_subscription}>
Just storage<br/> <i class="icon">save</i> Save
{#if window.user.subscription.id === "prepaid_storage"} </button>
Currently active <p>
{:else} The billshock limit limits how much bandwidth your account can use
<button on:click={() => {update_subscription("prepaid_storage")}}> in a 30 day window. When this limit is reached files will show ads
<i class="icon">attach_money</i> again and can only be downloaded from the file viewer page. This is
Activate mostly useful for prepaid plans, but it works for patreon plans too.
</button> Set to 0 to disable the limit.
{/if} </p>
</div>
<div class="feat_normal">
<ul>
<li>Base price of €1 per month</li>
<li>€4 per TB per month for storage</li>
<li>100 GB of hotlink bandwidth per month</li>
<li>You don't see ads, but people downloading your files do see ads</li>
</ul>
</div>
</div>
<div>
<div class="feat_label" class:feat_highlight={window.user.subscription.id === "prepaid_storage_temp"}>
Temporary storage<br/>
{#if window.user.subscription.id === "prepaid_storage_temp"}
Currently active
{:else}
<button on:click={() => {update_subscription("prepaid_storage_temp")}}>
<i class="icon">attach_money</i>
Activate
</button>
{/if}
</div>
<div class="feat_normal">
<ul>
<li>Base price of €1 per month</li>
<li>€2 per TB per month for storage</li>
<li>100 GB of hotlink bandwidth per month</li>
<li>You don't see ads, but people downloading your files do see ads</li>
<li>Files expire 90 days after the last time they're viewed</li>
</ul>
</div>
</div>
<div>
<div class="feat_label" class:feat_highlight={window.user.subscription.id === ""}>
Free<br/>
{#if window.user.subscription.id === ""}
Currently active
{:else}
<button on:click={() => {update_subscription("none")}}>
<i class="icon">money_off</i>
Activate
</button>
{/if}
</div>
<div class="feat_normal round_br">
<ul>
<li>Standard free plan, files expire after 30 days.</li>
</ul>
</div>
</div>
</div>
</div> </div>
</div> </div>
@@ -204,4 +247,11 @@ const update_subscription = async name => {
.feat_table > div > div.round_tr { border-top-right-radius: 0.5em; } .feat_table > div > div.round_tr { border-top-right-radius: 0.5em; }
.feat_table > div > div.round_br { border-bottom-right-radius: 0.5em; } .feat_table > div > div.round_br { border-bottom-right-radius: 0.5em; }
.green {
color: var(--highlight_color);
}
.red {
color: var(--danger_color);
}
</style> </style>

View File

@@ -74,7 +74,7 @@ func (wc *WebController) serveFileViewer(w http.ResponseWriter, r *http.Request,
var vd = fileViewerData{ var vd = fileViewerData{
CaptchaKey: wc.captchaKey(), CaptchaKey: wc.captchaKey(),
ViewToken: wc.viewTokenOrBust(), ViewToken: wc.viewTokenOrBust(),
UserAdsEnabled: !(templateData.Authenticated && templateData.User.Subscription.DisableAdDisplay), UserAdsEnabled: templateData.User.Subscription.ID == "",
} }
if len(ids) > 1 { if len(ids) > 1 {
@@ -149,7 +149,7 @@ func (wc *WebController) serveListViewer(w http.ResponseWriter, r *http.Request,
Type: "list", Type: "list",
CaptchaKey: wc.captchaSiteKey, CaptchaKey: wc.captchaSiteKey,
ViewToken: wc.viewTokenOrBust(), ViewToken: wc.viewTokenOrBust(),
UserAdsEnabled: !(templateData.Authenticated && templateData.User.Subscription.DisableAdDisplay), UserAdsEnabled: templateData.User.Subscription.ID == "",
APIResponse: list, APIResponse: list,
} }