Verified Commit c58c74d6 authored by Eliot Berriot's avatar Eliot Berriot
Browse files

Merge branch 'master' into develop

parents 9ce24284 e9e466bc
#!/bin/bash -eux
python /app/manage.py collectstatic --noinput
gunicorn config.asgi:application -w ${FUNKWHALE_WEB_WORKERS-1} -k uvicorn.workers.UvicornWorker -b 0.0.0.0:5000
gunicorn config.asgi:application -w ${FUNKWHALE_WEB_WORKERS-1} -k uvicorn.workers.UvicornWorker -b 0.0.0.0:5000 ${GUNICORN_ARGS-}
import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.production")
os.environ.setdefault("ASGI_THREADS", "5")
import django # noqa
......
......@@ -270,7 +270,7 @@ DATABASES = {
"default": env.db("DATABASE_URL")
}
DATABASES["default"]["ATOMIC_REQUESTS"] = True
DATABASES["default"]["CONN_MAX_AGE"] = env("DB_CONN_MAX_AGE", default=60 * 60)
DATABASES["default"]["CONN_MAX_AGE"] = env("DB_CONN_MAX_AGE", default=60 * 5)
MIGRATION_MODULES = {
# see https://github.com/jazzband/django-oauth-toolkit/issues/634
......
......@@ -72,7 +72,7 @@ def clean_id3_pictures(apic):
def get_mp4_tag(f, k):
if k == "pictures":
return f.get("covr")
return f.get("covr", [])
raw_value = f.get(k, None)
if not raw_value:
......
......@@ -320,6 +320,10 @@ def get_file_path(audio_file):
)
path = "/music" + audio_file.replace(prefix, "", 1)
if path.startswith("http://") or path.startswith("https://"):
protocol, remainder = path.split("://", 1)
hostname, r_path = remainder.split("/", 1)
r_path = urllib.parse.quote(r_path)
path = protocol + "://" + hostname + "/" + r_path
return (settings.PROTECT_FILES_PATH + "/media/" + path).encode("utf-8")
# needed to serve files with % or ? chars
path = urllib.parse.quote(path)
......
......@@ -219,6 +219,11 @@ def test_can_get_metadata_from_m4a_file(field, value):
assert data.get(field) == value
def test_get_pictures_m4a_empty():
pictures = metadata.get_mp4_tag({}, "pictures")
assert metadata.clean_mp4_pictures(pictures) == []
def test_can_get_metadata_from_flac_file_not_crash_if_empty():
path = os.path.join(DATA_DIR, "sample.flac")
data = metadata.Metadata(path)
......
......@@ -247,6 +247,18 @@ def test_serve_file_in_place_nginx_encode_url(
assert response["X-Accel-Redirect"] == expected
def test_serve_s3_nginx_encode_url(mocker, settings):
settings.PROTECT_FILE_PATH = "/_protected/media"
settings.REVERSE_PROXY_TYPE = "nginx"
audio_file = mocker.Mock(url="https://s3.storage.example/path/to/mp3?aws=signature")
expected = (
b"/_protected/media/https://s3.storage.example/path/to/mp3%3Faws%3Dsignature"
)
assert views.get_file_path(audio_file) == expected
@pytest.mark.parametrize(
"proxy,serve_path,expected",
[
......
Added a retry option for failed uploads (#942)
Fix import crash when importing M4A file with no embedded cover (#946)
Fixed style glitches in dropdowns
Reduce the number of simultaneous DB connections under some deployment scenario
Fix audio serving issues under S3/nginx when signatures are enabled
......@@ -47,6 +47,7 @@ Funkwhale packages are available for the following platforms:
- `YunoHost 3 <https://yunohost.org/>`_: https://github.com/YunoHost-Apps/funkwhale_ynh (kindly maintained by `@Jibec <https://github.com/Jibec>`_)
- ArchLinux (as an AUR package): if you'd rather use a package, check out this alternative installation method on ArchLinux: https://wiki.archlinux.org/index.php/Funkwhale (package and wiki kindly maintained by getzee)
- `NixOS <https://github.com/mmai/funkwhale-nixos>`_ (kindly maintained by @mmai)
- `Helm chart <https://gitlab.com/ananace/charts/>`_ to install Funkwhale on Kubenertes (kindly maintained by @ananace)
Project architecture
--------------------
......
......@@ -91,9 +91,20 @@
<table class="ui unstackable table">
<thead>
<tr>
<th><translate translate-context="Content/Library/Table.Label">Filename</translate></th>
<th class="ten wide"><translate translate-context="Content/Library/Table.Label">Filename</translate></th>
<th><translate translate-context="Content/*/*/Noun">Size</translate></th>
<th><translate translate-context="*/*/*">Status</translate></th>
<th><translate translate-context="*/*/*">Actions</translate></th>
</tr>
<tr v-if="retryableFiles.length > 1">
<th class="ten wide"></th>
<th></th>
<th></th>
<th>
<button class="ui right floated small basic button" @click.prevent="retry(retryableFiles)">
<translate translate-context="Content/Library/Table">Retry failed uploads</translate>
</button>
</th>
</tr>
</thead>
<tbody>
......@@ -113,9 +124,20 @@
<translate translate-context="Content/Library/Table" key="2">Uploading…</translate>
({{ parseInt(file.progress) }}%)
</span>
<template v-else>
<span class="ui label"><translate translate-context="Content/Library/*/Short" key="3">Pending</translate></span>
<button class="ui tiny basic red icon button" @click.prevent="$refs.upload.remove(file)"><i class="delete icon"></i></button>
<span v-else class="ui label"><translate translate-context="Content/Library/*/Short" key="3">Pending</translate></span>
</td>
<td>
<template v-if="file.error">
<button
class="ui tiny basic icon right floated button"
:title="labels.retry"
@click.prevent="retry([file])"
v-if="retryableFiles.indexOf(file) > -1">
<i class="redo icon"></i>
</button>
</template>
<template v-else-if="!file.success">
<button class="ui tiny basic red icon right floated button" @click.prevent="$refs.upload.remove(file)"><i class="delete icon"></i></button>
</template>
</td>
</tr>
......@@ -251,6 +273,13 @@ export default {
self.uploads.objects[event.upload.uuid] = event.upload;
self.needsRefresh = true
});
},
retry (files) {
files.forEach((file) => {
this.$refs.upload.update(file, {error: '', progress: '0.00'})
})
this.$refs.upload.active = true;
}
},
computed: {
......@@ -274,6 +303,7 @@ export default {
server,
network,
timeout,
retry: this.$pgettext('*/*/*/Verb', "Retry"),
extension: this.$gettextInterpolate(extension, {
extensions: this.supportedExtensions.join(", ")
})
......@@ -295,6 +325,11 @@ export default {
return f.error;
}).length;
},
retryableFiles () {
return this.files.filter(f => {
return f.error;
});
},
processableFiles() {
return (
this.uploads.pending +
......@@ -342,7 +377,9 @@ export default {
uploadedSize () {
let uploaded = 0
this.files.forEach((f) => {
uploaded += f.size * (f.progress / 100)
if (!f.error) {
uploaded += f.size * (f.progress / 100)
}
})
return uploaded
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment