diff --git a/CHANGELOG b/CHANGELOG index e7ba4d933..0b8505669 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -67,7 +67,7 @@ Instance-level moderation tools ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This release includes a first set of moderation tools that will give more control -to admins about the way their instance federate with other instance and accounts on the network. +to admins about the way their instance federates with other instance and accounts on the network. Using these tools, it's now possible to: - Browse known accounts and domains, and associated data (storage size, software version, etc.) @@ -75,7 +75,7 @@ Using these tools, it's now possible to: - Block or partially restrict interactions with any account or domain All those features are usable using a brand new "moderation" permission, meaning -you can appoints one or nultiple moderators to help with this task. +you can appoint one or multiple moderators to help with this task. I'd like to thank all Mastodon contributors, because some of the these tools are heavily inspired from what's being done in Mastodon. Thank you so much! @@ -84,7 +84,7 @@ inspired from what's being done in Mastodon. Thank you so much! Iframe widget to embed public tracks and albums [manual action required] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Funkwhale now support embedding a lightweight audio player on external websites +Funkwhale now supports embedding a lightweight audio player on external websites for album and tracks that are available in public libraries. Important pages, such as artist, album and track pages also include OpenGraph tags that will enable previews on compatible apps (like sharing a Funkwhale track link on Mastodon @@ -132,13 +132,13 @@ which should be ``/srv/funkwhale/front/dist`` by default, then reload your nginx Alternative docker deployment method ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Thanks to the awesome done by @thetarkus at https://github.com/thetarkus/docker-funkwhale, +Thanks to the awesome work done by @thetarkus at https://github.com/thetarkus/docker-funkwhale, we're now able to provide an alternative and easier Docker deployment method! In contrast with our current, multi-container offer, this method integrates all Funkwhale processes and services (database, redis, etc.) into a single, easier to deploy container. -Both method will coexist in parallel, as each one has pros and cons. You can learn more +Both methods will coexist in parallel, as each one has pros and cons. You can learn more about this exciting new deployment option by visiting https://docs.funkwhale.audio/installation/docker.html! Automatically load .env file @@ -146,7 +146,7 @@ Automatically load .env file On non-docker deployments, earlier versions required you to source the config/.env file before launching any Funkwhale command, with ``export $(cat config/.env | grep -v ^# | xargs)`` -This led to more complex and error prode deployment / setup. +This led to more complex and error prone deployment / setup. This is not the case anymore, and Funkwhale will automatically load this file if it's available. @@ -174,7 +174,7 @@ Enable gzip compression [manual action suggested] Gzip compression will be enabled on new instances by default and will reduce the amount of bandwidth consumed by your instance. -If you with to benefit from gzip compression on your instance, +If you want to benefit from gzip compression on your instance, edit your reverse proxy virtualhost file (located at ``/etc/nginx/sites-available/funkwhale.conf``) and add the following snippet in the server block, then reload your nginx server:: diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 9c59fd4be..19f034b9f 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -41,15 +41,19 @@ Setup front-end only development environment yarn install -4. Launch the development server:: +4. Compile the translations:: + + yarn i18n-compile + +5. Launch the development server:: # this will serve the front-end on http://localhost:8000/front/ VUE_PORT=8000 yarn serve -5. Make the front-end talk with an existing server (like https://demo.funkwhale.audio), +6. Make the front-end talk with an existing server (like https://demo.funkwhale.audio or https://open.audio), by clicking on the corresponding link in the footer -6. Start hacking! +7. Start hacking! Setup your development environment ---------------------------------- diff --git a/api/funkwhale_api/music/models.py b/api/funkwhale_api/music/models.py index 325cdacec..4ba832717 100644 --- a/api/funkwhale_api/music/models.py +++ b/api/funkwhale_api/music/models.py @@ -7,6 +7,7 @@ import uuid import markdown import pendulum +import pydub from django.conf import settings from django.contrib.postgres.fields import JSONField from django.core.files.base import ContentFile @@ -780,6 +781,15 @@ class Upload(models.Model): "size": self.get_file_size(), } + def get_audio_segment(self): + input = self.get_audio_file() + if not input: + return + + input_format = utils.MIMETYPE_TO_EXTENSION[self.mimetype] + audio = pydub.AudioSegment.from_file(input, format=input_format) + return audio + def save(self, **kwargs): if not self.mimetype: if self.audio_file: @@ -824,10 +834,9 @@ class Upload(models.Model): 0 ] + ".{}".format(format) version.audio_file.save(new_name, f) - utils.transcode_file( - input=self.audio_file, + utils.transcode_audio( + audio=self.get_audio_segment(), output=version.audio_file, - input_format=utils.MIMETYPE_TO_EXTENSION[self.mimetype], output_format=utils.MIMETYPE_TO_EXTENSION[mimetype], ) version.size = version.audio_file.size diff --git a/api/funkwhale_api/music/utils.py b/api/funkwhale_api/music/utils.py index ae5cda750..574f4c8e1 100644 --- a/api/funkwhale_api/music/utils.py +++ b/api/funkwhale_api/music/utils.py @@ -75,5 +75,9 @@ def get_actor_from_request(request): def transcode_file(input, output, input_format, output_format, **kwargs): with input.open("rb"): audio = pydub.AudioSegment.from_file(input, format=input_format) + return transcode_audio(audio, output, output_format, **kwargs) + + +def transcode_audio(audio, output, output_format, **kwargs): with output.open("wb"): return audio.export(output, format=output_format, **kwargs) diff --git a/api/tests/music/test_views.py b/api/tests/music/test_views.py index aa1214f83..85ba2955a 100644 --- a/api/tests/music/test_views.py +++ b/api/tests/music/test_views.py @@ -374,6 +374,32 @@ def test_listen_transcode(factories, now, logged_in_api_client, mocker): ) +@pytest.mark.parametrize("serve_path", [("/host/music",), ("/app/music",)]) +def test_listen_transcode_in_place( + serve_path, factories, now, logged_in_api_client, mocker, settings +): + settings.MUSIC_DIRECTORY_PATH = "/app/music" + settings.MUSIC_DIRECTORY_SERVE_PATH = serve_path + upload = factories["music.Upload"]( + import_status="finished", + library__actor__user=logged_in_api_client.user, + audio_file=None, + source="file://" + os.path.join(DATA_DIR, "test.ogg"), + ) + + assert upload.get_audio_segment() + + url = reverse("api:v1:listen-detail", kwargs={"uuid": upload.track.uuid}) + handle_serve = mocker.spy(views, "handle_serve") + response = logged_in_api_client.get(url, {"to": "mp3"}) + + assert response.status_code == 200 + + handle_serve.assert_called_once_with( + upload, user=logged_in_api_client.user, format="mp3" + ) + + def test_user_can_create_library(factories, logged_in_api_client): actor = logged_in_api_client.user.create_actor() url = reverse("api:v1:libraries-list") diff --git a/changes/changelog.d/667.bugfix b/changes/changelog.d/667.bugfix new file mode 100644 index 000000000..d553867ca --- /dev/null +++ b/changes/changelog.d/667.bugfix @@ -0,0 +1 @@ +Make Apache configuration file work with 0.18 changes (#667) diff --git a/changes/changelog.d/681.enhancement b/changes/changelog.d/681.enhancement new file mode 100644 index 000000000..9f8723106 --- /dev/null +++ b/changes/changelog.d/681.enhancement @@ -0,0 +1 @@ +Hide pagination when there is only one page of results (#681) \ No newline at end of file diff --git a/changes/changelog.d/688.bugfix b/changes/changelog.d/688.bugfix new file mode 100644 index 000000000..085f205cd --- /dev/null +++ b/changes/changelog.d/688.bugfix @@ -0,0 +1 @@ +Fix transcoding of in-place imported tracks (#688) diff --git a/changes/notes.rst b/changes/notes.rst index 96ac3d765..8e54adf8b 100644 --- a/changes/notes.rst +++ b/changes/notes.rst @@ -5,3 +5,38 @@ Next release notes Those release notes refer to the current development branch and are reset after each release. + +Fix Apache configuration file for 0.18 [manual action required] +---------------------------------------------------------- + +The way front is served has changed since 0.18. The Apache configuration can't serve 0.18 properly, leading to blank screens. + +If you are on an Apache setup, you will have to replace the `` block with the following:: + + + # similar to nginx 'client_max_body_size 100M;' + LimitRequestBody 104857600 + + ProxyPass ${funkwhale-api}/ + ProxyPassReverse ${funkwhale-api}/ + + +And add some more `ProxyPass` directives so that the `Alias` part of your configuration file looks this way:: + + ProxyPass "/front" "!" + Alias /front /srv/funkwhale/front/dist + + ProxyPass "/media" "!" + Alias /media /srv/funkwhale/data/media + + ProxyPass "/staticfiles" "!" + Alias /staticfiles /srv/funkwhale/data/static + +In case you are using custom css and theming, you also need to match this block:: + + ProxyPass "/settings.json" "!" + Alias /settings.json /srv/funkwhale/custom/settings.json + + ProxyPass "/custom" "!" + Alias /custom /srv/funkwhale/custom + diff --git a/deploy/apache.conf b/deploy/apache.conf index f348566a0..52eee9533 100644 --- a/deploy/apache.conf +++ b/deploy/apache.conf @@ -46,10 +46,6 @@ Define MUSIC_DIRECTORY_PATH /srv/funkwhale/data/music # Tell the api that the client is using https RequestHeader set X-Forwarded-Proto "https" - DocumentRoot /srv/funkwhale/front/dist - - FallbackResource /index.html - # Configure Proxy settings # ProxyPreserveHost pass the original Host header to the backend server ProxyVia On @@ -69,14 +65,14 @@ Define MUSIC_DIRECTORY_PATH /srv/funkwhale/data/music # Activating WebSockets - ProxyPass "/api/v1/activity" ${funkwhale-api-ws}/api/v1/activity + ProxyPass "/api/v1/activity" ${funkwhale-api-ws}/api/v1/activity - + # similar to nginx 'client_max_body_size 100M;' LimitRequestBody 104857600 - ProxyPass ${funkwhale-api}/api - ProxyPassReverse ${funkwhale-api}/api + ProxyPass ${funkwhale-api}/ + ProxyPassReverse ${funkwhale-api}/ ProxyPass ${funkwhale-api}/federation @@ -94,8 +90,13 @@ Define MUSIC_DIRECTORY_PATH /srv/funkwhale/data/music ProxyPassReverse ${funkwhale-api}/.well-known/ + ProxyPass "/front" "!" + Alias /front /srv/funkwhale/front/dist + + ProxyPass "/media" "!" Alias /media /srv/funkwhale/data/media + ProxyPass "/staticfiles" "!" Alias /staticfiles /srv/funkwhale/data/static # Setting appropriate access levels to serve frontend diff --git a/docs/upgrading/index.rst b/docs/upgrading/index.rst index 209c4ec25..7942bd288 100644 --- a/docs/upgrading/index.rst +++ b/docs/upgrading/index.rst @@ -62,6 +62,37 @@ easy: This is a warning, not an error, and it can be safely ignored. Never run the ``makemigrations`` command yourself. + +Upgrading the Postgres container +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +With some Funkwhale releases, it is recommended to upgrade the version of the +Postgres database server container. For example, Funkwhale 0.17 recommended +Postgres 9.4, but Funkwhale 0.18 recommends Postgres 11. When upgrading +Postgres, it is not sufficient to change the container referenced in +``docker-compose.yml``. New major versions of Postgres cannot read the databases +created by older major versions. The data has to be exported from a running +instance of the old version and imported by the new version. + +Thankfully, there is a Docker container available to automate this process. You +can use the following snippet to upgrade your database in ``./postgres``, +keeping a backup of the old version in ``./postgres-old``: + +.. parsed-literal:: + + # Replace "9.4" and "11" with the versions you are migrating between. + export OLD_POSTGRES=9.4 + export NEW_POSTGRES=11 + docker-compose stop postgres + docker run --rm \ + -v `pwd`/data/postgres:/var/lib/postgresql/${OLD_POSTGRES}/data \ + -v `pwd`/data/postgres-new:/var/lib/postgresql/${NEW_POSTGRES}/data \ + tianon/postgres-upgrade:${OLD_POSTGRES}-to-${NEW_POSTGRES} + # Add back the access control rule that doesn't survive the upgrade + echo "host all all all trust" | sudo tee -a ./postgres-new/pg_hba.conf + # Swap over to the new database + mv ./data/postgres ./data/postgres-old + mv ./data/postgres-new ./data/postgres Non-docker setup diff --git a/front/src/components/Pagination.vue b/front/src/components/Pagination.vue index 57cac2815..963b000a8 100644 --- a/front/src/components/Pagination.vue +++ b/front/src/components/Pagination.vue @@ -1,5 +1,5 @@ We cannot load this track

