Experimental CDN support for album zip downloads.
This commit is contained in:
Bobby Wibowo 2018-04-27 04:04:21 +07:00
parent 0bce5e6da3
commit d46611ee57
No known key found for this signature in database
GPG Key ID: 51C3A1E1E22D26CF
5 changed files with 105 additions and 29 deletions

View File

@ -191,23 +191,57 @@ albumsController.get = async (req, res, next) => {
}
albumsController.generateZip = async (req, res, next) => {
const identifier = req.params.identifier
if (identifier === undefined) { return res.status(401).json({ success: false, description: 'No identifier provided.' }) }
if (!config.uploads.generateZips) { return res.status(401).json({ success: false, description: 'Zip generation disabled.' }) }
const download = (filePath, fileName) => {
const headers = { 'Access-Control-Allow-Origin': '*' }
// Album page will append zipGeneratedAt timestamp to the download link by default
if (parseInt(req.query.v) > 0) {
// Cache-Control header is useful when using CDN (max-age: 30 days)
headers['Cache-Control'] = 'public, max-age=2592000, must-revalidate, proxy-revalidate, immutable, stale-while-revalidate=86400, stale-if-error=604800'
}
return res.download(filePath, fileName, { headers })
}
const album = await db.table('albums').where({ identifier, enabled: 1 }).first()
if (!album) { return res.json({ success: false, description: 'Album not found.' }) }
const identifier = req.params.identifier
if (identifier === undefined) {
return res.status(401).json({
success: false,
description: 'No identifier provided.'
})
}
if (!config.uploads.generateZips) {
return res.status(401).json({
success: false,
description: 'Zip generation disabled.'
})
}
const album = await db.table('albums')
.where({ identifier, enabled: 1 })
.first()
if (!album) {
return res.json({
success: false,
description: 'Album not found.'
})
}
if (album.zipGeneratedAt > album.editedAt) {
const filePath = path.join(config.uploads.folder, 'zips', `${identifier}.zip`)
const fileName = `${album.name}.zip`
return res.download(filePath, fileName)
return download(filePath, fileName)
} else {
console.log(`Generating zip for album identifier: ${identifier}`)
const files = await db.table('files')
.select('name')
.where('albumid', album.id)
if (files.length === 0) { return res.json({ success: false, description: 'There are no files in the album.' }) }
if (files.length === 0) {
return res.json({
success: false,
description: 'There are no files in the album.'
})
}
const zipPath = path.join(__dirname, '..', config.uploads.folder, 'zips', `${album.identifier}.zip`)
const archive = new Zip()
@ -222,7 +256,10 @@ albumsController.generateZip = async (req, res, next) => {
}
archive
.generateNodeStream({ type: 'nodebuffer', streamFiles: true })
.generateNodeStream({
type: 'nodebuffer',
streamFiles: true
})
.pipe(fs.createWriteStream(zipPath))
.on('finish', async () => {
console.log(`Generated zip for album identifier: ${identifier}`)
@ -232,7 +269,7 @@ albumsController.generateZip = async (req, res, next) => {
const filePath = path.join(config.uploads.folder, 'zips', `${identifier}.zip`)
const fileName = `${album.name}.zip`
return res.download(filePath, fileName)
return download(filePath, fileName)
})
}
}

View File

@ -1,3 +1,22 @@
html {
background-color: #232629;
}
.section {
background: none;
}
.message {
background-color: #31363b;
}
.message-body {
color: #eff0f1;
border: 0;
-webkit-box-shadow: 0 20px 60px rgba(10, 10, 10, 0.05), 0 5px 10px rgba(10, 10, 10, 0.1), 0 1px 1px rgba(10, 10, 10, 0.2);
box-shadow: 0 20px 60px rgba(10, 10, 10, 0.05), 0 5px 10px rgba(10, 10, 10, 0.1), 0 1px 1px rgba(10, 10, 10, 0.2);
}
/*
This is the same sheets used in dashboard.css, minus the on-hover ones.
I should probably put this in a file named _thumbs.css, remove the ones in dashboard.css,

View File

@ -11,7 +11,7 @@ routes.get('/a/:identifier', async (req, res, next) => {
if (identifier === undefined) {
return res.status(401).json({
success: false,
description: 'No identifier provided'
description: 'No identifier provided.'
})
}
@ -62,6 +62,7 @@ routes.get('/a/:identifier', async (req, res, next) => {
files,
identifier,
enableDownload: Boolean(config.uploads.generateZips),
zipGeneratedAt: album.zipGeneratedAt,
url: `${homeDomain}/a/${album.identifier}`
})
})

View File

@ -12,7 +12,7 @@
v1: CSS and JS files.
v2: Images and config files (manifest.json, browserconfig.xml, etcetera).
#}
{% set v1 = "fR6SBegTbv" %}
{% set v1 = "uuEpP64ca8" %}
{% set v2 = "MSEpgpfFIQ" %}
{#

View File

@ -5,15 +5,6 @@
<link rel="stylesheet" type="text/css" href="../libs/bulma/bulma.min.css?v={{ globals.v1 }}">
<link rel="stylesheet" type="text/css" href="../css/style.css?v={{ globals.v1 }}">
<link rel="stylesheet" type="text/css" href="../css/album.css?v={{ globals.v1 }}">
<style>
html {
background-color: #232629;
}
.section {
background: none;
}
</style>
{% endblock %}
{% block opengraph %}
@ -36,16 +27,37 @@
{{ super() }}
<section class="section">
<div class="container">
<h1 id="title" class="title">
{{ title }}
</h1>
<h1 id="count" class="subtitle">
{{ count }} files
</h1>
{% if enableDownload %}
<a class="button is-primary is-outlined" title="Download album" href="../api/album/zip/{{ identifier }}">Download Album</a>
{% endif %}
<nav class="level">
<div class="level-left">
<div class="level-item">
<h1 id="title" class="title">
{{ title }}
</h1>
</div>
<div class="level-item">
<h1 id="count" class="subtitle">
{{ count }} files
</h1>
</div>
</div>
{% if enableDownload -%}
<div class="level-right">
<p class="level-item">
<a class="button is-primary is-outlined" title="Download album" href="../api/album/zip/{{ identifier }}?v={{ zipGeneratedAt }}">Download Album</a>
</p>
</div>
{%- endif %}
</nav>
{% if enableDownload -%}
<article class="message">
<div class="message-body">
Album archives may be cached by CDN, if the one you downloaded seems outdated, you should try refreshing the page to get the latest version of the download link.
</div>
</article>
{%- endif %}
<hr>
{% if files.length -%}
<div id="table" class="columns is-multiline is-mobile is-centered has-text-centered">
{% for file in files %}
<div class="image-container column is-narrow">
@ -57,6 +69,13 @@
</div>
{% endfor %}
</div>
{%- else -%}
<article class="message">
<div class="message-body">
There is nothing here yet!
</div>
</article>
{%- endif %}
</div>
</section>
{% endblock %}