validate settings form and userspace archive page_size

This commit is contained in:
simon 2021-10-29 22:37:31 +07:00
parent f24a3dd1f5
commit a4397b5204
5 changed files with 147 additions and 53 deletions

View File

@ -0,0 +1,62 @@
"""functionality:
- hold all form classes used in the views
"""
from django import forms
from django.contrib.auth.forms import AuthenticationForm
from django.forms.widgets import PasswordInput, TextInput
class CustomAuthForm(AuthenticationForm):
"""better styled login form"""
username = forms.CharField(
widget=TextInput(attrs={"placeholder": "Username"}), label=False
)
password = forms.CharField(
widget=PasswordInput(attrs={"placeholder": "Password"}), label=False
)
class UserSettingsForm(forms.Form):
"""user configurations values"""
CHOICES = [
("", "-- change color scheme --"),
("dark", "Dark"),
("light", "Light"),
]
colors = forms.ChoiceField(
widget=forms.Select, choices=CHOICES, required=False
)
page_size = forms.IntegerField(required=False)
class ApplicationSettingsForm(forms.Form):
"""handle all application settings"""
METADATA_CHOICES = [
("", "-- change metadata embed --"),
("0", "don't embed metadata"),
("1", "embed metadata"),
]
THUMBNAIL_CHOICES = [
("", "-- change thumbnail embed --"),
("0", "don't embed thumbnail"),
("1", "embed thumbnail"),
]
subscriptions_channel_size = forms.IntegerField(required=False)
downloads_limit_count = forms.IntegerField(required=False)
downloads_limit_speed = forms.IntegerField(required=False)
downloads_throttledratelimit = forms.IntegerField(required=False)
downloads_sleep_interval = forms.IntegerField(required=False)
downloads_format = forms.CharField(required=False)
downloads_add_metadata = forms.ChoiceField(
widget=forms.Select, choices=METADATA_CHOICES, required=False
)
downloads_add_thumbnail = forms.ChoiceField(
widget=forms.Select, choices=THUMBNAIL_CHOICES, required=False
)

View File

@ -86,11 +86,23 @@ class AppConfig:
elif to_write.isdigit(): elif to_write.isdigit():
to_write = int(to_write) to_write = int(to_write)
config_dict, config_value = key.split(".") config_dict, config_value = key.split("_", maxsplit=1)
config[config_dict][config_value] = to_write config[config_dict][config_value] = to_write
RedisArchivist().set_message("config", config, expire=False) RedisArchivist().set_message("config", config, expire=False)
@staticmethod
def set_user_config(form_post, user_id):
"""set values in redis for user settings"""
for key, value in form_post.items():
to_write = value[0]
if len(to_write):
if to_write.isdigit():
to_write = int(to_write)
message = {"status": to_write}
redis_key = f"{user_id}:{key}"
RedisArchivist().set_message(redis_key, message, expire=False)
def load_new_defaults(self): def load_new_defaults(self):
"""check config.json for missing defaults""" """check config.json for missing defaults"""
default_config = self.get_config_file() default_config = self.get_config_file()

View File

@ -12,6 +12,7 @@ from datetime import datetime
import requests import requests
from home.src.config import AppConfig from home.src.config import AppConfig
from home.src.helper import RedisArchivist
from home.src.thumbnails import ThumbManager from home.src.thumbnails import ThumbManager
@ -181,13 +182,23 @@ class Pagination:
figure out the pagination based on page size and total_hits figure out the pagination based on page size and total_hits
""" """
def __init__(self, page_get, search_get=False): def __init__(self, page_get, user_id, search_get=False):
config = AppConfig().config self.user_id = user_id
self.page_size = config["archive"]["page_size"] self.page_size = self.get_page_size()
self.page_get = page_get self.page_get = page_get
self.search_get = search_get self.search_get = search_get
self.pagination = self.first_guess() self.pagination = self.first_guess()
def get_page_size(self):
"""get default or user modified page_size"""
key = f"{self.user_id}:page_size"
page_size = RedisArchivist().get_message(key)["status"]
if not page_size:
config = AppConfig().config
page_size = config["archive"]["page_size"]
return page_size
def first_guess(self): def first_guess(self):
"""build first guess before api call""" """build first guess before api call"""
page_get = self.page_get page_get = self.page_get

View File

@ -1,20 +1,16 @@
{% extends "home/base.html" %} {% extends "home/base.html" %}
{% block content %} {% block content %}
<div class="title-bar"> <div class="title-bar">
<h1>Settings</h1> <h1>User Configurations</h1>
</div> </div>
<form action="/settings/" method="POST" name="settings-update"> <form action="/settings/" method="POST" name="user-update">
{% csrf_token %} {% csrf_token %}
<div class="settings-group"> <div class="settings-group">
<h2>Color scheme</h2> <h2>Color scheme</h2>
<div class="settings-item"> <div class="settings-item">
<p>Current color scheme: <span class="settings-current">{{ config.application.colors }}</span></p> <p>Current color scheme: <span class="settings-current">{{ config.application.colors }}</span></p>
<i>Select your preferred color scheme between dark and light mode.</i><br> <i>Select your preferred color scheme between dark and light mode.</i><br>
<select name="application.colors" id="application.colors"> {{ user_form.colors }}
<option value="" disabled selected> -- change color scheme -- </option>
<option value="dark">dark mode</option>
<option value="light">light mode</option>
</select>
</div> </div>
</div> </div>
<div class="settings-group"> <div class="settings-group">
@ -22,15 +18,22 @@
<div class="settings-item"> <div class="settings-item">
<p>Current page size: <span class="settings-current">{{ config.archive.page_size }}</span></p> <p>Current page size: <span class="settings-current">{{ config.archive.page_size }}</span></p>
<i>Result of videos showing in archive page</i><br> <i>Result of videos showing in archive page</i><br>
<input type="number" name="archive.page_size" id="archive.page_size"> {{ user_form.page_size }}
</div> </div>
</div> </div>
<button type="submit" name="user-settings">Update User Configurations</button>
</form>
<div class="title-bar">
<h1>Application Configurations</h1>
</div>
<form action="/settings/" method="POST" name="application-update">
{% csrf_token %}
<div class="settings-group"> <div class="settings-group">
<h2 id="subscriptions">Subscriptions</h2> <h2 id="subscriptions">Subscriptions</h2>
<div class="settings-item"> <div class="settings-item">
<p>Current channel page size: <span class="settings-current">{{ config.subscriptions.channel_size }}</span></p> <p>Current channel page size: <span class="settings-current">{{ config.subscriptions.channel_size }}</span></p>
<i>Recent videos to check on check pending, max recommended 50.</i><br> <i>Recent videos to check on check pending, max recommended 50.</i><br>
<input type="number" name="subscriptions.channel_size" id="subscriptions.channel_size"> {{ app_form.subscriptions_channel_size }}
</div> </div>
<div class="settings-item"> <div class="settings-item">
<p>Auto scan subscribed channels:</p> <p>Auto scan subscribed channels:</p>
@ -46,22 +49,22 @@
<div class="settings-item"> <div class="settings-item">
<p>Current download limit: <span class="settings-current">{{ config.downloads.limit_count }}</span></p> <p>Current download limit: <span class="settings-current">{{ config.downloads.limit_count }}</span></p>
<i>Limit the number of videos getting downloaded on every run. 0 (zero) to deactivate.</i><br> <i>Limit the number of videos getting downloaded on every run. 0 (zero) to deactivate.</i><br>
<input type="number" name="downloads.limit_count" id="downloads.limit_count"> {{ app_form.downloads_limit_count }}
</div> </div>
<div class="settings-item"> <div class="settings-item">
<p>Current download speed limit: <span class="settings-current">{{ config.downloads.limit_speed }}</span></p> <p>Current download speed limit: <span class="settings-current">{{ config.downloads.limit_speed }}</span></p>
<i>Limit download speed. 0 (zero) to deactivate.</i><br> <i>Limit download speed. 0 (zero) to deactivate.</i><br>
<input type="number" name="downloads.limit_speed" id="downloads.limit_speed"><span>KB/sec</span> {{ app_form.downloads_limit_speed }}
</div> </div>
<div class="settings-item"> <div class="settings-item">
<p>Current throttled rate limit: <span class="settings-current">{{ config.downloads.throttledratelimit }}</span></p> <p>Current throttled rate limit: <span class="settings-current">{{ config.downloads.throttledratelimit }}</span></p>
<i>Assume the download is being throttled below this speed and restart. 0 (zero) to deactivate, e.g. 100KB/sec</i><br> <i>Assume the download is being throttled below this speed and restart. 0 (zero) to deactivate, e.g. 100KB/sec</i><br>
<input type="number" name="downloads.throttledratelimit" id="downloads.throttledratelimit"><span>KB/sec</span> {{ app_form.downloads_throttledratelimit }}
</div> </div>
<div class="settings-item"> <div class="settings-item">
<p>Current scraping sleep interval: <span class="settings-current">{{ config.downloads.sleep_interval }}</p> <p>Current scraping sleep interval: <span class="settings-current">{{ config.downloads.sleep_interval }}</p>
<i>Seconds to sleep between calls to YouTube. Might be necessary to avoid throttling. Recommended 3.</i><br> <i>Seconds to sleep between calls to YouTube. Might be necessary to avoid throttling. Recommended 3.</i><br>
<input type="number" name="downloads.sleep_interval" id="downloads.sleep_interval"> {{ app_form.downloads_sleep_interval }}
</div> </div>
<div class="settings-item"> <div class="settings-item">
<p>External downloader:</p> <p>External downloader:</p>
@ -82,29 +85,21 @@
<li><span class="settings-current">0</span>: deactivate and download the best quality possible as decided by yt-dlp.</li> <li><span class="settings-current">0</span>: deactivate and download the best quality possible as decided by yt-dlp.</li>
</ul> </ul>
<i>Make sure your custom format gets merged into a single file. Check out the <a href="https://github.com/yt-dlp/yt-dlp#format-selection" target="_blank">documentation</a> for valid configurations.</i><br> <i>Make sure your custom format gets merged into a single file. Check out the <a href="https://github.com/yt-dlp/yt-dlp#format-selection" target="_blank">documentation</a> for valid configurations.</i><br>
<input type="text" name="downloads.format" id="downloads.format"> {{ app_form.downloads_format }}
<br> <br>
</div> </div>
<div class="settings-item"> <div class="settings-item">
<p>Current metadata embed setting: <span class="settings-current">{{ config.downloads.add_metadata }}</span></p> <p>Current metadata embed setting: <span class="settings-current">{{ config.downloads.add_metadata }}</span></p>
<i>Metadata is not embedded into the downloaded files by default.</i><br> <i>Metadata is not embedded into the downloaded files by default.</i><br>
<select name="downloads.add_metadata" id="downloads.add_metadata""> {{ app_form.downloads_add_metadata }}
<option value="" disabled selected> -- change metadata embed -- </option>
<option value="0">don't embed metadata</option>
<option value="1">embed metadata</option>
</select>
</div> </div>
<div class="settings-item"> <div class="settings-item">
<p>Current thumbnail embed setting: <span class="settings-current">{{ config.downloads.add_thumbnail }}</span></p> <p>Current thumbnail embed setting: <span class="settings-current">{{ config.downloads.add_thumbnail }}</span></p>
<i>Embed thumbnail into the mediafile.</i><br> <i>Embed thumbnail into the mediafile.</i><br>
<select name="downloads.add_thumbnail" id="downloads.add_thumbnail""> {{ app_form.downloads_add_thumbnail }}
<option value="" disabled selected> -- change thumbnail embed -- </option>
<option value="0">don't embed thumbnail</option>
<option value="1">embed thumbnail</option>
</select>
</div> </div>
</div> </div>
<button type="submit">Update Settings</button> <button type="submit" name="application-settings">Update Application Configurations</button>
</form> </form>
<div class="title-bar"> <div class="title-bar">
<h1>Actions</h1> <h1>Actions</h1>