- The next track will play automatically in a few seconds... + The next track will play automatically in a few seconds…

diff --git a/front/src/components/auth/Profile.vue b/front/src/components/auth/Profile.vue index 32dae5336..73c9ab2d9 100644 --- a/front/src/components/auth/Profile.vue +++ b/front/src/components/auth/Profile.vue @@ -10,7 +10,7 @@

{{ profile.username }} -
Registered since %{ date }
+
Member since %{ date }
diff --git a/front/src/components/auth/Settings.vue b/front/src/components/auth/Settings.vue index c417f9fbc..8305d0e05 100644 --- a/front/src/components/auth/Settings.vue +++ b/front/src/components/auth/Settings.vue @@ -68,8 +68,7 @@ Change my password
- Changing your password will also change your Subsonic API password if you have requested one. - You will have to update your password on your clients that use this password. + Changing your password will also change your Subsonic API password if you have requested one. You will have to update your password on your clients that use this password.
diff --git a/front/src/components/auth/SubsonicTokenForm.vue b/front/src/components/auth/SubsonicTokenForm.vue index c5e6783de..ac752d921 100644 --- a/front/src/components/auth/SubsonicTokenForm.vue +++ b/front/src/components/auth/SubsonicTokenForm.vue @@ -5,8 +5,7 @@ The Subsonic API is not available on this Funkwhale instance.

