diff --git a/config/urls.py b/config/urls.py index a6bb7c3..17d7f21 100644 --- a/config/urls.py +++ b/config/urls.py @@ -3,7 +3,6 @@ from django.contrib import admin from django.urls import include, path from django.views import defaults as default_views -from django.views.decorators.cache import cache_page from django.views.generic import TemplateView from drf_spectacular.views import SpectacularAPIView, SpectacularSwaggerView from rest_framework.authtoken.views import obtain_auth_token @@ -28,26 +27,26 @@ urlpatterns = [ # Podcast - path("", cache_page(settings.CACHE_DEFAULT_TTL)(Core_HomepageView.as_view()), name="homepage"), - path("player/", cache_page(settings.CACHE_DEFAULT_TTL)(Core_PlayerView.as_view()), name="player"), - path("episode/", cache_page(settings.CACHE_SMART_TTL)(Core_EpisodeView.as_view()), name="episode"), - path("settings/", cache_page(settings.CACHE_SMART_TTL)(Core_Settings.as_view()), name="settings"), + path("", Core_HomepageView.as_view(), name="homepage"), + path("player/", Core_PlayerView.as_view(), name="player"), + path("episode/", Core_EpisodeView.as_view(), name="episode"), + path("settings/", Core_Settings.as_view(), name="settings"), path("playlist/", Core_PlaylistView.as_view(), name="playlist"), path( "add-datasource/", - cache_page(settings.CACHE_DEFAULT_TTL)(Core_AddDataSourceView.as_view()), + Core_AddDataSourceView.as_view(), name="add-datasource", ), path( "delete-datasource/", - cache_page(settings.CACHE_DEFAULT_TTL)(Core_DeleteDataSourceView.as_view()), + Core_DeleteDataSourceView.as_view(), name="delete-datasource", ), *static("persist/", document_root=settings.PERSIST_AUDIO_ROOTDIR), # Youtube Urls path( "yt/add-channel/", - cache_page(settings.CACHE_DEFAULT_TTL)(Youtube_AddChannelView.as_view()), + Youtube_AddChannelView.as_view(), name="yt-add-channel", ), path( @@ -57,7 +56,7 @@ ), path( "yt/add-playlist/", - cache_page(settings.CACHE_DEFAULT_TTL)(Youtube_AddPlaylistView.as_view()), + Youtube_AddPlaylistView.as_view(), name="yt-add-playlist", ), path( @@ -68,7 +67,7 @@ # Spreaker Urls path( "sk/add-podcast/", - cache_page(settings.CACHE_DEFAULT_TTL)(Spreaker_AddPodcastView.as_view()), + Spreaker_AddPodcastView.as_view(), name="sk-add-podcast", ), path( diff --git a/core/templates/base.html b/core/templates/base.html index f6806ff..eb69a74 100644 --- a/core/templates/base.html +++ b/core/templates/base.html @@ -65,19 +65,21 @@ - - - - + {% if user.is_authenticated %} + + + + + {% endif %} diff --git a/core/templates/core/player.html b/core/templates/core/player.html index 27f4bd2..a81e1b6 100644 --- a/core/templates/core/player.html +++ b/core/templates/core/player.html @@ -50,7 +50,7 @@ controls: true, loop: false, preload: "auto", - poster: "/static/core/images/player.jpg", + poster: "/static/images/player.jpg", audioPosterMode: true, responsive: true, aspectRatio: "16:9" @@ -216,8 +216,7 @@

Player

Playlist
-
diff --git a/core/views.py b/core/views.py index 6441795..f6df339 100644 --- a/core/views.py +++ b/core/views.py @@ -1,13 +1,17 @@ -from django.contrib.auth.mixins import LoginRequiredMixin +from django.conf import settings +from django.contrib.auth.decorators import login_required from django.http import HttpResponse from django.shortcuts import render +from django.utils.decorators import method_decorator from django.views import View +from django.views.decorators.cache import cache_page from core.models import DataSource, Episode, Playlist, Settings # Create your views here. -class Core_HomepageView(LoginRequiredMixin, View): +@method_decorator([login_required, cache_page(settings.CACHE_DEFAULT_TTL)], name="dispatch") +class Core_HomepageView(View): def get(self, request): episode = Episode.objects.all().order_by("-episode_date") playlist = Playlist.objects.all() @@ -30,7 +34,8 @@ def get(self, request): return render(request, "core/index.html", context=context) -class Core_PlayerView(LoginRequiredMixin, View): +@method_decorator([login_required, cache_page(settings.CACHE_DEFAULT_TTL)], name="dispatch") +class Core_PlayerView(View): def get(self, request): return render(request, "core/player.html") @@ -41,17 +46,20 @@ def get(self, request): return HttpResponse("ok") -class Core_AddDataSourceView(LoginRequiredMixin, View): +@method_decorator([login_required, cache_page(settings.CACHE_DEFAULT_TTL)], name="dispatch") +class Core_AddDataSourceView(View): def get(self, request): return render(request, "core/add_datasource.html") -class Core_DeleteDataSourceView(LoginRequiredMixin, View): +@method_decorator([login_required, cache_page(settings.CACHE_DEFAULT_TTL)], name="dispatch") +class Core_DeleteDataSourceView(View): def get(self, request): return render(request, "core/delete_datasource.html") -class Core_Settings(LoginRequiredMixin, View): +@method_decorator([login_required, cache_page(settings.CACHE_DEFAULT_TTL)], name="dispatch") +class Core_Settings(View): def get(self, request): try: total_size = Settings.objects.get(name="persist_total_size") @@ -64,7 +72,8 @@ def get(self, request): return render(request, "core/settings.html", context={"total_size": total_size, "total_count": total_count}) -class Core_EpisodeView(LoginRequiredMixin, View): +@method_decorator([login_required, cache_page(settings.CACHE_SMART_TTL)], name="dispatch") +class Core_EpisodeView(View): def get(self, request): episode_extended = [] playlist = Playlist.objects.all() @@ -77,7 +86,8 @@ def get(self, request): return render(request, "core/episode.html", context={"episodes": episode_extended}) -class Core_PlaylistView(LoginRequiredMixin, View): +@method_decorator([login_required, cache_page(settings.CACHE_SMART_TTL)], name="dispatch") +class Core_PlaylistView(View): def get(self, request): playlist = Playlist.objects.all() return render(request, "core/playlist.html", context={"playlist": playlist}) diff --git a/docs/config.md b/docs/config.md index 4d05c5f..e0cc14d 100644 --- a/docs/config.md +++ b/docs/config.md @@ -8,4 +8,6 @@ | CELERY_BROKER_URL | | redis://verbacap-redis:6379/0 | Redis URL for store a celery data | | PERSIST_AUDIO_ROOTDIR | /persist/audio | /persist/audio | Persist Path to store the audio files | | DJANGO_ACCOUNT_ALLOW_REGISTRATION | False | False | A boolean that turns on/off the user registration. | -| DJANGO_ALLOWED_HOSTS | example.com | example.com | Django Allowed Hosts separated by comma | \ No newline at end of file +| DJANGO_ALLOWED_HOSTS | example.com | example.com | Django Allowed Hosts separated by comma | +| DEBUG_INTERNALIPS | 127.0.0.1 | 127.0.0.1,192.168.1.1 | If Debug is enabled, you can add your ip below to show the debug toolbar | +| CSRF_TRUSTED_ORIGINS | localhost,0.0.0.0,127.0.0.1 | 127.0.0.1 | CSRF_TRUSTED_ORIGINS exposed separated by comma | \ No newline at end of file diff --git a/docs/install.md b/docs/install.md index 0dde4c7..2cd07f0 100644 --- a/docs/install.md +++ b/docs/install.md @@ -1,9 +1,10 @@ ## Requirements * Postgres 15+ -* Docker / Podman / ContainerD +* Redis +* Docker / Podman / ContainerD / Kubernetes * HDD/SSD 2Gb + -## Install on Docker like daemon +## Install on Docker 1. Create a new user and assign full permission to the database in Postgres 2. Install `docker` and `docker-compose` ([More Info](https://docs.docker.com/engine/install/)) @@ -35,3 +36,32 @@ Insert the user and password of the super admin 7. Open your browser to [http://127.0.0.1:8080/](http://127.0.0.1:8080/) 8. Login with the super admin credential + +## Install via Helm +1. Create a new user and assign full permission to the database in Postgres + +2. Install `helm` ([More Info](https://helm.sh/docs/intro/install/)) + +3. Add the helm repository +``` +helm repo add verbacap https://mirio.github.io/verbacap-chart/ +``` + +4. Download the latest `values.yaml` and edit it based by your configuration +``` +wget -q https://raw.githubusercontent.com/Mirio/verbacap-chart/main/charts/verbacap/values.yaml +``` + +5. Install it using Helm +``` +helm install verbacap verbacap/verbacap -f values.yaml +``` + +6. Wait until the pod `verbacap-app` returns `Listening at: http://0.0.0.0:8000` + +7. Create a super admin user using: +``` +kubectl exec -n NAMESPACE -it POD_ID /entrypoint.bash createadminuser +``` + +8. Open the browser and go to the web interface exposed. \ No newline at end of file diff --git a/spreaker/views.py b/spreaker/views.py index 3f362de..93c17a3 100644 --- a/spreaker/views.py +++ b/spreaker/views.py @@ -1,7 +1,10 @@ -from django.contrib.auth.mixins import LoginRequiredMixin +from django.conf import settings +from django.contrib.auth.decorators import login_required from django.db import transaction from django.shortcuts import render +from django.utils.decorators import method_decorator from django.views import View +from django.views.decorators.cache import cache_page from core.models import DataSource, Provider from spreaker.forms import AddPodcastForm @@ -9,7 +12,8 @@ # Create your views here. -class Spreaker_AddPodcastView(LoginRequiredMixin, View): +@method_decorator([login_required, cache_page(settings.CACHE_DEFAULT_TTL)], name="dispatch") +class Spreaker_AddPodcastView(View): def get(self, request): form = AddPodcastForm() return render(request, "spreaker/add-podcast.html", context={"form": form}) @@ -45,7 +49,8 @@ def post(self, request): ) -class Spreaker_DeletePodcastView(LoginRequiredMixin, View): +@method_decorator([login_required, cache_page(settings.CACHE_DEFAULT_TTL)], name="dispatch") +class Spreaker_DeletePodcastView(View): def get(self, request): provider = Provider.objects.get(name="Spreaker") return render( diff --git a/verbacap/templates/account/login.html b/verbacap/templates/account/login.html index ca18295..1a79cd9 100644 --- a/verbacap/templates/account/login.html +++ b/verbacap/templates/account/login.html @@ -8,7 +8,7 @@ {% translate "Sign In" %} {% endblock head_title %} {% block inner %} -

{% translate "Sign In" %}

+

{% translate "Sign In" %}

{% get_providers as socialaccount_providers %} {% if socialaccount_providers %}

@@ -45,8 +45,10 @@

{% translate "Sign In" %}

name="{{ redirect_field_name }}" value="{{ redirect_field_value }}" /> {% endif %} - {% translate "Forgot Password?" %} - +
+
+ +
+
{% endblock inner %} diff --git a/youtube/views.py b/youtube/views.py index bc05d3d..7c02724 100644 --- a/youtube/views.py +++ b/youtube/views.py @@ -1,7 +1,10 @@ -from django.contrib.auth.mixins import LoginRequiredMixin +from django.conf import settings +from django.contrib.auth.decorators import login_required from django.db import transaction from django.shortcuts import render +from django.utils.decorators import method_decorator from django.views import View +from django.views.decorators.cache import cache_page from core.models import DataSource, Provider from youtube.forms import AddChannelForm, AddPlaylistForm @@ -9,7 +12,8 @@ # Create your views here. -class Youtube_AddPlaylistView(LoginRequiredMixin, View): +@method_decorator([login_required, cache_page(settings.CACHE_DEFAULT_TTL)], name="dispatch") +class Youtube_AddPlaylistView(View): def get(self, request): form = AddPlaylistForm() return render(request, "youtube/add-playlist.html", context={"form": form}) @@ -45,7 +49,8 @@ def post(self, request): ) -class Youtube_DeletePlaylistView(LoginRequiredMixin, View): +@method_decorator([login_required, cache_page(settings.CACHE_DEFAULT_TTL)], name="dispatch") +class Youtube_DeletePlaylistView(View): def get(self, request): provider = Provider.objects.get(name="Youtube-Playlist") return render( @@ -73,7 +78,8 @@ def post(self, request): return render(request, "youtube/submit.html", context={"outmsg": outmsg}, status=status) -class Youtube_AddChannelView(LoginRequiredMixin, View): +@method_decorator([login_required, cache_page(settings.CACHE_DEFAULT_TTL)], name="dispatch") +class Youtube_AddChannelView(View): def get(self, request): form = AddChannelForm() return render(request, "youtube/add-channel.html", context={"form": form}) @@ -109,7 +115,8 @@ def post(self, request): ) -class Youtube_DeleteChannelView(LoginRequiredMixin, View): +@method_decorator([login_required, cache_page(settings.CACHE_DEFAULT_TTL)], name="dispatch") +class Youtube_DeleteChannelView(View): def get(self, request): provider = Provider.objects.get(name="Youtube") return render(