View File

@ -11,7 +11,6 @@ from time import sleep
from django import forms from django import forms
from django.contrib.auth import login from django.contrib.auth import login
from django.contrib.auth.forms import AuthenticationForm from django.contrib.auth.forms import AuthenticationForm
from django.forms.widgets import PasswordInput, TextInput
from django.http import JsonResponse from django.http import JsonResponse
from django.shortcuts import redirect, render from django.shortcuts import redirect, render
from django.utils.http import urlencode from django.utils.http import urlencode
@ -21,6 +20,11 @@ from home.src.download import ChannelSubscription, PendingList
from home.src.helper import RedisArchivist, RedisQueue, process_url_list from home.src.helper import RedisArchivist, RedisQueue, process_url_list
from home.src.index import WatchState, YoutubeChannel, YoutubeVideo from home.src.index import WatchState, YoutubeChannel, YoutubeVideo
from home.src.searching import Pagination, SearchForm, SearchHandler from home.src.searching import Pagination, SearchForm, SearchHandler
from home.forms import (
ApplicationSettingsForm,
CustomAuthForm,
UserSettingsForm
)
from home.tasks import ( from home.tasks import (
download_pending, download_pending,
download_single, download_single,
@ -44,7 +48,8 @@ class HomeView(View):
def get(self, request): def get(self, request):
"""return home search results""" """return home search results"""
view_config = self.read_config(user_id=request.user.id) user_id = request.user.id
view_config = self.read_config(user_id)
# handle search # handle search
search_get = request.GET.get("search", False) search_get = request.GET.get("search", False)
if search_get: if search_get:
@ -53,7 +58,9 @@ class HomeView(View):
search_encoded = False search_encoded = False
# define page size # define page size
page_get = int(request.GET.get("page", 0)) page_get = int(request.GET.get("page", 0))
pagination_handler = Pagination(page_get, search_encoded) pagination_handler = Pagination(
page_get, user_id, search_get=search_encoded
)
url = self.ES_URL + "/ta_video/_search" url = self.ES_URL + "/ta_video/_search"
data = self.build_data( data = self.build_data(
@ -157,17 +164,6 @@ class HomeView(View):
return redirect(search_url, permanent=True) return redirect(search_url, permanent=True)
class CustomAuthForm(AuthenticationForm):
"""better styled login form"""
username = forms.CharField(
widget=TextInput(attrs={"placeholder": "Username"}), label=False
)
password = forms.CharField(
widget=PasswordInput(attrs={"placeholder": "Password"}), label=False
)
class LoginView(View): class LoginView(View):
"""resolves to /login/ """resolves to /login/
Greeting and login page Greeting and login page
@ -222,10 +218,11 @@ class DownloadView(View):
def get(self, request): def get(self, request):
"""handle get requests""" """handle get requests"""
view_config = self.read_config(user_id=request.user.id) user_id = request.user.id
view_config = self.read_config(user_id)
page_get = int(request.GET.get("page", 0)) page_get = int(request.GET.get("page", 0))
pagination_handler = Pagination(page_get) pagination_handler = Pagination(page_get, user_id)
url = view_config["es_url"] + "/ta_download/_search" url = view_config["es_url"] + "/ta_download/_search"
data = self.build_data( data = self.build_data(
@ -370,7 +367,7 @@ class ChannelIdView(View):
def get_channel_videos(self, request, channel_id_detail, view_config): def get_channel_videos(self, request, channel_id_detail, view_config):
"""get channel from video index""" """get channel from video index"""
page_get = int(request.GET.get("page", 0)) page_get = int(request.GET.get("page", 0))
pagination_handler = Pagination(page_get) pagination_handler = Pagination(page_get, request.user.id)
# get data # get data
url = view_config["es_url"] + "/ta_video/_search" url = view_config["es_url"] + "/ta_video/_search"
data = self.build_data( data = self.build_data(
@ -465,7 +462,7 @@ class ChannelView(View):
user_id = request.user.id user_id = request.user.id
view_config = self.read_config(user_id=user_id) view_config = self.read_config(user_id=user_id)
page_get = int(request.GET.get("page", 0)) page_get = int(request.GET.get("page", 0))
pagination_handler = Pagination(page_get) pagination_handler = Pagination(page_get, user_id)
page_size = pagination_handler.pagination["page_size"] page_size = pagination_handler.pagination["page_size"]
page_from = pagination_handler.pagination["page_from"] page_from = pagination_handler.pagination["page_from"]
# get # get
@ -610,18 +607,35 @@ class SettingsView(View):
config = AppConfig().config config = AppConfig().config
colors = config["application"]["colors"] colors = config["application"]["colors"]
context = {"title": "Settings", "config": config, "colors": colors} user_form = UserSettingsForm()
app_form = ApplicationSettingsForm()
context = {
"title": "Settings",
"config": config,
"colors": colors,
"user_form": user_form,
"app_form": app_form,
}
return render(request, "home/settings.html", context) return render(request, "home/settings.html", context)
@staticmethod @staticmethod
def post(request): def post(request):
"""handle form post to update settings""" """handle form post to update settings"""
form_response = forms.Form(request.POST)
if form_response.is_valid():
form_post = dict(request.POST) form_post = dict(request.POST)
del form_post["csrfmiddlewaretoken"]
print(form_post) print(form_post)
del form_post["csrfmiddlewaretoken"]
config_handler = AppConfig() config_handler = AppConfig()
if "application-settings" in form_post:
del form_post["application-settings"]
config_handler.update_config(form_post) config_handler.update_config(form_post)
elif "user-settings" in form_post:
del form_post["user-settings"]
config_handler.set_user_config(form_post, request.user.id)
return redirect("settings", permanent=True) return redirect("settings", permanent=True)