- Funkwhale is compatible with other music players that support the Subsonic API. - You can use those to enjoy your playlist and music in offline mode, on your smartphone or tablet, for instance. + Funkwhale is compatible with other music players that support the Subsonic API. You can use those to enjoy your playlist and music in offline mode, on your smartphone or tablet, for instance.

However, accessing Funkwhale from those clients require a separate password you can set below. diff --git a/front/src/components/manage/moderation/AccountsTable.vue b/front/src/components/manage/moderation/AccountsTable.vue index 1e97ebaf7..8259e8ec8 100644 --- a/front/src/components/manage/moderation/AccountsTable.vue +++ b/front/src/components/manage/moderation/AccountsTable.vue @@ -168,7 +168,7 @@ export default { computed: { labels () { return { - searchPlaceholder: this.$gettext('Search by domain, username, bio...') + searchPlaceholder: this.$gettext('Search by domain, username, bio…') } }, actionFilters () { diff --git a/front/src/components/manage/moderation/DomainsTable.vue b/front/src/components/manage/moderation/DomainsTable.vue index 28698ba62..ed9eb5be8 100644 --- a/front/src/components/manage/moderation/DomainsTable.vue +++ b/front/src/components/manage/moderation/DomainsTable.vue @@ -148,7 +148,7 @@ export default { computed: { labels () { return { - searchPlaceholder: this.$gettext('Search by name...') + searchPlaceholder: this.$gettext('Search by name…') } }, actionFilters () { diff --git a/front/src/components/manage/moderation/InstancePolicyCard.vue b/front/src/components/manage/moderation/InstancePolicyCard.vue index c7d115856..b72c6bac8 100644 --- a/front/src/components/manage/moderation/InstancePolicyCard.vue +++ b/front/src/components/manage/moderation/InstancePolicyCard.vue @@ -22,11 +22,11 @@

-
Silence activity
+
Mute activity
-
Silence notifications
+
Mute notifications
diff --git a/front/src/components/manage/moderation/InstancePolicyForm.vue b/front/src/components/manage/moderation/InstancePolicyForm.vue index 98fd1d644..e90f9ad10 100644 --- a/front/src/components/manage/moderation/InstancePolicyForm.vue +++ b/front/src/components/manage/moderation/InstancePolicyForm.vue @@ -112,7 +112,7 @@ export default { blockAllHelp: this.$gettext("Block everything from this account or domain. This will prevent any interaction with the entity, and purge related content (uploads, libraries, follows, etc.)"), silenceActivity: { help: this.$gettext("Hide account or domain content, except from followers."), - label: this.$gettext("Silence activity"), + label: this.$gettext("Mute activity"), }, silenceNotifications: { help: this.$gettext("Prevent account or domain from triggering notifications, except from followers."), diff --git a/front/src/components/notifications/NotificationRow.vue b/front/src/components/notifications/NotificationRow.vue index b134bc96b..530e15270 100644 --- a/front/src/components/notifications/NotificationRow.vue +++ b/front/src/components/notifications/NotificationRow.vue @@ -38,9 +38,11 @@ export default { labels () { let libraryFollowMessage = this.$gettext('%{ username } followed your library "%{ library }"') let libraryAcceptFollowMessage = this.$gettext('%{ username } accepted your follow on library "%{ library }"') + let libraryPendingFollowMessage = this.$gettext('%{ username } wants to follow your library "%{ library }"') return { libraryFollowMessage, libraryAcceptFollowMessage, + libraryPendingFollowMessage, markRead: this.$gettext('Mark as read'), markUnread: this.$gettext('Mark as unread'), @@ -55,19 +57,23 @@ export default { if (a.type === 'Follow') { if (a.object && a.object.type === 'music.Library') { let action = null + let message = null if (!a.related_object.approved) { + message = this.labels.libraryPendingFollowMessage action = { buttonClass: 'green', icon: 'check', label: this.$gettext('Approve'), handler: () => { self.approveLibraryFollow(a.related_object) } } - } + } else { + message = this.labels.libraryFollowMessage + } return { action, detailUrl: {name: 'content.libraries.detail', params: {id: a.object.uuid}}, message: this.$gettextInterpolate( - this.labels.libraryFollowMessage, + message, {username: this.username, library: a.object.name} ) } diff --git a/front/src/components/playlists/Editor.vue b/front/src/components/playlists/Editor.vue index 8e7e0ae9d..5b5311f14 100644 --- a/front/src/components/playlists/Editor.vue +++ b/front/src/components/playlists/Editor.vue @@ -160,7 +160,7 @@ export default { }), labels () { return { - copyTitle: this.$gettext('Copy tracks from current queue to playlist') + copyTitle: this.$gettext('Copy queued tracks to playlist') } }, status () { diff --git a/front/src/views/Notifications.vue b/front/src/views/Notifications.vue index 66aaccfa2..98e666943 100644 --- a/front/src/views/Notifications.vue +++ b/front/src/views/Notifications.vue @@ -24,7 +24,7 @@

- No notifications yet. + No notification to show.

diff --git a/front/src/views/content/remote/Home.vue b/front/src/views/content/remote/Home.vue index 636b2fb8c..007fbadca 100644 --- a/front/src/views/content/remote/Home.vue +++ b/front/src/views/content/remote/Home.vue @@ -1,7 +1,7 @@