From 39c1eb80dcb0cb6951ce42da80038412a111c579 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 3 Oct 2023 04:37:34 +0000 Subject: [PATCH 01/26] Bump urllib3 from 1.26.5 to 1.26.17 Bumps [urllib3](https://github.com/urllib3/urllib3) from 1.26.5 to 1.26.17. - [Release notes](https://github.com/urllib3/urllib3/releases) - [Changelog](https://github.com/urllib3/urllib3/blob/main/CHANGES.rst) - [Commits](https://github.com/urllib3/urllib3/compare/1.26.5...1.26.17) --- updated-dependencies: - dependency-name: urllib3 dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 09891ff415..ecee6485b0 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,7 +7,7 @@ django-modeltranslation==0.18.7 django-cas-client==1.5.3 ldap3==2.9 django-simple-captcha==0.5.17 -urllib3==1.26.5 +urllib3==1.26.17 elasticsearch==6.3.1 djangorestframework==3.14.0 django-filter==22.1 From 483ca6fefcd77d72bceb9b77aaf0efe5af59a5e7 Mon Sep 17 00:00:00 2001 From: Ptitloup Date: Tue, 3 Oct 2023 10:54:20 +0200 Subject: [PATCH 02/26] [DONE] Use cache to store video data (#969) * Use cache to store video data - get it in context - create command to store video data * change name of video context processor * add some pydoc * update cache timeout to 600 seconds - use DRY and call context cache video data instead of repeat code * use delete many to clear cache --- pod/settings.py | 2 +- pod/video/context_processors.py | 74 +++++++++++-------- .../management/commands/cache_video_data.py | 28 +++++++ 3 files changed, 73 insertions(+), 31 deletions(-) create mode 100644 pod/video/management/commands/cache_video_data.py diff --git a/pod/settings.py b/pod/settings.py index 39f0867b10..00a1179592 100644 --- a/pod/settings.py +++ b/pod/settings.py @@ -117,7 +117,7 @@ # Local contexts "pod.main.context_processors.context_settings", "pod.main.context_processors.context_footer", - "pod.video.context_processors.context_navbar", + "pod.video.context_processors.context_video_data", "pod.video.context_processors.context_video_settings", "pod.authentication.context_processors.context_authentication_settings", "pod.recorder.context_processors.context_recorder_settings", diff --git a/pod/video/context_processors.py b/pod/video/context_processors.py index f76f2e337b..c0bc18a2b4 100644 --- a/pod/video/context_processors.py +++ b/pod/video/context_processors.py @@ -10,6 +10,7 @@ from django.db.models import OuterRef from datetime import timedelta +from django.core.cache import cache from django.contrib.sites.shortcuts import get_current_site from pod.video_encode_transcript.models import EncodingVideo from pod.video_encode_transcript.models import PlaylistVideo @@ -19,7 +20,7 @@ HIDE_USER_FILTER = getattr(django_settings, "HIDE_USER_FILTER", False) OEMBED = getattr(django_settings, "OEMBED", False) USE_STATS_VIEW = getattr(django_settings, "USE_STATS_VIEW", False) - +CACHE_VIDEO_DEFAULT_TIMEOUT = getattr(django_settings, "CACHE_VIDEO_DEFAULT_TIMEOUT", 600) __AVAILABLE_VIDEO_FILTER__ = { "encoding_in_progress": False, "is_draft": False, @@ -78,37 +79,50 @@ def context_video_settings(request): return new_settings -def context_navbar(request): - types = ( - Type.objects.filter( - sites=get_current_site(request), - video__is_draft=False, - video__sites=get_current_site(request), +def context_video_data(request): + """Get video data in cache, if not, create and add it in cache.""" + types = cache.get('TYPES') + if types is None: + types = ( + Type.objects.filter( + sites=get_current_site(request), + video__is_draft=False, + video__sites=get_current_site(request), + ) + .distinct() + .annotate(video_count=Count("video", distinct=True)) ) - .distinct() - .annotate(video_count=Count("video", distinct=True)) - ) - - disciplines = ( - Discipline.objects.filter( - site=get_current_site(request), - video__is_draft=False, - video__sites=get_current_site(request), + cache.set("TYPES", types, timeout=CACHE_VIDEO_DEFAULT_TIMEOUT) + + disciplines = cache.get('DISCIPLINES') + if disciplines is None: + disciplines = ( + Discipline.objects.filter( + site=get_current_site(request), + video__is_draft=False, + video__sites=get_current_site(request), + ) + .distinct() + .annotate(video_count=Count("video", distinct=True)) ) - .distinct() - .annotate(video_count=Count("video", distinct=True)) - ) - - v_filter = get_available_videos_filter(request) - - aggregate_videos = v_filter.aggregate(duration=Sum("duration"), number=Count("id")) - - VIDEOS_COUNT = aggregate_videos["number"] - VIDEOS_DURATION = ( - str(timedelta(seconds=aggregate_videos["duration"])) - if aggregate_videos["duration"] - else 0 - ) + cache.set("DISCIPLINES", disciplines, timeout=CACHE_VIDEO_DEFAULT_TIMEOUT) + + VIDEOS_COUNT = cache.get('VIDEOS_COUNT') + VIDEOS_DURATION = cache.get('VIDEOS_DURATION') + if VIDEOS_COUNT is None: + v_filter = get_available_videos_filter(request) + aggregate_videos = v_filter.aggregate( + duration=Sum("duration"), + number=Count("id") + ) + VIDEOS_COUNT = aggregate_videos["number"] + cache.set("VIDEOS_COUNT", VIDEOS_COUNT, timeout=CACHE_VIDEO_DEFAULT_TIMEOUT) + VIDEOS_DURATION = ( + str(timedelta(seconds=aggregate_videos["duration"])) + if aggregate_videos["duration"] + else 0 + ) + cache.set("VIDEOS_DURATION", VIDEOS_DURATION, timeout=CACHE_VIDEO_DEFAULT_TIMEOUT) return { "TYPES": types, diff --git a/pod/video/management/commands/cache_video_data.py b/pod/video/management/commands/cache_video_data.py new file mode 100644 index 0000000000..9e7a7c33dc --- /dev/null +++ b/pod/video/management/commands/cache_video_data.py @@ -0,0 +1,28 @@ +from django.core.management.base import BaseCommand +from django.core.cache import cache +from pod.video.context_processors import context_video_data +from django.core import serializers +import json + + +class Command(BaseCommand): + """Command to store video data in cache.""" + help = "Store video data in django cache : " \ + + "types, discipline, video count and videos duration" + + def handle(self, *args, **options): + """Function called to store video data in cache.""" + cache.delete_many(['DISCIPLINES', 'VIDEOS_COUNT', 'VIDEOS_DURATION', 'TYPES']) + video_data = context_video_data(request=None) + msg = 'Successfully store video data in cache' + for data in video_data: + try: + msg += "\n %s : %s" % ( + data, + json.dumps(serializers.serialize("json", video_data[data])) + ) + except (TypeError, AttributeError): + msg += "\n %s : %s" % (data, video_data[data]) + self.stdout.write( + self.style.SUCCESS(msg) + ) From cf8f2579e0e5412dba14aadb3f54eca00b422de5 Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 3 Oct 2023 08:54:54 +0000 Subject: [PATCH 03/26] Fixup. Format code with Black --- pod/video/context_processors.py | 11 +++++------ pod/video/management/commands/cache_video_data.py | 15 ++++++++------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/pod/video/context_processors.py b/pod/video/context_processors.py index c0bc18a2b4..9a5aeca9dd 100644 --- a/pod/video/context_processors.py +++ b/pod/video/context_processors.py @@ -81,7 +81,7 @@ def context_video_settings(request): def context_video_data(request): """Get video data in cache, if not, create and add it in cache.""" - types = cache.get('TYPES') + types = cache.get("TYPES") if types is None: types = ( Type.objects.filter( @@ -94,7 +94,7 @@ def context_video_data(request): ) cache.set("TYPES", types, timeout=CACHE_VIDEO_DEFAULT_TIMEOUT) - disciplines = cache.get('DISCIPLINES') + disciplines = cache.get("DISCIPLINES") if disciplines is None: disciplines = ( Discipline.objects.filter( @@ -107,13 +107,12 @@ def context_video_data(request): ) cache.set("DISCIPLINES", disciplines, timeout=CACHE_VIDEO_DEFAULT_TIMEOUT) - VIDEOS_COUNT = cache.get('VIDEOS_COUNT') - VIDEOS_DURATION = cache.get('VIDEOS_DURATION') + VIDEOS_COUNT = cache.get("VIDEOS_COUNT") + VIDEOS_DURATION = cache.get("VIDEOS_DURATION") if VIDEOS_COUNT is None: v_filter = get_available_videos_filter(request) aggregate_videos = v_filter.aggregate( - duration=Sum("duration"), - number=Count("id") + duration=Sum("duration"), number=Count("id") ) VIDEOS_COUNT = aggregate_videos["number"] cache.set("VIDEOS_COUNT", VIDEOS_COUNT, timeout=CACHE_VIDEO_DEFAULT_TIMEOUT) diff --git a/pod/video/management/commands/cache_video_data.py b/pod/video/management/commands/cache_video_data.py index 9e7a7c33dc..b2d386a207 100644 --- a/pod/video/management/commands/cache_video_data.py +++ b/pod/video/management/commands/cache_video_data.py @@ -7,22 +7,23 @@ class Command(BaseCommand): """Command to store video data in cache.""" - help = "Store video data in django cache : " \ + + help = ( + "Store video data in django cache : " + "types, discipline, video count and videos duration" + ) def handle(self, *args, **options): """Function called to store video data in cache.""" - cache.delete_many(['DISCIPLINES', 'VIDEOS_COUNT', 'VIDEOS_DURATION', 'TYPES']) + cache.delete_many(["DISCIPLINES", "VIDEOS_COUNT", "VIDEOS_DURATION", "TYPES"]) video_data = context_video_data(request=None) - msg = 'Successfully store video data in cache' + msg = "Successfully store video data in cache" for data in video_data: try: msg += "\n %s : %s" % ( data, - json.dumps(serializers.serialize("json", video_data[data])) + json.dumps(serializers.serialize("json", video_data[data])), ) except (TypeError, AttributeError): msg += "\n %s : %s" % (data, video_data[data]) - self.stdout.write( - self.style.SUCCESS(msg) - ) + self.stdout.write(self.style.SUCCESS(msg)) From 7a45f880e08dd6ed15cd68a620b416cdd12ed603 Mon Sep 17 00:00:00 2001 From: Ptitloup Date: Tue, 3 Oct 2023 15:01:51 +0200 Subject: [PATCH 04/26] [DONE] add configuration_fr.md (#975) --- CONFIGURATION_FR.md | 2752 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 2752 insertions(+) create mode 100644 CONFIGURATION_FR.md diff --git a/CONFIGURATION_FR.md b/CONFIGURATION_FR.md new file mode 100644 index 0000000000..ceedd88995 --- /dev/null +++ b/CONFIGURATION_FR.md @@ -0,0 +1,2752 @@ + +# Configuration de la plateforme Esup-Pod + + +## Information générale + + +La plateforme Esup-Pod se base sur le framework Django écrit en Python.
+Elle supporte les versions 3.7, 3.8 et 3.9 de Python.
+ +**Django Version : 3.2 LTS**
+ +> La documentation complète du framework : [https://docs.djangoproject.com/fr/3.2/]() (ou [https://docs.djangoproject.com/en/3.2/]())

+> L’ensemble des variables de configuration du framework est accessible à cette adresse : [https://docs.djangoproject.com/fr/3.2/ref/settings/]()
+ +Voici les configurations des applications tierces utilisées par Esup-Pod.
+ + + - `CAS` + + > valeur par défaut : `1.5.2` + + >> Système d’authentification SSO_CAS
+ >> [https://github.com/kstateome/django-cas]()
+ + - `ModelTransalation` + + > valeur par défaut : `0.18.7` + + >> L’application modeltranslation est utilisée pour traduire le contenu dynamique des modèles Django existants
+ >> [https://django-modeltranslation.readthedocs.io/en/latest/installation.html#configuration]()
+ + - `captcha` + + > valeur par défaut : `0.5.17` + + >> Gestion du captcha du formulaire de contact
+ >> [https://django-simple-captcha.readthedocs.io/en/latest/usage.html]()
+ + - `chunked_upload` + + > valeur par défaut : `2.0.0` + + >> Envoi de fichier par morceaux // voir pour mettre à jour si nécessaire
+ >> [https://github.com/juliomalegria/django-chunked-upload]()
+ + - `ckeditor` + + > valeur par défaut : `6.3.0` + + >> Application permettant d’ajouter un éditeur CKEditor dans certains champs
+ >> [https://django-ckeditor.readthedocs.io/en/latest/#installation]()
+ + - `django_select2` + + > valeur par défaut : `latest` + + >> Recherche et completion dans les formulaires
+ >> [https://django-select2.readthedocs.io/en/latest/]()
+ + - `honeypot` + + > valeur par défaut : `1.0.3` + + >> Utilisé pour le formulaire de contact de Pod - ajoute un champ caché pour diminuer le spam
+ >> [https://github.com/jamesturk/django-honeypot/]()
+ + - `mozilla_django_oidc` + + > valeur par défaut : `3.0.0` + + >> Système d’authentification OpenID Connect
+ >> [https://mozilla-django-oidc.readthedocs.io/en/stable/installation.html]()
+ + - `rest_framework` + + > valeur par défaut : `3.14.0` + + >> version 3.14.0: mise en place de l’API rest pour l’application
+ >> [https://www.django-rest-framework.org/]()
+ + - `shibboleth` + + > valeur par défaut : `latest` + + >> Système d’authentification Shibboleth
+ >> [https://github.com/Brown-University-Library/django-shibboleth-remoteuser]()
+ + - `sorl.thumbnail` + + > valeur par défaut : `12.9.0` + + >> Utilisée pour la génération de miniature des images
+ >> [https://sorl-thumbnail.readthedocs.io/en/latest/reference/settings.html]()
+ + - `tagging` + + > valeur par défaut : `0.5.0` + + >> Gestion des mots-clés associés à une vidéo // voir pour référencer une nouvelle application
+ >> [https://django-tagging.readthedocs.io/en/develop/#settings]()
+ +## Configuration Générale de la plateforme Esup_Pod + + +### Base de données + + - `DATABASES` + + > valeur par défaut : + + ```python + { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), + } + } + ``` + + >> Un dictionnaire contenant les réglages de toutes les bases de données à utiliser avec Django.
+ >> C’est un dictionnaire imbriqué dont les contenus font correspondre l’alias de base de données avec un dictionnaire contenant les options de chacune des bases de données.
+ >> __ref: [https://docs.djangoproject.com/fr/3.2/ref/settings/#databases]()__
+ >> valeur par défaut : une base de données au format sqlite
+ >> Voici un exemple de configuration pour utiliser une base MySQL :
+ >> + >> ``` + >> DATABASES = { + >> 'default': { + >> 'ENGINE': 'django.db.backends.mysql', + >> 'NAME': 'pod', + >> 'USER': 'pod', + >> 'PASSWORD': 'password', + >> 'HOST': 'mysql.univ.fr', + >> 'PORT': '3306', + >> 'OPTIONS': { + >> 'init_command': "SET storage_engine=INNODB, sql_mode='STRICT_TRANS_TABLES', innodb_strict_mode=1, foreign_key_checks = 1", + >> }, + >> } + >> } + >> + >> ``` + +### Courriel + + - `CONTACT_US_EMAIL` + + > valeur par défaut : `` + + >> Liste des adresses destinataires des courriels de contact
+ + - `CUSTOM_CONTACT_US` + + > valeur par défaut : `False` + + >> Si 'True', les e-mails de contacts seront adressés, selon le sujet,
+ >> soit au propriétaire de la vidéo soit au(x) manager(s) des vidéos Pod.
+ >> (voir `USER_CONTACT_EMAIL_CASE` et `USE_ESTABLISHMENT_FIELD`)
+ + - `DEFAULT_FROM_EMAIL` + + > valeur par défaut : `noreply` + + >> Expediteur par défaut pour les envois de courriel (contact, encodage etc.)
+ + - `EMAIL_HOST` + + > valeur par défaut : `smtp.univ.fr` + + >> nom du serveur smtp
+ >> _ref: [https://docs.djangoproject.com/fr/3.2/ref/settings/#email-host]()_
+ + - `EMAIL_PORT` + + > valeur par défaut : `25` + + >> Port d’écoute du serveur SMTP.
+ + - `EMAIL_SUBJECT_PREFIX` + + > valeur par défaut : `` + + >> Préfixe par défaut pour l’objet des courriels.
+ + - `SERVER_EMAIL` + + > valeur par défaut : `noreply` + + >> Expediteur par défaut pour les envois automatique (erreur de code etc.)
+ + - `SUBJECT_CHOICES` + + > valeur par défaut : `()` + + >> Choix de sujet pour les courriels envoyés depuis la plateforme
+ >> + >> ``` + >> SUBJECT_CHOICES = ( + >> ('', '-----'), + >> ('info', ('Request more information')), + >> ('contribute', ('Learn more about how to contribute')), + >> ('request_password', ('Password request for a video')), + >> ('inappropriate_content', ('Report inappropriate content')), + >> ('bug', ('Correction or bug report')), + >> ('other', ('Other (please specify)')) + >> ) + >> + >> ``` + + - `SUPPORT_EMAIL` + + > valeur par défaut : `None` + + >> Liste de destinataire(s) pour les demandes d’assistance, si différent de `CONTACT_US_EMAIL`
+ >> i.e.: `SUPPORT_EMAIL = ["assistance_pod@univ.fr"]`
+ + - `USER_CONTACT_EMAIL_CASE` + + > valeur par défaut : `` + + >> Une liste contenant les sujets de contact dont l’utilisateur
+ >> sera seul destinataire plutôt que le(s) manager(s).
+ >> Si la liste est vide, les mails de contact seront envoyés au(x) manager(s).
+ >> Valeurs possibles :
+ >> `info`, `contribute`, `request_password`,
+ >> `inapropriate_content`, `bug`, `other
+ + - `USE_ESTABLISHMENT_FIELD` + + > valeur par défaut : `False` + + >> Si valeur vaut 'True', rajoute un attribut 'establishment'
+ >> à l’utilisateur Pod, ce qui permet de gérer plus d’un établissement.
+ >> Dans ce cas, les emails de contact par exemple seront envoyés
+ >> soit à l’utilisateur soit au(x) manager(s)
+ >> de l’établissement de l’utilisateur.
+ >> (voir `USER_CONTACT_EMAIL_CASE`)
+ >> Également, les emails de fin d’encodage seront envoyés au(x) manager(s)
+ >> de l’établissement du propriétaire de la vidéo encodée,
+ >> en plus d’un email au propriétaire confirmant la fin d’encodage d’une vidéo.
+ +### Encodage + + - `FFMPEG_AUDIO_BITRATE` + + > valeur par défaut : `192k` + + + + - `FFMPEG_CMD` + + > valeur par défaut : `ffmpeg` + + + + - `FFMPEG_CREATE_THUMBNAIL` + + > valeur par défaut : `-vf "fps=1/(%(duration)s/%(nb_thumbnail)s)" -vsync vfr "%(output)s_%%04d.png"` + + + + - `FFMPEG_CRF` + + > valeur par défaut : `20` + + + + - `FFMPEG_EXTRACT_SUBTITLE` + + > valeur par défaut : `-map 0:%(index)s -f webvtt -y "%(output)s" ` + + + + - `FFMPEG_EXTRACT_THUMBNAIL` + + > valeur par défaut : `-map 0:%(index)s -an -c:v copy -y "%(output)s" ` + + + + - `FFMPEG_HLS_COMMON_PARAMS` + + > valeur par défaut : `-c:v %(libx)s -preset %(preset)s -profile:v %(profile)s -pix_fmt yuv420p -level %(level)s -crf %(crf)s -sc_threshold 0 -force_key_frames "expr:gte(t,n_forced*1)" -c:a aac -ar 48000 -max_muxing_queue_size 4000 ` + + + + - `FFMPEG_HLS_ENCODE_PARAMS` + + > valeur par défaut : `-vf "scale=-2:%(height)s" -maxrate %(maxrate)s -bufsize %(bufsize)s -b:a:0 %(ba)s -hls_playlist_type vod -hls_time %(hls_time)s -hls_flags single_file -master_pl_name "livestream%(height)s.m3u8" -y "%(output)s" ` + + + + - `FFMPEG_HLS_TIME` + + > valeur par défaut : `2` + + + + - `FFMPEG_INPUT` + + > valeur par défaut : `-hide_banner -threads %(nb_threads)s -i "%(input)s" ` + + + + - `FFMPEG_LEVEL` + + > valeur par défaut : `3` + + + + - `FFMPEG_LIBX` + + > valeur par défaut : `libx264` + + + + - `FFMPEG_M4A_ENCODE` + + > valeur par défaut : `-vn -c:a aac -b:a %(audio_bitrate)s "%(output)s" ` + + + + - `FFMPEG_MP3_ENCODE` + + > valeur par défaut : `-vn -codec:a libmp3lame -qscale:a 2 -y "%(output)s" ` + + + + - `FFMPEG_MP4_ENCODE` + + > valeur par défaut : `-map 0:v:0 %(map_audio)s -c:v %(libx)s -vf "scale=-2:%(height)s" -preset %(preset)s -profile:v %(profile)s -pix_fmt yuv420p -level %(level)s -crf %(crf)s -maxrate %(maxrate)s -bufsize %(bufsize)s -sc_threshold 0 -force_key_frames "expr:gte(t,n_forced*1)" -max_muxing_queue_size 4000 -c:a aac -ar 48000 -b:a %(ba)s -movflags faststart -y -vsync 0 "%(output)s" ` + + + + - `FFMPEG_NB_THREADS` + + > valeur par défaut : `0` + + + + - `FFMPEG_NB_THUMBNAIL` + + > valeur par défaut : `3` + + + + - `FFMPEG_PRESET` + + > valeur par défaut : `slow` + + + + - `FFMPEG_PROFILE` + + > valeur par défaut : `high` + + + + - `FFMPEG_STUDIO_COMMAND` + + > valeur par défaut : ` -hide_banner -threads %(nb_threads)s %(input)s %(subtime)s -c:a aac -ar 48000 -c:v h264 -profile:v high -pix_fmt yuv420p -crf %(crf)s -sc_threshold 0 -force_key_frames "expr:gte(t,n_forced*1)" -max_muxing_queue_size 4000 -deinterlace ` + + + + - `FFPROBE_CMD` + + > valeur par défaut : `ffprobe` + + + + - `FFPROBE_GET_INFO` + + > valeur par défaut : `%(ffprobe)s -v quiet -show_format -show_streams %(select_streams)s -print_format json -i %(source)s` + + + +### Gestion des fichiers + + + - `FILES_DIR` + + > valeur par défaut : `files` + + >> Nom du répertoire racine où les fichiers "complémentaires"
+ >> (hors vidéos etc.) sont téléversés. Notament utilisé par PODFILE
+ >> À modifier principalement pour indiquer dans LOCATION votre serveur de cache si elle n’est pas sur la même machine que votre POD.
+ + - `FILE_UPLOAD_TEMP_DIR` + + > valeur par défaut : `/var/tmp` + + >> Le répertoire dans lequel stocker temporairement les données (typiquement pour les fichiers plus grands que `FILE_UPLOAD_MAX_MEMORY_SIZE`) lors des téléversements de fichiers.

+ >> _ref: [https://docs.djangoproject.com/fr/3.2/ref/settings/#file-upload-temp-dir]()_
+ + - `MEDIA_ROOT` + + > valeur par défaut : `/pod/media` + + >> Chemin absolu du système de fichiers pointant vers le répertoire qui contiendra les fichiers téléversés par les utilisateurs.

+ >> Attention, ce répertoire doit exister

+ >> _ref: [https://docs.djangoproject.com/fr/3.2/ref/settings/#std:setting-MEDIA_ROOT]()_
+ + - `MEDIA_URL` + + > valeur par défaut : `/media/` + + >> prefix url utilisé pour accéder aux fichiers du répertoire media
+ + - `STATICFILES_STORAGE` + + > valeur par défaut : `` + + >> Indique à django de compresser automatiquement les fichiers css/js les plus gros lors du collectstatic pour optimiser les tailles de requetes.

+ >> À combiner avec un réglage webserver (`gzip_static on;` sur nginx)

+ >> _ref: [https://github.com/whs/django-static-compress]()
+ + - `STATIC_ROOT` + + > valeur par défaut : `/pod/static` + + >> Le chemin absolu vers le répertoire dans lequel collectstatic rassemble les fichiers statiques en vue du déploiement. Ce chemin sera précisé dans le fichier de configurtation du vhost nginx.

+ >> _ref: [https://docs.djangoproject.com/fr/3.2/ref/settings/#std:setting-STATIC_ROOT]()_
+ + - `STATIC_URL` + + > valeur par défaut : `/static/` + + >> prefix url utilisé pour accèder aux fichiers static
+ + - `USE_PODFILE` + + > valeur par défaut : `False` + + >> Utiliser l’application de gestion de fichier fourni avec le projet.
+ >> Si False, chaque fichier envoyé ne pourra être utilisé qu’une seule fois.
+ + - `VIDEOS_DIR` + + > valeur par défaut : `videos` + + >> Répertoire par défaut pour le téléversement des vidéos.
+ +### Langue +Par défaut, Esup-Pod est fournie en Francais et en anglais.
+Vous pouvez tout à fait rajouter des langues comme vous le souhaitez. Il faudra pour cela créer un fichier de langue et traduire chaque entrée.
+ + - `LANGUAGES` + + > valeur par défaut : `(('fr', 'Français'), ('en', 'English')))` + + >> Langue disponible et traduite
+ + - `LANGUAGE_CODE` + + > valeur par défaut : `fr` + + >> Langue par défaut si non détectée
+ +### Divers + + - `ADMINS` + + > valeur par défaut : `[("Name", "adminmail@univ.fr"),]` + + >> Une liste de toutes les personnes qui reçoivent les notifications d’erreurs dans le code.

+ >> Lorsque DEBUG=False et qu’une vue lève une exception, Django envoie un courriel à ces personnes contenant les informations complètes de l’exception.

+ >> Chaque élément de la liste doit être un tuple au format « (nom complet, adresse électronique) ».

+ >> Exemple : `[('John', 'john@example.com'), ('Mary', 'mary@example.com')]`

+ >> Dans Pod, les "admins" sont également destinataires des courriels de contact, d’encodage ou de flux RSS si la variable `CONTACT_US_EMAIL` n’est pas renseignée.

+ >> __ref: [https://docs.djangoproject.com/fr/3.2/ref/settings/#admins]()__
+ + - `ALLOWED_HOSTS` + + > valeur par défaut : `['localhost']` + + >> Une liste de chaînes représentant des noms de domaine/d’hôte que ce site Django peut servir.

+ >> C’est une mesure de sécurité pour empêcher les attaques d’en-tête Host HTTP, qui sont possibles même avec bien des configurations de serveur Web apparemment sécurisées.

+ >> __ref: [https://docs.djangoproject.com/fr/3.2/ref/settings/#allowed-hosts]()__
+ + - `BASE_DIR` + + > valeur par défaut : `os.path.dirname(os.path.dirname(os.path.abspath(__file__)))` + + >> répertoire de base
+ + - `CACHES` + + > valeur par défaut : `{}` + + >> + >> ```python + >> CACHES = { + >> # … default cache config and others + >> # "default": { + >> # "BACKEND": "django.core.cache.backends.locmem.LocMemCache", + >> # }, + >> "default": { + >> "BACKEND": "django_redis.cache.RedisCache", + >> "LOCATION": "redis://127.0.0.1:6379/1", + >> "OPTIONS": { + >> "CLIENT_CLASS": "django_redis.client.DefaultClient", + >> }, + >> }, + >> # Persistent cache setup for select2 (NOT DummyCache or LocMemCache). + >> "select2": { + >> "BACKEND": "django_redis.cache.RedisCache", + >> "LOCATION": "redis://127.0.0.1:6379/2", + >> "OPTIONS": { + >> "CLIENT_CLASS": "django_redis.client.DefaultClient", + >> }, + >> }, + >> } + >> + >> ``` + + - `CSRF_COOKIE_SECURE` + + > valeur par défaut : ` not DEBUG` + + >> Ces 3 variables servent à sécuriser la plateforme en passant l’ensemble des requetes en https. Idem pour les cookies de session et de cross-sites qui seront également sécurisés

+ >> Il faut les passer à False en cas d’usage du runserver (phase de développement / debugage)

+ >> __ref: [https://docs.djangoproject.com/fr/3.2/ref/settings/#secure-ssl-redirect]()__
+ + - `DEBUG` + + > valeur par défaut : `True` + + >> Une valeur booléenne qui active ou désactive le mode de débogage.

+ >> Ne déployez jamais de site en production avec le réglage DEBUG activé.

+ >> __ref: [https://docs.djangoproject.com/fr/3.2/ref/settings/#debug]()__
+ + - `LOGIN_URL` + + > valeur par défaut : `/authentication_login/` + + >> url de redirection pour l’authentification de l’utilisateur
+ >> voir : [https://docs.djangoproject.com/fr/3.2/ref/settings/#login-url]()
+ + - `MANAGERS` + + > valeur par défaut : `[]` + + >> Dans Pod, les "managers" sont destinataires des courriels de fin d’encodage (et ainsi des vidéos déposées sur la plateforme).

+ >> Le premier manager renseigné est également contact des flus RSS.

+ >> Ils sont aussi destinataires des courriels de contact si la variable `CONTACT_US_EMAIL` n’est pas renseignée.

+ >> __ref: [https://docs.djangoproject.com/fr/3.2/ref/settings/#managers]()__
+ + - `PROXY_HOST` + + > valeur par défaut : `` + + >> Utilisation du proxy - host
+ + - `PROXY_PORT` + + > valeur par défaut : `` + + >> Utilisation du proxy - port
+ + - `SECRET_KEY` + + > valeur par défaut : `A_CHANGER` + + >> La clé secrète d’une installation Django.

+ >> Elle est utilisée dans le contexte de la signature cryptographique, et doit être définie à une valeur unique et non prédictible.

+ >> Vous pouvez utiliser ce site pour en générer une : [https://djecrety.ir/]()

+ >> __ref: [https://docs.djangoproject.com/fr/3.2/ref/settings/#secret-key]()__
+ + - `SECURE_SSL_REDIRECT` + + > valeur par défaut : `not DEBUG` + + + + - `SESSION_COOKIE_AGE` + + > valeur par défaut : `14400` + + >> _Valeur par défaut : 14400 (secondes, soit 4 heures)_

+ >> L’âge des cookies de sessions, en secondes.
+ + - `SESSION_COOKIE_SAMESITE` + + > valeur par défaut : `Lax` + + >> Cette option empêche le cookie d’être envoyé dans les requêtes inter-sites, ce qui prévient les attaques CSRF et rend impossible certaines méthodes de vol du cookie de session.
+ >> Voir [https://docs.djangoproject.com/en/3.2/ref/settings/#std-setting-SESSION_COOKIE_SAMESITE]()
+ + - `SESSION_COOKIE_SECURE` + + > valeur par défaut : ` not DEBUG` + + + + - `SESSION_EXPIRE_AT_BROWSER_CLOSE` + + > valeur par défaut : `True` + + >> Indique s’il faut que la session expire lorsque l’utilisateur ferme son navigateur.
+ + - `SITE_ID` + + > valeur par défaut : `1` + + >> L’identifiant (nombre entier) du site actuel. Peut être utilisé pour mettre en place une instance multi-tenant et ainsi gérer dans une même base de données du contenu pour plusieurs sites.

+ >> __ref : [https://docs.djangoproject.com/fr/3.2/ref/settings/#site-id]()__
+ + - `TEST_SETTINGS` + + > valeur par défaut : `False` + + >> Permet de vérifier si la configuration de la plateforme est en mode test.
+ + - `THIRD_PARTY_APPS` + + > valeur par défaut : `[]` + + >> Liste des applications tierces accessibles.
+ >> + >> ``` + >> THIRD_PARTY_APPS = ["enrichment", "live"] + >> + >> ``` + + - `TIME_ZONE` + + > valeur par défaut : `UTC` + + >> Une chaîne représentant le fuseau horaire pour cette installation.

+ >> __ref: [https://docs.djangoproject.com/fr/3.2/ref/settings/#std:setting-TIME_ZONE]()__
+ >> Liste des adresses destinataires des courriels de contact
+ +### Obsolescence + + - `ACCOMMODATION_YEARS` + + > valeur par défaut : `{}` + + >> Durée d’obsolescence personnalisée par Affiliation
+ >> + >> ``` + >> ACCOMMODATION_YEARS = { + >> 'affiliate': 1 + >> } + >> + >> ``` + + - `ARCHIVE_OWNER_USERNAME` + + > valeur par défaut : `"archive"` + + >> Nom de l’utilisateur pour l’archivage des vidéos.
+ + - `POD_ARCHIVE_AFFILIATION` + + > valeur par défaut : `[]` + + >> Affiliations pour lesquelles on souhaite archiver la vidéo plutôt que de la supprimer.
+ >> Si l’affiliation du propriétaire est dans cette variable, alors les vidéos sont affectées à un utilisateur précis
+ >> que l’on peut spécifier via le paramètre `ARCHIVE_OWNER_USERNAME`.
+ >> Elles sont mises en mode brouillon et le mot "archived" est ajouté à leur titre.
+ >> Enfin, elles sont également ajoutées à l’ensemble `Vidéo à Supprimer` (accessible via l’interface d’admin).
+ >> + >> ```python + >> POD_ARCHIVE_AFFILIATION = ['faculty', + >> 'staff', + >> 'employee', + >> 'affiliate', + >> 'alum', + >> 'library-walk-in', + >> 'researcher', + >> 'retired', + >> 'emeritus', + >> 'teacher', + >> 'registered-reader', + >> 'member'] + >> + >> ``` + + - `WARN_DEADLINES` + + > valeur par défaut : `[60, 30, 7]` + + >> Liste de jours de délais avant l’obsolescence de la vidéo.
+ >> À chaque délai, le propriétaire reçoit un mail d’avertissement pour éventuellement changer la date d’obsolescence de sa vidéo.
+ +### Modèle + + - `COOKIE_LEARN_MORE` + + > valeur par défaut : `` + + >> Ce paramètre permet d’afficher un lien "En savoir plus"
+ >> sur la boite de dialogue d’information sur l’usage des cookies dans Pod.
+ >> On peut préciser un lien vers les mentions légales ou page DPO.
+ + - `DARKMODE_ENABLED` + + > valeur par défaut : `False` + + >> Activation du mode sombre
+ + - `DYSLEXIAMODE_ENABLED` + + > valeur par défaut : `False` + + >> Activation du mode dyslexie
+ + - `HIDE_CHANNEL_TAB` + + > valeur par défaut : `False` + + >> Si True, permet de cacher l’onglet chaine dans la barre de menu du haut.
+ + - `HIDE_DISCIPLINES` + + > valeur par défaut : `False` + + >> Si True, permet de ne pas afficher les disciplines dans la colonne de droite
+ + - `HIDE_CURSUS` + + > valeur par défaut : `False` + + >> Si True, permet de ne pas afficher les cursus dans la colonne de droite
+ + - `HIDE_LANGUAGE_SELECTOR` + + > valeur par défaut : `False` + + >> Si True, permet de cacher le sélecteur de langue dans le menu du haut.
+ + - `HIDE_SHARE` + + > valeur par défaut : `False` + + >> Si True, permet de ne pas afficher les liens de partage sur les réseaux sociaux dans la colonne de droite.
+ + - `HIDE_TAGS` + + > valeur par défaut : `False` + + >> Si True, permet de ne pas afficher le nuage de mots clés dans la colonne de droite.
+ + - `HIDE_TYPES` + + > valeur par défaut : `False` + + >> si True, permet de ne pas afficher la liste des types dans la colonne de droite
+ + - `HIDE_TYPES_TAB` + + > valeur par défaut : `False` + + >> Si True, permet de cacher l’entrée 'type' dans le menu de navigation.
+ + - `HIDE_USERNAME` + + > valeur par défaut : `False` + + >> Voir description dans authentification
+ >> Si valeur vaut 'True', le username de l’utilisateur ne sera pas visible sur la plate-forme Pod et
+ >> si la valeur vaut 'False' le username sera affiché aux utilisateurs authentifiés. (pour respecter le RGPD)
+ + - `HIDE_USER_FILTER` + + > valeur par défaut : `False` + + >> Si 'True', le filtre des vidéos par utilisateur ne sera plus visible
+ >> si 'False' le filtre sera visible qu’aux personnes authentifiées.
+ >> (pour respecter le RGPD)
+ + - `HIDE_USER_TAB` + + > valeur par défaut : `False` + + >> Si valeur vaut 'True', l’onglet Utilisateur ne sera pas visible
+ >> et si la valeur vaut 'False' l’onglet Utilisateur ne sera visible
+ >> qu’aux personnes authentifiées.
+ >> (pour respecter le RGPD)
+ + - `HOMEPAGE_NB_VIDEOS` + + > valeur par défaut : `12` + + >> Nombre de vidéos à afficher sur la page d’accueil.
+ + - `HOMEPAGE_SHOWS_PASSWORDED` + + > valeur par défaut : `False` + + >> Afficher les vidéos dont l’accès est protégé par mot de passe sur la page d’accueil.
+ + - `HOMEPAGE_SHOWS_RESTRICTED` + + > valeur par défaut : `False` + + >> Afficher les vidéos dont l’accès est protégé par authentification sur la page d’accueil.
+ + - `MENUBAR_HIDE_INACTIVE_OWNERS` + + > valeur par défaut : `True` + + >> Les utilisateurs inactifs ne sont plus affichés dans la barre de menu utilisateur.
+ + - `MENUBAR_SHOW_STAFF_OWNERS_ONLY` + + > valeur par défaut : `False` + + >> Les utilisateurs non staff ne sont plus affichés dans la barre de menu utilisateur.
+ + - `SHIB_NAME` + + > valeur par défaut : `Identify Federation` + + >> Nom de la fédération d’identité utilisée
+ >> Affiché sur le bouton de connexion si l’authentification Shibboleth est utilisée.
+ + - `SHOW_EVENTS_ON_HOMEPAGE` + + > valeur par défaut : `False` + + >> Si True, affiche les prochains évènements sur la page d’accueil.
+ + - `SHOW_ONLY_PARENT_THEMES` + + > valeur par défaut : `False` + + >> Si True, affiche uniquement les thèmes de premier niveau dans l’onglet 'Chaîne'.
+ + - `TEMPLATE_VISIBLE_SETTINGS` + + > valeur par défaut : `{}` + + >> + >> ``` + >> TEMPLATE_VISIBLE_SETTINGS = { + >> # Titre du site. + >> 'TITLE_SITE': 'Pod', + >> + >> # Description du site. + >> 'DESC_SITE': 'L’objectif d’Esup-Pod est de faciliter la mise à disposition de vidéos et ainsi d’encourager son utilisation dans l’enseignement et la recherche.', + >> + >> # Titre de l’établissement. + >> 'TITLE_ETB': 'University name', + >> + >> # Logo affiché en haut à gauche sur toutes les pages. + >> # Doit se situer dans le répertoire static + >> 'LOGO_SITE': 'img/logoPod.svg', + >> + >> # Logo affiché dans le footer sur toutes les pages. + >> # Doit se situer dans le répertoire static + >> 'LOGO_ETB': 'img/esup-pod.svg', + >> + >> # Logo affiché sur le player video. + >> # Doit se situer dans le répertoire static + >> 'LOGO_PLAYER': 'img/pod_favicon.svg', + >> + >> # Lien de destination du logo affiché sur le player. + >> 'LINK_PLAYER': '', + >> + >> # Intitulé de la page de redirection du logo affiché sur le player. + >> 'LINK_PLAYER_NAME': _('Home'), + >> + >> # Texte affiché dans le footer. Une ligne par entrée, accepte du code html. + >> # Par exemple : + >> # ( '42, rue Paul Duez', + >> # '59000 Lille - France', + >> # ('> # ' target="_blank">Google maps') ) + >> 'FOOTER_TEXT': ('',), + >> + >> # Icone affichée dans la barre d'adresse du navigateur + >> 'FAVICON': 'img/pod_favicon.svg', + >> + >> # Si souhaitée, à créer et sauvegarder + >> # dans le répertoire static de l'application custom et + >> # préciser le chemin d'accès. Par exemple : "custom/etab.css" + >> 'CSS_OVERRIDE': '', + >> + >> # Vous pouvez créer un template dans votre application custom et + >> # indiquer son chemin dans cette variable pour que ce code html, + >> # ce template soit affiché en haut de votre page, le code est ajouté + >> # juste après la balise body.(Hors iframe) + >> # Si le fichier créé est + >> # '/opt/django_projects/podv3/pod/custom/templates/custom/preheader.html' + >> # alors la variable doit prendre la valeur 'custom/preheader.html' + >> 'PRE_HEADER_TEMPLATE': '', + >> + >> # Idem que pre-header, le code contenu dans le template + >> # sera affiché juste avant la fermeture du body. (Or iframe) + >> 'POST_FOOTER_TEMPLATE': '', + >> + >> # vous pouvez créer un template dans votre application custom + >> # pour y intégrer votre code Piwik ou Google analytics. + >> # Ce template est inséré dans toutes les pages de la plateforme, + >> # y compris en mode iframe + >> 'TRACKING_TEMPLATE': '', + >> } + >> + >> ``` + +### Transcodage + + - `TRANSCRIPTION_AUDIO_SPLIT_TIME` + + > valeur par défaut : `600` + + >> Découpage de l’audio pour la transcription.
+ + - `TRANSCRIPTION_MODEL_PARAM` + + > valeur par défaut : `{}` + + >> Paramétrage des modèles pour la transcription
+ >> Voir la documentation à cette adresse : [https://www.esup-portail.org/wiki/display/ES/Installation+de+l%27autotranscription+en+Pod+V3]()
+ >> Pour télécharger les Modeles Vosk : [https://alphacephei.com/vosk/models]()
+ >> + >> ``` + >> TRANSCRIPTION_MODEL_PARAM = { + >> # le modèle stt + >> 'STT': { + >> 'fr': { + >> 'model': "/path/to/project/Esup-Pod/transcription/model_fr/stt/output_graph.tflite", + >> 'scorer': "/path/to/project/Esup-Pod/transcription/model_fr/stt/kenlm.scorer", + >> } + >> }, + >> # le modèle vosk + >> 'VOSK': { + >> 'fr': { + >> 'model': "/path/of/project/Esup-Pod/transcription/model_fr/vosk/vosk-model-fr-0.6-linto-2.2.0", + >> } + >> } + >> } + >> + >> ``` + + - `TRANSCRIPTION_NORMALIZE` + + > valeur par défaut : `False` + + >> Activation de la normalisation de l’audio avant sa transcription.
+ + - `TRANSCRIPTION_NORMALIZE_TARGET_LEVEL` + + > valeur par défaut : `-16.0` + + >> Niveau de normalisation de l’audio avant sa transcription.
+ + - `TRANSCRIPTION_STT_SENTENCE_BLANK_SPLIT_TIME` + + > valeur par défaut : `0.5` + + >> Temps maximum en secondes des blancs entre chaque mot pour le decoupage des sous-titres avec l’outil STT.
+ + - `TRANSCRIPTION_STT_SENTENCE_MAX_LENGTH` + + > valeur par défaut : `3` + + >> Temps en secondes maximum pour une phrase lors de la transcription avec l’outil STT.
+ + - `TRANSCRIPTION_TYPE` + + > valeur par défaut : `STT` + + >> Choix de l’outil pour la transcription : STT ou VOSK.
+ + - `TRANSCRIPT_VIDEO` + + > valeur par défaut : `start_transcript` + + >> Fonction appelée pour lancer la transcription des vidéos.
+ + - `USE_TRANSCRIPTION` + + > valeur par défaut : `False` + + >> Activation de la transcription.
+ +## Configuration Générale de la plateforme Esup_Pod + + +### Configuration application authentification. + + - `AFFILIATION` + + > valeur par défaut : `` + + >> Valeurs possibles pour l’affiliation du compte.
+ + - `AFFILIATION_EVENT` + + > valeur par défaut : `` + + >> Groupes ou affiliations des personnes autorisées à créer un évènement.
+ + - `AFFILIATION_STAFF` + + > valeur par défaut : `` + + >> Les personnes ayant pour affiliation les valeurs
+ >> renseignées dans cette variable ont automatiquement
+ >> la valeur staff de leur compte à True.
+ + - `AUTH_CAS_USER_SEARCH` + + > valeur par défaut : `user` + + >> Variable utilisée pour trouver les informations de l’individu
+ >> connecté dans le fichier renvoyé par le CAS lors de l’authentification.
+ + - `AUTH_LDAP_BIND_DN` + + > valeur par défaut : `` + + >> Identifiant (DN) du compte pour se connecter au serveur LDAP.
+ + - `AUTH_LDAP_BIND_PASSWORD` + + > valeur par défaut : `` + + >> Mot de passe du compte pour se connecter au serveur LDAP.
+ + - `AUTH_LDAP_USER_SEARCH` + + > valeur par défaut : `` + + >> Filtre LDAP permettant la recherche de l’individu dans le serveur LDAP.
+ + - `AUTH_TYPE` + + > valeur par défaut : `` + + >> Type d’authentification possible sur votre instance.
+ >> Choix : local, CAS, OIDC, Shibboleth
+ + - `CAS_ADMIN_AUTH` + + > valeur par défaut : `False` + + >> Permet d’activer l’authentification CAS pour la partie admin
+ >> Voir : [https://pypi.org/project/django-cas-sso/]()
+ + - `CAS_FORCE_LOWERCASE_USERNAME` + + > valeur par défaut : `False` + + >> Forcer le passage en minuscule du nom d’utilisateur CAS
+ >> (permet de prévenir des doubles créations de comptes dans certain cas).
+ + - `CAS_GATEWAY` + + > valeur par défaut : `False` + + >> Si True, authentifie automatiquement l’individu
+ >> si déjà authentifié sur le serveur CAS
+ + - `CAS_LOGOUT_COMPLETELY` + + > valeur par défaut : `True` + + >> Voir [https://github.com/kstateome/django-cas]()
+ + - `CAS_SERVER_URL` + + > valeur par défaut : `sso_cas` + + >> Url du serveur CAS de l’établissement. Format http://url_cas
+ + - `CREATE_GROUP_FROM_AFFILIATION` + + > valeur par défaut : `False` + + >> Si True, des groupes sont créés automatiquement
+ >> à partir des affiliations des individus qui se connectent sur la plateforme
+ >> et l’individu qui se connecte est ajouté automatiquement à ces groupes.
+ + - `CREATE_GROUP_FROM_GROUPS` + + > valeur par défaut : `False` + + >> Si True, des groupes sont créés automatiquement
+ >> à partir des groupes (attribut groups à memberOf)
+ >> des individus qui se connectent sur la plateforme
+ >> et l’individu qui se connecte est ajouté automatiquement à ces groupes
+ + - `DEFAULT_AFFILIATION` + + > valeur par défaut : `` + + >> Affiliation par défaut d’un utilisateur authentifié par OIDC.
+ >> Ce contenu sera comparé à la liste AFFILIATION_STAFF pour déterminer si l’utilisateur doit être admin Django
+ + - `ESTABLISHMENTS` + + > valeur par défaut : `` + + >> [TODO] À compléter
+ + - `GROUP_STAFF` + + > valeur par défaut : `AFFILIATION_STAFF` + + >> utilisé dans populatedCasbackend
+ + - `HIDE_LOCAL_LOGIN` + + > valeur par défaut : `False` + + >> Si True, masque l’authentification locale
+ + - `HIDE_USERNAME` + + > valeur par défaut : `False` + + >> Si valeur vaut `True`, le username de l’utilisateur ne sera pas visible sur la plate-forme Pod et si la valeur vaut `False` le username sera affiché aux utilisateurs authentifiés. (pour respecter le RGPD)
+ + - `LDAP` + + > valeur par défaut : `` + + >> - LDAP (Interroge le serveur LDAP pour renseigner les champs)
+ + - `LDAP_SERVER` + + > valeur par défaut : `` + + >> Information de connection au serveur LDAP.
+ >> Le champ url peut contenir une ou plusieurs url
+ >> pour ajouter des hôtes de référence, exemple :
+ >> Si un seul host :
+ >> + >> `{'url': "ldap.univ.fr'', 'port': 389, 'use_ssl': False}` + >> Si plusieurs : + >> + >> `{'url': ("ldap.univ.fr'',"ldap2.univ.fr"), 'port': 389, 'use_ssl': False}` + + - `OIDC_CLAIM_FAMILY_NAME` + + > valeur par défaut : `family_name` + + + + - `OIDC_CLAIM_GIVEN_NAME` + + > valeur par défaut : `given_name` + + >> Noms des Claim permettant de récupérer les attributs nom, prénom, email
+ + - `OIDC_DEFAULT_ACCESS_GROUP_CODE_NAMES` + + > valeur par défaut : `[]` + + >> Groupes d’accès attribués par défaut à un nouvel utilisateur authentifié par OIDC
+ + - `OIDC_DEFAULT_AFFILIATION` + + > valeur par défaut : `` + + >> Affiliation par défaut d’un utilisateur authentifié par OIDC.
+ >> Ce contenu sera comparé à la liste AFFILIATION_STAFF pour déterminer si l’utilisateur doit être admin Django
+ + - `OIDC_NAME` + + > valeur par défaut : `` + + >> Nom du Service Provider OIDC
+ + - `OIDC_OP_AUTHORIZATION_ENDPOINT` + + > valeur par défaut : `https` + + + + - `OIDC_OP_JWKS_ENDPOINT` + + > valeur par défaut : `https` + + >> Différents paramètres pour OIDC
+ >> tant que `mozilla_django_oidc` n’accepte pas le mécanisme de discovery
+ >> ref: [https://github.com/mozilla/mozilla-django-oidc/pull/309]()
+ + - `OIDC_OP_TOKEN_ENDPOINT` + + > valeur par défaut : `https` + + + + - `OIDC_OP_USER_ENDPOINT` + + > valeur par défaut : `https` + + + + - `OIDC_RP_CLIENT_ID` + + > valeur par défaut : `os.environ` + + + + - `OIDC_RP_CLIENT_SECRET` + + > valeur par défaut : `os.environ` + + >> + >> `CLIENT_ID` et `CLIENT_SECRET` de OIDC sont plutôt à positionner + >> à travers des variables d’environnement. + + - `OIDC_RP_SIGN_ALGO` + + > valeur par défaut : `` + + + + - `POPULATE_USER` + + > valeur par défaut : `None` + + >> Si utilisation de la connection CAS, renseigne les champs du compte
+ >> de la personne depuis une source externe.
+ >> Valeurs possibles :
+ >> - None (pas de renseignement),
+ >> - CAS (renseigne les champs depuis les informations renvoyées par le CAS),
+ + - `REMOTE_USER_HEADER` + + > valeur par défaut : `REMOTE_USER` + + >> Nom de l’attribut dans les headers qui sert à identifier
+ >> l’utilisateur connecté avec Shibboleth.
+ + - `SHIBBOLETH_ATTRIBUTE_MAP` + + > valeur par défaut : `` + + >> Mapping des attributs entre Shibboleth et la classe utilisateur
+ + - `SHIBBOLETH_STAFF_ALLOWED_DOMAINS` + + > valeur par défaut : `` + + >> Permettre à l’utilisateur d’un domaine d’être membre du personnel.
+ >> Si vide, tous les domaines seront autorisés.
+ + - `SHIB_LOGOUT_URL` + + > valeur par défaut : `` + + >> URL de déconnexion à votre instance Shibboleth
+ + - `SHIB_NAME` + + > valeur par défaut : `` + + >> Nom de la fédération d’identité utilisée.
+ + - `SHIB_URL` + + > valeur par défaut : `` + + >> URL de connexion à votre instance Shibboleth.
+ + - `USER_CAS_MAPPING_ATTRIBUTES` + + > valeur par défaut : `` + + >> Liste de correspondance entre les champs d’un compte de Pod
+ >> et les champs renvoyés par le CAS.
+ + - `USER_LDAP_MAPPING_ATTRIBUTES` + + > valeur par défaut : `` + + >> Liste de correspondance entre les champs d’un compte de Pod
+ >> et les champs renvoyés par le LDAP.
+ + - `USE_CAS` + + > valeur par défaut : `False` + + >> Activation de l’authentification CAS en plus de l’authentification locale.
+ + - `USE_OIDC` + + > valeur par défaut : `False` + + >> Mettre à True pour utiliser l’authentification OpenID Connect.
+ + - `USE_SHIB` + + > valeur par défaut : `False` + + >> Mettre à True pour utiliser l’authentification Shibboleth.
+ +### Configuration application chapter. + +### Configuration application completion + + - `ACTIVE_MODEL_ENRICH` + + > valeur par défaut : `False` + + >> Définissez à True pour activer la case à cocher dans l’édition des sous-titres.
+ + - `ALL_LANG_CHOICES` + + > valeur par défaut : `` + + >> liste toutes les langues pour l’ajout de fichier de sous-titre
+ >> voir le fichier `pod/main/lang_settings.py`.
+ + - `DEFAULT_LANG_TRACK` + + > valeur par défaut : `fr` + + >> langue par défaut pour l’ajout de piste à une vidéo.
+ + - `KIND_CHOICES` + + > valeur par défaut : `` + + >> Liste de types de piste possibles pour une vidéo (sous-titre, légende etc.)
+ + - `LANG_CHOICES` + + > valeur par défaut : `` + + >> Liste des langues proposées lors de l’ajout des vidéos.
+ >> Affichés en dessous d’une vidéo, les choix sont aussi utilisés pour affiner la recherche.
+ + - `LINK_SUPERPOSITION` + + > valeur par défaut : `False` + + >> Si valeur vaut 'True', les URLs contenues dans le texte de superposition seront transformées, à la lecture de la vidéo, en liens cliquables.
+ + - `MODEL_COMPILE_DIR` + + > valeur par défaut : `/path/of/project/Esup-Pod/compile-model` + + >> Paramétrage des chemins du modèle pour la compilation
+ >> Pour télécharger les modèles : [https://alphacephei.com/vosk/lm#update-process]()
+ >> Ajouter le modèle dans les sous-dossier de la langue correspondante
+ >> Exemple pour le français : `/path/of/project/Esup-Pod/compile-model/fr/`
+ + - `PREF_LANG_CHOICES` + + > valeur par défaut : `` + + >> liste des langues à afficher en premier dans la liste des toutes les langues
+ >> voir le fichier `pod/main/lang_settings.py`
+ + - `ROLE_CHOICES` + + > valeur par défaut : `` + + >> Liste de rôles possibles pour un contributeur.
+ + - `TRANSCRIPTION_MODEL_PARAM` + + > valeur par défaut : `` + + >> Paramétrage des modèles pour la transcription
+ >> Voir la documentation à cette adresse :
+ >> [https://www.esup-portail.org/wiki/display/ES/Installation+de+l%27autotranscription+en+Pod+V3]()
+ >> Pour télécharger les modèles Vosk : [https://alphacephei.com/vosk/models]()
+ >> + >> ```python + >> TRANSCRIPTION_MODEL_PARAM = { + >> # le modèle stt + >> 'STT': { + >> 'fr': { + >> 'model': "/path/to/project/Esup-Pod/transcription/model_fr/stt/output_graph.tflite", + >> 'scorer': "/path/to/project/Esup-Pod/transcription/model_fr/stt/kenlm.scorer", + >> } + >> }, + >> # le modèle vosk + >> 'VOSK': { + >> 'fr': { + >> 'model': "/path/of/project/Esup-Pod/transcription/model_fr/vosk/vosk-model-fr-0.6-linto-2.2.0", + >> } + >> } + >> } + >> + >> ``` + + - `TRANSCRIPTION_TYPE` + + > valeur par défaut : `STT` + + >> STT ou VOSK
+ + - `USE_ENRICH_READY` + + > valeur par défaut : `False ` + + >> voir `ACTIVE_MODEL_ENRICH`
+ +### Configuration application enrichment + +### Configuration application d'import vidéo +Application Import_video permettant d'importer des vidéos externes dans Pod.
+Mettre `USE_IMPORT_VIDEO` à True pour activer cette application.
+ + - `RESTRICT_EDIT_IMPORT_VIDEO_ACCESS_TO_STAFF_ONLY` + + > valeur par défaut : `True` + + >> Seuls les utilisateurs "staff" pourront importer des vidéos
+ + - `MAX_UPLOAD_SIZE_ON_IMPORT` + + > valeur par défaut : `4` + + >> Taille maximum en Go des fichiers vidéos qui peuvent être importés sur la plateforme
+ >> via l'application import_video (0 = pas de taille maximum).
+ + - `USE_IMPORT_VIDEO` + + > valeur par défaut : `True` + + >> Activation de l’application d'import des vidéos
+ +### Configuration application live + + - `AFFILIATION_EVENT` + + > valeur par défaut : `['faculty', 'employee', 'staff']` + + >> Groupes ou affiliations des personnes autorisées à créer un évènement.
+ + - `BROADCASTER_PILOTING_SOFTWARE` + + > valeur par défaut : `[]` + + >> Types de logiciel de serveur de streaming utilisés.
+ >> Actuellement disponible Wowza et SMP. Il faut préciser cette valeur pour l’activer `['Wowza', 'SMP']`
+ >> Si vous utilisez une autre logiciel,
+ >> il faut développer une interface dans `pod/live/pilotingInterface.py`
+ + - `DEFAULT_EVENT_PATH` + + > valeur par défaut : `` + + >> Chemin racine du répertoire où sont déposés temporairement les enregistrements des évènements éffectués depuis POD pour convertion en ressource vidéo (VOD)
+ + - `DEFAULT_EVENT_THUMBNAIL` + + > valeur par défaut : `/img/default-event.svg` + + >> Image par défaut affichée comme poster ou vignette, utilisée pour présenter l’évènement.
+ >> Cette image doit se situer dans le répertoire `static`.
+ + - `DEFAULT_EVENT_TYPE_ID` + + > valeur par défaut : `1` + + >> Type par défaut affecté à un évènement direct (en général, le type ayant pour identifiant '1' est 'Other')
+ + - `DEFAULT_THUMBNAIL` + + > valeur par défaut : `img/default.svg` + + >> Image par défaut affichée comme poster ou vignette, utilisée pour présenter la vidéo.
+ >> Cette image doit se situer dans le répertoire static.
+ + - `EMAIL_ON_EVENT_SCHEDULING` + + > valeur par défaut : `True` + + >> Si True, un courriel est envoyé aux managers et à l’auteur (si DEBUG est à False) à la création/modification d’un event.
+ + - `EVENT_ACTIVE_AUTO_START` + + > valeur par défaut : `False` + + >> Permet de lancer automatiquement l’enregistrement sur l’interface utilisée (wowza, ) sur le broadcaster et spécifié par `BROADCASTER_PILOTING_SOFTWARE`
+ + - `EVENT_GROUP_ADMIN` + + > valeur par défaut : `event admin` + + >> Permet de préciser le nom du groupe dans lequel les utilisateurs peuvent planifier un évènement sur plusieurs jours.
+ + - `EVENT_CHECK_MAX_ATTEMPT` + + > valeur par défaut : `10` + + >> Nombre de tentatives maximum pour vérifier la présence / taille d'un fichier sur le filesystem
+ + - `HEARTBEAT_DELAY` + + > valeur par défaut : `45` + + >> Temps (en secondes) entre deux envois d’un signal au serveur, pour signaler la présence sur un live.
+ >> Peut être augmenté en cas de perte de performance, mais au détriment de la qualité du comptage des valeurs.
+ + - `LIVE_CELERY_TRANSCRIPTION ` + + > valeur par défaut : `False` + + + >> Activer la transcription déportée sur une machine distante.
+ + - `LIVE_TRANSCRIPTIONS_FOLDER` + + > valeur par défaut : `` + + + >> Dossier contenat les fichiers de sous-titre au format vtt pour les directs
+ + - `LIVE_VOSK_MODEL` + + > valeur par défaut : `{}` + + + >> Paramétrage des modèles pour la transcription des directs
+ >> La documentation sera présente prochaînement
+ >> Pour télécharger les Modèles Vosk : [https://alphacephei.com/vosk/models]()
+ >> + >> ``` + >> LIVE_VOSK_MODEL = { + >> 'fr': { + >> 'model': "/path/of/project/django_projects/transcription/live/fr/vosk-model-small-fr-0.22", + >> } + >> } + >> + >> ``` + + - `USE_BBB` + + > valeur par défaut : `True` + + >> Utilisation de BigBlueButton - [TODO] À retirer dans les futures versions de Pod
+ + - `USE_BBB_LIVE` + + > valeur par défaut : `False ` + + >> Utilisation du système de diffusion de Webinaires en lien avec BigBlueButton - [TODO] À retirer dans les futures versions de Pod
+ + - `USE_LIVE_TRANSCRIPTION` + + > valeur par défaut : `False` + + + >> Activer l'auto-transcription pour les directs
+ + - `VIEW_EXPIRATION_DELAY` + + > valeur par défaut : `60` + + >> Délai (en seconde) selon lequel une vue est considérée comme expirée si elle n’a pas renvoyé de signal depuis.
+ +### Configuration application LTI + + - `LTI_ENABLED` + + > valeur par défaut : `False` + + >> Configuration / Activation du LTI voir pod/main/settings.py L.224
+ + - `PYLTI_CONFIG` + + > valeur par défaut : `{}` + + >> Cette variable permet de configurer l’application cliente et le secret partagé
+ >> + >> ``` + >> PYLTI_CONFIG = { + >> 'consumers': { + >> '': { + >> 'secret': '' + >> } + >> } + >> } + >> + >> ``` + +### Configuration application main + + - `HOMEPAGE_VIEW_VIDEOS_FROM_NON_VISIBLE_CHANNELS` + + > valeur par défaut : `False` + + >> Affiche les vidéos de chaines non visibles sur la page d'accueil
+ + - `USE_BBB` + + > valeur par défaut : `True` + + >> Utilisation de BigBlueButton - [TODO] À retirer dans les futures versions de Pod
+ + - `USE_BBB_LIVE` + + > valeur par défaut : `False ` + + >> Utilisation du système de diffusion de Webinaires en lien avec BigBlueButton - [TODO] À retirer dans les futures versions de Pod
+ + - `USE_IMPORT_VIDEO` + + > valeur par défaut : `True` + + >> Activation de l’application d'import des vidéos
+ + - `USE_MEETING` + + > valeur par défaut : `False` + + >> Activation de l’application meeting
+ + - `USE_OPENCAST_STUDIO` + + > valeur par défaut : `False` + + >> Activation du studio [https://opencast.org/](Opencast)
+ + - `VERSION` + + > valeur par défaut : `` + + >> Version courante du projet
+ +### Configuration application meeting + +Application Meeting pour la gestion de reunion avec BBB.
+Mettre `USE_MEETING` à True pour activer cette application.
+`BBB_API_URL` et `BBB_SECRET_KEY` sont obligatoires pour faire fonctionner l’application
+ + - `BBB_API_URL` + + > valeur par défaut : `` + + >> Indiquer l’URL API de BBB par ex `https://webconf.univ.fr/bigbluebutton/api
+ + - `BBB_LOGOUT_URL` + + > valeur par défaut : `` + + >> Indiquer l’URL de retour au moment où vous quittez la réunion BBB. Ce champ est optionnel.
+ + - `BBB_MEETING_INFO` + + > valeur par défaut : `{}` + + >> Dictionnaire de clé:valeur permettant d’afficher les informations d’une session de réunion dans BBB
+ >> Voici la liste par défaut
+ >> + >> ``` + >> BBB_MEETING_INFO: + >> { + >> "meetingName": _("Meeting name"), + >> "hasUserJoined": _("Has user joined?"), + >> "recording": _("Recording"), + >> "participantCount": _("Participant count"), + >> "listenerCount": _("Listener count"), + >> "moderatorCount": _("Moderator count"), + >> "attendees": _("Attendees"), + >> "attendee": _("Attendee"), + >> "fullName": _("Full name"), + >> "role": _("Role"), + >> } + >> + >> ``` + + - `BBB_SECRET_KEY` + + > valeur par défaut : `` + + >> Clé de votre serveur BBB.
+ >> Vous pouvez récupérer cette clé à l’aide de la commande `bbb-conf --secret` sur le serveur BBB.
+ + - `DEFAULT_MEETING_THUMBNAIL` + + > valeur par défaut : `/img/default-meeting.svg` + + >> Image par défaut affichée comme poster ou vignette, utilisée pour présenter la réunion.
+ >> Cette image doit se situer dans le répertoire `static`.
+ + - `MEETING_DATE_FIELDS` + + > valeur par défaut : `()` + + >> liste des champs du formulaire de creation d’une reunion
+ >> les champs sont regroupés dans un ensemble de champs
+ >> + >> ``` + >> MEETING_DATE_FIELDS: + >> ( + >> "start", + >> "start_time", + >> "expected_duration", + >> ) + >> + >> ``` + + - `MEETING_DISABLE_RECORD` + + > valeur par défaut : `True` + + >> Mettre à True pour désactiver les enregistrements de réunion
+ >> Configuration de l’enregistrement des réunions.
+ >> Ce champ n’est pas pris en compte si `MEETING_DISABLE_RECORD = True`.
+ + - `MEETING_MAIN_FIELDS` + + > valeur par défaut : `()` + + >> Permet de définir les champs principaux du formulaire de création d’une réunion
+ >> les champs principaux sont affichés directement dans la page de formulaire d’une réunion
+ >> + >> ``` + >> MEETING_MAIN_FIELDS: + >> ( + >> "name", + >> "owner", + >> "additional_owners", + >> "attendee_password", + >> "is_restricted", + >> "restrict_access_to_groups", + >> ) + >> + >> ``` + + - `MEETING_MAX_DURATION` + + > valeur par défaut : `5` + + >> permet de définir la durée maximum pour une reunion
+ >> (en heure)
+ + - `MEETING_PRE_UPLOAD_SLIDES` + + > valeur par défaut : `` + + + >> Diaporama préchargé pour les réunions virtuelles.
+ >> Un utilisateur peut remplacer cette valeur en choisissant un diaporama lors de la création d'une réunion virtuelle.
+ >> Doit se trouver dans le répertoire statique.
+ + - `MEETING_RECORD_FIELDS` + + > valeur par défaut : `()` + + >> ensemble des champs qui seront cachés si `MEETING_DISABLE_RECORD` est défini à true.
+ >> + >> ``` + >> MEETING_RECORD_FIELDS: ("record", "auto_start_recording", "allow_start_stop_recording") + >> + >> ``` + + - `MEETING_RECURRING_FIELDS` + + > valeur par défaut : `()` + + >> Liste de tous les champs permettant de définir la récurrence d’une reunion
+ >> tous ces champs sont regroupés dans un ensemble de champs affichés dans une modale
+ >> + >> ``` + >> MEETING_RECURRING_FIELDS: + >> ( + >> "recurrence", + >> "frequency", + >> "recurring_until", + >> "nb_occurrences", + >> "weekdays", + >> "monthly_type", + >> ) + >> + >> ``` + + - `RESTRICT_EDIT_MEETING_ACCESS_TO_STAFF_ONLY` + + > valeur par défaut : `False` + + >> Seuls les utilisateurs "staff" pourront éditer les réunions
+ + - `USE_MEETING` + + > valeur par défaut : `False` + + >> Activer l’application meeting
+ +### Configuration application playlist +Application Playlist pour la gestion des playlists.
+Mettre `USE_PLAYLIST` à True pour activer cette application.
+ + - `DEFAULT_PLAYLIST_THUMBNAIL` + + > valeur par défaut : `/static/playlist/img/default-playlist.svg` + + >> Image par défaut affichée comme poster ou vignette, utilisée pour présenter la playlist.
+ >> Cette image doit se situer dans le répertoire `static`.
+ + - `COUNTDOWN_PLAYLIST_PLAYER` + + > valeur par défaut : `0` + + >> Compte à rebours utilisé entre chaque vidéo lors de la lecture d'une playlist en lecture automatique.
+ >> Le compte à rebours n'est pas présent s'il est à 0.
+ + - `USE_FAVORITES` + + > valeur par défaut : `True` + + >> Activation des vidéos favorites. Permet aux utilisateurs d'ajouter des vidéos dans leurs favoris.
+ + - `USE_PLAYLIST` + + > valeur par défaut : `True` + + >> Activation des playlist. Permet aux utilisateurs d'ajouter des vidéos dans une playlist.
+ +### Configuration application podfile + + - `FILES_DIR` + + > valeur par défaut : `files` + + >> Nom du répertoire racine où les fichiers "complémentaires"
+ >> (hors vidéos etc.) sont téléversés. Notament utilisé par PODFILE
+ >> À modifier principalement pour indiquer dans LOCATION votre serveur de cache si elle n’est pas sur la même machine que votre POD.
+ + - `FILE_ALLOWED_EXTENSIONS` + + > valeur par défaut : `('doc', 'docx', 'odt', 'pdf', 'xls', 'xlsx', 'ods', 'ppt', 'pptx', 'txt', 'html', 'htm', 'vtt', 'srt')` + + >> Extensions autorisées pour les documents téléversés dans le gestionnaire de fichier (en minuscules).
+ + - `FILE_MAX_UPLOAD_SIZE` + + > valeur par défaut : `10` + + >> Poids maximum en Mo par fichier téléversé dans le gestionnaire de fichier
+ + - `IMAGE_ALLOWED_EXTENSIONS` + + > valeur par défaut : `('jpg', 'jpeg', 'bmp', 'png', 'gif', 'tiff', 'webp')` + + >> Extensions autorisées pour les images téléversées dans le gestionnaire de fichier. (en minuscules)
+ +### Configuration application progressive_web_app + + - `WEBPUSH_SETTINGS` + + > valeur par défaut : + + ```python + { + 'VAPID_PUBLIC_KEY': '', + 'VAPID_PRIVATE_KEY': '', + 'VAPID_ADMIN_EMAIL': 'contact@esup-portail.org' + } + ``` + + >> Les clés VAPID sont nécessaires à la lib [django-webpush](https://github.com/safwanrahman/django-webpush). Elles peuvent être générées avec [https://web-push-codelab.glitch.me/]()
+ +### Configuration application recorder + + - `ALLOW_MANUAL_RECORDING_CLAIMING` + + > valeur par défaut : `False` + + >> si True, active un lien dans le menu de l’utilisateur permettant de réclamer un enregistrement
+ + - `ALLOW_RECORDER_MANAGER_CHOICE_VID_OWNER` + + > valeur par défaut : `True` + + >> Si True, le manager de l’enregistreur pourra choisir un propriétaire de l’enregistrement.
+ + - `DEFAULT_RECORDER_ID` + + > valeur par défaut : `1` + + >> Ajoute un enregistreur par défaut à un enregistrement non identifiable (mauvais chemin dans le dépôt FTP)
+ + - `DEFAULT_RECORDER_PATH` + + > valeur par défaut : `/data/ftp-pod/ftp/` + + >> Chemin racine du répertoire où sont déposés les enregistrements
+ >> (chemin du serveur FTP).
+ + - `DEFAULT_RECORDER_TYPE_ID` + + > valeur par défaut : `1` + + >> Identifiant du type de vidéo par défaut (si non spécifié).
+ >> (Exemple : 3 pour Colloque/conférence, 4 pour Cours...)
+ + - `DEFAULT_RECORDER_USER_ID` + + > valeur par défaut : `1` + + >> Identifiant du propriétaire par défaut (si non spécifié) des enregistrements déposés.
+ + - `OPENCAST_DEFAULT_PRESENTER` + + > valeur par défaut : `mid` + + >> Permet de spécifier la valeur par défaut du placement de la vidéo du
+ >> presenteur par rapport à la vidéo de présentation (écran)
+ >> les valeurs possibles sont :
+ >> * "mid" (écran et caméra ont la même taille)
+ >> * "piph" (le presenteur, caméra, est incrusté dans la vidéo de présentation, en haut à droite)
+ >> * "pipb" (le presenteur, caméra, est incrusté dans la vidéo de présentation, en bas à droite)
+ >> Contenu par défaut du fichier xml pour créer le mediapackage pour le studio.
+ >> Ce fichier va contenir toutes les spécificités de l’enregistrement
+ >> (source, cutting, title, presenter etc.)
+ + - `OPENCAST_FILES_DIR` + + > valeur par défaut : `opencast-files` + + >> Permet de spécifier le dossier de stockage des enregistrements du studio avant traitement.
+ + - `OPENCAST_MEDIAPACKAGE` + + > valeur par défaut : `-> see xml content` + + >> Contenu par défaut du fichier xml pour créer le mediapackage pour le studio. Ce fichier va contenir toutes les spécificités de l’enregistrement (source, cutting, title, presenter etc.)
+ >> + >> ``` + >> OPENCAST_MEDIAPACKAGE = """ + >> + >> + >> + >> + >> + >> """ + >> + >> ``` + + - `PUBLIC_RECORD_DIR` + + > valeur par défaut : `records` + + >> Chemin d’accès web (public) au répertoire de dépot des enregistrements (`DEFAULT_RECORDER_PATH`).
+ >> Attention : penser à modifier la conf de NGINX.
+ + - `RECORDER_ADDITIONAL_FIELDS` + + > valeur par défaut : `()` + + >> Liste des champs supplémentaires pour le formulaire des enregistreurs. Cette liste reprend le nom des champs correspondants aux paramètres d’édition d’une vidéo (Discipline, Chaine, Theme, mots clés...).
+ >> L’exemple suivant comporte l’ensemble des champs possibles, mais peut être allégée en fonction des besoins.
+ >> Les vidéos seront alors générées avec les valeurs des champs supplémentaires telles que définies dans leur enregistreur.
+ + - `RECORDER_ALLOW_INSECURE_REQUESTS` + + > valeur par défaut : `False` + + >> Autorise la requête sur l’application en elle-même sans vérifier le certificat SSL
+ + - `RECORDER_BASE_URL` + + > valeur par défaut : `https://pod.univ.fr` + + >> url racine de l’instance permettant l’envoi de notification lors de la réception d’enregistrement.
+ + - `RECORDER_SELF_REQUESTS_PROXIES` + + > valeur par défaut : `{"http": None, "https": None}` + + >> Précise les proxy à utiliser pour une requête vers l’application elle même dans le cadre d’enregistrement par défaut force la non utilisation de proxy.
+ + - `RECORDER_SKIP_FIRST_IMAGE` + + > valeur par défaut : `False` + + >> Si True, permet de ne pas prendre en compte la 1ère image lors du traitement d’un fichier d’enregistrement de type AudioVideoCast.
+ + - `RECORDER_TYPE` + + > valeur par défaut : `(('video', _('Video')), ('audiovideocast', _('Audiovideocast')), ('studio', _('Studio')))` + + >> Type d’enregistrement géré par la plateforme.
+ >> Un enregistreur ne peut déposer que des fichiers de type proposé par la plateforme.
+ >> Le traitement se fait en fonction du type de fichier déposé.
+ + - `USE_OPENCAST_STUDIO` + + > valeur par défaut : `False` + + >> Activer l’utilisation du studio Opencast.
+ + - `USE_RECORD_PREVIEW` + + > valeur par défaut : `False` + + >> Si True, affiche l’icone de prévisualisation des vidéos dans la page "Revendiquer un enregistrement".
+ +### Configuration application vidéo. + + - `ACTIVE_VIDEO_COMMENT` + + > valeur par défaut : `False` + + >> Activer les commentaires au niveau de la plateforme
+ + - `CHANNEL_FORM_FIELDS_HELP_TEXT` + + > valeur par défaut : `` + + >> Ensemble des textes d’aide affichés avec le formulaire d’édition de chaine.
+ >> voir pod/video/forms.py
+ + - `CHUNK_SIZE` + + > valeur par défaut : `1000000` + + >> Taille d’un fragment lors de l’envoi d’une vidéo
+ >> le fichier sera mis en ligne par fragment de cette taille.
+ + - `CURSUS_CODES` + + > valeur par défaut : `()` + + >> Liste des cursus proposés lors de l’ajout des vidéos.
+ >> Affichés en dessous d’une vidéos, ils sont aussi utilisés pour affiner la recherche.
+ >> + >> ``` + >> CURSUS_CODES = ( + >> ('0', _("None / All")), + >> ('L', _("Bachelor’s Degree")), + >> ('M', _("Master’s Degree")), + >> ('D', _("Doctorate")), + >> ('1', _("Other")) + >> ) + >> + >> ``` + + - `DEFAULT_DC_COVERAGE` + + > valeur par défaut : `TITLE_ETB + " - Town - Country"` + + >> couverture du droit pour chaque vidéo
+ + - `DEFAULT_DC_RIGHTS` + + > valeur par défaut : `BY-NC-SA` + + >> droit par défaut affichés dans le flux RSS si non renseigné
+ + - `DEFAULT_THUMBNAIL` + + > valeur par défaut : `img/default.svg` + + >> Image par défaut affichée comme poster ou vignette, utilisée pour présenter la vidéo.
+ >> Cette image doit se situer dans le répertoire static.
+ + - `DEFAULT_TYPE_ID` + + > valeur par défaut : `1` + + >> Les vidéos créées sans type (par importation par exemple) seront affectées au type par défaut (en général, le type ayant pour identifiant '1' est 'Other')
+ + - `DEFAULT_YEAR_DATE_DELETE` + + > valeur par défaut : `2` + + >> Durée d’obsolescence par défaut (en années après la date d’ajout).
+ + - `FORCE_LOWERCASE_TAGS` + + > valeur par défaut : `True` + + >> Les mots clés saisis lors de l’ajout de vidéo sont convertis automatiquement en minuscule.
+ + - `LANG_CHOICES` + + > valeur par défaut : `` + + >> Liste des langues proposées lors de l’ajout des vidéos.
+ >> Affichés en dessous d’une vidéos, les choix sont aussi utilisés pour affiner la recherche.
+ + - `LICENCE_CHOICES` + + > valeur par défaut : `()` + + >> Licence proposées pour les vidéos en creative commons :
+ >> + >> ``` + >> LICENCE_CHOICES = ( + >> ('by', ("Attribution 4.0 International (CC BY 4.0)")), + >> ('by-nd', ("Attribution-NoDerivatives 4.0 " + >> "International (CC BY-ND 4.0)")), + >> ('by-nc-nd', ("Attribution-NonCommercial-NoDerivatives 4.0 " + >> "International (CC BY-NC-ND 4.0)")), + >> ('by-nc', ("Attribution-NonCommercial 4.0 " + >> "International (CC BY-NC 4.0)")), + >> ('by-nc-sa', ("Attribution-NonCommercial-ShareAlike 4.0 " + >> "International (CC BY-NC-SA 4.0)")), + >> ('by-sa', ("Attribution-ShareAlike 4.0 International (CC BY-SA 4.0)")) + >> ) + >> + >> ``` + + - `MAX_DURATION_DATE_DELETE` + + > valeur par défaut : `10` + + >> Fixe une durée maximale que la date de suppression d’une vidéo ne peut dépasser.
+ >> Par défaut : 10 (Année courante + 10 ans).
+ + - `MAX_TAG_LENGTH` + + > valeur par défaut : `50` + + >> Les mots clés saisis lors de l’ajout de vidéo ne peuvent dépasser cette longueur.
+ + - `NOTES_STATUS` + + > valeur par défaut : `()` + + >> Valeurs possible pour l’accès à une note.
+ >> + >> ``` + >> NOTES_STATUS = ( + >> ("0", _("Private (me only)")), + >> ("1", _("Shared with video owner")), + >> ("2", _("Public")), + >> ) + >> + >> ``` + + - `OEMBED` + + > valeur par défaut : `False` + + >> Permettre l’usage du oembed, partage dans Moodle, Facebook, Twitter etc.
+ + - `ORGANIZE_BY_THEME` + + > valeur par défaut : `False` + + >> Affichage uniquement des vidéos de la chaîne ou du thème actuel(le).
+ >> Affichage des sous-thèmes directs de la chaîne ou du thème actuel(le)
+ + - `RESTRICT_EDIT_VIDEO_ACCESS_TO_STAFF_ONLY` + + > valeur par défaut : `False` + + >> Si True, seule les personnes "Staff" peuvent déposer des vidéos
+ + - `THEME_FORM_FIELDS_HELP_TEXT` + + > valeur par défaut : `""` + + >> Ensemble des textes d’aide affichés avec le formulaire d’édition de theme.
+ >> voir pod/video/forms.py
+ >> + >> ``` + >> THEME_FORM_FIELDS_HELP_TEXT = OrderedDict( + >> [ + >> ( + >> "{0}".format(_("Title field")), + >> [ + >> _( + >> "Please choose a title as short and accurate as possible, " + >> "reflecting the main subject / context of the content." + >> ), + >> _( + >> "You can use the “Description” field below for all " + >> "additional information." + >> ), + >> ], + >> ), + >> ( + >> "{0}".format(_("Description")), + >> [ + >> _( + >> "In this field you can describe your content, add all needed " + >> "related information, and format the result " + >> "using the toolbar." + >> ) + >> ], + >> ), + >> ] + >> ) + >> + >> ``` + + - `USER_VIDEO_CATEGORY` + + > valeur par défaut : `False` + + >> Permet d’activer le fonctionnement de categorie au niveau de ses vidéos.
+ >> Vous pouvez créer des catégories pour pouvoir ranger vos propres vidéos.
+ >> Les catégories sont liées à l’utilisateur.
+ + - `USE_OBSOLESCENCE` + + > valeur par défaut : `False` + + >> Activation de l’obsolescence des video. Permet d’afficher la date de suppression de la video
+ >> dans le formulaire d’edition et dans la partie admin.
+ + - `USE_STATS_VIEW` + + > valeur par défaut : `False` + + >> Permet d’activer la possibilité de voir en details le nombre de visualisation d’une vidéo durant un jour donné ou mois,
+ >> année ou encore le nombre de vue total depuis la création de la vidéo.
+ >> Un lien est rajouté dans la partie info lors de la lecture d’une vidéo, un lien est rajouté dans la page de visualisation d’une chaîne ou un theme
+ >> ou encore toutes les vidéos présentes sur la plateforme.
+ + - `USE_VIDEO_EVENT_TRACKING` + + > valeur par défaut : `False` + + >> Ce paramètre permet d’activer l’envoi d’évènements sur le lecteur vidéo à Matomo.
+ >> N’est utile que si le code piwik / matomo est présent dans l’instance de Esup-Pod.
+ >> Les évènements envoyés sont :
+ >> play, pause, seeked, ended, ratechange, fullscreen, error, loadmetadata
+ >> Pour rajouter le code Piwik/Matomo dans votre instance de Pod, il suffit de créer un fichier `pod/custom/templates/custom/tracking.html`
+ >> Il faut ensuite y insérer le code javascript puis dans votre fichier `settings_local.py`,
+ >> de préciser dans la variable `TEMPLATE_VISIBLE_SETTINGS`: `'TRACKING_TEMPLATE': 'custom/tracking.html'`
+ + - `USE_XAPI_VIDEO` + + > valeur par défaut : `False` + + + >> Active l‘envoi d’instructions xAPI pour le lecteur vidéo.
+ >> Attention, il faut mettre USE_XAPI à True pour que les instructions soient envoyées.
+ + - `VIDEO_ALLOWED_EXTENSIONS` + + > valeur par défaut : `()` + + >> Extensions autorisées pour le téléversement vidéo sur la plateforme (en minuscules).
+ >> + >> ``` + >> VIDEO_ALLOWED_EXTENSIONS = ( + >> "3gp", + >> "avi", + >> "divx", + >> "flv", + >> "m2p", + >> "m4v", + >> "mkv", + >> "mov", + >> "mp4", + >> "mpeg", + >> "mpg", + >> "mts", + >> "wmv", + >> "mp3", + >> "ogg", + >> "wav", + >> "wma", + >> "webm", + >> "ts", + >> ) + >> + >> ``` + + - `VIDEO_FEED_NB_ITEMS` + + > valeur par défaut : `100` + + + >> nombre d'item renvoyé par le flux rss
+ + - `VIDEO_FORM_FIELDS` + + > valeur par défaut : `__all__` + + >> Liste des champs du formulaire d’édition de vidéos affichées.
+ + - `VIDEO_FORM_FIELDS_HELP_TEXT` + + > valeur par défaut : `` + + >> Ensemble des textes d’aide affichés avec le formulaire d’envoi de vidéo.
+ >> + >> ``` + >> VIDEO_FORM_FIELDS_HELP_TEXT = OrderedDict( + >> [ + >> ( + >> "{0}".format(_("File field")), + >> [ + >> _("You can send an audio or video file."), + >> _("The following formats are supported: %s") + >> % ", ".join(map(str, VIDEO_ALLOWED_EXTENSIONS)), + >> ], + >> ), + >> ( + >> "{0}".format(_("Title field")), + >> [ + >> _( + >> "Please choose a title as short and accurate as possible, " + >> "reflecting the main subject / context of the content." + >> ), + >> _( + >> "You can use the “Description” field below for all " + >> "additional information." + >> ), + >> _( + >> "You may add contributors later using the second button of " + >> "the content edition toolbar: they will appear in the “Info” " + >> "tab at the bottom of the audio / video player." + >> ), + >> ], + >> ), + >> ( + >> "{0}".format(_("Type")), + >> [ + >> _( + >> "Select the type of your content. If the type you wish does " + >> "not appear in the list, please temporary select “Other” " + >> "and contact us to explain your needs." + >> ) + >> ], + >> ), + >> ( + >> "{0}".format(_("Additional owners")), + >> [ + >> _( + >> "In this field you can select and add additional owners to the " + >> "video. These additional owners will have the same rights as " + >> "you except that they can't delete this video." + >> ) + >> ], + >> ), + >> ( + >> "{0}".format(_("Description")), + >> [ + >> _( + >> "In this field you can describe your content, add all needed " + >> "related information, and format the result " + >> "using the toolbar." + >> ) + >> ], + >> ), + >> ( + >> "{0}".format(_("Date of the event field")), + >> [ + >> _( + >> "Enter the date of the event, if applicable, in the " + >> "AAAA-MM-JJ format." + >> ) + >> ], + >> ), + >> ( + >> "{0}".format(_("University course")), + >> [ + >> _( + >> "Select an university course as audience target of " + >> "the content." + >> ), + >> _( + >> "Choose “None / All” if it does not apply or if all are " + >> "concerned, or “Other” for an audience outside " + >> "the european LMD scheme." + >> ), + >> ], + >> ), + >> ( + >> "{0}".format(_("Main language")), + >> [_("Select the main language used in the content.")], + >> ), + >> ( + >> "{0}".format(_("Tags")), + >> [ + >> _( + >> "Please try to add only relevant keywords that can be " + >> "useful to other users." + >> ) + >> ], + >> ), + >> ( + >> "{0}".format(_("Disciplines")), + >> [ + >> _( + >> "Select the discipline to which your content belongs. " + >> "If the discipline you wish does not appear in the list, " + >> "please select nothing and contact us to explain your needs." + >> ), + >> _( + >> 'Hold down "Control", or "Command" on a Mac, ' + >> "to select more than one." + >> ), + >> ], + >> ), + >> ( + >> "{0}".format(_("Licence")), + >> [ + >> ( + >> '> 'title="%(lic)s" target="_blank">%(lic)s' + >> ) + >> % {"lic": _("Attribution 4.0 International (CC BY 4.0)")}, + >> ( + >> '> 'title="%(lic)s" target="_blank">%(lic)s' + >> ) + >> % { + >> "lic": _( + >> "Attribution-NoDerivatives 4.0 " + >> "International (CC BY-ND 4.0)" + >> ) + >> }, + >> ( + >> '> 'title="%(lic)s" target="_blank">%(lic)s' + >> ) + >> % { + >> "lic": _( + >> "Attribution-NonCommercial-NoDerivatives 4.0 " + >> "International (CC BY-NC-ND 4.0)" + >> ) + >> }, + >> ( + >> '> 'title="%(lic)s" target="_blank">%(lic)s' + >> ) + >> % { + >> "lic": _( + >> "Attribution-NonCommercial 4.0 " + >> "International (CC BY-NC 4.0)" + >> ) + >> }, + >> ( + >> '> 'title="%(lic)s" target="_blank">%(lic)s' + >> ) + >> % { + >> "lic": _( + >> "Attribution-NonCommercial-ShareAlike 4.0 " + >> "International (CC BY-NC-SA 4.0)" + >> ) + >> }, + >> ( + >> '> 'title="%(lic)s" target="_blank">%(lic)s' + >> ) + >> % { + >> "lic": _( + >> "Attribution-ShareAlike 4.0 " "International (CC BY-SA 4.0)" + >> ) + >> }, + >> ], + >> ), + >> ( + >> "{0} / {1}".format(_("Channels"), _("Themes")), + >> [ + >> _("Select the channel in which you want your content to appear."), + >> _( + >> "Themes related to this channel will " + >> "appear in the “Themes” list below." + >> ), + >> _( + >> 'Hold down "Control", or "Command" on a Mac, ' + >> "to select more than one." + >> ), + >> _( + >> "If the channel or Themes you wish does not appear " + >> "in the list, please select nothing and contact " + >> "us to explain your needs." + >> ), + >> ], + >> ), + >> ( + >> "{0}".format(_("Draft")), + >> [ + >> _( + >> "In “Draft mode”, the content shows nowhere and nobody " + >> "else but you can see it." + >> ) + >> ], + >> ), + >> ( + >> "{0}".format(_("Restricted access")), + >> [ + >> _( + >> "If you don't select “Draft mode”, you can restrict " + >> "the content access to only people who can log in" + >> ) + >> ], + >> ), + >> ( + >> "{0}".format(_("Password")), + >> [ + >> _( + >> "If you don't select “Draft mode”, you can add a password " + >> "which will be asked to anybody willing to watch " + >> "your content." + >> ), + >> _( + >> "If your video is in a playlist the password of your " + >> "video will be removed automatically." + >> ), + >> ], + >> ), + >> ] + >> ) + >> + >> ``` + + - `VIDEO_MAX_UPLOAD_SIZE` + + > valeur par défaut : `1` + + >> Taille maximum en Go des fichiers téléversés sur la plateforme.
+ + - `VIDEO_PLAYBACKRATES` + + > valeur par défaut : `[0.5, 1, 1.5, 2]` + + >> Configuration des choix de vitesse de lecture pour le lecteur vidéo.
+ + - `VIDEO_RECENT_VIEWCOUNT` + + > valeur par défaut : `180` + + >> Durée (en nombre de jours) sur laquelle on souhaite compter le nombre de vues récentes.
+ + - `VIDEO_REQUIRED_FIELDS` + + > valeur par défaut : `[]` + + >> Permet d’ajouter l’attribut obligatoire dans le formulaire d’edition et d’ajout d’une video :
+ >> Exemple de valeur : ["discipline", "tags"]
+ >> NB : les champs cachés et suivant ne sont pas pris en compte :
+ >> + >> `(video, title, type, owner, date_added, cursus, main_lang)` + + - `VIEW_STATS_AUTH` + + > valeur par défaut : `False` + + >> Réserve l’accès aux statistiques des vidéos aux personnes authentifiées.
+ +### Configuration application video encodage et transcription + +Application pour l’encodage et la transcription de vidéo.
+Il est possible d'encoder en local ou en distant.
+Attention, il faut configurer Celery pour l’envoi des instructions pour l'encodage distant.
+ + - `CELERY_BROKER_URL` + + > valeur par défaut : `amqp://pod:xxx@localhost/rabbitpod` + + >> URL de Celery pour la gestion des taches d’encodage.
+ + - `CELERY_TO_ENCODE` + + > valeur par défaut : `False` + + >> Utilisation de Celery pour la gestion des taches d’encodage
+ + - `DEFAULT_LANG_TRACK` + + > valeur par défaut : `fr` + + >> langue par défaut pour l’ajout de piste à une vidéo.
+ + - `EMAIL_ON_ENCODING_COMPLETION` + + > valeur par défaut : `True` + + >> Si True, un courriel est envoyé aux managers et à l’auteur (si DEBUG est à False) à la fin de l’encodage.
+ + - `EMAIL_ON_TRANSCRIPTING_COMPLETION` + + > valeur par défaut : `True` + + >> Si True, un courriel est envoyé aux managers et à l’auteur (si DEBUG est à False) à la fin de la transcription
+ + - `ENCODING_CHOICES` + + > valeur par défaut : `()` + + >> Encodage possible sur la plateforme. Associé à un rendu dans le cas d’une vidéo.
+ >> + >> ``` + >> ENCODING_CHOICES = ( + >> ("audio", "audio"), + >> ("360p", "360p"), + >> ("480p", "480p"), + >> ("720p", "720p"), + >> ("1080p", "1080p"), + >> ("playlist", "playlist") + >> ) + >> + >> ``` + + - `FORMAT_CHOICES` + + > valeur par défaut : `()` + + >> Format d’encodage réalisé sur la plateforme.
+ >> + >> ``` + >> FORMAT_CHOICES = ( + >> ("video/mp4", "video/mp4"), + >> ("video/mp2t", "video/mp2t"), + >> ("video/webm", "video/webm"), + >> ("audio/mp3", "audio/mp3"), + >> ("audio/wav", "audio/wav"), + >> ("application/x-mpegURL", "application/x-mpegURL"), + >> ) + >> + >> ``` + + - `ENCODE_STUDIO` + + > valeur par défaut : `start_encode_studio` + + >> Fonction appelée pour lancer l’encodage du studio (merge and cut).
+ + - `ENCODE_VIDEO` + + > valeur par défaut : `start_encode` + + >> Fonction appelée pour lancer l’encodage des vidéos direct par thread ou distant par celery
+ + - `VIDEO_RENDITIONS` + + > valeur par défaut : `[]` + + >> Rendu serializé pour l’encodage des videos.
+ >> Cela permet de pouvoir encoder les vidéos sans l’environnement de Pod.
+ >> + >> ``` + >> VIDEO_RENDITIONS = [ + >> { + >> "resolution": "640x360", + >> "minrate": "500k", + >> "video_bitrate": "750k", + >> "maxrate": "1000k", + >> "audio_bitrate": "96k", + >> "encoding_resolution_threshold": 0, + >> "encode_mp4": True, + >> "sites": [1], + >> },{ + >> "resolution": "1280x720", + >> "minrate": "1000k", + >> "video_bitrate": "2000k", + >> "maxrate": "3000k", + >> "audio_bitrate": "128k", + >> "encoding_resolution_threshold": 0, + >> "encode_mp4": True, + >> "sites": [1], + >> },{ + >> "resolution": "1920x1080", + >> "minrate": "2000k", + >> "video_bitrate": "3000k", + >> "maxrate": "4500k", + >> "audio_bitrate": "192k", + >> "encoding_resolution_threshold": 0, + >> "encode_mp4": False, + >> "sites": [1], + >> }, + >> ] + >> + >> ``` + + - `ENCODING_TRANSCODING_CELERY_BROKER_URL` + + > valeur par défaut : `False` + + + >> Il faut renseigner l'url du redis sur lequel Celery va chercher les ordres d'encodage et de transcription
+ >> par exemple : "redis://redis:6379/7"
+ + - `USE_DISTANT_ENCODING_TRANSCODING` + + > valeur par défaut : `False` + + + >> Si True, active l'encodage et la transcription sur un environnement distant via redis+celery
+ +### Configuration application search + + - `ES_INDEX` + + > valeur par défaut : `pod` + + >> Valeur pour l’index de ElasticSearch
+ + - `ES_MAX_RETRIES` + + > valeur par défaut : `10` + + >> Valeur max de tentatives pour ElasticSearch.
+ + - `ES_TIMEOUT` + + > valeur par défaut : `30` + + >> Valeur de timeout pour ElasticSearch.
+ + - `ES_URL` + + > valeur par défaut : `["http://127.0.0.1:9200/"]` + + >> Adresse du ou des instances d’Elasticsearch utilisées pour l’indexation et la recherche de vidéo.
+ + - `ES_VERSION` + + > valeur par défaut : `6` + + >> Version d’ElasticSearch.
+ >> valeurs possibles 6, 7 ou 8 correspondant à la version du Elasticsearch utilisé.
+ >> Pour utiliser la version 7 ou 8, faire une mise à jour du paquet elasticsearch-py
+ >> Pour la 7, `pip3 install elasticsearch==7.17.7`,
+ >> et pour la 8, `pip3 install elasticsearch==8.8.1`.
+ >> Voir [https://elasticsearch-py.readthedocs.io/]() pour plus d'information.
+ +### Configuration application xapi + +Application pour l’envoi d‘instructions xAPI à un LRS.
+Aucune instruction ne persiste dans Pod, elles sont toutes envoyées au LRS paramétré.
+Attention, il faut configurer Celery pour l’envoi des instructions.
+ + - `USE_XAPI` + + > valeur par défaut : `False` + + + >> Activation de l'application xAPI
+ + - `XAPI_ANONYMIZE_ACTOR` + + > valeur par défaut : `True` + + + >> Si False, le nom de l'utilisateur sera stocké en clair dans les statements xAPI, si True, son nom d'utilisateur sera anonymisé
+ + - `XAPI_LRS_LOGIN` + + > valeur par défaut : `` + + + >> identifiant de connexion du LRS pour l'envoi des statements
+ + - `XAPI_LRS_PWD` + + > valeur par défaut : `` + + + >> mot de passe de connexion du LRS pour l'envoi des statements
+ + - `XAPI_LRS_URL` + + > valeur par défaut : `` + + + >> URL de destination pour l'envoi des statements. I.E. : https://ralph.univ.fr/xAPI/statements
\ No newline at end of file From 647c6a516d38071eb581df4afb08d58c206090b3 Mon Sep 17 00:00:00 2001 From: Ptitloup Date: Tue, 3 Oct 2023 15:43:49 +0200 Subject: [PATCH 05/26] [DONE] add CACHE_VIDEO_DEFAULT_TIMEOUT in configuration (#973) --- pod/main/configuration.json | 186 +++++++++++++++++++----------------- 1 file changed, 100 insertions(+), 86 deletions(-) diff --git a/pod/main/configuration.json b/pod/main/configuration.json index 4ba77c31c7..6ae630a562 100644 --- a/pod/main/configuration.json +++ b/pod/main/configuration.json @@ -859,33 +859,33 @@ ] }, "settings": { - "RESTRICT_EDIT_IMPORT_VIDEO_ACCESS_TO_STAFF_ONLY": { - "default_value": true, + "MAX_UPLOAD_SIZE_ON_IMPORT": { + "default_value": 4, "description": { "en": [ - "Only \"staff\" users will be able to import videos" + "Maximum size in Gb of video files that can be imported into the platform ", + "via the import_video application (0 = no maximum size)." ], "fr": [ - "Seuls les utilisateurs \"staff\" pourront importer des vidéos" + "Taille maximum en Go des fichiers vidéos qui peuvent être importés sur la plateforme ", + "via l'application import_video (0 = pas de taille maximum)." ] }, "pod_version_end": "", - "pod_version_init": "3.3.0" + "pod_version_init": "3.4.0" }, - "MAX_UPLOAD_SIZE_ON_IMPORT": { - "default_value": 4, + "RESTRICT_EDIT_IMPORT_VIDEO_ACCESS_TO_STAFF_ONLY": { + "default_value": true, "description": { "en": [ - "Maximum size in Gb of video files that can be imported into the platform ", - "via the import_video application (0 = no maximum size)." + "Only \"staff\" users will be able to import videos" ], "fr": [ - "Taille maximum en Go des fichiers vidéos qui peuvent être importés sur la plateforme ", - "via l'application import_video (0 = pas de taille maximum)." + "Seuls les utilisateurs \"staff\" pourront importer des vidéos" ] }, "pod_version_end": "", - "pod_version_init": "3.4.0" + "pod_version_init": "3.3.0" }, "USE_IMPORT_VIDEO": { "default_value": true, @@ -1018,31 +1018,31 @@ "pod_version_end": "", "pod_version_init": "3.1" }, - "EVENT_GROUP_ADMIN": { - "default_value": "event admin", + "EVENT_CHECK_MAX_ATTEMPT": { + "default_value": 10, "description": { "en": [ "" ], "fr": [ - "Permet de préciser le nom du groupe dans lequel les utilisateurs peuvent planifier un évènement sur plusieurs jours." + "Nombre de tentatives maximum pour vérifier la présence / taille d'un fichier sur le filesystem" ] }, "pod_version_end": "", - "pod_version_init": "3.1" + "pod_version_init": "3.4" }, - "EVENT_CHECK_MAX_ATTEMPT": { - "default_value": 10, + "EVENT_GROUP_ADMIN": { + "default_value": "event admin", "description": { "en": [ "" ], "fr": [ - "Nombre de tentatives maximum pour vérifier la présence / taille d'un fichier sur le filesystem" + "Permet de préciser le nom du groupe dans lequel les utilisateurs peuvent planifier un évènement sur plusieurs jours." ] }, "pod_version_end": "", - "pod_version_init": "3.4" + "pod_version_init": "3.1" }, "HEARTBEAT_DELAY": { "default_value": 45, @@ -1602,31 +1602,31 @@ ] }, "settings": { - "DEFAULT_PLAYLIST_THUMBNAIL": { - "default_value": "/static/playlist/img/default-playlist.svg", + "COUNTDOWN_PLAYLIST_PLAYER": { + "default_value": 0, "description": { "en": [ - "Default image displayed as a poster or thumbnail, used to present the playlist.", - "This image must be located in the `static` directory." + "Countdown used between each video when playing an autoplay playlist.", + "The coutdown is not present if it at 0." ], "fr": [ - "Image par défaut affichée comme poster ou vignette, utilisée pour présenter la playlist.", - "Cette image doit se situer dans le répertoire `static`." + "Compte à rebours utilisé entre chaque vidéo lors de la lecture d'une playlist en lecture automatique.", + "Le compte à rebours n'est pas présent s'il est à 0." ] }, "pod_version_end": "", "pod_version_init": "3.4" }, - "COUNTDOWN_PLAYLIST_PLAYER": { - "default_value": 0, + "DEFAULT_PLAYLIST_THUMBNAIL": { + "default_value": "/static/playlist/img/default-playlist.svg", "description": { "en": [ - "Countdown used between each video when playing an autoplay playlist.", - "The coutdown is not present if it at 0." + "Default image displayed as a poster or thumbnail, used to present the playlist.", + "This image must be located in the `static` directory." ], "fr": [ - "Compte à rebours utilisé entre chaque vidéo lors de la lecture d'une playlist en lecture automatique.", - "Le compte à rebours n'est pas présent s'il est à 0." + "Image par défaut affichée comme poster ou vignette, utilisée pour présenter la playlist.", + "Cette image doit se situer dans le répertoire `static`." ] }, "pod_version_end": "", @@ -2037,6 +2037,21 @@ "pod_version_end": "", "pod_version_init": "3.1.0" }, + "CACHE_VIDEO_DEFAULT_TIMEOUT": { + "default_value": 600, + "description": { + "en": [ + "", + "Time in second to cache video data" + ], + "fr": [ + "", + "Temps en seconde de conservation des données de l'application video" + ] + }, + "pod_version_end": "", + "pod_version_init": "3.5.0" + }, "CHANNEL_FORM_FIELDS_HELP_TEXT": { "default_value": "", "description": { @@ -2756,7 +2771,6 @@ "pod_version_end": "", "pod_version_init": "3.1.0" }, - "VIDEO_REQUIRED_FIELDS": { "default_value": "[]", "description": { @@ -2870,6 +2884,32 @@ "pod_version_end": "", "pod_version_init": "3.1.0" }, + "ENCODE_STUDIO": { + "default_value": "start_encode_studio", + "description": { + "en": [ + "" + ], + "fr": [ + "Fonction appelée pour lancer l’encodage du studio (merge and cut)." + ] + }, + "pod_version_end": "", + "pod_version_init": "3.1.0" + }, + "ENCODE_VIDEO": { + "default_value": "start_encode", + "description": { + "en": [ + "" + ], + "fr": [ + "Fonction appelée pour lancer l’encodage des vidéos direct par thread ou distant par celery" + ] + }, + "pod_version_end": "", + "pod_version_init": "3.1.0" + }, "ENCODING_CHOICES": { "default_value": "()", "description": { @@ -2893,6 +2933,21 @@ "pod_version_end": "", "pod_version_init": "3.1.0" }, + "ENCODING_TRANSCODING_CELERY_BROKER_URL": { + "default_value": false, + "description": { + "en": [ + "" + ], + "fr": [ + "", + "Il faut renseigner l'url du redis sur lequel Celery va chercher les ordres d'encodage et de transcription", + "par exemple : \"redis://redis:6379/7\"" + ] + }, + "pod_version_end": "", + "pod_version_init": "3.3.1" + }, "FORMAT_CHOICES": { "default_value": "()", "description": { @@ -2916,31 +2971,19 @@ "pod_version_end": "", "pod_version_init": "3.1.0" }, - "ENCODE_STUDIO": { - "default_value": "start_encode_studio", - "description": { - "en": [ - "" - ], - "fr": [ - "Fonction appelée pour lancer l’encodage du studio (merge and cut)." - ] - }, - "pod_version_end": "", - "pod_version_init": "3.1.0" - }, - "ENCODE_VIDEO": { - "default_value": "start_encode", + "USE_DISTANT_ENCODING_TRANSCODING": { + "default_value": false, "description": { "en": [ "" ], "fr": [ - "Fonction appelée pour lancer l’encodage des vidéos direct par thread ou distant par celery" + "", + "Si True, active l'encodage et la transcription sur un environnement distant via redis+celery" ] }, "pod_version_end": "", - "pod_version_init": "3.1.0" + "pod_version_init": "3.4.0" }, "VIDEO_RENDITIONS": { "default_value": "[]", @@ -2987,35 +3030,6 @@ }, "pod_version_end": "", "pod_version_init": "3.1.0" - }, - "ENCODING_TRANSCODING_CELERY_BROKER_URL": { - "default_value": false, - "description": { - "en": [ - "" - ], - "fr": [ - "", - "Il faut renseigner l'url du redis sur lequel Celery va chercher les ordres d'encodage et de transcription", - "par exemple : \"redis://redis:6379/7\"" - ] - }, - "pod_version_end": "", - "pod_version_init": "3.3.1" - }, - "USE_DISTANT_ENCODING_TRANSCODING": { - "default_value": false, - "description": { - "en": [ - "" - ], - "fr": [ - "", - "Si True, active l'encodage et la transcription sur un environnement distant via redis+celery" - ] - }, - "pod_version_end": "", - "pod_version_init": "3.4.0" } }, "title": { @@ -4363,31 +4377,31 @@ "pod_version_end": "", "pod_version_init": "3.1.0" }, - "HIDE_DISCIPLINES": { + "HIDE_CURSUS": { "default_value": false, "description": { "en": [ "" ], "fr": [ - "Si True, permet de ne pas afficher les disciplines dans la colonne de droite" + "Si True, permet de ne pas afficher les cursus dans la colonne de droite" ] }, "pod_version_end": "", - "pod_version_init": "3.1.0" + "pod_version_init": "3.4.0" }, - "HIDE_CURSUS": { + "HIDE_DISCIPLINES": { "default_value": false, "description": { "en": [ "" ], "fr": [ - "Si True, permet de ne pas afficher les cursus dans la colonne de droite" + "Si True, permet de ne pas afficher les disciplines dans la colonne de droite" ] }, "pod_version_end": "", - "pod_version_init": "3.4.0" + "pod_version_init": "3.1.0" }, "HIDE_LANGUAGE_SELECTOR": { "default_value": false, @@ -5013,4 +5027,4 @@ } } } -] +] \ No newline at end of file From 72e38c1b491993975d4d297da824971866fa3e90 Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 3 Oct 2023 13:44:53 +0000 Subject: [PATCH 06/26] Auto-update configuration files --- CONFIGURATION_FR.md | 99 ++++++++++++++++++++++++--------------------- 1 file changed, 53 insertions(+), 46 deletions(-) diff --git a/CONFIGURATION_FR.md b/CONFIGURATION_FR.md index ceedd88995..89ff3b0dfc 100644 --- a/CONFIGURATION_FR.md +++ b/CONFIGURATION_FR.md @@ -711,17 +711,17 @@ Vous pouvez tout à fait rajouter des langues comme vous le souhaitez. Il faudra >> Si True, permet de cacher l’onglet chaine dans la barre de menu du haut.
- - `HIDE_DISCIPLINES` + - `HIDE_CURSUS` > valeur par défaut : `False` - >> Si True, permet de ne pas afficher les disciplines dans la colonne de droite
+ >> Si True, permet de ne pas afficher les cursus dans la colonne de droite
- - `HIDE_CURSUS` + - `HIDE_DISCIPLINES` > valeur par défaut : `False` - >> Si True, permet de ne pas afficher les cursus dans la colonne de droite
+ >> Si True, permet de ne pas afficher les disciplines dans la colonne de droite
- `HIDE_LANGUAGE_SELECTOR` @@ -1401,12 +1401,6 @@ Vous pouvez tout à fait rajouter des langues comme vous le souhaitez. Il faudra Application Import_video permettant d'importer des vidéos externes dans Pod.
Mettre `USE_IMPORT_VIDEO` à True pour activer cette application.
- - `RESTRICT_EDIT_IMPORT_VIDEO_ACCESS_TO_STAFF_ONLY` - - > valeur par défaut : `True` - - >> Seuls les utilisateurs "staff" pourront importer des vidéos
- - `MAX_UPLOAD_SIZE_ON_IMPORT` > valeur par défaut : `4` @@ -1414,6 +1408,12 @@ Mettre `USE_IMPORT_VIDEO` à True pour activer cette application.
>> Taille maximum en Go des fichiers vidéos qui peuvent être importés sur la plateforme
>> via l'application import_video (0 = pas de taille maximum).
+ - `RESTRICT_EDIT_IMPORT_VIDEO_ACCESS_TO_STAFF_ONLY` + + > valeur par défaut : `True` + + >> Seuls les utilisateurs "staff" pourront importer des vidéos
+ - `USE_IMPORT_VIDEO` > valeur par défaut : `True` @@ -1475,18 +1475,18 @@ Mettre `USE_IMPORT_VIDEO` à True pour activer cette application.
>> Permet de lancer automatiquement l’enregistrement sur l’interface utilisée (wowza, ) sur le broadcaster et spécifié par `BROADCASTER_PILOTING_SOFTWARE`
- - `EVENT_GROUP_ADMIN` - - > valeur par défaut : `event admin` - - >> Permet de préciser le nom du groupe dans lequel les utilisateurs peuvent planifier un évènement sur plusieurs jours.
- - `EVENT_CHECK_MAX_ATTEMPT` > valeur par défaut : `10` >> Nombre de tentatives maximum pour vérifier la présence / taille d'un fichier sur le filesystem
+ - `EVENT_GROUP_ADMIN` + + > valeur par défaut : `event admin` + + >> Permet de préciser le nom du groupe dans lequel les utilisateurs peuvent planifier un évènement sur plusieurs jours.
+ - `HEARTBEAT_DELAY` > valeur par défaut : `45` @@ -1784,13 +1784,6 @@ Mettre `USE_MEETING` à True pour activer cette application.
Application Playlist pour la gestion des playlists.
Mettre `USE_PLAYLIST` à True pour activer cette application.
- - `DEFAULT_PLAYLIST_THUMBNAIL` - - > valeur par défaut : `/static/playlist/img/default-playlist.svg` - - >> Image par défaut affichée comme poster ou vignette, utilisée pour présenter la playlist.
- >> Cette image doit se situer dans le répertoire `static`.
- - `COUNTDOWN_PLAYLIST_PLAYER` > valeur par défaut : `0` @@ -1798,6 +1791,13 @@ Mettre `USE_PLAYLIST` à True pour activer cette application.
>> Compte à rebours utilisé entre chaque vidéo lors de la lecture d'une playlist en lecture automatique.
>> Le compte à rebours n'est pas présent s'il est à 0.
+ - `DEFAULT_PLAYLIST_THUMBNAIL` + + > valeur par défaut : `/static/playlist/img/default-playlist.svg` + + >> Image par défaut affichée comme poster ou vignette, utilisée pour présenter la playlist.
+ >> Cette image doit se situer dans le répertoire `static`.
+ - `USE_FAVORITES` > valeur par défaut : `True` @@ -1998,6 +1998,13 @@ Mettre `USE_PLAYLIST` à True pour activer cette application.
>> Activer les commentaires au niveau de la plateforme
+ - `CACHE_VIDEO_DEFAULT_TIMEOUT` + + > valeur par défaut : `600` + + + >> Temps en seconde de conservation des données de l'application video
+ - `CHANNEL_FORM_FIELDS_HELP_TEXT` > valeur par défaut : `` @@ -2569,6 +2576,18 @@ Attention, il faut configurer Celery pour l’envoi des instructions pour l'enco >> Si True, un courriel est envoyé aux managers et à l’auteur (si DEBUG est à False) à la fin de la transcription
+ - `ENCODE_STUDIO` + + > valeur par défaut : `start_encode_studio` + + >> Fonction appelée pour lancer l’encodage du studio (merge and cut).
+ + - `ENCODE_VIDEO` + + > valeur par défaut : `start_encode` + + >> Fonction appelée pour lancer l’encodage des vidéos direct par thread ou distant par celery
+ - `ENCODING_CHOICES` > valeur par défaut : `()` @@ -2587,6 +2606,14 @@ Attention, il faut configurer Celery pour l’envoi des instructions pour l'enco >> >> ``` + - `ENCODING_TRANSCODING_CELERY_BROKER_URL` + + > valeur par défaut : `False` + + + >> Il faut renseigner l'url du redis sur lequel Celery va chercher les ordres d'encodage et de transcription
+ >> par exemple : "redis://redis:6379/7"
+ - `FORMAT_CHOICES` > valeur par défaut : `()` @@ -2605,17 +2632,12 @@ Attention, il faut configurer Celery pour l’envoi des instructions pour l'enco >> >> ``` - - `ENCODE_STUDIO` - - > valeur par défaut : `start_encode_studio` - - >> Fonction appelée pour lancer l’encodage du studio (merge and cut).
+ - `USE_DISTANT_ENCODING_TRANSCODING` - - `ENCODE_VIDEO` + > valeur par défaut : `False` - > valeur par défaut : `start_encode` - >> Fonction appelée pour lancer l’encodage des vidéos direct par thread ou distant par celery
+ >> Si True, active l'encodage et la transcription sur un environnement distant via redis+celery
- `VIDEO_RENDITIONS` @@ -2658,21 +2680,6 @@ Attention, il faut configurer Celery pour l’envoi des instructions pour l'enco >> >> ``` - - `ENCODING_TRANSCODING_CELERY_BROKER_URL` - - > valeur par défaut : `False` - - - >> Il faut renseigner l'url du redis sur lequel Celery va chercher les ordres d'encodage et de transcription
- >> par exemple : "redis://redis:6379/7"
- - - `USE_DISTANT_ENCODING_TRANSCODING` - - > valeur par défaut : `False` - - - >> Si True, active l'encodage et la transcription sur un environnement distant via redis+celery
- ### Configuration application search - `ES_INDEX` From b4aa63e62072ac1d2a31f1de9b3115fac7c9aa62 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 4 Oct 2023 11:04:44 +0200 Subject: [PATCH 07/26] Bump pillow from 9.3.0 to 10.0.1 (#977) * add configuration_fr.md * Bump pillow from 9.3.0 to 10.0.1 Bumps [pillow](https://github.com/python-pillow/Pillow) from 9.3.0 to 10.0.1. - [Release notes](https://github.com/python-pillow/Pillow/releases) - [Changelog](https://github.com/python-pillow/Pillow/blob/main/CHANGES.rst) - [Commits](https://github.com/python-pillow/Pillow/compare/9.3.0...10.0.1) --- updated-dependencies: - dependency-name: pillow dependency-type: direct:production ... Signed-off-by: dependabot[bot] --------- Signed-off-by: dependabot[bot] Co-authored-by: Ptitloup Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index ecee6485b0..80d370581e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ -r requirements-encode.txt Django==3.2.20 django-ckeditor==6.3.0 -Pillow==9.3.0 +Pillow==10.0.1 django-tagging==0.5.0 django-modeltranslation==0.18.7 django-cas-client==1.5.3 From a4a93b0eacd98c9cdd7b69a0c3b814b30fa01e8a Mon Sep 17 00:00:00 2001 From: Ptitloup Date: Wed, 4 Oct 2023 11:59:39 +0200 Subject: [PATCH 08/26] [DONE] Ptitloup/work on configuration (#976) * add cconfiguration command and add python 3.10 in configuration * compare configuration and print result * add pydoc * fix typo * remove python 3.7 from supported version * add configuration for pwa * fix typo --- pod/main/configuration.json | 31 ++++++- .../commands/compareconfiguration.py | 84 +++++++++++++++++++ 2 files changed, 114 insertions(+), 1 deletion(-) create mode 100644 pod/main/management/commands/compareconfiguration.py diff --git a/pod/main/configuration.json b/pod/main/configuration.json index 6ae630a562..562e6b1481 100644 --- a/pod/main/configuration.json +++ b/pod/main/configuration.json @@ -4864,7 +4864,7 @@ "fr": [ "", "La plateforme Esup-Pod se base sur le framework Django écrit en Python.", - "Elle supporte les versions 3.7, 3.8 et 3.9 de Python.", + "Elle est compatible avec les versions 3.8, 3.9 et 3.10 de Python.", "", "**Django Version : 3.2 LTS**", "", @@ -4972,6 +4972,35 @@ "pod_version_end": "", "pod_version_init": "3.1" }, + "pwa": { + "default_value": "1.1.0", + "description": { + "en": "", + "fr": [ + "Mise en place du mode PWA grâce à l'application Django-pwa", + "Voici la configuration par défaut pour Pod, vous pouvez surcharger chaque variable dans votre fichier de configuration.", + "PWA_APP_NAME = \"Pod\"", + "PWA_APP_DESCRIPTION = _(", + " \"Pod is aimed at users of our institutions, by allowing the publication of \"", + " \"videos in the fields of research (promotion of platforms, etc.), training \"", + " \"(tutorials, distance training, student reports, etc.), institutional life (video \"", + " \"of events), offering several days of content.\"", + ")", + "PWA_APP_THEME_COLOR = \"#0A0302\"", + "PWA_APP_BACKGROUND_COLOR = \"#ffffff\"", + "PWA_APP_DISPLAY = \"standalone\"", + "PWA_APP_SCOPE = \"/\"", + "PWA_APP_ORIENTATION = \"any\"", + "PWA_APP_START_URL = \"/\"", + "PWA_APP_STATUS_BAR_COLOR = \"default\"", + "PWA_APP_DIR = \"ltr\"", + "PWA_APP_LANG = \"fr-FR\"", + "Pour en savoir plus : [https://github.com/silviolleite/django-pwa]()" + ] + }, + "pod_version_end": "", + "pod_version_init": "3.4" + }, "rest_framework": { "default_value": "3.14.0", "description": { diff --git a/pod/main/management/commands/compareconfiguration.py b/pod/main/management/commands/compareconfiguration.py new file mode 100644 index 0000000000..2633139c22 --- /dev/null +++ b/pod/main/management/commands/compareconfiguration.py @@ -0,0 +1,84 @@ +from django.core.management.base import BaseCommand, CommandError +from typing import List +import urllib.request +import json +import os + +__CONFIGURATION_POD_URL__ = "https://raw.githubusercontent.com/EsupPortail/Esup-Pod/__pod_version__/pod/main/configuration.json" + + +class Command(BaseCommand): + help = 'Compare configuration from specified version' + + def add_arguments(self, parser): + parser.add_argument('pod_version', type=str) + + def handle(self, *args, **options): + """Get confiuration from specific version passed in args and compare it to the local configuration.""" + configuration_url = __CONFIGURATION_POD_URL__.replace( + '__pod_version__', + options['pod_version'] + ) + distant_configuration = [] + try: + response = urllib.request.urlopen(configuration_url) + configuration_distant_data = json.loads(response.read().decode()) + distant_configuration = self.get_all_settings(configuration_distant_data) + except urllib.error.HTTPError as err: + if err.code == 404: + raise CommandError( + 'The configuration file for %s was not found' % options['pod_version'] + ) + raise CommandError(f'A HTTPError was thrown: {err.code} {err.reason}') + local_configuration = [] + with open(os.path.join("pod", "main", "configuration.json"), "r") as json_file: + configuration_local_data = json.load(json_file) + local_configuration = self.get_all_settings(configuration_local_data) + local_missing = self.get_local_missing(distant_configuration, local_configuration) + distant_missing = self.get_url_missing(distant_configuration, local_configuration) + + self.print_log( + "New configuration from %s not in local" % options['pod_version'], + local_missing + ) + self.print_log( + "Configuration found in local file but missing in %s version of pod" % options['pod_version'], + distant_missing + ) + + self.stdout.write(self.style.SUCCESS('End compare configuration')) + + def print_log(self, title: str, data: List[str]) -> None: + """Pretty print of array with title.""" + print(20 * "-") + print(f"{title} :") + print("\n - " + "\n - ".join(data)) + + def get_local_missing(self, distant_configuration, local_configuration): + """Return key from distant configuration not found in local configuration.""" + local_missing = [] + for key in distant_configuration: + if key not in local_configuration: + local_missing.append(key) + return local_missing + + def get_url_missing(self, distant_configuration, local_configuration): + """Return key from local configuration not found in distant configuration.""" + url_missing = [] + for key in local_configuration: + if key not in distant_configuration: + url_missing.append(key) + return url_missing + + def get_all_settings(self, data): + """Get all settings from json configuration.""" + json_settings = [] + pod_settings = data[0]["configuration_pod"]["description"] + for keys in pod_settings.keys(): + keys_settings = pod_settings[keys]["settings"] + json_settings += keys_settings.keys() + app_settings = data[0]["configuration_apps"]["description"] + for keys in app_settings.keys(): + keys_settings = app_settings[keys]["settings"] + json_settings += keys_settings.keys() + return json_settings From 423d2ddd3096243a233646f4b992966643540c35 Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 4 Oct 2023 10:00:20 +0000 Subject: [PATCH 09/26] Fixup. Format code with Black --- .../commands/compareconfiguration.py | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/pod/main/management/commands/compareconfiguration.py b/pod/main/management/commands/compareconfiguration.py index 2633139c22..df9a1754fb 100644 --- a/pod/main/management/commands/compareconfiguration.py +++ b/pod/main/management/commands/compareconfiguration.py @@ -8,16 +8,15 @@ class Command(BaseCommand): - help = 'Compare configuration from specified version' + help = "Compare configuration from specified version" def add_arguments(self, parser): - parser.add_argument('pod_version', type=str) + parser.add_argument("pod_version", type=str) def handle(self, *args, **options): """Get confiuration from specific version passed in args and compare it to the local configuration.""" configuration_url = __CONFIGURATION_POD_URL__.replace( - '__pod_version__', - options['pod_version'] + "__pod_version__", options["pod_version"] ) distant_configuration = [] try: @@ -27,9 +26,9 @@ def handle(self, *args, **options): except urllib.error.HTTPError as err: if err.code == 404: raise CommandError( - 'The configuration file for %s was not found' % options['pod_version'] + "The configuration file for %s was not found" % options["pod_version"] ) - raise CommandError(f'A HTTPError was thrown: {err.code} {err.reason}') + raise CommandError(f"A HTTPError was thrown: {err.code} {err.reason}") local_configuration = [] with open(os.path.join("pod", "main", "configuration.json"), "r") as json_file: configuration_local_data = json.load(json_file) @@ -38,15 +37,16 @@ def handle(self, *args, **options): distant_missing = self.get_url_missing(distant_configuration, local_configuration) self.print_log( - "New configuration from %s not in local" % options['pod_version'], - local_missing + "New configuration from %s not in local" % options["pod_version"], + local_missing, ) self.print_log( - "Configuration found in local file but missing in %s version of pod" % options['pod_version'], - distant_missing + "Configuration found in local file but missing in %s version of pod" + % options["pod_version"], + distant_missing, ) - self.stdout.write(self.style.SUCCESS('End compare configuration')) + self.stdout.write(self.style.SUCCESS("End compare configuration")) def print_log(self, title: str, data: List[str]) -> None: """Pretty print of array with title.""" From 8fea73cef46bef08c9f21a1c584c1f1ebf9c1e1c Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 4 Oct 2023 10:00:51 +0000 Subject: [PATCH 10/26] Auto-update configuration files --- CONFIGURATION_FR.md | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/CONFIGURATION_FR.md b/CONFIGURATION_FR.md index 89ff3b0dfc..6f989269a3 100644 --- a/CONFIGURATION_FR.md +++ b/CONFIGURATION_FR.md @@ -6,7 +6,7 @@ La plateforme Esup-Pod se base sur le framework Django écrit en Python.
-Elle supporte les versions 3.7, 3.8 et 3.9 de Python.
+Elle est compatible avec les versions 3.8, 3.9 et 3.10 de Python.
**Django Version : 3.2 LTS**
@@ -72,6 +72,30 @@ Voici les configurations des applications tierces utilisées par Esup-Pod.
>> Système d’authentification OpenID Connect
>> [https://mozilla-django-oidc.readthedocs.io/en/stable/installation.html]()
+ - `pwa` + + > valeur par défaut : `1.1.0` + + >> Mise en place du mode PWA grâce à l'application Django-pwa
+ >> Voici la configuration par défaut pour Pod, vous pouvez surcharger chaque variable dans votre fichier de configuration.
+ >> PWA_APP_NAME = "Pod"
+ >> PWA_APP_DESCRIPTION = _(
+ >> "Pod is aimed at users of our institutions, by allowing the publication of "
+ >> "videos in the fields of research (promotion of platforms, etc.), training "
+ >> "(tutorials, distance training, student reports, etc.), institutional life (video "
+ >> "of events), offering several days of content."
+ >> )
+ >> PWA_APP_THEME_COLOR = "#0A0302"
+ >> PWA_APP_BACKGROUND_COLOR = "#ffffff"
+ >> PWA_APP_DISPLAY = "standalone"
+ >> PWA_APP_SCOPE = "/"
+ >> PWA_APP_ORIENTATION = "any"
+ >> PWA_APP_START_URL = "/"
+ >> PWA_APP_STATUS_BAR_COLOR = "default"
+ >> PWA_APP_DIR = "ltr"
+ >> PWA_APP_LANG = "fr-FR"
+ >> Pour en savoir plus : [https://github.com/silviolleite/django-pwa]()
+ - `rest_framework` > valeur par défaut : `3.14.0` From 56514f00c761d7d7ca118629be200c7774ea9525 Mon Sep 17 00:00:00 2001 From: Olivier Bado-Faustin Date: Mon, 9 Oct 2023 10:51:38 +0200 Subject: [PATCH 11/26] [DONE] Code formatting (#979) * Use Stylelint (https://stylelint.io/) with "stylelint-config-standard" coding rules to uniformize all Esup-Pod CSS files. + minor Py code formatting * add minor code styling corrections * remove unused data-attribute * Auto Correct CSS by Prettier * Remove unused commented CSS lines * Remove CSS comments + correct a wrong default value "VOSK" for TRANSCRIPTION_TYPE --- .github/workflows/code_formatting.yml | 6 +- .pa11yci | 2 +- .stylelintrc.json | 3 + pod/authentication/backends.py | 5 +- pod/bbb/static/css/bbb.css | 23 +- pod/chapter/static/css/chapters.css | 95 ++- pod/chapter/static/css/videojs-chapters.css | 29 +- pod/completion/static/css/caption_maker.css | 395 ++++----- pod/completion/static/css/completion.css | 321 ++++---- pod/cut/static/css/video_cut.css | 24 +- pod/enrichment/static/css/enrichment.css | 71 +- pod/enrichment/static/css/videojs-slides.css | 124 ++- pod/import_video/static/css/import_video.css | 33 +- pod/live/static/css/event.css | 15 +- pod/live/static/css/event_list.css | 4 + pod/main/static/css/dark.css | 153 ++-- pod/main/static/css/dyslexia.css | 4 +- pod/main/static/css/iframe.css | 2 +- pod/main/static/css/pod-admin.css | 25 +- pod/main/static/css/pod.css | 679 ++++++--------- pod/meeting/static/css/meeting.css | 44 +- pod/playlist/static/playlist/css/playlist.css | 191 +++-- pod/podfile/static/podfile/css/podfile.css | 326 ++++---- .../templates/recorder/opencast-studio.html | 52 +- pod/video/static/css/change_video_owner.css | 107 +-- pod/video/static/css/comment-style.css | 772 +++++++++--------- pod/video/static/css/paginator.css | 21 +- .../static/css/regroup_videos_by_theme.css | 62 +- pod/video/static/css/video-iframe.css | 120 ++- pod/video/static/css/video_category.css | 427 +++++----- pod/video/static/css/video_notes.css | 114 ++- pod/video/static/css/video_stats_view.css | 78 +- pod/video/static/css/videojs-controlbar.css | 24 +- pod/video_encode_transcript/transcript.py | 13 +- .../transcript_model.py | 10 +- 35 files changed, 2140 insertions(+), 2234 deletions(-) create mode 100644 .stylelintrc.json diff --git a/.github/workflows/code_formatting.yml b/.github/workflows/code_formatting.yml index a1ee4ea2d3..bf7a7f4447 100644 --- a/.github/workflows/code_formatting.yml +++ b/.github/workflows/code_formatting.yml @@ -17,9 +17,11 @@ jobs: git config user.email github-actions@github.com git remote set-url origin https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }} - # Prettify js code with prettier + # Prettify js+css code with prettier - name: Running prettier - run: npx prettier --write pod/*/static/**/*.js + run: | + npx prettier --write pod/*/static/**/*.js + npx prettier --write pod/*/static/**/*.css - name: Check for modified files id: prettier-git-check diff --git a/.pa11yci b/.pa11yci index 2ff160e506..8bb2b412b0 100644 --- a/.pa11yci +++ b/.pa11yci @@ -16,7 +16,7 @@ "http://localhost:9090/video/0001-video-test/", "http://localhost:9090/live/events/" ], - "todo":[ + "todo": [ "These urls are not A11y compliant yet, and need more work from 3rd party", "http://localhost:9090/video/stats_view/videos/" ] diff --git a/.stylelintrc.json b/.stylelintrc.json new file mode 100644 index 0000000000..40db42c668 --- /dev/null +++ b/.stylelintrc.json @@ -0,0 +1,3 @@ +{ + "extends": "stylelint-config-standard" +} diff --git a/pod/authentication/backends.py b/pod/authentication/backends.py index 1b2ee527a7..57bda9b203 100644 --- a/pod/authentication/backends.py +++ b/pod/authentication/backends.py @@ -20,8 +20,9 @@ def is_staff_affiliation(affiliation): class ShibbBackend(ShibbolethRemoteUserBackend): def authenticate(self, request, remote_user, shib_meta): """ - The username passed as ``remote_user`` is considered trusted. Use the - username to get or create the user. + Username passed as `remote_user` is considered trusted. + + Use the username to get or create the user. """ if not remote_user: return diff --git a/pod/bbb/static/css/bbb.css b/pod/bbb/static/css/bbb.css index 521a6cc6e7..cd388c7916 100644 --- a/pod/bbb/static/css/bbb.css +++ b/pod/bbb/static/css/bbb.css @@ -1,15 +1,22 @@ +/** + * Esup-Pod BBB styles + */ + #bbb_meetings_list .card-header { background: var(--color-black-alpha); - padding: 0 .25rem; + padding: 0 0.25rem; z-index: 9; } -#bbb_meetings_list .card-header .text-muted{ - color: var(--color-white) !important; + +#bbb_meetings_list .card-header .text-muted { + color: var(--color-white) !important; } + /* To always see publish button */ -#bbb_meetings_list .infinite-item .card-body{ -height: auto !important; +#bbb_meetings_list .infinite-item .card-body { + height: auto !important; +} + +#bbb_meetings_list .infinite-item .card-body footer a { + width: 100% !important; } -#bbb_meetings_list .infinite-item .card-body footer a{ -width: 100% !important; -} \ No newline at end of file diff --git a/pod/chapter/static/css/chapters.css b/pod/chapter/static/css/chapters.css index 0530205422..b5d17425b6 100644 --- a/pod/chapter/static/css/chapters.css +++ b/pod/chapter/static/css/chapters.css @@ -1,90 +1,107 @@ +/** + * Esup-Pod Chapter styles + */ /*** Table scroll ***/ table.scroll { - width: 100%; - border-collapse: collapse; - border-spacing: 0; + width: 100%; + border-collapse: collapse; + border-spacing: 0; } + table.scroll .btn-sm, table.scroll .btn-group-sm > .btn { - border-radius: 3px; - font-size: 12px; - line-height: 0.5; - padding: 5px 10px; + border-radius: 3px; + font-size: 12px; + line-height: 0.5; + padding: 5px 10px; } + table.scroll tbody, table.scroll thead { - display: block; + display: block; } + table.scroll thead tr th { - height: 27px; - line-height: 27px; - text-align: left; + height: 27px; + line-height: 27px; + text-align: left; } + table.scroll tbody { - max-height: 200px; - overflow-y: auto; - overflow-x: hidden; + max-height: 200px; + overflow-y: auto; + overflow-x: hidden; } + table.scroll tbody td, table.scroll thead th { - width: 10%; - height: 20px; - white-space: nowrap; - line-height: 20px; + width: 10%; + height: 20px; + white-space: nowrap; + line-height: 20px; } + table.scroll thead th.chapter_title, table.scroll thead th.chapter_time_start, table.scroll thead th.chapter_time_end { - white-space: nowrap; + white-space: nowrap; } + #list_chapter .panel-heading, #form_chapter .panel-heading { - border-bottom: 1px solid transparent; - border-top-left-radius: 3px; - border-top-right-radius: 3px; - padding: 4px 15px; + border-bottom: 1px solid transparent; + border-top-left-radius: 3px; + border-top-right-radius: 3px; + padding: 4px 15px; } + #form_new { - padding-left: 12px; - padding-bottom: 10px; + padding-left: 12px; + padding-bottom: 10px; } + #form_chapter, #form_chapter_import, #form_vtt { - padding: 10px; + padding: 10px; } + form#form_chapter, form#form_chapter_import { - background-color: rgba(0, 0, 0, .05); + background-color: rgba(0 0 0 0.05); } + .form-group.row p { - padding: 2px; + padding: 2px; } /** Filepicker override **/ div.file-picker-overlay, div.file-picker, ul.css-tabs a { - box-sizing: content-box; + box-sizing: content-box; } + textarea#id_description { - line-height: normal; + line-height: normal; } + div.file-picker-overlay input[type="text"], -div.file-picker-overlay textarea, +div.file-picker-overlay textarea, div.file-picker-overlay select { - border: 1px solid #ccc; - border-radius: 4px; - padding: 5px 6px; - margin-top: 0; + border: 1px solid #ccc; + border-radius: 4px; + padding: 5px 6px; + margin-top: 0; } + .file-list a:hover { - cursor: pointer; - color: #007bff !important; + cursor: pointer; + color: #007bff !important; } /** Bootstrap override **/ .card-title { - margin: .45rem; -} \ No newline at end of file + margin: 0.45rem; +} diff --git a/pod/chapter/static/css/videojs-chapters.css b/pod/chapter/static/css/videojs-chapters.css index f8d2d1c38e..e196bdd172 100644 --- a/pod/chapter/static/css/videojs-chapters.css +++ b/pod/chapter/static/css/videojs-chapters.css @@ -1,3 +1,7 @@ +/** + * Esup-Pod video-js chapter styles + */ + .chapters-list.inactive, .chapters-list.active { position: absolute; @@ -5,12 +9,10 @@ top: 0; height: 100%; width: 20%; - background-color: rgba(43, 51, 63, .7); + background-color: rgba(43 51 63 0.7); overflow-y: auto; - /*border: 2px solid black;*/ cursor: default; z-index: 2; - } .chapters-list.inactive { @@ -45,9 +47,17 @@ display: list-item; list-style-type: none; text-align: -webkit-match-parent; - /*background-color: rgba(0, 0, 0, 0.8);*/ margin: 0 3px; - border-top: 1px solid rgba(0, 0, 0, .8); + border-top: 1px solid rgba(0 0 0 0.8); +} + +.chapters-list ol li a { + display: block; + padding: 0.7rem 1rem; + transition: 0.3s; + color: #fff; + text-align: left; + font-size: 1.3em; } .chapters-list ol li a:hover, @@ -58,15 +68,6 @@ cursor: pointer; } -.chapters-list ol li a { - display: block; - padding: .7rem 1rem; - transition: .3s; - color: #fff; - text-align: left; - font-size: 1.3em; -} - #chapters { display: none; } diff --git a/pod/completion/static/css/caption_maker.css b/pod/completion/static/css/caption_maker.css index a599853de7..4b7271ef65 100644 --- a/pod/completion/static/css/caption_maker.css +++ b/pod/completion/static/css/caption_maker.css @@ -1,356 +1,245 @@ +/** + * Esup-Pod caption_maker styles + */ + #videoElm { - display: block; - border: solid 1px #999; - width: 100%; - min-height: 297px; + display: block; + border: solid 1px #999; + width: 100%; + min-height: 297px; } + .videoError { - display: block; - background-color: #999; - width: 100%; - min-height: 297px; - color: white; - text-align: center; - padding: 12px; + display: block; + background-color: #999; + width: 100%; + min-height: 297px; + color: white; + text-align: center; + padding: 12px; } #videoError { - display: none; + display: none; } + #captionTitle { - padding-top: 4px; - padding-bottom: 4px; - min-height: 32px; + padding-top: 4px; + padding-bottom: 4px; + min-height: 32px; } #textCaptionEntry { - /* - width: 100%; - height: auto; - line-height: 19px; - border: 1px solid #999; - padding: 3px 8px 5px; - min-height: 50px; - overflow: hidden; - */ - text-align: center; + text-align: center; } #textCaptionEntry.playing { - background-color: var(--pod-background-dark); - color: white; + background-color: var(--pod-background-dark); + color: white; } -/*textarea { - line-height: 16px; - font-size: 14px; - resize: none; - border: 1px solid #ccc; - border-radius: 4px; -}*/ - .shortcutKey { - display: inline-block; - border: 2px solid #222; - border-radius: 6px; - padding: 3px 8px; - font-weight: 600; - margin-right: 8px; - margin-left: 8px; - min-width: 35px; - text-align: center; + display: inline-block; + border: 2px solid #222; + border-radius: 6px; + padding: 3px 8px; + font-weight: 600; + margin-right: 8px; + margin-left: 8px; + min-width: 35px; + text-align: center; } .shortcutKey svg { - transform: translateY(-2px); + transform: translateY(-2px); } /* the list of captions */ -.gray_no_video{ - display: flex; - flex-wrap: wrap; - border-top: 1px solid #E1E1E1; +.gray_no_video { + display: flex; + flex-wrap: wrap; + border-top: 1px solid #e1e1e1; } .videoSection { - float: left; - min-height: 425px; - width: 49%; - padding: 24px 0px; - padding-right: 24px; + float: left; + min-height: 425px; + width: 49%; + padding: 24px 0; + padding-right: 24px; } .caption_content { - border-left: 1px solid #E1E1E1; - display: inline-block; - width: 49%; - /* overflow-y: auto; */ -} - -.caption_content .caption_title{ - display: flex; - position: relative; -} -.caption_content svg{ - width: 20px; - color: var(--secondary); - margin-left: 4px; -} -.caption_content .caption_title svg:hover + .help_text{ - display: block; -} -.caption_content .help_text{ - display: none; - position: absolute; - background: var(--pod-primary); - color: #fff; - width: calc(100% - 110px); - right: 0; - padding: .4em .8em; - border-radius: 4px; - box-shadow: 4px 4px 10px #ccc; - font-size: 15px; - line-height: 1.4; + border-left: 1px solid #e1e1e1; + display: inline-block; + width: 49%; } -.captions_editor { - height: 470px; +.caption_content .caption_title { + display: flex; + position: relative; +} - overflow-y: auto; - /*resize: none; - width: 100%; - padding: 0;*/ +.caption_content svg { + width: 20px; + color: var(--secondary); + margin-left: 4px; +} +.caption_content .caption_title svg:hover + .help_text { + display: block; } -#newCaptionsEditor { - margin-bottom: 6px; +.caption_content .help_text { + display: none; + position: absolute; + background: var(--pod-primary); + color: #fff; + width: calc(100% - 110px); + right: 0; + padding: 0.4em 0.8em; + border-radius: 4px; + box-shadow: 4px 4px 10px #ccc; + font-size: 15px; + line-height: 1.4; +} +.captions_editor { + height: 470px; + overflow-y: auto; +} + +#newCaptionsEditor { + margin-bottom: 6px; } .newEditorBlock { - border-bottom: 1px solid #E1E1E1; - padding: 8px; - transition: 0.2s; + border-bottom: 1px solid #e1e1e1; + padding: 8px; + transition: 0.2s; } .newEditorBlock:hover { - background-color: rgba(223, 230, 246, 0.4); + background-color: rgba(223 230 246 0.4); } .newEditorBlock > textarea { - width: 77%; - /* - height: 80px; - border-style: hidden; - background-color: transparent; - padding: 8px; - transition: .4s; - */ + width: 77%; } .captionBeingEdited { - border-left: 3px solid var(--pod-primary); - background-color: rgba(223, 230, 246, 0.4); + border-left: 3px solid var(--pod-primary); + background-color: rgba(223 230 246 0.4); } -/*.captionBeingEdited > textarea { - border: 1px solid var(--pod-primary); - border-radius: 4px; - background-color: #FFF5FB; -}*/ - .captionTimestamps { - /*float: right;*/ - line-height: 32px; + line-height: 32px; } .newEditorBlock a { - display: block; - /* - margin: 6px 0; - max-width: 78px; - color: #3EA6FF; - font-weight: 400; - */ + display: block; } .newEditorBlock input { - margin: 6px 0; - max-width: 78px; - display: inline-block; - padding: 4px; + margin: 6px 0; + max-width: 78px; + display: inline-block; + padding: 4px; } -/*.captionButtons { - float: left; -}*/ - .captionButtons button { - /*margin: 9px 2px 2px 2px; - left: 16px;*/ - display: block; - width: 28px; - height: 28px; - padding: 0; - border: 0; - border-radius: 50%; - /*background: #fff; - box-shadow: 0 0 4px rgba(0,0,0,.15); - transition: 0.2s;*/ + display: block; + width: 28px; + height: 28px; + padding: 0; + border: 0; + border-radius: 50%; } .captionButtons button:hover { - background: var(--pod-primary-lighten); + background: var(--pod-primary-lighten); } -/* -.captionButtons button:hover svg { - color: #fff; -} - -.captionButtons svg{ - color: #707070; - margin: 0; -}*/ - #addSubtitle svg { - color: var(--pod-link-color); + color: var(--pod-link-color); } .makerNavbarRight { - float: right; + float: right; } @media only screen and (max-width: 1000px) { - .makerNavbarRight { - float: none; - } -} - -/* -#captionFilename { - width: 280px; - margin-left: 32px; - transform: translateY(-4px); - border-top-style: hidden; - border-right-style: hidden; - border-left-style: hidden; - border-bottom-style: groove; - background-color: transparent; -} - -#switchOldEditMode { - margin-bottom: 8px; + .makerNavbarRight { + float: none; + } } -#captionLanguageSelect { - margin-right: 10px; - height: 31px; - width: 120px; - background: none; - border: none; - color: var(--pod-primary); - font-weight: 600; - font-size: 20px; -} - -#captionLanguageSelect:hover { - cursor: pointer; -} - -#captionLanguageSelect option { - color: black; - text-align: left; - font-size: 16px; +#captionmakerModal.save > .modal-dialog { + max-width: 1000px; } - -#captionKindSelect { - margin-right: 10px; - height: 31px; - width: 120px; - background: none; - border: none; - color: var(--pod-primary); - font-weight: 600; - font-size: 20px; +#editorTipsAndGoBack { + width: 100%; + clear: both; + padding-top: 24px; + padding-bottom: 24px; + display: block; + border-top: 1px solid #e1e1e1; } -#captionKindSelect:hover { - cursor: pointer; -} +@media only screen and (max-width: 800px) { + .gray_no_video { + display: flex; + flex-direction: column; + } -#captionKindSelect option { - color: black; - text-align: left; - font-size: 16px; -}*/ + .gray_no_video > div { + width: 100% !important; + } -#captionmakerModal.save > .modal-dialog { - max-width: 1000px; -} + .gray_no_video div:first-child { + overflow: hidden; + margin: 0; + margin-bottom: 1em; + min-height: unset !important; + } -#editorTipsAndGoBack { - width: 100%; - clear: both; - padding-top: 24px; - padding-bottom: 24px; - display: block; - border-top: 1px solid #E1E1E1; -} - -@media only screen and (max-width: 800px){ - .gray_no_video{ - display: flex; - flex-direction: column; - } - .gray_no_video > div{ - width: 100% !important; - } - .gray_no_video div:first-child{ - overflow: hidden; - margin: 0; - margin-bottom: 1em; - min-height: unset !important; - } - - .newEditorBlock > textarea { - width: 60%; - } + .newEditorBlock > textarea { + width: 60%; + } } .keyframe { - position: absolute; - z-index: 2; - height: 11px; + position: absolute; + z-index: 2; + height: 11px; } .keyframe-left { - transform: translate(-6px, -11px); + transform: translate(-6px, -11px); } .keyframe-right { - transform: translate(0, -11px); + transform: translate(0, -11px); } .regionHighligh { - position: absolute; - z-index: 1; - background-color: rgba(173, 50, 122, .5); - height: 3px; + position: absolute; + z-index: 1; + background-color: rgba(173 50 122 0.5); + height: 3px; } ::-webkit-scrollbar { - padding: 2px; - width: 4px; + padding: 2px; + width: 4px; } ::-webkit-scrollbar-track { - background: none; + background: none; } ::-webkit-scrollbar-thumb { - background: var(--pod-primary); - border-radius: 2px; + background: var(--pod-primary); + border-radius: 2px; } diff --git a/pod/completion/static/css/completion.css b/pod/completion/static/css/completion.css index d50aee21a8..b228cbff4f 100644 --- a/pod/completion/static/css/completion.css +++ b/pod/completion/static/css/completion.css @@ -1,137 +1,184 @@ - -/** Table scroll **/ -table.scroll { - width: 100%; - border-collapse: collapse; - border-spacing: 0; -} -table.scroll .btn-sm, -table.scroll .btn-group-sm > .btn { - border-radius: 4px; - font-size: 14px; - line-height: 1.4; - padding: .2em .4em; -} -table.scroll tbody { - max-height: 100px; - overflow-y: auto; - overflow-x: hidden; -} -table.scroll tbody td, -table.scroll thead th { - width: 10%; - height: 20px; - line-height: 20px; - border-bottom: 0; -} -table.scroll thead tr th { - height: 27px; - line-height: 27px; - text-align: left; -} - -/** Table contributor **/ -table#table_list_contributors tbody td.contributor_name, -table#table_list_contributors thead th.contributor_name { - width: 20%; -} - -/** Accordeon for lists **/ -#accordeon li, -#accordeon div { - list-style: none; -} - -/** Lists style **/ -#list_contributor .panel-heading, -#list_track .panel-heading, -#list_document .panel-heading, -#list_overlay .panel-heading { - border-bottom: 1px solid transparent; - border-top-left-radius: 3px; - border-top-right-radius: 3px; - padding: 4px 15px; -} - -#id_background { - margin-left: 0.25rem; - position: inherit; -} - -.contenuTitre{ - display: flex; - flex-direction: column; -} -.contenuTitre #list_track{ - order: 1; -} -.contenuTitre .breadcrumb{ - padding: 0; -} -.contenuTitre .btn{ - margin-bottom: 1rem; - margin-right: 1rem; -} - -/***** Override track list *****/ - -.grid-list-track .division{ grid-column: 1 / span 4; border-bottom: 1px solid #ccc;} -.grid-list-track .track_kind.options .btn{ font-size: 14px;} -.grid-list-track .track_kind.options a.btn{ overflow: unset; align-self: self-start;} -.grid-list-track .track_kind.options .dropdown #dropdownMenuButton{ - background-color: var(--pod-primary); - color: #fff; - border-color: var(--pod-primary); - border-radius: 4px; -} -.grid-list-track .track_kind.options .dropdown .dropdown-item{ background-color: #fff; } -.grid-list-track .track_kind.options .dropdown .btn{ width: 100%; } -.grid-list-track .track_kind.options .dropdown{ display: none; background-color: #fff;} -.grid-list-track .thead_title{ - margin: 0; - padding-right: 20px; - color: var(--pod-primary); - word-wrap: break-word; - font-weight: 600; -} -.grid-list-track p{margin: 0;} -.grid-list-track{ - display: grid; - grid-template-columns: max-content min-content 1fr min-content; - grid-gap: 20px; - margin-bottom: 1em; - margin-top: 1em; -} -.grid-list-track .track_kind.file{word-break: break-word;} -.track_kind.options{ - display: grid; - grid-template-columns: repeat(3, 1fr); - grid-column-gap: 10px; -} -.track_kind.options .btn { - margin: 0; - padding: .2em .4em; - font-size: 1rem; - box-sizing: border-box; -} -@media only screen and (max-width: 840px) -{ -.grid-list-track .track_kind.options .dropdown{ display: inline-block;} -.grid-list-track .track_kind.options > form, -.grid-list-track .track_kind.options > #modifCapSubFile{ display: none;} -} - -/** Filepicker override **/ -div.file-picker-overlay, -div.file-picker, -ul.css-tabs a { - box-sizing: content-box; -} -textarea#id_description { - line-height: normal; -} - -/** Bootstrap override **/ -.card-title { - margin: .45rem; -} +/** + * Esup-Pod completion styles + */ + +/** Table scroll **/ +table.scroll { + width: 100%; + border-collapse: collapse; + border-spacing: 0; +} + +table.scroll .btn-sm, +table.scroll .btn-group-sm > .btn { + border-radius: 4px; + font-size: 14px; + line-height: 1.4; + padding: 0.2em 0.4em; +} + +table.scroll tbody { + max-height: 100px; + overflow-y: auto; + overflow-x: hidden; +} + +table.scroll tbody td, +table.scroll thead th { + width: 10%; + height: 20px; + line-height: 20px; + border-bottom: 0; +} + +table.scroll thead tr th { + height: 27px; + line-height: 27px; + text-align: left; +} + +/** Table contributor **/ +table#table_list_contributors tbody td.contributor_name, +table#table_list_contributors thead th.contributor_name { + width: 20%; +} + +/** Accordeon for lists **/ +#accordeon li, +#accordeon div { + list-style: none; +} + +/** Lists style **/ +#list_contributor .panel-heading, +#list_track .panel-heading, +#list_document .panel-heading, +#list_overlay .panel-heading { + border-bottom: 1px solid transparent; + border-top-left-radius: 3px; + border-top-right-radius: 3px; + padding: 4px 15px; +} + +#id_background { + margin-left: 0.25rem; + position: inherit; +} + +.contenuTitre { + display: flex; + flex-direction: column; +} + +.contenuTitre #list_track { + order: 1; +} + +.contenuTitre .breadcrumb { + padding: 0; +} + +.contenuTitre .btn { + margin-bottom: 1rem; + margin-right: 1rem; +} + +/***** Override track list *****/ + +.grid-list-track .division { + grid-column: 1 / span 4; + border-bottom: 1px solid #ccc; +} + +.grid-list-track .track_kind.options .btn { + font-size: 14px; +} + +.grid-list-track .track_kind.options a.btn { + overflow: unset; + align-self: self-start; +} + +.grid-list-track .track_kind.options .dropdown #dropdownMenuButton { + background-color: var(--pod-primary); + color: #fff; + border-color: var(--pod-primary); + border-radius: 4px; +} + +.grid-list-track .track_kind.options .dropdown .dropdown-item { + background-color: #fff; +} + +.grid-list-track .track_kind.options .dropdown .btn { + width: 100%; +} + +.grid-list-track .track_kind.options .dropdown { + display: none; + background-color: #fff; +} + +.grid-list-track .thead_title { + margin: 0; + padding-right: 20px; + color: var(--pod-primary); + word-wrap: break-word; + font-weight: 600; +} + +.grid-list-track p { + margin: 0; +} + +.grid-list-track { + display: grid; + grid-template-columns: max-content min-content 1fr min-content; + grid-gap: 20px; + margin-bottom: 1em; + margin-top: 1em; +} + +.grid-list-track .track_kind.file { + word-break: break-word; +} + +.track_kind.options { + display: grid; + grid-template-columns: repeat(3, 1fr); + grid-column-gap: 10px; +} + +.track_kind.options .btn { + margin: 0; + padding: 0.2em 0.4em; + font-size: 1rem; + box-sizing: border-box; +} + +@media only screen and (max-width: 840px) { + .grid-list-track .track_kind.options .dropdown { + display: inline-block; + } + + .grid-list-track .track_kind.options > form, + .grid-list-track .track_kind.options > #modifCapSubFile { + display: none; + } +} + +/** Filepicker override **/ +div.file-picker-overlay, +div.file-picker, +ul.css-tabs a { + box-sizing: content-box; +} + +textarea#id_description { + line-height: normal; +} + +/** Bootstrap override **/ +.card-title { + margin: 0.45rem; +} diff --git a/pod/cut/static/css/video_cut.css b/pod/cut/static/css/video_cut.css index d487da90ee..836765d64a 100644 --- a/pod/cut/static/css/video_cut.css +++ b/pod/cut/static/css/video_cut.css @@ -1,7 +1,11 @@ +/** + * Esup-Pod video-cutter styles + */ + #wrapper_cut { position: relative; width: 100%; - padding: 50px 10px 20px 10px; + padding: 50px 10px 20px; border-radius: 10px; } @@ -12,8 +16,6 @@ } input[type="range"] { - -webkit-appearance: none; - -moz-appearance: none; appearance: none; width: 100%; outline: none; @@ -63,13 +65,12 @@ input[type="range"]::-webkit-slider-thumb { -webkit-appearance: none; margin-top: -9px; border: 1px solid gray; - height: 1.7em; width: 1.7em; cursor: pointer; pointer-events: auto; border-radius: 50%; - background-color: #FFF; + background-color: #fff; } input[type="range"]::-moz-range-thumb { @@ -79,7 +80,7 @@ input[type="range"]::-moz-range-thumb { cursor: pointer; pointer-events: auto; border-radius: 50%; - background-color: #FFF; + background-color: #fff; } input[type="range"]::-ms-thumb { @@ -89,13 +90,14 @@ input[type="range"]::-ms-thumb { cursor: pointer; pointer-events: auto; border-radius: 50%; - background-color: #FFF; + background-color: #fff; } -#container_cut{ - /*--bs-btn-focus-shadow-rgb: var(--pod-primary-rgb);*/ +#container_cut { + /* --bs-btn-focus-shadow-rgb: var(--pod-primary-rgb); */ --bs-btn-focus-shadow-rgb: 200, 200, 253; - --bs-btn-focus-box-shadow:0 0 0 0.25rem rgba(var(--bs-btn-focus-shadow-rgb), .5);; + --bs-btn-focus-box-shadow: 0 0 0 0.25rem + rgba(var(--bs-btn-focus-shadow-rgb) 0.5); } input[type="range"]:active::-webkit-slider-thumb, @@ -124,7 +126,7 @@ input[type="range"]:focus-visible::-moz-range-thumb { font-size: 25px; } -#values_cut:before { +#values_cut::before { content: ""; position: absolute; height: 0; diff --git a/pod/enrichment/static/css/enrichment.css b/pod/enrichment/static/css/enrichment.css index 75ee3e1311..8d126e3ccd 100644 --- a/pod/enrichment/static/css/enrichment.css +++ b/pod/enrichment/static/css/enrichment.css @@ -4,59 +4,56 @@ /*** Table scroll ***/ table.scroll { - width: 100%; - border-collapse: collapse; - border-spacing: 0; + width: 100%; + border-collapse: collapse; + border-spacing: 0; } + table.scroll .btn-sm, table.scroll .btn-group-sm > .btn { - border-radius: 3px; - font-size: 12px; - line-height: 0.5; - padding: 5px 10px; + border-radius: 3px; + font-size: 12px; + line-height: 0.5; + padding: 5px 10px; } + table.scroll thead tr th { - height: 27px; - line-height: 27px; - text-align: left; - border: none; + height: 27px; + line-height: 27px; + text-align: left; + border: none; } + table.scroll tbody { - max-height: 200px; - overflow-y: auto; - overflow-x: hidden; + max-height: 200px; + overflow-y: auto; + overflow-x: hidden; } + table.scroll tbody td, table.scroll thead th { - width: 10%; - height: 20px; - white-space: nowrap; - line-height: 20px; + width: 10%; + height: 20px; + white-space: nowrap; + line-height: 20px; } -.enrich_type{ - text-transform: capitalize; + +.enrich_type { + text-transform: capitalize; } + #list_enrich .panel-heading, #form_enrich .panel-heading { - border-bottom: 1px solid transparent; - border-top-left-radius: 3px; - border-top-right-radius: 3px; - padding: 4px 15px; + border-bottom: 1px solid transparent; + border-top-left-radius: 3px; + border-top-right-radius: 3px; + padding: 4px 15px; } + #form_enrich { - padding: 10px; -} -form#form_enrich { - background-color: rgba(0, 0, 0, .05); + padding: 10px; } -/* -#form_new, -.video_back { - padding-left: 12px; - margin-bottom: 10px; -} -.video_back button { - margin-bottom: 10px; +form#form_enrich { + background-color: rgba(0 0 0 0.05); } -*/ \ No newline at end of file diff --git a/pod/enrichment/static/css/videojs-slides.css b/pod/enrichment/static/css/videojs-slides.css index 8185899249..3702ac9cd3 100644 --- a/pod/enrichment/static/css/videojs-slides.css +++ b/pod/enrichment/static/css/videojs-slides.css @@ -1,9 +1,16 @@ +/** + * Esup-Pod videojs-slides styles + */ + /* Main */ -.vjs-poster {z-index: 2} -.video-js .vjs-tech {padding: 0 10px 0 10px} +.vjs-poster { + z-index: 2; +} + .vjs-slides { display: block; } + .video-slides { display: flex; position: absolute; @@ -12,11 +19,13 @@ bottom: 0; padding: 0; } -.video-slides>li { + +.video-slides > li { background-size: contain; background-position: center center; background-repeat: no-repeat; - /*background-attachment: fixed;*/ + + /* background-attachment: fixed; */ display: none; position: absolute; left: 50%; @@ -24,16 +33,23 @@ bottom: 15%; width: 50%; padding: 0; - border-right: 8px solid transparent;/*make margin for contain background-attachment*/ - /*padding-bottom: 35px;*//*Works but maybe not usable because plyer menu is hidden duriong playing */ + border-right: 8px solid transparent; + + /* Make margin for contain background-attachment */ + + /* padding-bottom: 35px; */ + + /* Works but maybe not usable because plyer menu is hidden duriong playing */ } -.video-slides>li>div { + +.video-slides > li > div { height: 100%; - background-color: var(--bs-light); /*#fff;*/ + background-color: var(--bs-light); color: var(--pod-font-color); padding: 1em; } -.video-slides>li>.slide_embed { + +.video-slides > li > .slide_embed { overflow: auto; background-color: #000; text-align: center; @@ -41,10 +57,12 @@ align-items: center; justify-content: center; } -.video-slides>li>img { + +.video-slides > li > img { max-width: 100%; -webkit-user-select: none; } + /* Normal screen size */ /********* Default *********/ @@ -53,28 +71,37 @@ height: 100%; } +.video-js .vjs-tech { + padding: 0 10px; +} + /********* Pip slide -> pip-slide *********/ .vjs-tech.pip-slide { width: 80% !important; height: 100%; } + .video-slides li.pip-slide { left: 80% !important; top: 35% !important; bottom: 35% !important; width: 20%; } -/*.pip-slide img { + +/* +.pip-slide img { height: 30% !important; } .pip-slide div { height: 50% !important; -}*/ +} +*/ .video-slides li.pip-slide embed { position: absolute; right: 0; width: 150%; - /*height: 50%;*/ + + /* height: 50%; */ } /********* Pip video -> big-slides *********/ @@ -82,6 +109,7 @@ width: 20% !important; height: 100%; } + .video-slides li.big-slide { position: relative !important; width: 80%; @@ -89,21 +117,26 @@ top: 0 !important; bottom: 0 !important; } + .video-slides li.big-slide img { height: 100%; width: 100%; - /*padding-right: 5%;*/ + + /* padding-right: 5%; */ } + .video-slides li.big-slide embed { position: absolute; height: 100%; width: 90%; left: 25px; } + /********* Video off -> full-slide *********/ .vjs-tech.full-slide { - display:none; + display: none; } + .video-slides li.full-slide { position: relative !important; left: 0 !important; @@ -112,10 +145,12 @@ padding: 0 !important; width: 100%; } + .video-slides li.full-slide img { height: 100%; width: 100%; } + .video-slides li.full-slide embed { position: absolute; height: 100%; @@ -125,20 +160,23 @@ /********* Slide off -> no-slide *********/ .vjs-tech.no-slide { - width:100% !important; - height:100%; + width: 100% !important; + height: 100%; z-index: 1; } + .video-slides li.no-slide { - z-index:-1; + z-index: -1; } .vjs-text-track-display { - z-index:1; + z-index: 1; } /* Fullscreen */ -/*.vjs-fullscreen .video-slides img, + +/* +.vjs-fullscreen .video-slides img, .vjs-fullscreen .video-slides embed { width: 100%; height: 100%; @@ -166,18 +204,22 @@ height: 100%; width: 90%; left: 50px; -}*/ +} +*/ + /* Slide bar */ .vjs-chapbar { color: red; top: -0.5rem; height: 100%; position: relative; - background: rgba(100, 100, 100, 0.5); + background: rgba(100 100 100 0.5); } + .vjs-chapbar-holder { height: 100%; } + .vjs-chapbar-chap { height: 100%; float: left; @@ -188,19 +230,39 @@ background-color: #ffe800; } -.vjs-big-play-button {z-index: 2} -.vjs-control-bar {z-index: 3} +.vjs-big-play-button { + z-index: 2; +} + +.vjs-control-bar { + z-index: 3; +} /* Enrich types colors */ -.enrich_image{color:var(--bs-purple)} -.enrich_document{color:var(--bs-orange)} -.enrich_richtext{color:var(--bs-blue)} -.enrich_weblink{color:var(--bs-red)} -.enrich_embed{color:var(--bs-green)} +.enrich_image { + color: var(--bs-purple); +} + +.enrich_document { + color: var(--bs-orange); +} + +.enrich_richtext { + color: var(--bs-blue); +} + +.enrich_weblink { + color: var(--bs-red); +} -li[class^="enrich_"]{ +.enrich_embed { + color: var(--bs-green); +} + +li[class^="enrich_"] { line-height: 1.2em; } -li[class^="enrich_"]::marker{ + +li[class^="enrich_"]::marker { font-size: 1.5em; } diff --git a/pod/import_video/static/css/import_video.css b/pod/import_video/static/css/import_video.css index 68c7fed335..c5f25bd664 100644 --- a/pod/import_video/static/css/import_video.css +++ b/pod/import_video/static/css/import_video.css @@ -1,9 +1,12 @@ +/** + * Esup-Pod import_video styles + */ + #recordings.table { --bs-table-color: var(--pod-font-color); --bs-table-striped-color: var(--pod-font-color); } - /* Loading while uploading */ .recording-loader { position: absolute; @@ -19,6 +22,7 @@ padding: 10px; display: none; } + .recording-loading { margin: auto; border: 6px solid #f3f3f3; @@ -30,10 +34,15 @@ } @keyframes recording-spin { - 0% { transform: rotate(0deg); } - 100% { transform: rotate(360deg); } + 0% { + transform: rotate(0deg); + } + + 100% { + transform: rotate(360deg); + } } -/* */ + /* Message error */ div.alert.alert-dismissible { border-radius: 6px; @@ -43,7 +52,7 @@ div.alert.alert-dismissible { position: relative; padding-right: 60px; border: 1px solid #e6e6e6; - background: #FFF; + background: #fff; } div.alert .icon { @@ -68,37 +77,37 @@ div.alert .icon i { } div.alert.alert-success .icon, -div.alert.alert-success .icon:after { +div.alert.alert-success .icon::after { border-color: none; background: #00986a; } div.alert.alert-info .icon, -div.alert.alert-info .icon:after { +div.alert.alert-info .icon::after { border-color: none; background: #00b3c8; } div.alert.alert-warning .icon, -div.alert.alert-warning .icon:after { +div.alert.alert-warning .icon::after { border: none; background: #f9af2c; } div.alert.alert-error .icon, -div.alert.alert-error .icon:after { +div.alert.alert-error .icon::after { border-color: none; background: #c82630; } div.alert .proposition { color: #000; - font-weight: Bold; + font-weight: bold; } + div.alert .proposition::before { content: "\F137"; margin-right: 15px; font-family: bootstrap-icons; - vertical-align: -.125em; + vertical-align: -0.125em; } -/* */ diff --git a/pod/live/static/css/event.css b/pod/live/static/css/event.css index 16bfe0589e..48b1888ec3 100644 --- a/pod/live/static/css/event.css +++ b/pod/live/static/css/event.css @@ -1,13 +1,20 @@ -.current_event{ +/** + * Esup-Pod live event styles + */ + +.current_event { stroke: red; } + .video-js .vjs-time-control { display: block; } + .video-js .vjs-remaining-time { display: none; } - .filter-event-img { - max-height:32px; - max-width:32px; + +.filter-event-img { + max-height: 32px; + max-width: 32px; } diff --git a/pod/live/static/css/event_list.css b/pod/live/static/css/event_list.css index d8b38cec81..fad97a8f2c 100644 --- a/pod/live/static/css/event_list.css +++ b/pod/live/static/css/event_list.css @@ -1,3 +1,7 @@ +/** + * Esup-Pod live event list styles + */ + .event-card-container { min-width: 12rem; min-height: 11rem; diff --git a/pod/main/static/css/dark.css b/pod/main/static/css/dark.css index a71ea0a7d5..71697c1152 100644 --- a/pod/main/static/css/dark.css +++ b/pod/main/static/css/dark.css @@ -1,22 +1,6 @@ /** Dark mode for Esup Pod **/ -:root[data-theme="dark"] { - --pod-primary: var(--pod-primary-dark); - --pod-primary-lighten: var(--pod-primary-lighten-dark); - --pod-primary-darken: var(--pod-primary-darken-dark); - --pod-background: var(--pod-background-dark); - --pod-font-color: var(--pod-font-color-dark); - --pod-background-neutre1-bloc: var(--pod-background-neutre1-bloc-dark); - --pod-background-neutre2-bloc: var(--pod-background-neutre2-bloc-dark); - --pod-btn-text: var(--pod-btn-text-dark); - --pod-alert: var(--pod-alert-dark); - --pod-link-color: var(--pod-primary-lighten-dark); - --pod-link-color-rgb: var(--pod-primary-lighten-dark-rgb); - --pod-activelink-color: var(--pod-primary); -} - [data-theme="dark"] { - /* CUSTOM COLORS */ --color-shark: #212529; --bg-color: #303238; @@ -26,15 +10,15 @@ --bs-dark: #202025; --bs-light: var(--bs-dark); --bs-gray-dark: var(--bs-dark); - --bs-danger: #FE4C53; - + --bs-danger: #fe4c53; --color-formfields: #454c52; --color-silver-chalice: #000; --color-alto: var(--pod-background); - --color-black: #FFF; - --color-black-alpha: #FFFA; + --color-black: #fff; + --color-black-alpha: #fffa; /* Video Comment variable */ + /* --primary-background-color: var(--pod-background) !important; --third-background-color: var(--pod-background) !important; @@ -42,6 +26,21 @@ */ } +:root[data-theme="dark"] { + --pod-primary: var(--pod-primary-dark); + --pod-primary-lighten: var(--pod-primary-lighten-dark); + --pod-primary-darken: var(--pod-primary-darken-dark); + --pod-background: var(--pod-background-dark); + --pod-font-color: var(--pod-font-color-dark); + --pod-background-neutre1-bloc: var(--pod-background-neutre1-bloc-dark); + --pod-background-neutre2-bloc: var(--pod-background-neutre2-bloc-dark); + --pod-btn-text: var(--pod-btn-text-dark); + --pod-alert: var(--pod-alert-dark); + --pod-link-color: var(--pod-primary-lighten-dark); + --pod-link-color-rgb: var(--pod-primary-lighten-dark-rgb); + --pod-activelink-color: var(--pod-primary); +} + [data-theme="dark"] .table { /* copied from .table-dark class */ --bs-table-color: #fff; @@ -60,6 +59,7 @@ } /***** Auto DARK MODE (use browser setting) *****/ + /* @media (prefers-color-scheme: dark) { body[data-admin-utc-offset] { @@ -68,23 +68,25 @@ --pod-font-color: #eeeeee; --bg-color: #121212; } -}*/ +} +*/ /* switch logoPod color on dark theme */ [data-theme="dark"] .pod-navbar__brand img { - filter: invert(100%) saturate(2908%) hue-rotate(27deg) brightness(121%) contrast(99%); + filter: invert(100%) saturate(2908%) hue-rotate(27deg) brightness(121%) + contrast(99%); } [data-theme="dark"] .vjs-logo-button { filter: brightness(0) invert(1); } -[data-theme="dark"] :not(.alert)>.btn-close { +[data-theme="dark"] :not(.alert) > .btn-close { filter: invert(100%); } [data-theme="dark"] .form-control::placeholder { - color: #BEC1C6; + color: #bec1c6; } [data-theme="dark"] .text-muted { @@ -96,23 +98,26 @@ background-color: var(--background-color); color: var(--pod-font-color); border-color: var(--pod-primary); - box-shadow: 0 0 0 .2rem rgba(126, 126, 126, .25); + box-shadow: 0 0 0 0.2rem rgba(126 126 126 0.25); } -[data-theme="dark"] .category_modal_videos_list .infinite-item .checked_overlay { - background-color: rgba(0, 0, 0, .8); +[data-theme="dark"] + .category_modal_videos_list + .infinite-item + .checked_overlay { + background-color: rgba(0 0 0 0.8); } [data-theme="dark"] #card-takenote .header:hover { - background-color: var(--pod-background) + background-color: var(--pod-background); } -[data-theme="dark"] .breadcrumb-item+.breadcrumb-item::before { +[data-theme="dark"] .breadcrumb-item + .breadcrumb-item::before { color: var(--bs-white); } [data-theme="dark"] .breadcrumb-item.active { - color: #A8ABB3; + color: #a8abb3; } [data-theme="dark"] .nav-tabs .nav-item.show .nav-link, @@ -128,10 +133,12 @@ border-color: var(--pod-background); } -/*[data-theme="dark"] .navbar-nav .nav-link:focus, +/* +[data-theme="dark"] .navbar-nav .nav-link:focus, [data-theme="dark"] .navbar-nav .nav-link:hover { color: var(--pod-activelink-color); -}*/ +} +*/ [data-theme="dark"] .btn-link.disabled, [data-theme="dark"] .dropdown-item, @@ -141,20 +148,22 @@ } [data-theme="dark"] .btn-link.disabled { - opacity: .7; + opacity: 0.7; } -/*[data-theme="dark"] .btn:hover, +/* +[data-theme="dark"] .btn:hover, [data-theme="dark"] .btn:active, [data-theme="dark"] .btn:focus { color: inherit; -}*/ +} -/*[data-theme="dark"] .btn-link:focus, +[data-theme="dark"] .btn-link:focus, [data-theme="dark"] .btn-link:active, [data-theme="dark"] .btn-link:hover { color: var(--pod-activelink-color); -}*/ +} +*/ [data-theme="dark"] .btn-light { background-color: var(--bs-dark); @@ -172,27 +181,31 @@ [data-theme="dark"] .btn-secondary { color: var(--bs-white); } + [data-theme="dark"] .btn-outline-secondary { - color: #A8AFB5; + color: #a8afb5; } [data-theme="dark"] .btn-outline-primary { - --bs-btn-hover-bg: var(--pod-primary-darken-dark); color: var(--pod-font-color); + + --bs-btn-hover-bg: var(--pod-primary-darken-dark); } -[data-theme="dark"] .btn-outline-primary>svg { +[data-theme="dark"] .btn-outline-primary > svg { color: var(--pod-primary); } -[data-theme="dark"] .btn-outline-primary:hover>svg, -[data-theme="dark"] .btn-outline-primary:focus>svg { +[data-theme="dark"] .btn-outline-primary:hover > svg, +[data-theme="dark"] .btn-outline-primary:focus > svg { color: var(--bs-white); } [data-theme="dark"] .card { - /*background-color: var(--bs-dark); - border-color: var(--bs-dark);*/ + /* + background-color: var(--bs-dark); + border-color: var(--bs-dark); + */ color: var(--pod-font-color); } @@ -245,8 +258,8 @@ body.dark { /** Admin widgets styles **/ [data-theme="dark"] .selector .selector-filter, -[data-theme="dark"] .selector .selector-available h2, -[data-theme="dark"] .selector-chosen h2 { +[data-theme="dark"] .selector-chosen h2, +[data-theme="dark"] .selector .selector-available h2 { color: var(--pod-font-color); border-color: var(--background-color); } @@ -255,12 +268,11 @@ body.dark { background-color: var(--pod-background); } -[data-theme="dark"] .selector .selector-available h2, -[data-theme="dark"] .selector-chosen h2 { +[data-theme="dark"] .selector-chosen h2, +[data-theme="dark"] .selector .selector-available h2 { background-color: var(--color-silver-chalice); } - /* INPUT TEXT-AREA SELECT dark mode */ [data-theme="dark"] select, [data-theme="dark"] input:not(.btn), @@ -268,11 +280,15 @@ body.dark { [data-theme="dark"] .form-control, [data-theme="dark"] .form-control[readonly], [data-theme="dark"] .select2-container, -[data-theme="dark"] .select2-container-multi .select2-choices .select2-search-field input, +[data-theme="dark"] + .select2-container-multi + .select2-choices + .select2-search-field + input, [data-theme="dark"] .select2-container-multi .select2-choices, [data-theme="dark"] .select2-drop-active, [data-theme="dark"] .select2-choice, -[data-theme="dark"] .select2-choice .select2-search-choice-close+div, +[data-theme="dark"] .select2-choice .select2-search-choice-close + div, [data-theme="dark"] .select2-dropdown-open .select2-choice, [data-theme="dark"] .select2-results .select2-no-results, [data-theme="dark"] .select2-results .select2-searching, @@ -280,17 +296,20 @@ body.dark { background-color: var(--pod-background-neutre1-bloc); border-color: var(--pod-font-color); color: var(--pod-font-color); - /*box-shadow: none;*/ + + /* box-shadow: none; */ } -[data-theme="dark"] .select2-selection--multiple .select2-selection__choice{ + +[data-theme="dark"] .select2-selection--multiple .select2-selection__choice { color: #000; } -[data-theme="dark"] .form-select{ +[data-theme="dark"] .form-select { background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23f3f9ff' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e"); } -/*.theme-switch-wrapper { +/* +.theme-switch-wrapper { display: flex; align-items: center; } @@ -298,7 +317,8 @@ body.dark { .theme-switch-wrapper em { margin-left: 10px; font-size: 1rem; -}*/ +} +*/ .theme-switch { display: inline-block; @@ -314,16 +334,13 @@ body.dark { .slider { background-color: var(--pod-background-neutre1-bloc); - bottom: 0; cursor: pointer; - left: 0; - position: absolute; - right: 0; - top: 0; - transition: .4s; - border-radius: 24px; display: flex; justify-content: space-around; + inset: 0; + position: absolute; + transition: 0.4s; + border-radius: 24px; } .slider:focus, @@ -331,26 +348,26 @@ body.dark { box-shadow: 0 0 3px var(--pod-primary-lighten); } -.slider:before { +.slider::before { background-color: var(--bs-white); bottom: 2px; content: ""; height: 20px; left: 2px; position: absolute; - transition: .4s; + transition: 0.4s; width: 20px; border-radius: 50%; } -input:checked+.slider { +input:checked + .slider { background-color: var(--pod-primary); } -input:checked+.slider:before { +input:checked + .slider::before { transform: translateX(26px); } [data-theme="dark"] input.pod-multi-range { background-color: transparent; -} \ No newline at end of file +} diff --git a/pod/main/static/css/dyslexia.css b/pod/main/static/css/dyslexia.css index b222251ae1..bf4d915787 100644 --- a/pod/main/static/css/dyslexia.css +++ b/pod/main/static/css/dyslexia.css @@ -3,10 +3,10 @@ /* OpenDyslexic Font via CDN */ @font-face { font-family: "Open Dyslexic"; - src: url("https://cdn.jsdelivr.net/npm/open-dyslexic@1.0.3/woff/OpenDyslexic-Regular.woff") format("woff"); + src: url("https://cdn.jsdelivr.net/npm/open-dyslexic@1.0.3/woff/OpenDyslexic-Regular.woff") + format("woff"); } - .dyslexia-switch-wrapper { display: flex; align-items: center; diff --git a/pod/main/static/css/iframe.css b/pod/main/static/css/iframe.css index 3212c09221..b1dd327487 100644 --- a/pod/main/static/css/iframe.css +++ b/pod/main/static/css/iframe.css @@ -8,5 +8,5 @@ body, #livename, .pod-navbar, #event_add { - display:none !important; + display: none !important; } diff --git a/pod/main/static/css/pod-admin.css b/pod/main/static/css/pod-admin.css index 85336f8cd2..7578ce18d4 100644 --- a/pod/main/static/css/pod-admin.css +++ b/pod/main/static/css/pod-admin.css @@ -1,16 +1,23 @@ @media (prefers-color-scheme: dark) { - .select2-container--default .select2-selection--multiple, .select2-dropdown, - .select2-container--default .select2-selection--multiple .select2-selection__choice { + .select2-container--default .select2-selection--multiple, + .select2-dropdown, + .select2-container--default + .select2-selection--multiple + .select2-selection__choice { background-color: #121212 !important; } - .select2-container--default.select2-container--focus .select2-selection--multiple { + + .select2-container--default.select2-container--focus + .select2-selection--multiple { border: solid white 1px !important; } + .select2-search__field { color: white !important; } + :root { - --pod-font-color : white; + --pod-font-color: white; } } @@ -20,31 +27,24 @@ :root[data-theme="dark"] { --primary: #264b5d; --primary-fg: #eee; - --body-fg: #eee; --body-bg: #121212; --body-quiet-color: #e0e0e0; --body-loud-color: #fff; - --breadcrumbs-link-fg: #e0e0e0; --breadcrumbs-bg: var(--primary); - --link-fg: #81d4fa; --link-hover-color: #4ac1f7; --link-selected-fg: #6f94c6; - --hairline-color: #272727; --border-color: #353535; - --error-fg: #e35f5f; --message-success-bg: #006b1b; --message-warning-bg: #583305; --message-error-bg: #570808; - --darkened-bg: #212121; --selected-bg: #1b1b1b; --selected-row: #00363a; - --close-button-bg: #333; --close-button-hover-bg: #666; } @@ -54,7 +54,8 @@ color: #000; } -.deletelink, .cancel-link { +.deletelink, +.cancel-link { box-sizing: revert; } diff --git a/pod/main/static/css/pod.css b/pod/main/static/css/pod.css index 479878d392..b21509a8be 100755 --- a/pod/main/static/css/pod.css +++ b/pod/main/static/css/pod.css @@ -3,7 +3,7 @@ :root { /* COMMON COLORS */ --color-black: #000; - --color-black-alpha: rgba(0, 0, 0, .6); + --color-black-alpha: rgba(0 0 0 0.6); --color-alto: #ddd; --color-silver: #ccc; --color-silver-chalice: #aaa; @@ -11,19 +11,22 @@ /*** * exemple vert 'univ-lille.fr' 2022 ***/ + /*** Theme primary color ***/ - --pod-primary: #1F7C85; + --pod-primary: #1f7c85; --pod-primary-rgb: 31, 124, 133; /* a light variant of primary color, used for button hover */ --pod-primary-lighten: #08b0a0; + /* a dark variant of primary color, used for active links and disabled buttons */ - --pod-primary-darken: #18575D; - /* les valeurs '...-dark' ci-dessous sont pour le mode sombre.*/ - --pod-primary-dark: #1F7C85; + --pod-primary-darken: #18575d; + + /* les valeurs '...-dark' ci-dessous sont pour le mode sombre. */ + --pod-primary-dark: #1f7c85; --pod-primary-lighten-dark: #08b0a0; --pod-primary-lighten-dark-rgb: 8, 176, 160; - --pod-primary-darken-dark: #18575D; + --pod-primary-darken-dark: #18575d; /*** * Esup-Pod default colors @@ -57,12 +60,13 @@ /* couleur d'un élément actif (ex. : survol de bouton) */ --pod-primary-focus: var(--pod-primary-darken); - /* Couleur d'alerte*/ - --pod-alert: #FC8670; - --pod-alert-dark: #B11030; + /* Couleur d'alerte */ + --pod-alert: #fc8670; + --pod-alert-dark: #b11030; /**** font family ****/ - /* For better accessibility, avoid fonts where 1,i,L / O,0 are the same. */ + + /* For better accessibility, avoid fonts where [1, i, L] or [O, 0] are the same. */ --bs-body-font-family: "Verdana", sans-serif; --bs-body-font-size: 11pt; --pod-font-family-dyslexie: "Open Dyslexic"; @@ -77,13 +81,16 @@ --bs-link-color-rgb: var(--pod-link-color-rgb); --bs-link-hover-color: var(--pod-activelink-color); --bs-card-color: var(--pod-font-color); + /* better contrast on sidebar background */ - --bs-danger: #DC2028; + --bs-danger: #dc2028; + /* better contrasts */ - --bs-border-color: #8E969D; + --bs-border-color: #8e969d; /* Use system font (faster load) */ - --font-family-sans-serif: -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", Roboto, Verdana, sans-serif; + --font-family-sans-serif: -apple-system, system-ui, "BlinkMacSystemFont", + "Segoe UI", "Roboto", "Verdana", sans-serif; /** reinit before cleaning all old css vars ***/ --primary-background-color: var(--pod-background-neutre1-bloc) !important; @@ -94,54 +101,28 @@ --bs-body-font-family: var(--pod-font-family-dyslexie); } -.pod-card--video a:not(.btn) { - color: inherit; -} - /* copy "alert-danger" style from Bootstrap 4 */ .alert-error { - color: #721c24; background-color: #f8d7da; border-color: #f5c6cb; + color: #721c24; } -.navbar-light .navbar-nav .nav-link, -.navbar-light .navbar-toggler { - transition: background-color .3s ease-in-out, color .3s ease-in-out; - color: var(--pod-font-color); - box-shadow: .05rem .05rem .2rem .05rem rgba(0, 0, 0, .2); - border-radius: .15rem; - margin-top: 1rem; +tr, +.rowl { + display: table-row !important; } .table-hover tbody tr { - transition: background-color .5s; -} - -/*.table-hover tbody tr:hover { - color: var(--pod-font-color); - background-color: var(--pod-background); -}*/ - -.navbar-toggler:focus, -.navbar-toggler:hover { - transition: background-color .3s ease-in-out, color .3s ease-in-out; - color: var(--bs-link-color); - border-color: var(--bs-link-color); + transition: background-color 0.5s; } .navbar-light .navbar-brand:focus, .navbar-light .navbar-brand:hover { - transition: background-color .3s ease-in-out, color .3s ease-in-out; - color: var(--color-black) -} - -.btn-lang:focus, -.btn-lang:hover, -.btn-lang:active { - box-shadow: 0 0 3px var(--pod-primary); - --bs-btn-hover-color: var(--pod-font-color); - --bs-btn-active-color: var(--pod-font-color); + transition: + background-color 0.3s ease-in-out, + color 0.3s ease-in-out; + color: var(--color-black); } .pod-nav-link-icon, @@ -149,10 +130,6 @@ font-size: 120%; } -.modal-title svg { - color: var(--pod-primary) !important; -} - .bg-light { background-color: var(--bs-light) !important; } @@ -165,7 +142,7 @@ font-size: 85%; } -.pod-meta-title+ul { +.pod-meta-title + ul { display: inline-block; } @@ -173,39 +150,48 @@ vertical-align: top; } +.title-chaine > a { + margin-left: 0.5em; + margin-right: 0.5em; +} + +.pod-card--video a:not(.btn) { + color: inherit; +} + +a:not(.btn):hover, +a:not(.btn):focus { + color: var(--pod-activelink-color); + text-decoration: underline; +} + .btn-link { - /*font-weight: 400;*/ - /*color: var(--pod-link-color);*/ text-decoration: none; } +.btn-link:hover, +.btn-link:focus, +.nav-link:hover, +.nav-link:focus { + text-decoration: underline; +} + .btn-outline-primary { color: var(--pod-primary); border-color: var(--pod-primary); } -a.btn-outline-primary:not(:hover) svg { - fill: var(--pod-primary) -} - - -#collapseAside .card>.btn { +#collapseAside .card > .btn { white-space: normal !important; word-wrap: break-word; word-break: normal; - padding: .5rem; + padding: 0.5rem; } .submit-row a.deletelink { height: 35px; } -tr, -.rowl { - display: table-row !important; -} - - .pod-mt-7 { margin-top: 3.5rem; } @@ -219,18 +205,19 @@ tr, margin-bottom: 1.5rem; } -:not(footer)>.pod-btn-social { +:not(footer) > .pod-btn-social { font-size: 2rem; } .btn.pod-btn-social { color: var(--pod-font-color); + --bs-btn-hover-color: var(--pod-font-color); --bs-btn-active-color: var(--pod-font-color); } .pod-btn-social i { - transition: all .2s ease; + transition: all 0.2s ease; } .pod-btn-social:hover i, @@ -241,15 +228,15 @@ tr, .list-group-item { background: var(--pod-background); - padding: .25rem 1.25rem; + padding: 0.25rem 1.25rem; } /*** * video * ***/ #myTabContent #info p { - margin-top: .5rem; - margin-bottom: .5rem; + margin-top: 0.5rem; + margin-bottom: 0.5rem; } #share legend { @@ -266,7 +253,6 @@ tr, } @media (max-width: 576px) { - .link-center-pod, .file-image { display: block; @@ -276,7 +262,6 @@ tr, } @media (min-width: 576px) { - .link-center-pod, .file-image { display: block; @@ -285,17 +270,17 @@ tr, } } -.link-center-pod>img { +.link-center-pod > img { min-width: 100%; height: 100%; } -/*** +/********* * navbar - ***/ + *********/ .btn-lang { - padding: .2rem .25rem; + padding: 0.2rem 0.25rem; width: 100%; text-align: left; } @@ -305,16 +290,45 @@ tr, color: var(--pod-font-color); } +.btn-lang:focus, +.btn-lang:hover, +.btn-lang:active { + box-shadow: 0 0 3px var(--pod-primary); + + --bs-btn-hover-color: var(--pod-font-color); + --bs-btn-active-color: var(--pod-font-color); +} + .navbar-inner-pod { position: relative; } .navbar-toggler { - padding: .5rem; + padding: 0.5rem; line-height: inherit; font-size: 1rem; } +.navbar-light .navbar-nav .nav-link, +.navbar-light .navbar-toggler { + transition: + background-color 0.3s ease-in-out, + color 0.3s ease-in-out; + color: var(--pod-font-color); + box-shadow: 0.05rem 0.05rem 0.2rem 0.05rem rgba(0 0 0 0.2); + border-radius: 0.15rem; + margin-top: 1rem; +} + +.navbar-toggler:focus, +.navbar-toggler:hover { + transition: + background-color 0.3s ease-in-out, + color 0.3s ease-in-out; + color: var(--bs-link-color); + border-color: var(--bs-link-color); +} + .userpicture { height: 34px; line-height: 2.5em; /* Align username if no image available */ @@ -322,9 +336,9 @@ tr, /** modal **/ .modal-title svg { + /* color:var(--pod-primary); */ height: 40px; width: 40px; - /*color:var(--pod-primary);*/ } .modal-content { @@ -340,17 +354,18 @@ tr, font-size: 3rem; } +/** end modal **/ + +a.btn-outline-primary:not(:hover) svg { + fill: var(--pod-primary); +} + .title-chaine { - margin-right: .5rem; + margin-right: 0.5rem; font-weight: 600; flex-direction: row; } -.title-chaine>a { - margin-left: .5em; - margin-right: .5em; -} - #listeChaines { max-height: 30rem; overflow: auto; @@ -361,12 +376,10 @@ tr, z-index: 900; } -/**end modal **/ - /*** * tab ***/ -.tab-content>.active { +.tab-content > .active { border: 1px solid var(--color-alto); padding: 1.5rem; background: var(--pod-background); @@ -378,7 +391,7 @@ tr, border-top: 1px solid var(--color-alto) !important; padding: 1.5rem; background: var(--pod-background); - margin-top: .75rem; + margin-top: 0.75rem; } .nav-tabs { @@ -395,24 +408,21 @@ tr, color: var(--color-black); } -/***aside ***/ -/*.open-aside { - margin-right: 15px; -}*/ +/*** aside ***/ #card-takenote .dropdown-menu { border: none; } /* general search */ -#s+button { +#s + button { opacity: 0; - transition: opacity .8s ease-in; + transition: opacity 0.8s ease-in; } -#s:focus+button, -#s+button:focus, -#s+button:hover { +#s:focus + button, +#s + button:focus, +#s + button:hover { opacity: 1; } @@ -421,11 +431,6 @@ tr, .navbar-brand img { height: 35px; } - - /* .navbar-brand, - .nav-item>.btn { - font-size: .9rem; - } */ } @media (max-width: 992px) { @@ -438,17 +443,6 @@ tr, color: var(--bs-white); } - /*.navbar-items-pod { - position: absolute; - top: 60px; - left: 0; - padding: 1rem; - width: 100%; - background-color: var(--bs-light); - box-shadow: 1px 1px 3px gray; - z-index: 100; - }*/ - .navbar-nav .login .dropdown-menu { position: absolute; float: left; @@ -463,7 +457,7 @@ tr, #s { border-radius: 0; - transition: height .5s; + transition: height 0.5s; } .hide-search-input { @@ -476,7 +470,7 @@ tr, opacity: 0; } - #s.hide-search-input+button { + #s.hide-search-input + button { height: 1px; } @@ -485,7 +479,7 @@ tr, width: calc(100% - 4em); opacity: 1; display: inline-block; - padding: .5rem 1rem; + padding: 0.5rem 1rem; z-index: 99; height: 3rem; margin-top: 0; @@ -499,38 +493,26 @@ tr, .navbar label { padding-left: 1px; - /*display: inline-block;*/ - /*margin-top: .3em;*/ position: relative; - left: .1em; + left: 0.1em; cursor: pointer; } - } /*** end MQueries **/ -.login>.initials { +.login > .initials { font-weight: 600; } -/*.nav-link { - padding: .25rem .5rem; -}*/ - -/*button.nav-link { - background: none; - border: none; -}*/ - .btn .userpicture { border: 1px solid transparent; } .btn:hover .userpicture, .btn:focus .userpicture { - opacity: .8; - border-color: #CCC; + opacity: 0.8; + border-color: #ccc; } /*** Videos list header ***/ @@ -540,23 +522,22 @@ tr, /*** CARD ***/ .infinite-item .card-body { - padding: .9rem; + padding: 0.9rem; height: 3.5rem; overflow: hidden; } .infinite-item .card-header .octicon { - height: .9rem; - margin: .1rem; + height: 0.9rem; + margin: 0.1rem; +} + +.card-header { + background: none; } #videos_list .card-header { - /*position: absolute; - width: 100%; - background: var(--color-black-alpha); - padding: 0 .25rem; - z-index: 9;*/ - padding: .4rem !important; + padding: 0.4rem !important; } .pod-card--video .video-title { @@ -575,39 +556,22 @@ tr, } /* prevent default thumbnail to be too small on some screens */ -.video-card>.card-thumbnail { +.video-card > .card-thumbnail { min-height: 146px; background-color: #000; } .video-card .d-flex { - /*position:relative;*/ top: 0; - gap: .5rem; -} - -a:not(.btn):hover, -a:not(.btn):focus { - color: var(--pod-activelink-color); - text-decoration: underline; -} - -.btn-link:hover, -.btn-link:focus, -.nav-link:hover, -.nav-link:focus { - text-decoration: underline; + gap: 0.5rem; } div.card a img { - transition: -webkit-transform .5s ease; - transition: transform .5s ease; - transition: transform .5s ease, -webkit-transform .5s ease; + transition: transform 0.5s ease; background: #000; } -.card .link-center-pod:hover>img { - -webkit-transform: scale(1.1); +.card .link-center-pod:hover > img { transform: scale(1.1); z-index: 0; } @@ -626,12 +590,13 @@ div.card a img { border: none; color: white; background: none; - --bs-btn-hover-color: #FFF; - --bs-btn-active-color: #FFF; + + --bs-btn-hover-color: #fff; + --bs-btn-active-color: #fff; } .card-footer-pod a.btn i { - transition: .2s all ease; + transition: 0.2s all ease; display: inline-block; } @@ -640,46 +605,10 @@ div.card a img { transform: rotate(10deg); } -/*.video-card .card-footer, -.video-card .card-header { - height: 1rem; -}*/ - -/** menu channels **/ -/*.dropdown-submenu>.dropdown-menu { - top: 0; - left: 100%; - margin-top: -6px; - margin-left: -1px; - border-radius: 0 6px 6px 6px; -} - -.dropdown-submenu:hover { - background-color: var(--bs-white); -} - -.dropdown-submenu:hover>.dropdown-menu { - display: block; -} - -.dropdown-submenu>a:after { - display: block; - content: " "; - float: right; - width: 0; - height: 0; - border-color: transparent; - border-style: solid; - border-width: 5px 0 5px 5px; - border-left-color: var(--color-silver); - margin-top: 5px; - margin-right: -10px; -}*/ - /** aside list video **/ #collapseAside .card-body .card-title { position: relative; - padding-bottom: .8em; + padding-bottom: 0.8em; } #collapseAside .card-body .card-title::after { @@ -702,12 +631,9 @@ div.card a img { #filterTag div.collapse:not(.show) { height: 148px !important; overflow: hidden; - display: -webkit-box; display: flex; flex-direction: column; - display: -ms-flexbox; -webkit-line-clamp: 2; - -webkit-box-orient: vertical; } #filterType div.collapsing, @@ -717,18 +643,18 @@ div.card a img { min-height: 148px !important; } -#filterType a.collapsed:after, -#filterDiscipline a.collapsed:after, -#filterCursus a.collapsed:after, -#filterTag a.collapsed:after { - content: '+'; +#filterType a.collapsed::after, +#filterDiscipline a.collapsed::after, +#filterCursus a.collapsed::after, +#filterTag a.collapsed::after { + content: "+"; } -#filterType a:not(.collapsed):after, -#filterDiscipline a:not(.collapsed):after, -#filterCursus a:not(.collapsed):after, -#filterTag a:not(.collapsed):after { - content: '-'; +#filterType a:not(.collapsed)::after, +#filterDiscipline a:not(.collapsed)::after, +#filterCursus a:not(.collapsed)::after, +#filterTag a:not(.collapsed)::after { + content: "-"; } /** ckeditor **/ @@ -758,8 +684,8 @@ div.card a img { overflow-x: hidden; } -.errors>.form-control:focus { - box-shadow: 0 0 0 .25rem rgba(var(--bs-danger-rgb), .25); +.errors > .form-control:focus { + box-shadow: 0 0 0 0.25rem rgba(var(--bs-danger-rgb) 0.25); border-color: var(--bs-danger); } @@ -771,7 +697,6 @@ div.card a img { .form-group-required .errors, .form-group .errorlist { - /*background-color: rgba(var(--bs-danger-rgb),.2);*/ color: var(--bs-danger); } @@ -793,7 +718,9 @@ div.card a img { .flashing_field { border-color: var(--pod-primary); box-shadow: 0 0 4px var(--pod-primary); - transition: box-shadow .5s, border-color .5s; + transition: + box-shadow 0.5s, + border-color 0.5s; } /** channel form **/ @@ -815,8 +742,7 @@ div.card a img { width: 88%; } -@media screen and (min-width:992px) { - +@media screen and (min-width: 992px) { #channel_form .selector-available, #channel_form .selector-chosen, #enrichment_group_form .selector-available, @@ -830,7 +756,8 @@ div.card a img { width: 90%; } -#channel_form .selector .selector-filter label #enrichment_group_form .selector .selector-filter label { +#channel_form .selector .selector-filter label, +#enrichment_group_form .selector .selector-filter label { margin-top: 0; } @@ -852,12 +779,11 @@ div.card a img { } } -/*@media screen and (min-width:768px) { - .card-img-top { - max-height: 184.13px; - } -}*/ -@media screen and (min-width:992px) { +/* +@media screen and (min-width:768px) { } +*/ + +@media screen and (min-width: 992px) { .card-img-top { max-height: 195.36px; } @@ -867,11 +793,11 @@ div.card a img { } } -.footer_links>li:before { +.footer_links > li::before { margin-right: 2px; content: "\F234"; font-family: bootstrap-icons; - vertical-align: -.125em; + vertical-align: -0.125em; } #view-counter-icon { @@ -888,7 +814,6 @@ div.card a img { background-color: var(--pod-background-neutre1-bloc); padding: 10px 0; z-index: 2147483647; - /*bottom: 100px;*/ display: none; } @@ -900,9 +825,6 @@ div.card a img { height: 200px; list-style-type: none; padding-left: 0; -} - -#viewers-ul { overflow: hidden; overflow-y: scroll; } @@ -924,11 +846,12 @@ div.card a img { * (must be set after Bootsrap to reset Django defaults) **/ body[data-admin-utc-offset] { + background-color: var(--body-bg); padding-top: 0; + --primary: var(--pod-primary); --breadcrumbs-bg: var(--pod-primary); --button-bg: var(--pod-primary); - background-color: var(--body-bg); } body[data-admin-utc-offset] textarea.cke_source { @@ -981,7 +904,9 @@ body[data-admin-utc-offset] .select2-dropdown { background-color: var(--pod-background); } -body[data-admin-utc-offset] .select2-container--open .select2-selection--multiple { +body[data-admin-utc-offset] + .select2-container--open + .select2-selection--multiple { border-color: var(--body-quiet-color); } @@ -989,28 +914,30 @@ body[data-admin-utc-offset] .select2-search--inline .select2-search__field { color: var(--pod-font-color); } -body[data-admin-utc-offset] .select2-selection--multiple .select2-selection__choice, -body[data-admin-utc-offset] .select2-selection--multiple .select2-results__option[aria-selected="true"] { +body[data-admin-utc-offset] + .select2-selection--multiple + .select2-selection__choice, +body[data-admin-utc-offset] + .select2-selection--multiple + .select2-results__option[aria-selected="true"] { color: #333; } - .select2-container--focus, .cke_focus { - box-shadow: 0 0 0 .25rem rgba(var(--pod-primary-rgb), .25); + box-shadow: 0 0 0 0.25rem rgba(var(--pod-primary-rgb) 0.25); border-radius: 5px; } -.select2-container--default.select2-container--focus .select2-selection--multiple.select2-selection { +.select2-container--default.select2-container--focus + .select2-selection--multiple.select2-selection { border: solid 1px var(--pod-primary); } /* end select2 multiple corrections */ -/* System/browser dark mode */ - - /*** CUSTOM CLASSES POD - bootstrap5 - 2022/04 ****/ + /**** vers methodo BEM .element__souselement--variante ***/ body { display: flex; @@ -1022,20 +949,14 @@ body { background-color: var(--pod-background); } -/***reinit bootstrap 5***/ +/*** reinit bootstrap 5 ***/ .nav { --bs-nav-link-color: var(--pod-font-color); } -/* -.nav-link:focus, -.nav-link:hover { - color: inherit; -}*/ - .accordion { --bs-accordion-active-color: var(--pod-link-color); - --bs-accordion-active-bg: rgba(var(--bs-primary-rgb), .1); + --bs-accordion-active-bg: rgba(var(--bs-primary-rgb) 0.1); --bs-accordion-btn-focus-border-color: var(--pod-primary); } @@ -1045,15 +966,6 @@ body { font-style: italic; } -/*.btn{ - --bs-btn-hover-color: #FFF; -} - -.btn-link { - --bs-btn-hover-color: var(--pod-activelink-color); - --bs-btn-active-color: var(--pod-activelink-color); -}*/ - .btn-primary, .btn-outline-primary { --bs-btn-hover-color: var(--pod-btn-text); @@ -1072,7 +984,7 @@ body { /* dark navbars (see in "my files") */ .bg-primary { - --bs-link-color: #F5F5F5; + --bs-link-color: #f5f5f5; } .bg-primary .nav-link { @@ -1094,20 +1006,16 @@ body { background: var(--pod-primary-darken); } - .btn-close { color: var(--pod-font-color); } -.card-header { - background: none; -} - .pod-params-button { color: var(--pod-font-color); - --bs-btn-hover-color: var(--bs-link-color); font-size: 1.4rem; display: flex; + + --bs-btn-hover-color: var(--bs-link-color); } .pod-params-button:focus, @@ -1115,14 +1023,14 @@ body { text-decoration: none; } -.pod-params-button:focus>i::before, -.pod-params-button:hover>i::before { - transform: rotate(20deg); +/* Make icon rotate and button remain still */ +.pod-params-button > i::before { + transition: transform ease-in-out 0.3s; } -/* Make icon rotate and button remain still */ -.pod-params-button>i::before { - transition: transform ease-in-out .3s; +.pod-params-button:focus > i::before, +.pod-params-button:hover > i::before { + transform: rotate(20deg); } .pod-gotoup { @@ -1135,7 +1043,7 @@ body { .pod-aside-collapse { position: absolute; - right: .5rem; + right: 0.5rem; z-index: 6; } @@ -1147,7 +1055,7 @@ body { align-items: center; justify-content: center; font-size: 1.4rem; - transition: all .5s ease-in; + transition: all 0.5s ease-in; background: none; border: 1px solid silver; color: var(--pod-font-color); @@ -1185,13 +1093,16 @@ body { .pod-footer__credits { font-size: 85%; - /*opacity: .8;*/ + + /* + opacity: .8; + */ } .pod-footer__links { display: flex; justify-content: space-around; - gap: .5rem; + gap: 0.5rem; font-weight: 600; flex-wrap: wrap; } @@ -1214,21 +1125,22 @@ body { .pod-card__title, .pod-card__title label { display: flex; - gap: .5rem; + gap: 0.5rem; align-items: center; } @media (min-width: 992px) { - .pod-card__title, .pod-card__title label { - flex-flow: wrap + flex-flow: wrap; } } .pod-navbar { background: var(--pod-background); - box-shadow: 0 1px 3px rgba(0, 0, 0, .12), 0 1px 2px rgba(0, 0, 0, .24); + box-shadow: + 0 1px 3px rgba(0 0 0 0.12), + 0 1px 2px rgba(0 0 0 0.24); } .pod-info-video { @@ -1253,11 +1165,11 @@ body { .video-info_duration-view-share { display: flex; font-size: 90%; - gap: .75rem; + gap: 0.75rem; align-items: center; justify-content: flex-start; border-bottom: 1px solid var(--pod-background-neutre1-bloc); - padding-bottom: .75rem; + padding-bottom: 0.75rem; } .pod-info-video__info { @@ -1280,7 +1192,7 @@ body { } /* Additional class for modal element */ -/* -- */ + /* Download modal */ .pod-download-title { @@ -1288,9 +1200,8 @@ body { padding: 1rem 0 0 1rem; } - -.pod-download-title>.bi { - padding-right: .5rem; +.pod-download-title > .bi { + padding-right: 0.5rem; } /* ------ */ @@ -1303,26 +1214,9 @@ body { margin-left: auto; } -/*.pod-btn { - color: var(--pod-font-color); - text-decoration: none; -} - -.pod-btn:hover, -.pod-btn:focus { - color: var(--pod-primary); - text-decoration: underline; -}*/ - -/*.pod-btn-share { - border: 1px solid silver; - transition: all .2s ease-in; - color: var(--pod-font-color); -}*/ - .pod-btn-share i, .pod-info-video__signal i { - transition: all .2s ease-in; + transition: all 0.2s ease-in; display: inline-block; } @@ -1350,9 +1244,9 @@ body { .pod-navbar__brand { display: flex; align-items: center; - gap: .5rem; + gap: 0.5rem; color: var(--pod-font-color) !important; - transition: transform .4s ease; + transition: transform 0.4s ease; } .pod-navbar__brand:hover, @@ -1376,7 +1270,7 @@ body { margin-bottom: 1.5rem; } -.pod-navbar__theme-switch__item>* { +.pod-navbar__theme-switch__item > * { display: flex; align-items: center; margin: 1rem 2rem; @@ -1390,38 +1284,16 @@ body { position: absolute; } -/*.pod-navbar-nav { - margin-left: auto; - justify-content: space-around; -} - -.pod-navbar-nav .dropdown-menu { - position: absolute; -}*/ - .pod-navbar__form { margin-left: auto; } -@media(min-width:992px) { +@media (min-width: 992px) { .pod-navbar__form { flex-basis: 350px; } } -/*.pod-navbar__nav-item { - margin-right: .25rem; - margin-left: .25rem; -} - -.pod-navbar .pod-navbar-nav .pod-navbar__nav-item__nav-link { - text-decoration: none; - display: flex; - align-items: center; - gap: .25rem; - font-size: .8rem; -}*/ - /* small screens */ .pod-grid-content { display: grid; @@ -1430,7 +1302,7 @@ body { } /* medium screens */ -@media(min-width:992px) { +@media (min-width: 992px) { .pod-grid-content { gap: 2rem; grid-template-columns: minmax(0%, 100%) repeat(auto-fit, 33%); @@ -1438,34 +1310,20 @@ body { } /* large screens */ -@media(min-width:1200px) { +@media (min-width: 1200px) { .pod-grid-content { grid-template-columns: minmax(0%, 100%) repeat(auto-fit, 25%); } } -/*.pod-navbar .pod-navbar-nav .pod-navbar__nav-item__nav-link:hover, -.pod-navbar .pod-navbar-nav .pod-navbar__nav-item__nav-link:focus { - text-decoration: underline; -}*/ /**** static content homepage ***/ -/*.pod-content-static {} - -.pod-dropdown-item { - display: flex; - align-items: center; - gap: .5rem; -} - -.pod-dropdown-item:hover, -.pod-dropdown-item:focus { - text-decoration: underline; -}*/ .pod-card--video { border: none; - box-shadow: 0 3px 6px rgba(0, 0, 0, .16), 0 3px 6px rgba(0, 0, 0, .23); + box-shadow: + 0 3px 6px rgba(0 0 0 0.16), + 0 3px 6px rgba(0 0 0 0.23); background: var(--pod-background); } @@ -1485,10 +1343,10 @@ body { width: 0; overflow: hidden; margin-left: 100%; - transition: all .15s ease; + transition: all 0.15s ease; z-index: 5; padding-top: 5rem; - box-shadow: .05rem .05rem .2rem .05rem rgba(0, 0, 0, .2); + box-shadow: 0.05rem 0.05rem 0.2rem 0.05rem rgba(0 0 0 0.2); } .pod-aside.show { @@ -1496,17 +1354,17 @@ body { width: auto; } -@media(min-width:992px) { +@media (min-width: 992px) { .pod-show-lg { margin-left: 0; width: auto; } } -@media(max-width:992px) { +@media (max-width: 992px) { .pod-aside { - width: 101% !important; /* THIS IS NORMAL, it's to fit with pod-aside-collapse */ + width: 101% !important; min-height: 100%; position: absolute; } @@ -1516,7 +1374,7 @@ body { } } -@media(min-width:1450px) { +@media (min-width: 1450px) { .pod-mainContent { padding-left: 5rem; padding-right: 5rem; @@ -1525,19 +1383,16 @@ body { .pod-grid-content { gap: 0; } - } .pod-aside.collapsing { height: auto; } - .pod-aside .card { background: none; border-radius: 0; border: none; - ; } .pod-navbar__button-toggler { @@ -1546,7 +1401,7 @@ body { font-size: 1.8rem; margin: 0; border: 0; - margin-right: .3rem; + margin-right: 0.3rem; background: none; width: 2.5rem; height: 2.5rem; @@ -1573,52 +1428,33 @@ body { min-width: 9rem; } -/* ---------------------------------------------------------------------*/ +/* --------------------------------------------------------------------- */ + /* Minor corrections */ /* Buttons side by side under the title */ #event_add { display: inline-block !important; - padding-right: .5rem; + padding-right: 0.5rem; } -/*Fix table on "My meetings" */ +/* Fix table on "My meetings" */ -.table> :not(caption)>*>* { - padding: .5rem .25rem; +.table > :not(caption) > * > * { + padding: 0.5rem 0.25rem; border-bottom-width: 0 !important; } -table :not(footer)>.pod-btn-social { +table :not(footer) > .pod-btn-social { font-size: 1.5rem; width: 3rem !important; height: 3rem !important; } -/*table .btn:hover { - background-color: var(--pod-primary) !important; - color: var(--pod-font-color); -}*/ - -th+td+td+td+td { - /* border-right: .15rem solid var(--pod-link-color); */ +th + td + td + td + td { text-align: center; } -/* .table, .navbar-light .navbar-nav .nav-link, .navbar-light .navbar-toggler { - color: var(--pod-font-color); -} */ - -/*.table-hover > tbody > tr > * { - --bs-table-accent-bg: var(--bs-table-hover-bg) !important; - color: var(--pod-font-color) !important; -}*/ - -/*.table-hover > tbody > tr:hover > * { - --bs-table-accent-bg: var(--bs-table-hover-bg) !important; - color: var(--pod-font-color) !important; -}*/ - table .alert.alert-danger.btn.pod-btn-social { background-color: var(--pod-alert) !important; } @@ -1628,6 +1464,13 @@ table .alert.alert-danger.btn.pod-btn-social { background-size: cover !important; } +/* Custom subtitles block on Firefox & Chrome (Safari use it's own subtitle style) */ +.vjs-text-track-cue > div { + display: block; + padding: 0.3rem 0.5rem; + border-radius: 8px; +} + .vjs-logo-button { filter: invert(100%); } @@ -1643,24 +1486,23 @@ table .alert.alert-danger.btn.pod-btn-social { font-size: 11px; } - /* Upload page */ .form-group.hide-on-processing { border: dotted var(--pod-link-color); - margin-bottom: .5rem; + margin-bottom: 0.5rem; border-radius: 1rem; width: fit-content; } /** Esup-Pod callout messages **/ .pod-callout { - padding: .7rem 1rem; + padding: 0.7rem 1rem; margin-top: 1.25rem; margin-bottom: 1.25rem; border: 1px solid #eee; - border-left-width: .33rem; - border-radius: .25rem; + border-left-width: 0.33rem; + border-radius: 0.25rem; } .pod-callout-primary { @@ -1711,7 +1553,7 @@ table .alert.alert-danger.btn.pod-btn-social { margin: 6px; border: 6px solid var(--pod-font-color); border-radius: 50%; - animation: lds-ring 1.2s cubic-bezier(.5, 0, .5, 1) infinite; + animation: lds-ring 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite; border-color: var(--pod-font-color) transparent transparent transparent; } @@ -1749,55 +1591,54 @@ table .alert.alert-danger.btn.pod-btn-social { div.disabled, a.player-element.disabled { - background-image: linear-gradient(45deg, rgba(0, 0, 0, .2) 25%, transparent 25%, transparent 50%, rgba(0, 0, 0, .2) 50%, rgba(0, 0, 0, .2) 75%, transparent 75%, transparent); + background-image: linear-gradient( + 45deg, + rgba(0 0 0 0.2) 25%, + transparent 25%, + transparent 50%, + rgba(0 0 0 0.2) 50%, + rgba(0 0 0 0.2) 75%, + transparent 75%, + transparent + ); background-size: 4px 4px; background-repeat: repeat; } .progress { - height: .6em; + height: 0.6em; } .progress .progress-bar { width: 100%; } -/*.podfile-icon-selector::file-selector-button { - margin-right: 20px; - border: none; - background: #084cdf; - padding: 10px 20px; - border-radius: 10px; - color: #fff; - cursor: pointer; - transition: background .2s ease-in-out; -}*/ - .podfile-icon-selector { - /*display: inline-block;*/ + /* display: inline-block; */ width: 1.6em; - padding: 1.7em 1em 0 1em; - margin-top: .1em; + padding: 1.7em 1em 0; + margin-top: 0.1em; height: 1.6em; overflow: hidden; box-sizing: border-box; - background: url('/static/bootstrap-icons/icons/cloud-arrow-up.svg') center center no-repeat transparent; + background: url("/static/bootstrap-icons/icons/cloud-arrow-up.svg") center + center no-repeat transparent; border-radius: 5px; background-size: 1.6em 1.6em; } .navbar-expand-lg .navbar-nav .nav-link.podfile-icon-selector { - padding: 1.7em 1em 0 1em; + padding: 1.7em 1em 0; } .bg-primary .podfile-icon-selector { filter: invert(1); } -.bg-primary .podfile-icon-selector:focus-visible { - box-shadow: 0 0 0 .25rem rgba(0, 0, 0, .5); +.podfile-icon-selector:hover { + opacity: 0.66; } -.podfile-icon-selector:hover { - opacity: .66; +.bg-primary .podfile-icon-selector:focus-visible { + box-shadow: 0 0 0 0.25rem rgba(0 0 0 0.5); } diff --git a/pod/meeting/static/css/meeting.css b/pod/meeting/static/css/meeting.css index 18ed759b0c..3abef463c2 100644 --- a/pod/meeting/static/css/meeting.css +++ b/pod/meeting/static/css/meeting.css @@ -1,4 +1,8 @@ -.meeting-card-inactive{ +/** + * Esup-Pod Meeting styles + */ + +.meeting-card-inactive { border: 1px solid #f5a391; } @@ -15,8 +19,8 @@ } .meeting-infos { - background-color: #CFE2FF ; - border: 1px solid #000000; + background-color: #cfe2ff; + border: 1px solid #000; } #recordings.table { @@ -24,7 +28,6 @@ --bs-table-striped-color: var(--pod-font-color); } - /* Loading while uploading */ .recording-loader { position: absolute; @@ -40,6 +43,7 @@ padding: 10px; display: none; } + .recording-loading { margin: auto; border: 6px solid #f3f3f3; @@ -50,16 +54,16 @@ animation: recording-spin 3s linear infinite; } -@-webkit-keyframes recording-spin { - 0% { -webkit-transform: rotate(0deg); } - 100% { -webkit-transform: rotate(360deg); } -} - @keyframes recording-spin { - 0% { transform: rotate(0deg); } - 100% { transform: rotate(360deg); } + 0% { + transform: rotate(0deg); + } + + 100% { + transform: rotate(360deg); + } } -/* */ + /* Message error */ div.alert.alert-dismissible { border-radius: 6px; @@ -69,7 +73,7 @@ div.alert.alert-dismissible { position: relative; padding-right: 60px; border: 1px solid #e6e6e6; - background: #FFF; + background: #fff; } div.alert .icon { @@ -94,37 +98,37 @@ div.alert .icon i { } div.alert.alert-success .icon, -div.alert.alert-success .icon:after { +div.alert.alert-success .icon::after { border-color: none; background: #00986a; } div.alert.alert-info .icon, -div.alert.alert-info .icon:after { +div.alert.alert-info .icon::after { border-color: none; background: #00b3c8; } div.alert.alert-warning .icon, -div.alert.alert-warning .icon:after { +div.alert.alert-warning .icon::after { border: none; background: #f9af2c; } div.alert.alert-error .icon, -div.alert.alert-error .icon:after { +div.alert.alert-error .icon::after { border-color: none; background: #c82630; } div.alert .proposition { color: #000; - font-weight: Bold; + font-weight: bold; } + div.alert .proposition::before { content: "\F137"; margin-right: 15px; font-family: bootstrap-icons; - vertical-align: -.125em; + vertical-align: -0.125em; } -/* */ diff --git a/pod/playlist/static/playlist/css/playlist.css b/pod/playlist/static/playlist/css/playlist.css index 8fa72a64a6..41d309b56c 100644 --- a/pod/playlist/static/playlist/css/playlist.css +++ b/pod/playlist/static/playlist/css/playlist.css @@ -1,196 +1,195 @@ +/** + * Esup-Pod Playlist styles + */ + a.link-for-playlist { - text-decoration: none; + text-decoration: none; } a.link-for-playlist:hover { - text-decoration: underline; + text-decoration: underline; } .link-playlist { - right: 1rem; - border-radius: 0.375rem; + right: 1rem; + border-radius: 0.375rem; } #playlist-modal { - font-size: 1.7em; - gap: 1rem; + font-size: 1.7em; + gap: 1rem; } #playlist-modal .playlist-title { - text-decoration: none; - color: var(--pod-font-color); + text-decoration: none; + color: var(--pod-font-color); } #playlist-modal .playlist-title:hover { - text-decoration: underline; + text-decoration: underline; } .remove-video-from-playlist, .add-video-from-playlist { - font-weight: 700; - display: flex; - align-items: center; - justify-content: center; - border-radius: 90px; - color: var(--pod-background); - width: 40px; - height: 40px; + font-weight: 700; + display: flex; + align-items: center; + justify-content: center; + border-radius: 90px; + color: var(--pod-background); + width: 40px; + height: 40px; } .remove-video-from-playlist { - background-color: #CC3434; + background-color: #cc3434; } .remove-video-from-playlist:hover { - background-color: #AA3434; - color: var(--pod-background); + background-color: #aa3434; + color: var(--pod-background); } .add-video-from-playlist { - background-color: rgb(45, 168, 45); + background-color: rgb(45 168 45); } .add-video-from-playlist:hover { - background-color: rgb(35, 133, 35); - color: var(--pod-background); + background-color: rgb(35 133 35); + color: var(--pod-background); } - .shake-effect { - animation: shake 2.3s ease-in-out; - animation-iteration-count: infinite; - cursor: grab; + animation: shake 2.3s ease-in-out; + animation-iteration-count: infinite; + cursor: grab; } .shake-effect .badge { - display: block; + opacity: 1; + display: block; } - .shake-effect-active { - cursor: grabbing; + cursor: grabbing; } @keyframes shake { - 0% { - transform: translate(1px, 1px) rotate(0deg); - } + 0% { + transform: translate(1px, 1px) rotate(0deg); + } - 10% { - transform: translate(-1px, -2px) rotate(-1deg); - } + 10% { + transform: translate(-1px, -2px) rotate(-1deg); + } - 20% { - transform: translate(-3px, 0px) rotate(1deg); - } + 20% { + transform: translate(-3px, 0) rotate(1deg); + } - 30% { - transform: translate(3px, 2px) rotate(0deg); - } + 30% { + transform: translate(3px, 2px) rotate(0deg); + } - 40% { - transform: translate(1px, -1px) rotate(1deg); - } + 40% { + transform: translate(1px, -1px) rotate(1deg); + } - 50% { - transform: translate(-1px, 2px) rotate(-1deg); - } + 50% { + transform: translate(-1px, 2px) rotate(-1deg); + } - 60% { - transform: translate(-3px, 1px) rotate(0deg); - } + 60% { + transform: translate(-3px, 1px) rotate(0deg); + } - 70% { - transform: translate(3px, 1px) rotate(-1deg); - } + 70% { + transform: translate(3px, 1px) rotate(-1deg); + } - 80% { - transform: translate(-1px, -1px) rotate(1deg); - } + 80% { + transform: translate(-1px, -1px) rotate(1deg); + } - 90% { - transform: translate(1px, 2px) rotate(0deg); - } + 90% { + transform: translate(1px, 2px) rotate(0deg); + } - 100% { - transform: translate(1px, 2px) rotate(0deg); - } + 100% { + transform: translate(1px, 2px) rotate(0deg); + } } .no-click { - pointer-events: none; + pointer-events: none; } #sortForm.no-click, #collapse-button.no-click { - opacity: 0; - transition: opacity .9s ease; + opacity: 0; + transition: opacity 0.9s ease; } .card-hidden { - display: none; + display: none; } .card-footer, .draggable-container .badge { - transition: opacity 0.9s ease; + transition: opacity 0.9s ease; } .shake-effect .card-footer, .draggable-container .badge { - opacity: 0; -} - -.shake-effect .badge { - opacity: 1; + opacity: 0; } .dropzone-hover { - border: .2rem solid #1F7C85; + border: 0.2rem solid #1f7c85; } p.playlist-last-updated { - font-style: italic; + font-style: italic; } .grayscale-image { - filter: grayscale(100%); + filter: grayscale(100%); } .lock-icon-container { - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - font-size: 2em; - color: white; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + font-size: 2em; + color: white; } .scroll-container { - height: 40rem; - overflow: auto; + height: 40rem; + overflow: auto; } a.player-element, a.player-element:hover { - color: inherit; - text-decoration: none; - border: var(--bs-border-width) solid var(--color-alto) !important; + color: inherit; + text-decoration: none; + border: var(--bs-border-width) solid var(--color-alto) !important; } -a.player-element:not(.disabled):hover { - background-color: #F1F1F1; - border: var(--bs-border-width) solid var(--pod-primary) !important; +a.player-element.selected { + background-color: #d1d1d1; } -a.player-element:not(.disabled).selected:hover { - background-color: #BEBEBE; +a.player-element:not(.disabled):hover { + background-color: #f1f1f1; + border: var(--bs-border-width) solid var(--pod-primary) !important; } -a.player-element.selected { - background-color: #D1D1D1; +a.player-element:not(.disabled).selected:hover { + background-color: #bebebe; } .promoted-icon { - color: var(--pod-primary); -} \ No newline at end of file + color: var(--pod-primary); +} diff --git a/pod/podfile/static/podfile/css/podfile.css b/pod/podfile/static/podfile/css/podfile.css index df5ae6d449..bc22e663cc 100644 --- a/pod/podfile/static/podfile/css/podfile.css +++ b/pod/podfile/static/podfile/css/podfile.css @@ -1,3 +1,6 @@ +/** + * Esup-Pod Podfile styles + */ button.close { padding: 0; @@ -12,10 +15,7 @@ button.close { .modal { position: fixed; - top: 0; - right: 0; - bottom: 0; - left: 0; + inset: 0; z-index: 1050; display: none; overflow: hidden; @@ -29,7 +29,6 @@ button.close { .modal-dialog { position: relative; - width: auto; margin: 0 auto; pointer-events: none; width: calc(100% - 2em); @@ -47,11 +46,7 @@ button.close { } .modal-dialog-centered { - display: -webkit-box; - display: -ms-flexbox; display: flex; - -webkit-box-align: center; - -ms-flex-align: center; align-items: center; min-height: calc(100% - (0.5rem * 2)); } @@ -63,7 +58,7 @@ button.close { pointer-events: auto; background-color: #fff; background-clip: padding-box; - border: 1px solid rgba(0, 0, 0, 0.2); + border: 1px solid rgba(0 0 0 0.2); outline: 0; max-width: 100% !important; width: calc(100% - 2em); @@ -72,10 +67,7 @@ button.close { .modal-backdrop { position: fixed; - top: 0; - right: 0; - bottom: 0; - left: 0; + inset: 0; z-index: 1040; background-color: #000; } @@ -99,103 +91,119 @@ button.close { /********************************** ********** Improve css *********** **********************************/ -@media only screen and (min-width: 950px) -{ - /*.modal-dialog{ width: 850px; }*/ +@media only screen and (min-width: 950px) { + /* .modal-dialog{ width: 850px; } */ } -#podfile .row{ - margin: 10px 10px 5px 10px; + +#podfile .row { + margin: 10px 10px 5px; } -#podfile .col{ + +#podfile .col { padding: 5px; background: white; - border: 1px solid rgba(0,0,0,.125); + border: 1px solid rgba(0 0 0 0.125); } -#podifle .card-body{ + +#podifle .card-body { padding: 0; - font-size: .8rem; + font-size: 0.8rem; } + #podfile .card-img-top { width: 100%; height: 26vh; object-fit: scale-down; } + #podifle img.directory-image { height: 26px; vertical-align: middle; } -#podfile .list_folders{ +#podfile .list_folders { padding-left: 15px; height: auto; overflow: hidden; } -#podfile #listfiles{ - max-height:600px; +#podfile #listfiles { + max-height: 600px; overflow: auto; } /********************************** ********** Overrid css *********** **********************************/ -#modal-folder_id_src .modal-body{ +#modal-folder_id_src .modal-body { padding-top: 0 !important; padding-bottom: 0 !important; } -#shareModalCenter #shared-people.list-group .list-group-item{ - display: -webkit-box; - display: -ms-flexbox; + +#shareModalCenter #shared-people.list-group .list-group-item { display: flex; - -webkit-box-pack: justify; - -ms-flex-pack: justify; justify-content: space-between; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; - border: 1px solid rgba(0,0,0,.08); - padding: .8em; + align-items: center; + border: 1px solid rgba(0 0 0 0.08); + padding: 0.8em; } -#shareModalCenter #shared-people.list-group .list-group-item:not(:last-child){ + +#shareModalCenter #shared-people.list-group .list-group-item:not(:last-child) { border-bottom: none; } -#shareModalCenter #shared-people.list-group .list-group-item .username{ + +#shareModalCenter #shared-people.list-group .list-group-item .username { color: var(--bs-gray-dark); font-weight: 700; } -#shareModalCenter #shared-people.list-group .list-group-item .btn-share.btn-remove{ + +#shareModalCenter + #shared-people.list-group + .list-group-item + .btn-share.btn-remove { order: 1; - padding: .4em .8em; + padding: 0.4em 0.8em; color: #fff !important; background-color: var(--bs-danger); line-height: 1; flex: none; } -#shareModalCenter #shareFormName .form-group{position: relative;} -#shareModalCenter #shareFormName .form-group .form-control{ outline: none !important; -webkit-box-shadow: none !important; box-shadow: none !important;} -#shareModalCenter #user-search.list-group{ - padding: .8em 0; + +#shareModalCenter #shareFormName .form-group { + position: relative; +} + +#shareModalCenter #shareFormName .form-group .form-control { + outline: none !important; + box-shadow: none !important; +} + +#shareModalCenter #user-search.list-group { + padding: 0.8em 0; width: 400px; max-width: 100%; - border: 1px solid rgba(0,0,0,.1); - box-shadow: 0 8px 10px 4px rgba(0,0,0,.08); + border: 1px solid rgba(0 0 0 0.1); + box-shadow: 0 8px 10px 4px rgba(0 0 0 0.08); position: absolute; top: 100%; } -#shareModalCenter #user-search.list-group .list-group-item{ + +#shareModalCenter #user-search.list-group .list-group-item { border: none !important; display: flex; justify-content: space-between; align-items: center; - padding: .8em; + padding: 0.8em; line-height: 1; } -#shareModalCenter #user-search.list-group .list-group-item .btn-share.btn-add{ - padding: .4em .8em; + +#shareModalCenter #user-search.list-group .list-group-item .btn-share.btn-add { + padding: 0.4em 0.8em; line-height: 1; flex: none; } -#shareModalCenter #user-search.list-group .list-group-item .username{ + +#shareModalCenter #user-search.list-group .list-group-item .username { font-weight: 700; color: var(--bs-gray); } @@ -205,9 +213,11 @@ button.close { align-items: flex-start; justify-content: space-between; } -.modal-header .modal-title{ + +.modal-header .modal-title { color: var(--pod-primary); } + .modal-header .close { margin: 0; color: var(--pod-font-color); @@ -215,58 +225,88 @@ button.close { padding: 0; transform: translate(10px, -15px); } -.podfilemodal{ + +.podfilemodal { padding: 0 !important; } -#podfile{ + +#podfile { position: relative; padding-bottom: 4em; overflow: hidden; } -#podfile > .row{ - justify-content: space-between; +#podfile > .row { + justify-content: space-between; } -#podfile #dirs .dirs-nav{ +#podfile #dirs .dirs-nav { display: flex; justify-content: space-between; align-items: center; padding-left: 0; } -#podfile #dirs .dirs-nav .dirs-nav-container{ + +#podfile #dirs .dirs-nav .dirs-nav-container { display: flex; } + #podfile .list_folders .folder_container:nth-child(2n), #podfile .list_folders_sub .folder_container:nth-child(2n) { - background-color: #F5F5F5; + background-color: #f5f5f5; } + #podfile .list_folders .folder_container, -#podfile .list_folders_sub .folder_container{padding: .4em;} +#podfile .list_folders_sub .folder_container { + padding: 0.4em; +} + #podfile .list_folders .folder, #podfile .list_folders_sub .folder, -/*#podfile #dirs .dirs-nav a.folder*/{ +/*#podfile #dirs .dirs-nav a.folder*/ { display: flex; align-items: flex-end; margin-right: 1em; } + #podfile .list_folders .folder, -#podfile .list_folders_sub .folder{ -webkit-box-align: center; -ms-flex-align: center; align-items: center;} +#podfile .list_folders_sub .folder { + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; +} + +#podfile .share-folders { + padding-top: 0.4em; + border-top: 2px dotted var(--pod-primary); +} -#podfile .share-folders{ padding-top: .4em; border-top: 2px dotted var(--pod-primary); } #podfile .share-folders, -#podfile #list_folders_sub{ overflow-y: auto;} -#podfile .share-folders .folder_title{ display: -webkit-box; display: -ms-flexbox; display: flex; -webkit-box-align: center; -ms-flex-align: center; align-items: center; margin-bottom: .4em; color: var(--pod-primary);} -#podfile .share-folders .home-directory{-webkit-transform: translateY(-8px);-ms-transform: translateY(-8px);transform: translateY(-8px) } +#podfile #list_folders_sub { + overflow-y: auto; +} + +#podfile .share-folders .folder_title { + display: flex; + align-items: center; + margin-bottom: 0.4em; + color: var(--pod-primary); +} + +#podfile .share-folders .home-directory { + transform: translateY(-8px); +} #podfile a.folder:not(.folder-opened) .folder-open, -#podfile a.folder-opened .folder-close -{ display: none;} +#podfile a.folder-opened .folder-close { + display: none; +} #podfile .bi { margin-right: 3px; } -#podfile #dirs .dirs-nav + *{ + +#podfile #dirs .dirs-nav + * { /* display: -ms-grid; display: grid; -ms-grid-columns: 1fr; @@ -275,23 +315,26 @@ button.close { grid-template-rows: repeat(2, minmax(auto, 1fr) ); */ overflow: auto; } -#podfile #dirs .dirs-nav + * > *:nth-child(1){ + +#podfile #dirs .dirs-nav + * > *:nth-child(1) { -ms-grid-row: 1; -ms-grid-column: 1; } -#podfile #dirs .dirs-nav + * > *:nth-child(2){ + +#podfile #dirs .dirs-nav + * > *:nth-child(2) { -ms-grid-row: 2; -ms-grid-column: 1; } -/*#podfile #dirs .share-folder span.home-directory{ color: var(--pod-primary); }*/ -#podfile #dirs .folder-search{ + +/* +#podfile #dirs .share-folder span.home-directory{ color: var(--pod-primary); } +*/ +#podfile #dirs .folder-search { border: 1px solid #ccc; font-size: 14px; - padding: .4em; - color: rgba(0,0,0,.75); - -webkit-box-flex: 0; - -ms-flex: none; - flex: none; + padding: 0.4em; + color: rgba(0 0 0 0.75); + flex: none; height: 35px; } @@ -299,43 +342,47 @@ button.close { text-align: center; } -#podfile #files #currentfolder{ +#podfile #files #currentfolder { flex-grow: unset; flex-basis: auto; } -#podfile #currentfolder .nav-item:not(:last-child){margin-right: .8em} +#podfile #currentfolder .nav-item:not(:last-child) { + margin-right: 0.8em; +} -#podfile #currentfolder .nav-item{ +#podfile #currentfolder .nav-item { display: flex; align-items: center; } -#podfile .flex{ +#podfile .flex { display: grid; - grid-template-rows: minmax(.5fr, 1fr); - grid-auto-rows: minmax(.5fr, 1fr); + grid-template-rows: minmax(0.5fr, 1fr); + grid-auto-rows: minmax(0.5fr, 1fr); min-height: 100%; } -#podfile #listfiles{ +#podfile #listfiles { display: grid; grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); grid-gap: 5px; } -#podfile #files.loading .container-loader{ + +#podfile #files.loading .container-loader { position: relative; margin: 0 auto; margin-top: 4em; width: 75px; - } -#podfile #files.loading .lds-ellipsis{ + +#podfile #files.loading .lds-ellipsis { display: block; transform: translateX(-50%); width: 75px; } -#podfile #listfiles .empty-folder-warning{ + +#podfile #listfiles .empty-folder-warning { grid-column: 1/-1; grid-row: 10; text-align: center; @@ -343,93 +390,82 @@ button.close { color: #856404; font-weight: 600; } -#podfile #listfiles .navbar-toggler-icon{ + +#podfile #listfiles .navbar-toggler-icon { background: none; } -#podfile #listfiles .col-sm-2{ + +#podfile #listfiles .col-sm-2 { max-width: unset; } -#podfile #listfiles .navbar{ + +#podfile #listfiles .navbar { justify-content: flex-end; } - -#podfile #listfiles .card{ +#podfile #listfiles .card { overflow: unset; } -#podfile #listfiles .file{ + +#podfile #listfiles .file { position: absolute; bottom: 4px; left: 0; right: 0; transform: translateY(100%); - padding: .4em; - transition: .1s all; + padding: 0.4em; + transition: 0.1s all; } -#podfile #listfiles .file-navbar{ + +#podfile #listfiles .file-navbar { justify-content: space-around; - flex-direction: row; align-items: flex-end; - flex-wrap: wrap; + flex-flow: row wrap; overflow-y: auto; } -#podfile #listfiles .file-navbar .nav-item{ + +#podfile #listfiles .file-navbar .nav-item { width: 25px; display: inline-block; height: 25px; - margin: 0 .4em .4em .4em !important; + margin: 0 0.4em 0.4em !important; } -#podfile #listfiles .card-body{ +#podfile #listfiles .card-body { overflow: hidden; } -@media only screen and (max-width: 992px){ - #podfile #currentfolder{ - position: absolute; - right: 0; - bottom: 0; - -webkit-transform: translateY(100%); - -ms-transform: translateY(100%); - transform: translateY(100%); - max-width: 180px; - z-index: 9; - -webkit-transition: all .1s linear 0s; - -o-transition: all .1s linear 0s; - transition: all .1s linear 0s; + +@media only screen and (max-width: 992px) { + #podfile #currentfolder { + position: absolute; + right: 0; + bottom: 0; + transform: translateY(100%); + max-width: 180px; + z-index: 9; + transition: all 0.1s linear 0s; } - #podfile #currentfolder .navbar-nav{ - margin: O !important; - width: 100%; - display: -webkit-box; - display: -ms-flexbox; - display: flex; - -webkit-box-orient: horizontal; - -webkit-box-direction: normal; - -ms-flex-direction: row; - flex-direction: row; + + #podfile #currentfolder .navbar-nav { + margin: 0 !important; + width: 100%; + display: flex; + flex-direction: row; } - #podfile #currentfolder .custom-file label{ - margin: 0; + #podfile #currentfolder .custom-file label { + margin: 0; } } -@media only screen and (max-width: 550px) -{ - #podfile .alert-warning{ - -webkit-box-orient: vertical; - -webkit-box-direction: normal; - -ms-flex-direction: column; - flex-direction: column; - line-height: 1.2; +@media only screen and (max-width: 550px) { + #podfile .alert-warning { + flex-direction: column; + line-height: 1.2; } - #podfile #dirs .dirs-nav .dirs-nav-container{ - -webkit-box-orient: vertical; - -webkit-box-direction: normal; - -ms-flex-direction: column; - flex-direction: column; - -webkit-box-align: start; - -ms-flex-align: start; - align-items: flex-start; + + #podfile #dirs .dirs-nav .dirs-nav-container { + flex-direction: column; + align-items: flex-start; } } diff --git a/pod/recorder/templates/recorder/opencast-studio.html b/pod/recorder/templates/recorder/opencast-studio.html index 68bba91ce6..f6c1d5fb62 100644 --- a/pod/recorder/templates/recorder/opencast-studio.html +++ b/pod/recorder/templates/recorder/opencast-studio.html @@ -4,9 +4,8 @@ {% get_current_language as LANGUAGE_CODE %} {% block page_extra_head %} - - + + + {% endblock page_extra_head %} -{% block breadcrumbs %}{{ block.super }} - +{% block breadcrumbs %} + {{ block.super }} + {% endblock %} {% block page_title %}{% trans "Studio" %}{% endblock %} diff --git a/pod/video/static/css/change_video_owner.css b/pod/video/static/css/change_video_owner.css index 81434a5258..ee1308b500 100644 --- a/pod/video/static/css/change_video_owner.css +++ b/pod/video/static/css/change_video_owner.css @@ -1,3 +1,7 @@ +/** + * Esup-Pod Change_video_owner styles + */ + .children-center { display: flex; justify-content: center; @@ -10,11 +14,11 @@ color: #000; } -.flex{ +.flex { align-self: flex-end; display: flex; align-items: center; - gap: 0 .8em; + gap: 0 0.8em; } .full-width { @@ -54,26 +58,26 @@ main { display: flex; flex-direction: column; flex-grow: 1; - padding: .4em; + padding: 0.4em; } -[data-theme=dark][data-theme-mode=dark] .form .form-wrapper input{ +[data-theme="dark"] .form .form-wrapper input { background: var(--bs-dark) !important; border-color: var(--bs-dark) !important; } .form .form-wrapper.select_all_wrapper { - flex-direction: row; - flex-wrap: wrap; + flex-flow: row wrap; justify-content: space-between; padding: 0.8em 1em 0 0; align-items: center; } -/*.form .form-wrapper.select_all_wrapper label { - margin: 0; -}*/ - +/* +.form .form-wrapper.select_all_wrapper label { + margin: 0; +} +*/ .form-wrapper .suggestions { max-height: 310px; @@ -88,7 +92,7 @@ main { z-index: 1; } -.form-wrapper .suggestions>*:nth-child(even) { +.form-wrapper .suggestions > *:nth-child(even) { border-top: 1px solid #2c2f38; border-bottom: 1px solid #2c2f38; } @@ -102,18 +106,18 @@ main { border-left-color: #fff; } -.form-wrapper .suggestions>p:hover { +.form-wrapper .suggestions > p:hover { background-color: var(--pod-link-color); } -.form-wrapper .suggestions>* { - padding: .8em; +.form-wrapper .suggestions > * { + padding: 0.8em; cursor: pointer; margin: 0; } #list_videos__search { - padding: .4em; + padding: 0.4em; } .form .form-wrapper__control.select-videos { @@ -124,7 +128,7 @@ main { flex-grow: 1; width: 100%; height: 290px; - padding: .8em .4em; + padding: 0.8em 0.4em; overflow-y: auto; background-color: var(--pod-background); } @@ -134,7 +138,7 @@ main { flex-direction: column; justify-content: space-between; width: 160px; - margin: 0 .8em .8em 0; + margin: 0 0.8em 0.8em 0; overflow: hidden; border-radius: 4px; border: 1px solid var(--pod-link-color); @@ -146,17 +150,17 @@ main { width: 35px; height: 35px; background: var(--bs-success); - color: #FFF; + color: #fff; border-bottom-style: solid; border-right-style: solid; border-width: 1px; - border-color: #FFF9; + border-color: #fff9; position: absolute; top: calc(50% - 17.5px); right: calc(50% - 17.5px); border-radius: 50%; opacity: 0; - transition: opacity .3s ease-in-out; + transition: opacity 0.3s ease-in-out; font-size: 20px; text-align: center; line-height: 35px; @@ -171,9 +175,10 @@ main { } .form-wrapper__control.select-videos .card.manage_video .footer { - padding: .4em; + padding: 0.4em; font-size: 14px; } + .card.manage_video .footer .video-title { width: 100%; display: block; @@ -182,16 +187,10 @@ main { white-space: nowrap; } - /* Alert message */ alert-message { - display: -webkit-box; - display: -ms-flexbox; display: flex; - -webkit-box-orient: vertical; - -webkit-box-direction: normal; - -ms-flex-direction: column; flex-direction: column; padding: 11px 30px; border-radius: 4px; @@ -200,25 +199,23 @@ alert-message { bottom: 20px; right: 20px; transition: opacity 1s; - -webkit-animation: up 1s cubic-bezier(.77, 0, .18, 1) forwards; - animation: up 1s cubic-bezier(.77, 0, .18, 1) forwards; - -webkit-animation-direction: normal; + animation: up 1s cubic-bezier(0.77, 0, 0.18, 1) forwards; animation-direction: normal; z-index: 9; } -.alert{ +.alert { background-color: #00baf3; color: #fff; } + alert-message .alert_message { font-weight: 600; font-size: 20px; } .alert_close { - -webkit-animation: down 1s cubic-bezier(.77, 0, .18, 1) forwards; - animation: down 1s cubic-bezier(.77, 0, .18, 1) forwards; + animation: down 1s cubic-bezier(0.77, 0, 0.18, 1) forwards; } .alert .close_btn { @@ -229,57 +226,36 @@ alert-message .alert_message { cursor: pointer; } -@-webkit-keyframes down { - 0% { - bottom: 20px; - opacity: 1; - } - 100% { - bottom: -100%; - opacity: .1; - } -} - @keyframes down { 0% { - bottom: 20px; - opacity: 1; + bottom: 20px; + opacity: 1; } - 100% { - bottom: -100%; - opacity: .1; - } -} -@-webkit-keyframes up { - 0% { - bottom: -100%; - opacity: .1; - } 100% { - bottom: 20px; - opacity: 1; + bottom: -100%; + opacity: 0.1; } } @keyframes up { 0% { - bottom: -100%; - opacity: .1; + bottom: -100%; + opacity: 0.1; } + 100% { - bottom: 20px; - opacity: 1; + bottom: 20px; + opacity: 1; } } /* End Alert message */ - - /* Loader */ -/*.manage-video__loader { +/* +.manage-video__loader { position: relative; width: 100%; height: 40px; @@ -289,4 +265,3 @@ alert-message .alert_message { padding-top: .8em; } */ - diff --git a/pod/video/static/css/comment-style.css b/pod/video/static/css/comment-style.css index d956e3fc6d..5190b44f27 100644 --- a/pod/video/static/css/comment-style.css +++ b/pod/video/static/css/comment-style.css @@ -1,405 +1,367 @@ -:root { - --primary-background-color: #f8f9fa; - --third-background-color: rgb(255, 255, 255); - /*--content-primary-color: rgba(6, 14, 29, .75);*/ - --content-secondary-color: rgba(54, 56, 58, .65); - --content-third-color: #696969; - --padding-comment-content: 25px; - --margin-between-comment: 1em; - --voted-color: rgb(249, 165, 6); -} - -[data-theme="dark"] { - --content-third-color: #B6B4B4; -} - -.comment_disable { - text-align: center; - padding: .4em .8em; - color: #386066; - background: #afe0e8; - margin-top: .8em; - display: flex; - justify-content: center; - align-items: center; -} - -.comment_label, -.comment_main h3{ - font-weight: 600; - font-size: 16px; -} - -.comment_main .icon { - width: 18px; -} - -.reply_to { - letter-spacing: 1.1px; - color: var(--content-third-color); - margin-bottom: .8em; - margin-left: .8em; -} - -.reply_to svg { - width: 16px; -} - -.reply_author { - font-weight: 600; -} - -/*.reply_content { - font-weight: 500; -}*/ - -/*.comment_main .icon.comment_vote_icon svg { - transform: translateY(-1px); -}*/ - -.comment_main .icon.comments_icon { - width: var(--padding-comment-content); - margin-right: 3px; - /*flex: none;*/ -} - -.comment_main .inline_flex_space { - display: flex; - align-items: center; - justify-content: space-between; - flex-wrap: wrap; -} - -.comment_main .comment_disable::before { - content: ""; - display: block; - height: 1px; - background-color: var(--pod-background); - width: 100%; - margin-bottom: 2em; -} - -.comment_main .comment_disable { - display: flex; - justify-content: center; - flex-wrap: wrap; - font-weight: 400; - color: var(--pod-primary); - padding-top: 2em; -} - -.comment_main { - margin-top: 1em; - overflow-y: auto; - border: 1px solid var(--color-alto); -} - -.comment_main .comment_container { - width: 100%; -} - - -/* Confirm Modal */ -.comment_main .confirm_delete { - display: none; - align-items: center; - justify-content: center; - padding-top: 20px; - z-index: 99; - position: fixed; - left: 0; - right: 0; - top: 0; - bottom: 0; - min-height: 100vh; - background-color: rgba(54, 56, 58, .5); -} - -.comment_main .confirm_delete.show { - display: flex; -} - -/*.comment_main .confirm_delete_container { - display: flex; - flex-direction: column; - overflow: hidden; - width: 500px; - border-radius: 4px; - padding: .8em; - box-shadow: 2px 2px 4px rgba(54, 56, 58, .6); -} - -.comment_main .confirm_delete_container .confirm_title { - text-align: center; - text-transform: uppercase; -} - -.comment_main .confirm_delete_container .content { - border: none; - text-align: center; - font-size: 16px; - padding-top: .8em; - padding-bottom: .4em; - font-weight: 400; -} - -.comment_main .confirm_delete_container .actions { - display: flex; - justify-content: space-around; - align-items: center; - padding: .8em 0; -}*/ - -/* End Confirm Modal */ - -.comment_content { - padding: 1em; -} - -.comment_main .add_comment { - width: 100%; - /*padding: 1em 0;*/ - position: relative; -} - -.comment_main .form-wrapper { - display: flex; - flex-direction: column; - font-size: 14px; -} - -.comment_main .comment { - position: relative; - display: flex; - padding-bottom: var(--margin-between-comment); -} - -.comment_element .comment_container { - display: flex; - flex-direction: column; - flex-grow: 1; - position: relative; - width: calc(100% - 37px); -} - -.comment_main .comment .comment_content { - display: flex; - flex-direction: column; - justify-content: space-between; - border-left: 4px solid var(--pod-primary); - padding: .4em; - box-shadow: 2px 2px 12px #e6e2e2; - border-top-right-radius: 4px; - border-bottom-right-radius: 4px; - background-color: var(--pod-background-neutre2-bloc); -} - -.comment_main .comment_element .comment_container>.comments_children_container { - height: 0; - overflow: hidden; - transition: .5s height; -} - -.comment_main .comment_element.show .comment_container>.comments_children_container { - height: auto; -} - -.comment_main .comment_element .comment_container .comment_element>.comment_child_container { - display: flex; - margin-top: calc(var(--margin-between-comment) - .2em); - padding-right: 0.8em; -} - -.comment_main .comment_element>.comment.onDelete, -.comment_main .comment_element .comment_container .comment_element>.comment_child_container.onDelete { - animation-name: deletecomment; - animation-duration: 1s; - animation-fill-mode: forwards; -} - -.comment_main .comment_element .comment_container .comment_element>.comment_child_container .comments_icon { - margin-left: 0; - flex: none; - align-self: center; -} - -.comment_main .comment .comment_content_child { - border-radius: 5px; - border-top: 1px solid var(--primary-background-color); - border-right: 1px solid var(--primary-background-color); - border-bottom: 1px solid var(--primary-background-color); - border-left: 4px solid var(--content-secondary-color); - flex-grow: 1; - /* width reduced by "re" svg width */ - max-width: calc(100% - 21px) -} - -.comment_main .comment .comment_content_header .comment_since { - color: var(--content-third-color); - font-size: 14px; -} - -/* -.comment_main .comment .comment_content_body { - color: var(--content-primary-color); -} */ - -.comment_main .comment .comment_content_body { - margin: 0 0 2em 0; - /*font-weight: 400;*/ - word-break: break-all; - font-size: 14px; -} - -.comment_main .comment .comment_content_body a { - display: block; - width: 500px; - max-width: 100%; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - margin-bottom: .8em; -} - -.comment_main .comment .comment_content_body .comment_text { - font-weight: 500; -} - -.comment_main .comment .comment_content_footer { - display: flex; - flex-direction: column; - flex-wrap: wrap; - color: var(--content-secondary-color); -} - -.comment_main .comment .comment_content_footer>* { - display: flex; - align-items: center; - font-size: 13px; -} - -.comment_main .comment .comment_content_footer>* .icon { - margin-right: 4px; -} - -.comment_main .actions.inline_flex_space { - justify-content: space-around; -} - -.comment_main .comment .comment_content_footer .comment_actions { - display: flex; - /*align-items: center;*/ - color: var(--pod-font-color); - /*transition: .3s color; - font-weight: 400;*/ -} - -.comment_main .comment .comment_content_footer .comment_actions:hover { - color: var(--pod-primary); -} - -.comment_main .comment .comment_content_footer .comment_actions.voting .comment_vote_icon { - display: none; -} - -.comment_main .comment_vote_action.voted .unvoted, -.comment_main .comment_vote_action .voted, -.comment_main .comment_element .comment-hide, -.comment_main .comment_element.show .comment-show { - display: none; -} - -.comment_main .comment_vote_action .unvoted, -.comment_main .comment_vote_action.voted .voted, -.comment_main .comment_element.show .comment-hide, -.comment_main .comment_element .comment-show { - display: inline-block; -} - -.comment_main .comment_vote_action.voted:hover .voted, -.comment_main .comment_vote_action.voted .voted { - color: var(--voted-color); -} - -.comment_main .comment_element .comment_content_footer .form { - height: 0; - overflow: hidden; - transition: .5s height; -} - -.comment_main .comment_element .comment_content_footer .form.show { - height: 60px; -} - -.comment_main .comment .comment_content_footer .add_comment { - margin: .8em .2em 0; -} - -.comment_main .add_comment .new_comment { - resize: none; - padding-right: 3em; -} - -.comment_main .send_reply { - width: 1.5em; - position: absolute; - right: 1rem; - top: 0; - height: 100%; - padding: 0; -} - -/*.comment_main .send_reply.active { - cursor: pointer; - color: var(--pod-link-color); -} - -.comment_main .send_reply.active:hover, -.comment_main .send_reply.active:focus { - color: var(--pod-activelink-color); -}*/ - -.comment_main .send_reply i { - width: 100%; - height: 100%; -} - - -@media only screen and (max-width: 650px) { - .comment_main .comment_actions:not(.comment_vote_action) span { - display: none; - } -} - -/* ***** on scroll to comment background */ -.scroll_to { - animation-name: scrolltocomment; - animation-duration: 5s; - animation-fill-mode: forwards; -} - -@keyframes scrolltocomment { - 0% { - background-color: #f9f99b; - /* rgba(255, 234, 59)*/ - } - - 100% { - background-color: var(--third-background-color); - } -} - -/* ******* on delete comment ******* */ -@keyframes deletecomment { - 0% { - position: relative; - box-shadow: 0 0 8px 8px rgba(255, 0, 0, .3) !important; - z-index: 9999; - transform: translateX(0); - } - - 100% { - transform: translateX(110%); - } -} - +/** + * Esup-Pod comments styles + */ + +:root { + /* --content-primary-color: rgba(6, 14, 29, .75); */ + --primary-background-color: #f8f9fa; + --third-background-color: rgb(255 255 255); + --content-secondary-color: rgba(54 56 58 0.65); + --content-third-color: #696969; + --padding-comment-content: 25px; + --margin-between-comment: 1em; + --voted-color: rgb(249 165 6); +} + +[data-theme="dark"] { + --content-third-color: #b6b4b4; +} + +.comment_disable { + text-align: center; + padding: 0.4em 0.8em; + color: #386066; + background: #afe0e8; + margin-top: 0.8em; + display: flex; + justify-content: center; + align-items: center; +} + +.comment_label, +.comment_main h3 { + font-weight: 600; + font-size: 16px; +} + +.comment_main .icon { + width: 18px; +} + +.reply_to { + letter-spacing: 1.1px; + color: var(--content-third-color); + margin-bottom: 0.8em; + margin-left: 0.8em; +} + +.reply_to svg { + width: 16px; +} + +.reply_author { + font-weight: 600; +} + +.comment_main .icon.comments_icon { + width: var(--padding-comment-content); + margin-right: 3px; +} + +.comment_main .inline_flex_space { + display: flex; + align-items: center; + justify-content: space-between; + flex-wrap: wrap; +} + +.comment_main .comment_disable::before { + content: ""; + display: block; + height: 1px; + background-color: var(--pod-background); + width: 100%; + margin-bottom: 2em; +} + +.comment_main .comment_disable { + display: flex; + justify-content: center; + flex-wrap: wrap; + font-weight: 400; + color: var(--pod-primary); + padding-top: 2em; +} + +.comment_main { + margin-top: 1em; + overflow-y: auto; + border: 1px solid var(--color-alto); +} + +.comment_main .comment_container { + width: 100%; +} + +/* Confirm Modal */ +.comment_main .confirm_delete { + display: none; + align-items: center; + justify-content: center; + padding-top: 20px; + z-index: 99; + position: fixed; + inset: 0; + min-height: 100vh; + background-color: rgba(54 56 58 0.5); +} + +.comment_main .confirm_delete.show { + display: flex; +} + +/* End Confirm Modal */ + +.comment_content { + padding: 1em; +} + +.comment_main .add_comment { + width: 100%; + position: relative; +} + +.comment_main .form-wrapper { + display: flex; + flex-direction: column; + font-size: 14px; +} + +.comment_main .comment { + position: relative; + display: flex; + padding-bottom: var(--margin-between-comment); +} + +.comment_element .comment_container { + display: flex; + flex-direction: column; + flex-grow: 1; + position: relative; + width: calc(100% - 37px); +} + +.comment_main .comment .comment_content { + display: flex; + flex-direction: column; + justify-content: space-between; + border-left: 4px solid var(--pod-primary); + padding: 0.4em; + box-shadow: 2px 2px 12px #e6e2e2; + border-top-right-radius: 4px; + border-bottom-right-radius: 4px; + background-color: var(--pod-background-neutre2-bloc); +} + +.comment_main + .comment_element + .comment_container + > .comments_children_container { + height: 0; + overflow: hidden; + transition: 0.5s height; +} + +.comment_main + .comment_element.show + .comment_container + > .comments_children_container { + height: auto; +} + +.comment_main + .comment_element + .comment_container + .comment_element + > .comment_child_container { + display: flex; + margin-top: calc(var(--margin-between-comment) - 0.2em); + padding-right: 0.8em; +} + +.comment_main .comment_element > .comment.onDelete, +.comment_main + .comment_element + .comment_container + .comment_element + > .comment_child_container.onDelete { + animation-name: deletecomment; + animation-duration: 1s; + animation-fill-mode: forwards; +} + +.comment_main + .comment_element + .comment_container + .comment_element + > .comment_child_container + .comments_icon { + margin-left: 0; + flex: none; + align-self: center; +} + +.comment_main .comment .comment_content_child { + border-radius: 5px; + border-top: 1px solid var(--primary-background-color); + border-right: 1px solid var(--primary-background-color); + border-bottom: 1px solid var(--primary-background-color); + border-left: 4px solid var(--content-secondary-color); + flex-grow: 1; + + /* width reduced by "re" svg width */ + max-width: calc(100% - 21px); +} + +.comment_main .comment .comment_content_header .comment_since { + color: var(--content-third-color); + font-size: 14px; +} + +.comment_main .comment .comment_content_body { + margin: 0 0 2em; + word-break: break-all; + font-size: 14px; +} + +.comment_main .comment .comment_content_body a { + display: block; + width: 500px; + max-width: 100%; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + margin-bottom: 0.8em; +} + +.comment_main .comment .comment_content_body .comment_text { + font-weight: 500; +} + +.comment_main .comment .comment_content_footer { + display: flex; + flex-flow: column wrap; + color: var(--content-secondary-color); +} + +.comment_main .comment .comment_content_footer > * { + display: flex; + align-items: center; + font-size: 13px; +} + +.comment_main .comment .comment_content_footer > * .icon { + margin-right: 4px; +} + +.comment_main .actions.inline_flex_space { + justify-content: space-around; +} + +.comment_main .comment .comment_content_footer .comment_actions { + display: flex; + color: var(--pod-font-color); +} + +.comment_main .comment .comment_content_footer .comment_actions:hover { + color: var(--pod-primary); +} + +.comment_main + .comment + .comment_content_footer + .comment_actions.voting + .comment_vote_icon { + display: none; +} + +.comment_main .comment_vote_action.voted .unvoted, +.comment_main .comment_vote_action .voted, +.comment_main .comment_element .comment-hide, +.comment_main .comment_element.show .comment-show { + display: none; +} + +.comment_main .comment_vote_action .unvoted, +.comment_main .comment_vote_action.voted .voted, +.comment_main .comment_element.show .comment-hide, +.comment_main .comment_element .comment-show { + display: inline-block; +} + +.comment_main .comment_vote_action.voted:hover .voted, +.comment_main .comment_vote_action.voted .voted { + color: var(--voted-color); +} + +.comment_main .comment_element .comment_content_footer .form { + height: 0; + overflow: hidden; + transition: 0.5s height; +} + +.comment_main .comment_element .comment_content_footer .form.show { + height: 60px; +} + +.comment_main .comment .comment_content_footer .add_comment { + margin: 0.8em 0.2em 0; +} + +.comment_main .add_comment .new_comment { + resize: none; + padding-right: 3em; +} + +.comment_main .send_reply { + width: 1.5em; + position: absolute; + right: 1rem; + top: 0; + height: 100%; + padding: 0; +} + +.comment_main .send_reply i { + width: 100%; + height: 100%; +} + +@media only screen and (max-width: 650px) { + .comment_main .comment_actions:not(.comment_vote_action) span { + display: none; + } +} + +/* ***** on scroll to comment background */ +.scroll_to { + animation-name: scrolltocomment; + animation-duration: 5s; + animation-fill-mode: forwards; +} + +@keyframes scrolltocomment { + 0% { + background-color: #f9f99b; + + /* rgba(255 234 59) */ + } + + 100% { + background-color: var(--third-background-color); + } +} + +/* ******* on delete comment ******* */ +@keyframes deletecomment { + 0% { + position: relative; + box-shadow: 0 0 8px 8px rgba(255 0 0 0.3) !important; + z-index: 9999; + transform: translateX(0); + } + + 100% { + transform: translateX(110%); + } +} diff --git a/pod/video/static/css/paginator.css b/pod/video/static/css/paginator.css index a24bc86138..435b404fd4 100644 --- a/pod/video/static/css/paginator.css +++ b/pod/video/static/css/paginator.css @@ -1,16 +1,11 @@ -.paginator { - display: -webkit-box; - display: -ms-flexbox; - display: flex; -} +/** + * Esup-Pod Paginator styles + */ .paginator { - width: 100%; - -webkit-box-pack: center; - -ms-flex-pack: center; - justify-content: center; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; - grid-column: 1 / -1; + display: flex; + width: 100%; + justify-content: center; + align-items: center; + grid-column: 1 / -1; } diff --git a/pod/video/static/css/regroup_videos_by_theme.css b/pod/video/static/css/regroup_videos_by_theme.css index fc8d01bef2..24e814d85e 100644 --- a/pod/video/static/css/regroup_videos_by_theme.css +++ b/pod/video/static/css/regroup_videos_by_theme.css @@ -1,35 +1,40 @@ +/** + * Esup-Pod regroup_video_by_theme styles + */ + .scroll_wrapper { - width: 100%; - overflow: hidden; - display: flex; + width: 100%; + overflow: hidden; + display: flex; } .list-children-theme { - margin-bottom: 1rem; - display: flex; - justify-content: center; - align-items: flex-start; - flex-wrap: wrap; - padding: 0; - flex-grow: 1; - width: 100%; - min-width: 100%; - transition: transform .5s ease-in-out; + margin-bottom: 1rem; + display: flex; + justify-content: center; + align-items: flex-start; + flex-wrap: wrap; + padding: 0; + flex-grow: 1; + width: 100%; + min-width: 100%; + transition: transform 0.5s ease-in-out; } .list-children-theme.scroll-left { - transform: translateX(-100%); + transform: translateX(-100%); } .list-children-theme.scroll-right { - transform: translateX(100%); + transform: translateX(100%); } +/* .paginator, .headband-description { - /*margin-bottom: 1em;*/ + margin-bottom: 1em; } -/* + .channelheader { float: left; margin-right: 1em; @@ -41,18 +46,19 @@ max-width: 100%; } */ + li.child-theme { - padding: 0; - margin: .4em 0; - margin-right: .8em; - max-width: 200px; - min-width: 200px + padding: 0; + margin: 0.4em 0; + margin-right: 0.8em; + max-width: 200px; + min-width: 200px; } .child-theme a { - padding: .4em; - max-width: 100%; - width: 100%; - display: block; - color: inherit !important; -} \ No newline at end of file + padding: 0.4em; + max-width: 100%; + width: 100%; + display: block; + color: inherit !important; +} diff --git a/pod/video/static/css/video-iframe.css b/pod/video/static/css/video-iframe.css index 21abd83b62..09fe0fcbde 100644 --- a/pod/video/static/css/video-iframe.css +++ b/pod/video/static/css/video-iframe.css @@ -1,10 +1,15 @@ -body{ +/** + * Esup-Pod video-iframe styles + */ + +body { margin: 0; padding: 0; background: #000; height: 100%; } -/* Add extra classes for a variable width / height*/ + +/* Add extra classes for a variable width / height */ #div-video-wrapper { position: absolute; display: block; @@ -13,10 +18,12 @@ body{ overflow: hidden; z-index: 0; } + #podvideoplayer { margin-left: auto; margin-right: auto; } + #info-video-wrapper { overflow: hidden; position: absolute; @@ -27,14 +34,16 @@ body{ border-radius: 0; padding: 0; margin: 0; - background-color: rgba(250, 250, 250, .9); + background-color: rgba(250 250 250 0.9); z-index: 10; } + #info-video { padding: 1em; box-sizing: border-box; overflow: auto; position: absolute; + /* top: 3em; */ width: 100%; bottom: 0; @@ -46,71 +55,81 @@ body{ .tab-title { font-size: 1.5em; } -/*.meta-title { + +/* +.meta-title { font-size: 1.2rem; -}*/ +} +*/ + .list-group-item { - background-color: rgba(250, 250, 250, .9) !important; + background-color: rgba(250 250 250 0.9) !important; } .iframe-header { - padding: 0 .5rem 0 1.25rem; + padding: 0 0.5rem 0 1.25rem; margin: 0; border-radius: 0; overflow: hidden; } + .iframe-header > h1 { display: inline-block; font-size: 1.25em; - padding: .25em 5em 0 0; + padding: 0.25em 5em 0 0; } .iframe-header .close { - /* position: absolute; + /* + position: absolute; top: .5em; - right: .5em; */ + right: .5em; + margin: .395em 0 0 .75em; + padding: 0 .25em .15em; + overflow: hidden; + opacity: 1; + font-size: 1.1em; + */ float: right; - /*margin: .395em 0 0 .75em;*/ border: 1px solid var(--bs-light); color: var(--bs-light); - /*padding: 0 .25em .15em;*/ background-color: var(--bs-dark); border-radius: 2px; - /*overflow: hidden; - opacity: 1; - font-size: 1.1em;*/ } + .iframe-header .close:hover { background-color: var(--bs-light); color: var(--bs-dark); - /*opacity: 1;*/ -} + /* opacity: 1; */ +} #div-video-wrapper #overlay-footer { - position: absolute; /* bottom: 0; */ + position: absolute; background-color: #2b333f; - background-color: rgba(43,51,63,.7); + background-color: rgba(43 51 63 0.7); z-index: 10; height: 30px; - padding: 0 .5em; + padding: 0 0.5em; width: 100%; color: #fff; display: none; text-align: right; } + #div-video-wrapper #overlay-footer > p { + /* margin-right: 70px; */ float: left; text-align: left; line-height: 30px; max-width: calc(100% - 75px); - /* margin-right: 70px; */ overflow: auto; - margin-left:-.5em; - padding: 0 .5em; + margin-left: -0.5em; + padding: 0 0.5em; background-color: #343a40; } + /* Info button with current color */ #overlay-footer .vjs-button { display: inline-block; @@ -120,21 +139,25 @@ body{ box-shadow: none; background: transparent; box-sizing: border-box; - margin: 0 -.1em 0 .5em; + margin: 0 -0.1em 0 0.5em; padding: 0; } + #overlay-footer .vjs-button:focus, -#overlay-footer .vjs-button:active {outline: none} +#overlay-footer .vjs-button:active { + outline: none; +} #overlay-footer .vjs-control-text { - border: 0; - clip: rect(0 0 0 0); - height: 1px; - overflow: hidden; - padding: 0; - position: absolute; - width: 1px; + border: 0; + clip: rect(0 0 0 0); + height: 1px; + overflow: hidden; + padding: 0; + position: absolute; + width: 1px; } + /* #overlay-footer .vjs-info-button::before, .video-js .vjs-info-button::before { @@ -143,31 +166,40 @@ body{ background-color: #FFF; mask-size: 20px; -webkit-mask-size: 20px; -}*/ - -#overlay-footer .vjs-info-button, -.video-js .vjs-info-button { - background-position: center; - background-image: url( 'data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-info-circle" viewBox="0 0 16 16"%3E%3Cpath d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z"/%3E %3Cpath d="m8.93 6.588-2.29.287-.082.38.45.083c.294.07.352.176.288.469l-.738 3.468c-.194.897.105 1.319.808 1.319.545 0 1.178-.252 1.465-.598l.088-.416c-.2.176-.492.246-.686.246-.275 0-.375-.193-.304-.533L8.93 6.588zM9 4.5a1 1 0 1 1-2 0 1 1 0 0 1 2 0z"/%3E%3C/svg%3E' ); - background-repeat: no-repeat; - background-size: contain; } +*/ + /* %3Csvg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-info-circle" viewBox="0 0 16 16"%3E%3Cpath d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z"/%3E %3Cpath d="m8.93 6.588-2.29.287-.082.38.45.083c.294.07.352.176.288.469l-.738 3.468c-.194.897.105 1.319.808 1.319.545 0 1.178-.252 1.465-.598l.088-.416c-.2.176-.492.246-.686.246-.275 0-.375-.193-.304-.533L8.93 6.588zM9 4.5a1 1 0 1 1-2 0 1 1 0 0 1 2 0z"/%3E%3C/svg%3E */ -#div-video-wrapper #info-video-wrapper {display: none} +#div-video-wrapper #info-video-wrapper { + display: none; +} + #div-video-wrapper.overlay.info #info-video-wrapper, #div-video-wrapper.overlay #overlay-footer, -#div-video-wrapper.vjs-not-started #overlay-footer {display: block} +#div-video-wrapper.vjs-not-started #overlay-footer { + display: block; +} -.vjs-logo-button, .vjs-info-button { +.vjs-logo-button, +.vjs-info-button { filter: invert(100%); background-size: 1.2rem !important; } + .vjs-logo-button:hover, .vjs-logo-button:focus, .vjs-info-button:hover, .vjs-info-button:focus { transform: rotate(30deg); background-color: transparent !important; -} \ No newline at end of file +} + +.video-js .vjs-info-button, +#overlay-footer .vjs-info-button { + background-position: center; + background-image: url('data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-info-circle" viewBox="0 0 16 16"%3E%3Cpath d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z"/%3E %3Cpath d="m8.93 6.588-2.29.287-.082.38.45.083c.294.07.352.176.288.469l-.738 3.468c-.194.897.105 1.319.808 1.319.545 0 1.178-.252 1.465-.598l.088-.416c-.2.176-.492.246-.686.246-.275 0-.375-.193-.304-.533L8.93 6.588zM9 4.5a1 1 0 1 1-2 0 1 1 0 0 1 2 0z"/%3E%3C/svg%3E'); + background-repeat: no-repeat; + background-size: contain; +} diff --git a/pod/video/static/css/video_category.css b/pod/video/static/css/video_category.css index 221f981127..aa838407b3 100644 --- a/pod/video/static/css/video_category.css +++ b/pod/video/static/css/video_category.css @@ -1,232 +1,227 @@ +/** + * Esup-Pod video category styles + */ + /* Override alert message css */ -.category_alert{ - position: fixed; - z-index: 99999; - -webkit-transform: translateX(105%); - -ms-transform: translateX(105%); - transform: translateX(105%); - bottom: 4px; - right: 4px; - -webkit-transition: .5s transform; - -o-transition: .5s transform; - transition: .5s transform; - border-radius: 4px; -} - -.category_alert.show{ -webkit-transform: translateX(0); -ms-transform: translateX(0); transform: translateX(0); } -.category_alert.hide{ -webkit-transform: translateY(150%); -ms-transform: translateY(150%); transform: translateY(150%); } - -.category_alert .alert_icon{ - margin-right: .8rem; - font-size: 25px; -} - -.category_alert .alert_title{ - font-weight: 700; - margin-right: .8em; -} - -#videos_list .alert-warning{ - display: -webkit-box; - display: -ms-flexbox; - display: flex; - -webkit-box-pack: center; - -ms-flex-pack: center; - justify-content: center; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; - width: 100%; - border-radius: var(--bs-border-radius); - padding: .4em 0; -} -.hidden{ - display: none !important; +.category_alert { + position: fixed; + z-index: 99999; + transform: translateX(105%); + bottom: 4px; + right: 4px; + transition: 0.5s transform; + border-radius: 4px; +} + +.category_alert.show { + transform: translateX(0); +} + +.category_alert.hide { + transform: translateY(150%); +} + +.category_alert .alert_icon { + margin-right: 0.8rem; + font-size: 25px; +} + +.category_alert .alert_title { + font-weight: 700; + margin-right: 0.8em; +} + +#videos_list .alert-warning { + display: flex; + justify-content: center; + align-items: center; + width: 100%; + border-radius: var(--bs-border-radius); + padding: 0.4em 0; +} + +.hidden { + display: none !important; } /* Override modal category css */ -#manageCategoryModal.show{ - display: -webkit-box !important; - display: -ms-flexbox !important; - display: flex !important; - -webkit-box-pack: center !important; - -ms-flex-pack: center !important; - justify-content: center !important; - -webkit-box-align: start !important; - -ms-flex-align: start !important; - align-items: flex-start !important; - padding: 0 !important; - margin: 0 !important; -} - -#manageCategoryModal .modal-dialog{ - width: 900px; - max-width: calc(100% - 2em); - margin: 0 auto; - top: 50%; - transform: translateY(-50%); -} - -#manageCategoryModal .category_modal_videos_list{ - display: grid; - grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); - grid-gap: .4em; -} -#manageCategoryModal .category_modal_videos_list .infinite-item{ - position: relative; - padding: .2em .4em; - min-width: 133px; - max-width: 100%; - -webkit-transition: .3s all; - -o-transition: .3s all; - transition: .3s all; +#manageCategoryModal.show { + display: flex !important; + justify-content: center !important; + align-items: flex-start !important; + padding: 0 !important; + margin: 0 !important; +} + +#manageCategoryModal .modal-dialog { + width: 900px; + max-width: calc(100% - 2em); + margin: 0 auto; + top: 50%; + transform: translateY(-50%); } + +#manageCategoryModal .category_modal_videos_list { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); + grid-gap: 0.4em; +} + +#manageCategoryModal .category_modal_videos_list .infinite-item { + position: relative; + padding: 0.2em 0.4em; + min-width: 133px; + max-width: 100%; + transition: 0.3s all; +} + .category_modal_videos_list .infinite-item .checked_overlay { - display: -webkit-box; - display: -ms-flexbox; - display: flex; - position: absolute; - margin: .2em .4em; - background-color: rgba(255, 255, 255, .8); - border: 2px solid var(--pod-link-color); - border-radius: var(--bs-border-radius-sm); - left: 0; - right: 0; - bottom: 0; - top: 0; - -webkit-box-pack: center; - -ms-flex-pack: center; - justify-content: center; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; - z-index: 9; - cursor: pointer; - opacity: 0; - -webkit-transition: opacity .3s; - -o-transition: opacity .3s; - transition: opacity .3s; -} -#manageCategoryModal .category_modal_videos_list .infinite-item .card_selected{ - display: block; - width: 25%; - font-size: 2em; - color: var(--pod-primary); - transition: all .3s; -} -#manageCategoryModal .category_modal_videos_list .infinite-item:not(.selected):hover, -#manageCategoryModal .category_modal_videos_list .infinite-item .checked_overlay:hover .card_selected{ - transform: scale(1.04); -} -#manageCategoryModal .category_modal_videos_list .infinite-item.selected .checked_overlay{ - opacity: 1; -} - -#manageCategoryModal .category_modal_videos_list .modal_category_card{ - margin-bottom: .4em !important; - height: 100%; - border-radius: var(--bs-border-radius-sm); -} - -#manageCategoryModal .category_modal_videos_list .card-header{ - background-color: var(--pod-primary); - color: white; - font-size: 14px; - padding: .4em; - border-top-left-radius: var(--bs-border-radius-sm); -} - -#manageCategoryModal .category_modal_videos_list .card-header *{ - color: inherit !important; -} - -#manageCategoryModal .category_modal_videos_list .card-footer{ - padding: .4em; -} - -#manageCategoryModal .category_modal_videos_list .card-footer .video_title{ - display: inline-block; - line-height: 1; - height: 100%; - max-width: 100%; - overflow: hidden; - -o-text-overflow: ellipsis; - text-overflow: ellipsis; - white-space: nowrap; - text-align: left; - font-size: 14px; - color: var(--pod-primary); -} - -#deleteCategoryModal .modal-body .category_title{ - display: block; - text-align: center; - color: var(--pod-primary); - margin-bottom: .8em; - font-weight: 700; -} -.categories_list{ - padding: 0; - padding-left: .4em; -} -.categories_list_item{ - list-style: square; - padding: .4em; - line-height: 1; - color: var(--bs-secondary); - font-size: 14px; - display: -webkit-box; - display: -ms-flexbox; - display: flex; - -webkit-box-pack: justify; - -ms-flex-pack: justify; - justify-content: space-between; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; - border-bottom: 1px solid #ccc; - -webkit-transition: .3s all; - -o-transition: .3s all; - transition: .3s all; -} -.categories_list_item.active{ - color: #fff; - background-color: var(--pod-primary); -} -.active .category_actions>button{ - color: #fff; -} -.categories_list_item:not(.active):hover{ - background-color: rgba(149, 149, 149, 0.09); - border-color: rgba(149, 149, 149, 0.09); -} - -.categories_list_item.active .cat_title{ - color: inherit; + display: flex; + position: absolute; + margin: 0.2em 0.4em; + background-color: rgba(255 255 255 0.8); + border: 2px solid var(--pod-link-color); + border-radius: var(--bs-border-radius-sm); + inset: 0; + justify-content: center; + align-items: center; + z-index: 9; + cursor: pointer; + opacity: 0; + transition: opacity 0.3s; +} + +#manageCategoryModal .category_modal_videos_list .infinite-item .card_selected { + display: block; + width: 25%; + font-size: 2em; + color: var(--pod-primary); + transition: all 0.3s; } -.categories_list_item:last-child{ border: none;} +#manageCategoryModal + .category_modal_videos_list + .infinite-item:not(.selected):hover, +#manageCategoryModal + .category_modal_videos_list + .infinite-item + .checked_overlay:hover + .card_selected { + transform: scale(1.04); +} + +#manageCategoryModal + .category_modal_videos_list + .infinite-item.selected + .checked_overlay { + opacity: 1; +} + +#manageCategoryModal .category_modal_videos_list .modal_category_card { + margin-bottom: 0.4em !important; + height: 100%; + border-radius: var(--bs-border-radius-sm); +} + +#manageCategoryModal .category_modal_videos_list .card-header { + background-color: var(--pod-primary); + color: white; + font-size: 14px; + padding: 0.4em; + border-top-left-radius: var(--bs-border-radius-sm); +} -.edit_category{ +#manageCategoryModal .category_modal_videos_list .card-header * { + color: inherit !important; +} + +#manageCategoryModal .category_modal_videos_list .card-footer { + padding: 0.4em; +} + +#manageCategoryModal .category_modal_videos_list .card-footer .video_title { + display: inline-block; + line-height: 1; + height: 100%; + max-width: 100%; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + text-align: left; + font-size: 14px; + color: var(--pod-primary); +} + +#deleteCategoryModal .modal-body .category_title { + display: block; + text-align: center; + color: var(--pod-primary); + margin-bottom: 0.8em; + font-weight: 700; +} + +.categories_list { + padding: 0; + padding-left: 0.4em; +} + +.categories_list_item { + list-style: square; + padding: 0.4em; + line-height: 1; + color: var(--bs-secondary); + font-size: 14px; + display: flex; + justify-content: space-between; + align-items: center; + border-bottom: 1px solid #ccc; + transition: 0.3s all; +} + +.categories_list_item.active { + color: #fff; + background-color: var(--pod-primary); +} + +.active .category_actions > button { + color: #fff; +} + +.categories_list_item:last-child { + border: none; +} + +.categories_list_item:not(.active):hover { + background-color: rgba(149 149 149 0.09); + border-color: rgba(149 149 149 0.09); +} + +.categories_list_item.active .cat_title { + color: inherit; +} + +.edit_category { --bs-btn-hover-color: var(--pod-primary-darken); } -.remove_category{ + +.remove_category { --bs-btn-hover-color: var(--bs-danger); } /* Override Paginator css */ -.category_modal_videos_list.show{ height: 385px !important; } +.category_modal_videos_list.show { + height: 385px !important; +} + +.paginator { + display: none; + width: 100%; + justify-content: center; + align-items: center; + grid-column: 1 / -1; +} + .category_modal_videos_list.show .paginator, -.loader_wrapper.show{ display: -webkit-box; display: -ms-flexbox; display: flex; } - -.paginator{ - display:none; - width: 100%; - -webkit-box-pack: center; - -ms-flex-pack: center; - justify-content: center; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; - grid-column: 1 / -1; -} \ No newline at end of file +.loader_wrapper.show { + display: flex; +} diff --git a/pod/video/static/css/video_notes.css b/pod/video/static/css/video_notes.css index 040fd1d9a9..679b2ed9fe 100644 --- a/pod/video/static/css/video_notes.css +++ b/pod/video/static/css/video_notes.css @@ -1,3 +1,7 @@ +/** + * Esup-Pod video notes styles + */ + #video_notes_form { padding: 0 2px; } @@ -13,29 +17,33 @@ #id_notes small { font-size: 9px; - display: inline-block; + display: inline-block; margin-top: 0; font-weight: bold; } -/*.bigtakenote #id_notes small { +/* +.bigtakenote #id_notes { + overflow: scroll; + height: 600px; +} + +.bigtakenote #id_notes small { font-size: 11px; -}*/ +} +*/ #id_notes .form-group { margin: 0; } -#id_notes p.note.form, #id_notes div.comment.form { +#id_notes p.note.form, +#id_notes div.comment.form { margin: auto; } -/*.bigtakenote #id_notes { - overflow: scroll; - height: 600px; -}*/ - -.mgtNote div.dropdown-menu, .mgtComment div.dropdown-menu { +.mgtNote div.dropdown-menu, +.mgtComment div.dropdown-menu { min-width: auto; padding: 5px; } @@ -43,7 +51,9 @@ span.timestamp { font-size: 11px; } -/*.bigtakenote span.timestamp { + +/* +.bigtakenote span.timestamp { font-size: 14px; } @@ -55,7 +65,8 @@ span.timestamp { .view_video_note_coms_form { cursor: ns-resize; /padding: 3px 0 3px 0;* -}*/ +} +*/ .bigtakenote .note, .bigtakenote .comment { @@ -69,32 +80,31 @@ div.comment { .pod-note-header { cursor: pointer; font-size: 12px; - flex-grow: 2; + flex-grow: 2; } -.pod-note-date{ + +.pod-note-date { display: inline-block; font-size: 10px; max-width: 8rem; } -.pod-note-header:hover, -.pod-note-header:focus, -.pod-note-header:hover>.pod-note-truncated, -.pod-note-header:focus>.pod-note-truncated { - text-decoration: underline; -} -.view_video_notes_form{ - flex-grow: 2; + +.view_video_notes_form { + flex-grow: 2; } -.view_video_note_coms_form{ + +.view_video_note_coms_form { width: 100%; } -.pod-note-item, .pod-note-comment { +.pod-note-item, +.pod-note-comment { display: flex; - gap: .3rem; + gap: 0.3rem; align-items: baseline; } -.pod-note-comment{ + +.pod-note-comment { flex-wrap: wrap; } @@ -103,20 +113,24 @@ div.comment { background-color: var(--pod-background-neutre1-bloc); } -/*.pod-note-item > span, +/* +.pod-note-item > span, .pod-note-item > form { flex: auto; align-self: center; -}*/ +} +*/ span.user { font-size: 11px; font-weight: bold; } -/*.bigtakenote span.user { +/* +.bigtakenote span.user { font-size: 14px; -}*/ +} +*/ .pod-note-truncated { text-overflow: ellipsis; @@ -124,25 +138,38 @@ span.user { white-space: nowrap; font-size: 12px; } + .pod-note-truncated.pod-note-content { display: inline-block; vertical-align: bottom; max-width: 8em; } + .pod-note-content.pod-callout, .pod-comment-content.pod-callout { white-space: pre-wrap; } -textarea#id_note, textarea#id_comment, select#id_status { +.pod-note-header:hover, +.pod-note-header:focus, +.pod-note-header:hover > .pod-note-truncated, +.pod-note-header:focus > .pod-note-truncated { + text-decoration: underline; +} + +textarea#id_note, +textarea#id_comment, +select#id_status { font-size: 11px; height: auto; padding: 5px; } -/*.bigtakenote textarea#id_note, .bigtakenote textarea#id_comment, .bigtakenote select#id_status { +/* +.bigtakenote textarea#id_note, .bigtakenote textarea#id_comment, .bigtakenote select#id_status { font-size: 14px; -}*/ +} +*/ #card-takenote > div.card-text { width: 100%; @@ -152,28 +179,33 @@ textarea#id_note, textarea#id_comment, select#id_status { background-color: #fff5f5; } -/*div.mgtNotes, div.mgtNote, div.mgtComment { +/* +div.mgtNotes, div.mgtNote, div.mgtComment { align-self: center; -}*/ +} +*/ -div.mgtNotes form{ +div.mgtNotes form { display: inline-block; } -/*div.mgtNotes.dropleft > button, +/* +div.mgtNotes.dropleft > button, div.mgtNote.dropleft > button, div.mgtComment.dropleft > button { border: none; -}*/ +} +*/ .noNotes { - font-size: .8rem; + font-size: 0.8rem; font-style: italic; margin: 5px; } -div.note, div.comment { - margin: 3px 0 3px 0; +div.note, +div.comment { + margin: 3px 0; } .user-comment { diff --git a/pod/video/static/css/video_stats_view.css b/pod/video/static/css/video_stats_view.css index f46edc2513..218d370d5b 100644 --- a/pod/video/static/css/video_stats_view.css +++ b/pod/video/static/css/video_stats_view.css @@ -1,71 +1,11 @@ -.grid-container{ - padding-top: 4em; - display: flex; - align-items: center; - flex-direction: column; - min-height: calc(100vh - 255px); -} -/*.grid-container h1.title{ - margin-bottom: 1em; - font-size: 24px; - padding: 0 .8em; - color: var(--pod-primary) !important; -} -.ui-jqgrid tr.jqgrow td{ - height: 30px; - white-space: normal; - padding: .5em; -} -.ui-state-default .ui-icon{ - background-image: url("/static/img/ui-icons_6da8d5_256x240.png"); -} -.ui-icon .ui-widget-content .ui-icon{ - background-image: url("/static/img/ui-icons_469bdd_256x240.png"); -} -.ui-state-default .ui-icon { - background-image: url("/static/img/ui-icons_6da8d5_256x240.png"); -} -ui-icon, .ui-widget-content .ui-icon { - background-image: url("/static/img/ui-icons_469bdd_256x240.png"); -}*/ - -/* Override jqgrid default css background-image */ -/*.ui-widget-content, -.ui-state-default, -.ui-widget-content .ui-state-default, -.ui-widget-header .ui-state-default, -.ui-state-hover, -.ui-widget-content .ui-state-hover, -.ui-widget-header .ui-state-hover, -.ui-state-focus, -.ui-widget-content .ui-state-focus, -.ui-widget-header .ui-state-focus{ - background-image:none; -}*/ - +/** + * Esup-Pod video stats styles + */ -/*.stat-form-group{ - display: flex; - justify-content: flex-start; - max-width: 755px; - align-items: center; -} -.stat-form-group .col-form-label{ - font-weight: 700; - color: var(--secondary); -} -.stat-form-group .col-form-label, -.stat-form-group .col-date{ - width: auto; - flex: none; - max-width: unset; +.grid-container { + padding-top: 4em; + display: flex; + align-items: center; + flex-direction: column; + min-height: calc(100vh - 255px); } -@media only screen and (max-width: 512px){ - .stat-form-group{ - flex-direction: column; - width: 100%; - } - .stat-form-group .col-date{ - width: calc(100% - 2em); - } -}*/ diff --git a/pod/video/static/css/videojs-controlbar.css b/pod/video/static/css/videojs-controlbar.css index 19767887fc..9e929be818 100644 --- a/pod/video/static/css/videojs-controlbar.css +++ b/pod/video/static/css/videojs-controlbar.css @@ -6,17 +6,27 @@ .vjs-control-bar button:hover, .vjs-control-bar button:active, .vjs-control-bar button:focus, -.vjs-volume-control:hover,.vjs-volume-control:active,.vjs-volume-control:focus{ - background-color: #0006; +.vjs-volume-control:hover, +.vjs-volume-control:active, +.vjs-volume-control:focus { + background-color: #0006; } -.vjs-button{cursor:pointer;} -.video-js .vjs-volume-horizontal{margin-right:0} -.video-js .vjs-volume-bar{margin-right:1em;} +.vjs-button { + cursor: pointer; +} + +.video-js .vjs-volume-horizontal { + margin-right: 0; +} + +.video-js .vjs-volume-bar { + margin-right: 1em; +} /* Hide seek buttons & volume pannel on x-small screens */ .video-js.vjs-layout-small .vjs-seek-button, .video-js.vjs-layout-x-small .vjs-seek-button, -.video-js.vjs-layout-x-small .vjs-volume-panel{ - display: none; +.video-js.vjs-layout-x-small .vjs-volume-panel { + display: none; } diff --git a/pod/video_encode_transcript/transcript.py b/pod/video_encode_transcript/transcript.py index 70933461a7..df21e392eb 100644 --- a/pod/video_encode_transcript/transcript.py +++ b/pod/video_encode_transcript/transcript.py @@ -1,3 +1,4 @@ +"""Esup-Pod transcript video functions.""" from django.conf import settings from django.core.files import File from pod.completion.models import Track @@ -42,7 +43,7 @@ TRANSCRIPTION_MODEL_PARAM = getattr(settings, "TRANSCRIPTION_MODEL_PARAM", False) USE_TRANSCRIPTION = getattr(settings, "USE_TRANSCRIPTION", False) if USE_TRANSCRIPTION: - TRANSCRIPTION_TYPE = getattr(settings, "TRANSCRIPTION_TYPE", "VOSK") + TRANSCRIPTION_TYPE = getattr(settings, "TRANSCRIPTION_TYPE", "STT") TRANSCRIPTION_NORMALIZE = getattr(settings, "TRANSCRIPTION_NORMALIZE", False) CELERY_TO_ENCODE = getattr(settings, "CELERY_TO_ENCODE", False) @@ -72,7 +73,8 @@ # ########################################################################## def start_transcript(video_id, threaded=True): """ - Main function call to start transcript. + Call to start transcript main function. + Will launch transcript mode depending on configuration. """ if threaded: @@ -89,7 +91,8 @@ def start_transcript(video_id, threaded=True): def main_threaded_transcript(video_to_encode_id): """ - Main function to transcript. + Transcript main function. + Will check all configuration and file and launch transcript. """ change_encoding_step(video_to_encode_id, 5, "transcripting audio") @@ -100,7 +103,7 @@ def main_threaded_transcript(video_to_encode_id): lang = video_to_encode.transcript # check if TRANSCRIPTION_MODEL_PARAM [lang] exist if not TRANSCRIPTION_MODEL_PARAM[TRANSCRIPTION_TYPE].get(lang): - msg += "\n no stt model found for lang:%s." % lang + msg += "\n no stt model found for lang: %s." % lang msg += "Please add it in TRANSCRIPTION_MODEL_PARAM." change_encoding_step(video_to_encode.id, -1, msg) send_email(msg, video_to_encode.id) @@ -111,7 +114,7 @@ def main_threaded_transcript(video_to_encode_id): else None ) if mp3file is None: - msg += "\n no mp3 file found for video :%s." % video_to_encode.id + msg += "\n no mp3 file found for video: %s." % video_to_encode.id change_encoding_step(video_to_encode.id, -1, msg) send_email(msg, video_to_encode.id) else: diff --git a/pod/video_encode_transcript/transcript_model.py b/pod/video_encode_transcript/transcript_model.py index f3a66e2bb4..81c162fa5d 100644 --- a/pod/video_encode_transcript/transcript_model.py +++ b/pod/video_encode_transcript/transcript_model.py @@ -85,6 +85,8 @@ def get_model(lang): def start_transcripting(mp3filepath, duration, lang): """ + Start direct transcription. + Normalize the audio if set, get the model according to the lang and start transcript. """ if TRANSCRIPTION_NORMALIZE: @@ -161,7 +163,7 @@ def normalize_mp3(mp3filepath): # ################################# -# TRANSCRIPT VIDEO : MAIN FUNCTION +# TRANSCRIPT VIDEO: MAIN FUNCTION # ################################# @@ -228,7 +230,7 @@ def words_to_vtt( ((word[start_key]) - start_caption) + word_duration ) all_text += word["word"] + " " - # word : {'word': 'bonjour', 'start ': + # word: {'word': 'bonjour', 'start ': # 0.58, 'duration': 7.34} text_caption.append(word["word"]) if not ( @@ -371,7 +373,7 @@ def main_stt_transcript(norm_mp3_file, duration, transript_model): metadata = transript_model.sttWithMetadata(audio) for transcript in metadata.transcripts: - msg += "\nConfidence : %s" % transcript.confidence + msg += "\nConfidence: %s" % transcript.confidence words = words_from_candidate_transcript(transcript) start_caption = start_trim + words[0]["start_time"] text_caption = [] @@ -415,7 +417,7 @@ def format_time_caption(time_caption): def get_text_caption(text_caption, last_word_added): - """get the text for a caption.""" + """Get the text for a caption.""" try: first_index = text_caption.index(last_word_added) return text_caption[first_index + 1 :] From 3144847a2bd68bb1d78a08d7a5a1f418e1b2dffd Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 9 Oct 2023 08:52:07 +0000 Subject: [PATCH 12/26] Fixup. Format code with Prettier --- pod/main/static/css/pod.css | 1 - 1 file changed, 1 deletion(-) diff --git a/pod/main/static/css/pod.css b/pod/main/static/css/pod.css index b21509a8be..df42ca76ac 100755 --- a/pod/main/static/css/pod.css +++ b/pod/main/static/css/pod.css @@ -1316,7 +1316,6 @@ body { } } - /**** static content homepage ***/ .pod-card--video { From c79866f8b725984773377d158587754102512fc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Bonavent?= <56730254+LoicBonavent@users.noreply.github.com> Date: Fri, 13 Oct 2023 18:00:20 +0200 Subject: [PATCH 13/26] [DONE] New 3.4.0 fixes (#981) * Bugfix for create a thumbnail * Fixed bug preventing change of pages or number of lines in interface * Bugfix for issue #948 (An error appears in the form for adding a video, for a super admin, for the owner attribute) * Adding comments and using getElementById * Manage the background and color of select2 single field, for the dark mode --- pod/main/static/css/dark.css | 12 ++++++++++- pod/video/forms.py | 3 ++- .../management/commands/create_thumbnail.py | 4 ++-- pod/video/static/js/video_stats_view.js | 20 +++++++++++-------- .../Encoding_video_model.py | 2 +- 5 files changed, 28 insertions(+), 13 deletions(-) diff --git a/pod/main/static/css/dark.css b/pod/main/static/css/dark.css index 71697c1152..77f69ed2c2 100644 --- a/pod/main/static/css/dark.css +++ b/pod/main/static/css/dark.css @@ -292,7 +292,8 @@ body.dark { [data-theme="dark"] .select2-dropdown-open .select2-choice, [data-theme="dark"] .select2-results .select2-no-results, [data-theme="dark"] .select2-results .select2-searching, -[data-theme="dark"] .select2-container--default .select2-selection--multiple { +[data-theme="dark"] .select2-container--default .select2-selection--multiple, +[data-theme="dark"] .select2-container--default .select2-selection--single { background-color: var(--pod-background-neutre1-bloc); border-color: var(--pod-font-color); color: var(--pod-font-color); @@ -304,6 +305,15 @@ body.dark { color: #000; } +[data-theme="dark"] .select2-container--default .select2-selection--single .select2-selection__rendered{ + color: var(--pod-font-color); +} + +[data-theme="dark"] .select2-results__option { + background-color: var(--pod-background-neutre1-bloc); + color: var(--pod-font-color); +} + [data-theme="dark"] .form-select { background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23f3f9ff' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e"); } diff --git a/pod/video/forms.py b/pod/video/forms.py index 3c1f0e2292..c66f23f976 100644 --- a/pod/video/forms.py +++ b/pod/video/forms.py @@ -829,7 +829,8 @@ def __init__(self, *args, **kwargs): if self.instance and self.instance.video: if self.instance.encoding_in_progress or not self.instance.encoded: - self.remove_field("owner") + if not self.is_superuser: + self.remove_field("owner") self.remove_field("video") # .widget = forms.HiddenInput() # remove required=True for videofield if instance diff --git a/pod/video/management/commands/create_thumbnail.py b/pod/video/management/commands/create_thumbnail.py index a7bdf72316..a6b884f10c 100755 --- a/pod/video/management/commands/create_thumbnail.py +++ b/pod/video/management/commands/create_thumbnail.py @@ -1,7 +1,7 @@ from django.core.management.base import BaseCommand from pod.video.models import Video -from pod.video.Encoding_video_model import Encoding_video_model -from pod.video.models import EncodingLog +from pod.video_encode_transcript.Encoding_video_model import Encoding_video_model +from pod.video_encode_transcript.models import EncodingLog class Command(BaseCommand): diff --git a/pod/video/static/js/video_stats_view.js b/pod/video/static/js/video_stats_view.js index af9fa50027..d8256e9c5f 100644 --- a/pod/video/static/js/video_stats_view.js +++ b/pod/video/static/js/video_stats_view.js @@ -99,13 +99,17 @@ $(() => { pager: "#pager", sortorder: "asc", beforeProcessing: function (data) { - // Set min date - let min_date = data.filter((obj) => { - return obj.min_date != undefined; - }); - // remove date_min in data - data.pop(); - document.querySelector("#jsperiode").min = min_date[0].min_date; + // Avoid "data.filter is not a function" error (if change number of lines or page) + try { + // Set min date + let min_date = data.filter((obj) => { + return obj.min_date != undefined; + }); + // remove date_min in data + data.pop(); + document.getElementById("jsperiode").min = min_date[0].min_date; + } + catch(uselesserr) { } }, postData: { csrfmiddlewaretoken: $("[name=csrfmiddlewaretoken]").val(), @@ -113,7 +117,7 @@ $(() => { }); let today = new Date().toISOString().split("T")[0]; $("#jsperiode").val(today); // set date input value to today - document.querySelector("#jsperiode").max = today; + document.getElementById("jsperiode").max = today; $("#jsperiode").on("change paste keyup", function (e) { if ($(this).val() != undefined && $(this).val().trim() !== "") { diff --git a/pod/video_encode_transcript/Encoding_video_model.py b/pod/video_encode_transcript/Encoding_video_model.py index f8dd078e9d..573333751d 100644 --- a/pod/video_encode_transcript/Encoding_video_model.py +++ b/pod/video_encode_transcript/Encoding_video_model.py @@ -383,7 +383,7 @@ def recreate_thumbnail(self): encoding_log.save() if len(self.list_thumbnail_files) > 0: info_video["list_thumbnail_files"] = self.list_thumbnail_files - self.store_json_list_thumbnail_files(info_video, video_to_encode) + self.store_json_list_thumbnail_files(info_video) def encode_video(self): """Start video encoding.""" From 8c920c27b5db2b61ebc42717fc3f4b9ae1557ec5 Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 13 Oct 2023 16:00:57 +0000 Subject: [PATCH 14/26] Fixup. Format code with Prettier --- pod/main/static/css/dark.css | 5 ++++- pod/video/static/js/video_stats_view.js | 3 +-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/pod/main/static/css/dark.css b/pod/main/static/css/dark.css index 77f69ed2c2..63120ddd07 100644 --- a/pod/main/static/css/dark.css +++ b/pod/main/static/css/dark.css @@ -305,7 +305,10 @@ body.dark { color: #000; } -[data-theme="dark"] .select2-container--default .select2-selection--single .select2-selection__rendered{ +[data-theme="dark"] + .select2-container--default + .select2-selection--single + .select2-selection__rendered { color: var(--pod-font-color); } diff --git a/pod/video/static/js/video_stats_view.js b/pod/video/static/js/video_stats_view.js index d8256e9c5f..d20b200790 100644 --- a/pod/video/static/js/video_stats_view.js +++ b/pod/video/static/js/video_stats_view.js @@ -108,8 +108,7 @@ $(() => { // remove date_min in data data.pop(); document.getElementById("jsperiode").min = min_date[0].min_date; - } - catch(uselesserr) { } + } catch (uselesserr) {} }, postData: { csrfmiddlewaretoken: $("[name=csrfmiddlewaretoken]").val(), From 8fdf7f05fc8250439407897b7a15cfa65c15820f Mon Sep 17 00:00:00 2001 From: Olivier Bado-Faustin Date: Mon, 16 Oct 2023 14:50:59 +0200 Subject: [PATCH 15/26] [DONE] A11y for caption_maker (#982) * * Change TRANSCRIPTION_STT_SENTENCE_MAX_LENGTH default value to 2s * Now caption-maker textareas are limited to 40 chars max per row, with max chars at 80 * When editing a caption/subtitle, the player auto-seek at related time * add missing aria-hidden + aria-label on some button-icons * Uniformize caption/subtitle naming * Reorder CSS for code styling * Add .po lang files * Add missing JsDocs on caption_maker.js + Add .eslintrc.js to lint JS errors/warnings * Add client Validation to caption maker for better ergonomy * last minor corrections * Add a minor code comment + rename some vars. --- .eslintrc.js | 41 ++ pod/completion/static/js/caption_maker.js | 518 ++++++++++++------ .../templates/video_caption_maker.html | 15 +- pod/locale/fr/LC_MESSAGES/django.po | 11 +- pod/locale/fr/LC_MESSAGES/djangojs.po | 49 +- pod/locale/nl/LC_MESSAGES/django.po | 9 +- pod/locale/nl/LC_MESSAGES/djangojs.po | 30 +- pod/main/configuration.json | 6 +- pod/main/static/css/pod.css | 303 +++++----- pod/main/templates/base.html | 4 +- .../transcript_model.py | 2 +- 11 files changed, 631 insertions(+), 357 deletions(-) create mode 100644 .eslintrc.js diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000000..a043666029 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,41 @@ +module.exports = { + "env": { + "browser": true, + "commonjs": true, + "es2021": true, + "node": true + }, + "extends": "eslint:recommended", + "parserOptions": { + "ecmaVersion": "latest", + "sourceType": "script" + }, + "rules": { + "indent": [ + "error", + 2, + {"SwitchCase": 1} + ], + "linebreak-style": [ + "error", + "unix" + ], + "semi": [ + "error", + "always", + ], + /*"camelcase": ["warn", {"ignoreGlobals": true}],*/ + /* First capital letter is reserved for "new" Objects. */ + "new-cap": ["warn", { "capIsNew": true }] + }, + /* functions and Objects that will not trigger a "not defined" error. */ + "globals": { + "Cookies": "readonly", + "gettext": "readonly", + "interpolate": "readonly", + "bootstrap": "readonly", + "videojs": "readonly", + "send_form_data": "writable", + "showalert": "writable", + } +}; diff --git a/pod/completion/static/js/caption_maker.js b/pod/completion/static/js/caption_maker.js index 11c0a3704e..14668bf07a 100644 --- a/pod/completion/static/js/caption_maker.js +++ b/pod/completion/static/js/caption_maker.js @@ -1,8 +1,21 @@ -const caption_memories = { +// Esup-Pod Caption maker Tool + +// Read-only globals defined in video_caption_maker.html +/* + global current_folder +*/ + +// Global vars +var fileLoaded = false; +var fileLoadedId = undefined; +var captionsArray = []; +var autoPauseAtTime = -1; + +const captionMemories = { start_time: "00:00.000", }; const file_prefix = window.location.pathname - .match(/[\d\w\-]+\/$/)[0] + .match(/[\d\w-]+\/$/)[0] .replace("/", ""); document.addEventListener("click", (e) => { @@ -17,7 +30,7 @@ document.addEventListener("click", (e) => { let form = document.getElementById("captionmaker_form"); let data_form = new FormData(form); - send_form_data(url, data_form, "ProcessProxyVttResponse"); + send_form_data(url, data_form, "processProxyVttResponse"); }); // Charge caption/subtitle file if exists @@ -30,7 +43,7 @@ document.addEventListener("DOMContentLoaded", function () { csrfmiddlewaretoken: Cookies.get("csrftoken"), }; - send_form_data(url, data, "ProcessProxyVttResponse"); + send_form_data(url, data, "processProxyVttResponse"); } else { document.getElementById( "captionFilename", @@ -42,7 +55,7 @@ document.addEventListener("DOMContentLoaded", function () { ); let captionContent = document.getElementById("captionContent"); captionContent.setAttribute("placeholder", placeholder); - captionContent.addEventListener("mouseup", function (e) { + captionContent.addEventListener("mouseup", function () { let selectedText = this.value.substring( this.selectionStart, this.selectionEnd, @@ -57,10 +70,9 @@ document.addEventListener("DOMContentLoaded", function () { elt.remove(); }); if (this.value.match(/^WEBVTT/)) { - ParseAndLoadWebVTT(this.value); + parseAndLoadWebVTT(this.value); } else { alert(gettext("Unrecognized caption file format.")); - t; } }); }); @@ -69,13 +81,18 @@ document.addEventListener("submit", (e) => { if (e.target.id != "form_save_captions") return; e.preventDefault(); let caption_content = document.getElementById("captionContent"); - if (!oldModeSelected) caption_content.value = GenerateWEBVTT(); + if (!oldModeSelected) caption_content.value = generateWEBVTT(); + + if(caption_content.value === "false") { + showalert(gettext("There are errors in your captions/subtitles. Please review."), "alert-warning"); + return; + } if (caption_content.value.trim() === "") { - showalert(gettext("There is no captions to save."), "alert-danger"); + showalert(gettext("There is no caption/subtitle to save."), "alert-danger"); return; } - if (typeof file_loaded != "undefined" && file_loaded) { + if (typeof fileLoaded != "undefined" && fileLoaded) { let saveModalId = document.getElementById("saveCaptionsModal"); let saveModal = bootstrap.Modal.getOrCreateInstance(saveModalId); saveModal.show(); @@ -85,25 +102,25 @@ document.addEventListener("submit", (e) => { } }); -document.addEventListener("click", (elt) => { - if (elt.target.id != "modal-btn-new" && elt.target.id != "modal-btn-override") +document.addEventListener("click", (evt) => { + if (evt.target.id != "modal-btn-new" && evt.target.id != "modal-btn-override") return; let caption_content = document.getElementById("captionContent"); - if (!oldModeSelected) caption_content.value = GenerateWEBVTT(); + if (!oldModeSelected) caption_content.value = generateWEBVTT(); let saveModalId = document.getElementById("saveCaptionsModal"); let saveModal = bootstrap.Modal.getOrCreateInstance(saveModalId); saveModal.hide(); let form_save_captions = document.getElementById("form_save_captions"); - if (elt.target.id == "modal-btn-override") { + if (evt.target.id == "modal-btn-override") { document .getElementById("form_save_captions") - .querySelector('input[name="file_id"]').value = file_loaded_id; + .querySelector('input[name="file_id"]').value = fileLoadedId; //form_save_captions.querySelector('input[name="enrich_ready"]').value = ""; updateCaptionsArray(caption_content.value); send_form_save_captions(); - } else if (elt.target.id == "modal-btn-new") { + } else if (evt.target.id == "modal-btn-new") { form_save_captions.querySelector('input[name="file_id"]').value = ""; //form_save_captions.querySelector('input[name="enrich_ready"]').value=""; @@ -111,15 +128,18 @@ document.addEventListener("click", (elt) => { } }); +/** + * Send the captions form to be saved + */ const send_form_save_captions = function () { let fileName = document.getElementById("captionFilename").value; if (fileName.length == 0) { fileName = `${file_prefix}_captions_${Date.now()}`; } - rxSignatureLine = /^WEBVTT(?:\s.*)?$/; - vttContent = document.getElementById("captionContent").value.trim(); - vttLines = vttContent.split(/\r\n|\r|\n/); + let rxSignatureLine = /^WEBVTT(?:\s.*)?$/; + let vttContent = document.getElementById("captionContent").value.trim(); + let vttLines = vttContent.split(/\r\n|\r|\n/); if (!rxSignatureLine.test(vttLines[0])) { alert(gettext("Not a valid time track file.")); return; @@ -130,7 +150,9 @@ const send_form_save_captions = function () { data_form.append("folder", current_folder); data_form.append("file", f); - url = document.getElementById("form_save_captions").getAttribute("action"); + let url = document + .getElementById("form_save_captions") + .getAttribute("action"); fetch(url, { method: "POST", @@ -194,7 +216,6 @@ document video_error.textContent = gettext( "The video could not be loaded, either because the server or network failed or because the format is not supported.", ); - break; default: video_error.textContent = gettext("An unknown error occurred."); @@ -207,7 +228,7 @@ document let shortcutsDisplayed = false; document .getElementById("showShortcutTips") - .addEventListener("click", function (e) { + .addEventListener("click", function () { let shortcuts = document.getElementById("shortcutsBlock"); if (shortcutsDisplayed) { shortcuts.style.display = "none"; @@ -218,12 +239,12 @@ document shortcutsDisplayed = !shortcutsDisplayed; }); -document.getElementById("addSubtitle").addEventListener("click", function (e) { +document.getElementById("addSubtitle").addEventListener("click", function () { const pod = document.getElementById("podvideoplayer"); const podPlayer = pod.player; var playTime = podPlayer.currentTime(); var captionsEndTime = existingCaptionsEndTime(); - AddCaption( + addCaption( captionsEndTime, playTime > captionsEndTime ? playTime : parseInt(captionsEndTime) + 2, "", @@ -251,24 +272,31 @@ let oldModeSelected = false; document .getElementById("switchOldEditMode") - .addEventListener("click", function (e) { - oldModeSelected = !oldModeSelected; - - if (oldModeSelected) { - document.getElementById("captionContent").value = GenerateWEBVTT(); - document.getElementById("rawCaptionsEditor").style.display = "block"; - document.getElementById("newCaptionsEditor").style.display = "none"; + .addEventListener("click", function () { + if (!oldModeSelected) { + let vtt = generateWEBVTT(); + if(vtt) { + document.getElementById("captionContent").value = vtt; + document.getElementById("rawCaptionsEditor").style.display = "block"; + document.getElementById("newCaptionsEditor").style.display = "none"; + oldModeSelected = !oldModeSelected; + } } else { + oldModeSelected = !oldModeSelected; document.getElementById("rawCaptionsEditor").style.display = "none"; document.getElementById("newCaptionsEditor").style.display = "block"; } }); -// index into captionsArray of the caption being displayed. -1 if none. +// index into captionsArray of the caption being displayed. -1 if none. var captionBeingDisplayed = -1; -function DisplayExistingCaption(seconds) { - var ci = FindCaptionIndex(seconds); +/** + * Display existing caption + * @param {[type]} seconds [description] + */ +function displayExistingCaption(seconds) { + var ci = findCaptionIndex(seconds); captionBeingDisplayed = ci; if (ci != -1) { var theCaption = captionsArray[ci]; @@ -276,8 +304,8 @@ function DisplayExistingCaption(seconds) { divs[divs.length - 1].innerText = theCaption.caption; var message = gettext("Caption for segment from %s to %s:"); document.getElementById("captionTitle").textContent = interpolate(message, [ - FormatTime(theCaption.start), - FormatTime(theCaption.end), + formatTime(theCaption.start), + formatTime(theCaption.end), ]); document.getElementById("textCaptionEntry").value = theCaption.caption; @@ -289,12 +317,20 @@ function DisplayExistingCaption(seconds) { } } +/** + * Get last existing captions end time. + * @return {int} end time + */ function existingCaptionsEndTime() { return captionsArray.length > 0 ? captionsArray[captionsArray.length - 1].end : 0; } +/** + * Update captions array. + * @param {[type]} vtt [description] + */ let updateCaptionsArray = (vtt) => { let arr = vtt.split("\n\n"); captionsArray = []; @@ -306,19 +342,22 @@ let updateCaptionsArray = (vtt) => { let data = text.split("\n"); let times = data[0].split("-->"); let newCaption = { - start: ParseTime(times[0]), - end: ParseTime(times[1]), + start: parseTime(times[0]), + end: parseTime(times[1]), caption: data[1], }; captionsArray.push(newCaption); - CreateCaptionBlock(newCaption); + createCaptionBlock(newCaption); } }); }; +/** + * Video play event handler + */ function videoPlayEventHandler() { captionBeingDisplayed = -1; - // give Opera a beat before doing this + // give Opera a beat before doing this window.setTimeout(function () { let textCaption = document.getElementById("textCaptionEntry"); textCaption.value = ""; @@ -333,6 +372,9 @@ function videoPlayEventHandler() { }, 16); } +/** + * Video pause event handler + */ function videoPauseEventHandler() { document .querySelectorAll("#playButton, #justSaveCaption, #saveCaptionAndPlay") @@ -351,14 +393,14 @@ function videoPauseEventHandler() { var captionsEndTime = existingCaptionsEndTime(); var message = ""; if (playTime - 1 < captionsEndTime) { - var ci = FindCaptionIndex(playTime - 1); + var ci = findCaptionIndex(playTime - 1); if (ci != -1) { var theCaption = captionsArray[ci]; message = gettext("Edit caption for segment from %s to %s:"); document.getElementById("captionTitle").textContent = interpolate( message, - [FormatTime(theCaption.start), FormatTime(theCaption.end)], + [formatTime(theCaption.start), formatTime(theCaption.end)], ); textCaption.value = theCaption.caption; @@ -373,8 +415,8 @@ function videoPauseEventHandler() { } else { message = gettext("Enter caption for segment from %s to %s:"); document.getElementById("captionTitle").textContent = interpolate(message, [ - FormatTime(existingCaptionsEndTime()), - FormatTime(playTime), + formatTime(existingCaptionsEndTime()), + formatTime(playTime), ]); document.getElementById("textCaptionEntry").value = ""; @@ -384,6 +426,9 @@ function videoPauseEventHandler() { //$("#textCaptionEntry").focus().get(0).setSelectionRange(1000, 1000); // set focus and selection point to end } +/** + * Video time update event handler. + */ function videoTimeUpdateEventHandler() { const pod = document.getElementById("podvideoplayer"); const podPlayer = pod.player; @@ -396,12 +441,12 @@ function videoTimeUpdateEventHandler() { var captionsEndTime = existingCaptionsEndTime(); if (playTime < captionsEndTime) { - DisplayExistingCaption(playTime); + displayExistingCaption(playTime); } else { var message = gettext("Pause to enter caption for segment from %s to %s."); document.getElementById("captionTitle").textContent = interpolate(message, [ - FormatTime(captionsEndTime), - FormatTime(playTime), + formatTime(captionsEndTime), + formatTime(playTime), ]); let divs = document.querySelectorAll(".vjs-text-track-display div"); @@ -414,8 +459,10 @@ function videoTimeUpdateEventHandler() { } } -// this enables the demo after a successful video load -function EnableDemoAfterLoadVideo() { +/** + * Enables the demo after a successful video load + */ +function enableDemoAfterLoadVideo() { document .querySelectorAll(".grayNoVideo a, .grayNoVideo") .forEach(function (e) { @@ -443,8 +490,8 @@ const pod = document.getElementById("podvideoplayer"); pod.addEventListener("play", videoPlayEventHandler); pod.addEventListener("timeupdate", videoTimeUpdateEventHandler); pod.addEventListener("pause", videoPauseEventHandler); -pod.addEventListener("canplay", EnableDemoAfterLoadVideo); -pod.addEventListener("loadeddata", EnableDemoAfterLoadVideo); +pod.addEventListener("canplay", enableDemoAfterLoadVideo); +pod.addEventListener("loadeddata", enableDemoAfterLoadVideo); document.getElementById("playButton").addEventListener("click", function () { const pod = document.getElementById("podvideoplayer"); @@ -458,49 +505,90 @@ document.getElementById("pauseButton").addEventListener("click", function () { podPlayer.pause(); }); -function GenerateWEBVTT() { +/** + * Generate a WEBVTT file from all the captionTextInput. + * @return {string|false} The generated WEBVTT string + */ +function generateWEBVTT() { let vtt = ""; - document - .querySelectorAll("#newCaptionsEditor > .newEditorBlock") - .forEach((e) => { - let captionText = e.querySelector(".captionTextInput").value; - let startTime = e.querySelector(".startTimeBtn").text; - let endTime = e.querySelector(".endTimeBtn").text; - vtt += `\n\n${startTime} --> ${endTime}\n${captionText}`; - }); + let captionBlocks = document + .querySelectorAll("#newCaptionsEditor > .newEditorBlock"); + + // If form has invalid fields, do not continue. + if (!validateForms(captionBlocks)) { + return false; + } + captionBlocks.forEach((e) => { + /* We use FormData to get a formatted version of captionText + * including auto "\n" generated by cols='y' rows='x' wrap='hard' + */ + let captionText = new FormData(e).get("captionTextInput"); + let startTime = e.querySelector(".startTimeBtn").text; + let endTime = e.querySelector(".endTimeBtn").text; + + vtt += `\n\n${startTime} --> ${endTime}\n${captionText}`; + }); if (vtt.length > 0) vtt = "WEBVTT" + vtt; return vtt; } -function SaveCurrentCaption() { +/** + * Check validity of every form and fires an invalid event on invalid elements + * @return {bool} true if everything's fine + */ +function validateForms(forms) { + let validity = true; + forms.forEach((e) => { + e.classList.remove("was-validated"); + + // After Browser checks, we add some custom ones + let captionInput = e.querySelector(".captionTextInput"); + if (captionInput.value.length > 80) { + captionInput.setCustomValidity(gettext("A caption cannot has more than 80 characters.") + "[" + captionInput.value.length + "]"); + } else { + captionInput.setCustomValidity(""); + } + + if (!e.reportValidity()) { + e.classList.add("was-validated"); + validity = false; + } + }); + return validity; +} + +/** + * Save current caption. + */ +function saveCurrentCaption() { const pod = document.getElementById("podvideoplayer"); const podPlayer = pod.player; var playTime = podPlayer.currentTime(); var captionsEndTime = existingCaptionsEndTime(); let new_entry = document.getElementById("textCaptionEntry").value; if (playTime - 1 < captionsEndTime) { - var ci = FindCaptionIndex(playTime - 1); + var ci = findCaptionIndex(playTime - 1); if (ci != -1) { - UpdateCaption(ci, new_entry); + updateCaption(ci, new_entry); } } else { - AddCaption(captionsEndTime, playTime, new_entry); + addCaption(captionsEndTime, playTime, new_entry); } } document .getElementById("justSaveCaption") .addEventListener("click", function () { - SaveCurrentCaption(); + saveCurrentCaption(); }); document .getElementById("saveCaptionAndPlay") .addEventListener("click", function () { - SaveCurrentCaption(); + saveCurrentCaption(); const pod = document.getElementById("podvideoplayer"); const podPlayer = pod.player; @@ -518,12 +606,12 @@ document }); /** - * Updat caption html content + * Update caption html content. */ let updateCaptionHtmlContent = () => { let vtt = "WEBVTT\n\n"; captionsArray.forEach((cap, i) => { - vtt += `${FormatTime(cap.start)} --> ${FormatTime(cap.end)}\n${ + vtt += `${formatTime(cap.start)} --> ${formatTime(cap.end)}\n${ cap.caption }`; if (i !== captionsArray.length - 1) vtt += "\n\n"; @@ -531,22 +619,36 @@ let updateCaptionHtmlContent = () => { document.getElementById("captionContent").value = vtt; }; -function UpdateCaption(ci, captionText) { +/** + * Update caption. + * @param {[type]} ci caption index + * @param {[type]} captionText caption text + */ +function updateCaption(ci, captionText) { captionsArray[ci].caption = captionText; updateCaptionHtmlContent(); } let lastEditedBlock = null; -function CreateCaptionBlock(newCaption, spawnFunction) { +/** + * Create a caption block object. + * @param {Object} newCaption Simple object representing the caption block + * @param {Function} spawnFunction Function to call after block init + */ +function createCaptionBlock(newCaption, spawnFunction) { let captionText = newCaption.caption; - let start = FormatTime(newCaption.start); - let end = FormatTime(newCaption.end); - - let block = { + let start = formatTime(newCaption.start); + let end = formatTime(newCaption.end); + + /** + * Caption Block Object + * @type {Object} + */ + let Block = { // parent div: new DOMParser().parseFromString( - `
`, + `
`, "text/html", ).body.firstChild, @@ -557,15 +659,19 @@ function CreateCaptionBlock(newCaption, spawnFunction) { ).body.firstChild, insertBtn: new DOMParser().parseFromString( - ``, + )}">`, "text/html", ).body.firstChild, deleteBtn: new DOMParser().parseFromString( - ``, + )}">`, "text/html", ).body.firstChild, // textarea @@ -573,13 +679,13 @@ function CreateCaptionBlock(newCaption, spawnFunction) { "
", "text/html", ).body.firstChild, - //captionTextInput: $(``), + captionTextLabel: new DOMParser().parseFromString( - ``, + ``, "text/html", ).body.firstChild, captionTextInput: new DOMParser().parseFromString( - ``, + ``, "text/html", ).body.firstChild, // time editable @@ -592,7 +698,7 @@ function CreateCaptionBlock(newCaption, spawnFunction) { "text/html", ).body.firstChild, startTimeInput: new DOMParser().parseFromString( - ``, + ``, "text/html", ).body.firstChild, endTimeLabel: new DOMParser().parseFromString( @@ -600,7 +706,7 @@ function CreateCaptionBlock(newCaption, spawnFunction) { "text/html", ).body.firstChild, endTimeInput: new DOMParser().parseFromString( - ``, + ``, "text/html", ).body.firstChild, @@ -623,6 +729,9 @@ function CreateCaptionBlock(newCaption, spawnFunction) { isEditEnabled: false, // methods + /** + * Enable Block edition mode + */ enableEdit: function () { if (!this.isEditEnabled) { if (lastEditedBlock) { @@ -630,9 +739,7 @@ function CreateCaptionBlock(newCaption, spawnFunction) { } this.startTimeInput.value = this.startTimeBtn.textContent; - this.endTimeInput.value = this.endTimeBtn.textContent; - this.timeBlockEditable.style.display = ""; this.timeBlock.style.display = "none"; this.div.classList.add("captionBeingEdited"); @@ -640,19 +747,23 @@ function CreateCaptionBlock(newCaption, spawnFunction) { lastEditedBlock = this; this.isEditEnabled = true; + seekVideoTo(newCaption.start); } }, + /** + * Disable Block edition mode + */ disableEdit: function () { if (this.isEditEnabled) { - let newStartTime = ParseTime(this.startTimeInput.value); - let newEndTime = ParseTime(this.endTimeInput.value); + let newStartTime = parseTime(this.startTimeInput.value); + let newEndTime = parseTime(this.endTimeInput.value); newCaption.start = newStartTime; newCaption.end = newEndTime; - this.startTimeBtn.textContent = FormatTime(newStartTime); - this.endTimeBtn.textContent = FormatTime(newEndTime); + this.startTimeBtn.textContent = formatTime(newStartTime); + this.endTimeBtn.textContent = formatTime(newEndTime); this.timeBlockEditable.style.display = "none"; this.timeBlock.style.display = ""; @@ -663,6 +774,9 @@ function CreateCaptionBlock(newCaption, spawnFunction) { } }, + /** + * Place Block In Order + */ placeInOrder: function () { for (let i in captionsArray) { let cap = captionsArray[i]; @@ -696,10 +810,19 @@ function CreateCaptionBlock(newCaption, spawnFunction) { } }, - spawnNew: function () { + /** + * Spawn New Block + * @param {Event} e Triggered Event + */ + spawnNew: function (e) { + e.preventDefault(); const pod = document.getElementById("podvideoplayer"); const podPlayer = pod.player; let playTime = podPlayer.currentTime(); + /** + * Caption object + * @type {Object} + */ let captionObj = { start: newCaption.end, end: @@ -709,18 +832,26 @@ function CreateCaptionBlock(newCaption, spawnFunction) { let index = Array.from(this.div.parentNode.children).indexOf(this.div); captionsArray.splice(index + 1, 0, captionObj); - CreateCaptionBlock(captionObj, (newDiv) => + createCaptionBlock(captionObj, (newDiv) => this.div.parentNode.insertBefore(newDiv, this.div.nextSibling), ); }, - delete: function () { + /** + * Delete Block + * @param {Event} e Triggered Event + */ + delete: function (e) { + e.preventDefault(); let index = Array.from(this.div.parentNode.children).indexOf(this.div); captionsArray.splice(index, 1); this.div.remove(); }, + /** + * Init Block + */ init: function () { var uniq = "c" + Math.floor(Math.random() * 100000000); this.div.captionBlockObject = this; @@ -730,8 +861,8 @@ function CreateCaptionBlock(newCaption, spawnFunction) { this.captionTextInput.setAttribute("id", uniq); this.captionTextLabel.setAttribute("for", uniq); - this.insertBtn.addEventListener("click", () => this.spawnNew()); - this.deleteBtn.addEventListener("click", () => this.delete()); + this.insertBtn.addEventListener("click", (e) => this.spawnNew(e)); + this.deleteBtn.addEventListener("click", (e) => this.delete(e)); this.startTimeBtn.addEventListener("click", () => seekVideoTo(newCaption.start), ); @@ -784,21 +915,21 @@ function CreateCaptionBlock(newCaption, spawnFunction) { }, }; - block.init(); - newCaption.blockObject = block; + Block.init(); + newCaption.blockObject = Block; if (spawnFunction) { - spawnFunction(block.div); + spawnFunction(Block.div); } else { let addSubtitle = document.getElementById("addSubtitle"); - addSubtitle.parentNode.insertBefore(block.div, addSubtitle); + addSubtitle.parentNode.insertBefore(Block.div, addSubtitle); } - block.captionTextInput.addEventListener("input propertychange", function () { - captionsArray[block.div.index()].caption = this.value; + Block.captionTextInput.addEventListener("input propertychange", function () { + captionsArray[Block.div.index()].caption = this.value; }); - block.div.addEventListener( + Block.div.addEventListener( "hover", function () { highlightVideoRegion(newCaption.start, newCaption.end); @@ -809,17 +940,21 @@ function CreateCaptionBlock(newCaption, spawnFunction) { ); document.getElementById("noCaptionsText")?.remove(); - return block; + return Block; } +/** + * Assign some keyboard shortcuts to editor functions + * @type {Object} + */ let editorShortcuts = { Delete: function (e) { if (e.altKey && lastEditedBlock) { - lastEditedBlock.delete(); + lastEditedBlock.delete(e); return false; } }, - PageUp: function (e) { + PageUp: function () { if (lastEditedBlock) { let prev = lastEditedBlock.div.previousElementSibling; if (prev) { @@ -829,7 +964,7 @@ let editorShortcuts = { } } }, - PageDown: function (e) { + PageDown: function () { if (lastEditedBlock) { let next = lastEditedBlock.div.nextElementSibling; if (next) { @@ -839,19 +974,19 @@ let editorShortcuts = { } } }, - ArrowLeft: function (e) { + ArrowLeft: function () { if (this.notFocused()) { seekVideo(-10); return false; } }, - ArrowRight: function (e) { + ArrowRight: function () { if (this.notFocused()) { seekVideo(10); return false; } }, - " ": function (e) { + " ": function () { // space if (this.notFocused()) { const pod = document.getElementById("podvideoplayer"); @@ -863,7 +998,7 @@ let editorShortcuts = { return false; } }, - m: function (e) { + m: function () { if (this.notFocused()) { let player = podPlayer; @@ -873,13 +1008,13 @@ let editorShortcuts = { return false; } }, - "?": function (e) { + "?": function () { if (this.notFocused()) { document.getElementById("showShortcutTips").click(); return false; } }, - Insert: function (e) { + Insert: function () { if (lastEditedBlock) { lastEditedBlock.spawnNew(); } else { @@ -894,11 +1029,15 @@ let editorShortcuts = { return false; } }, - End: function (e) { + End: function () { document.getElementById("saveCaptionAndPlay").click(); return false; }, + /** + * Check if there is no element on document that is focused + * @return {bool} true if not focused + */ notFocused: function () { var focused = document.activeElement; return focused.length == 0; @@ -916,15 +1055,20 @@ let editorShortcuts = { editorShortcuts.init(); -function AddCaptionListRow(ci, newCaption) { +/** + * Add caption list row + * @param {[type]} ci [description] + * @param {[type]} newCaption [description] + */ +function addCaptionListRow(ci, newCaption) { let vtt = document.getElementById("captionContent"); let vtt_entry = document.getElementById("textCaptionEntry").value.trim(); - let start = caption_memories.start_time; + let start = captionMemories.start_time; const pod = document.getElementById("podvideoplayer"); const podPlayer = pod.player; - var end = FormatTime(podPlayer.currentTime()); - var captionsEndTime = existingCaptionsEndTime(); + var end = formatTime(podPlayer.currentTime()); + // var captionsEndTime = existingCaptionsEndTime(); let caption_text = `${start} --> ${end}\n${vtt_entry}`; if (vtt_entry !== "") { if (vtt.value.trim() === "") { @@ -934,11 +1078,17 @@ function AddCaptionListRow(ci, newCaption) { } } - CreateCaptionBlock(newCaption); - caption_memories.start_time = end; + createCaptionBlock(newCaption); + captionMemories.start_time = end; } -function AddCaption(captionStart, captionEnd, captionText) { +/** + * Add caption + * @param {[type]} captionStart [description] + * @param {[type]} captionEnd [description] + * @param {[type]} captionText [description] + */ +function addCaption(captionStart, captionEnd, captionText) { const pod = document.getElementById("podvideoplayer"); const podPlayer = pod.player; let videoDuration = podPlayer.duration(); @@ -952,9 +1102,14 @@ function AddCaption(captionStart, captionEnd, captionText) { }; captionsArray.push(newCaption); - AddCaptionListRow(captionsArray.length - 1, newCaption); + addCaptionListRow(captionsArray.length - 1, newCaption); } +/** + * Convert HMS time format to seconds only + * @param {string} str hms + * @return {number} corresponding seconds + */ function hmsToSecondsOnly(str) { let p = str.split(":"), s = 0, @@ -966,8 +1121,11 @@ function hmsToSecondsOnly(str) { return s; } -// parses webvtt time string format into floating point seconds -function ParseTime(sTime) { +/** + * Parses webvtt time string format into floating point seconds + * @param {[type]} sTime [description] + */ +function parseTime(sTime) { let seconds = hmsToSecondsOnly(sTime); return parseFloat(seconds + "." + (sTime.split(".")[1] || 0)); /*// parse time formatted as hours:mm:ss.sss where hours are optional @@ -985,8 +1143,11 @@ function ParseTime(sTime) { return 0;*/ } -// formats floating point seconds into the webvtt time string format -function FormatTime(seconds) { +/** + * formats floating point seconds into the webvtt time string format + * @param {[type]} seconds [description] + */ +function formatTime(seconds) { var hh = Math.floor(seconds / (60 * 60)); var mm = Math.floor(seconds / 60) % 60; var ss = seconds % 60; @@ -1000,7 +1161,11 @@ function FormatTime(seconds) { ); } -function FindCaptionIndex(seconds) { +/** + * Find caption index + * @param {[type]} seconds [description] + */ +function findCaptionIndex(seconds) { var below = -1; var above = captionsArray.length; var i = Math.floor((below + above) / 2); @@ -1018,11 +1183,15 @@ function FindCaptionIndex(seconds) { return -1; } +/** + * Play selected caption + * @param {[type]} timeline [description] + */ function playSelectedCaption(timeline) { if (timeline.includes("-->")) { - let times = timeline.trim().split(/\s?\-\->\s?/); - let start = times[0].match(/[\d:\.]/) ? ParseTime(times[0]) : null; - let end = times[1].match(/[\d:\.]/) ? ParseTime(times[1]) : null; + let times = timeline.trim().split(/\s?-->\s?/); + let start = times[0].match(/[\d:.]/) ? parseTime(times[0]) : null; + let end = times[1].match(/[\d:.]/) ? parseTime(times[1]) : null; if (!isNaN(start) && !isNaN(end)) { const pod = document.getElementById("podvideoplayer"); const podPlayer = pod.player; @@ -1036,10 +1205,11 @@ function playSelectedCaption(timeline) { /** * Escape Html entities + * @param {string} s String to be escaped */ function XMLEncode(s) { return s - .replace(/\&/g, "&") + .replace(/&/g, "&") .replace(/“/g, """) .replace(/”/g, """) .replace(/"/g, """) @@ -1047,6 +1217,10 @@ function XMLEncode(s) { .replace(/>/g, ">"); } +/** + * Decode Html entities + * @param {String} s String to be decoded + */ function XMLDecode(s) { return s .replace(/</g, "<") @@ -1056,12 +1230,17 @@ function XMLDecode(s) { .replace(/&/g, "&"); } -function LoadCaptionFile(fileObject) { +/** + * Load caption file + * @param {[type]} fileObject [description] + */ +/* +function loadCaptionFile(fileObject) { if (window.FileReader) { var reader = new window.FileReader(); reader.addEventListener("load", function () { - ProcessProxyVttResponse({ status: "success", response: reader.result }); + processProxyVttResponse({ status: "success", response: reader.result }); }); reader.addEventListener("onerror", function (evt) { @@ -1078,18 +1257,21 @@ function LoadCaptionFile(fileObject) { } else { alert(gettext("Your browser does not support FileReader.")); } -} +}*/ -// invoked by script insertion of proxyvtt.ashx -function ProcessProxyVttResponse(obj) { +/** + * Invoked by script insertion of proxyvtt.ashx + * @param {[type]} obj [description] + */ +function processProxyVttResponse(obj) { obj = JSON.parse(obj); if (obj.status == "error") alert(gettext("Error loading caption file: ") + obj.message); else if (obj.status == "success") { // delete any captions we've got captionsArray.length = 0; - file_loaded = true; - file_loaded_id = obj.id_file; + fileLoaded = true; + fileLoadedId = obj.id_file; current_folder = obj.id_folder; document.querySelectorAll(".newEditorBlock").forEach((elt) => { elt.remove(); @@ -1102,18 +1284,18 @@ function ProcessProxyVttResponse(obj) { ); if (obj.response.match(/^WEBVTT/)) { - ParseAndLoadWebVTT(obj.response); + parseAndLoadWebVTT(obj.response); } else { alert(gettext("Unrecognized caption file format.")); } } } -//----------------------------------------------------------------------------------------------------------------------------------------- -// Partial parser for WebVTT files based on the spec at http://dev.w3.org/html5/webvtt/ -//----------------------------------------------------------------------------------------------------------------------------------------- - -function ParseAndLoadWebVTT(vtt) { +/** + * Partial parser for WebVTT files based on the spec at http://dev.w3.org/html5/webvtt/ + * @param {[type]} vtt [description] + */ +function parseAndLoadWebVTT(vtt) { var vttLines = vtt.split(/\r\n|\r|\n/); // create an array of lines from our file if (vttLines[0].trim().toLowerCase() != "webvtt") { @@ -1126,7 +1308,7 @@ function ParseAndLoadWebVTT(vtt) { elt.remove(); }); - var rxTimeLine = /^([\d\.:]+)\s+-->\s+([\d\.:]+)(?:\s.*)?$/; + var rxTimeLine = /^([\d.:]+)\s+-->\s+([\d.:]+)(?:\s.*)?$/; var rxCaptionLine = /^(?:]+)>)?([^\r\n]+)$/; var rxBlankLine = /^\s*$/; var rxMarkup = /<[^>]>/g; @@ -1135,6 +1317,9 @@ function ParseAndLoadWebVTT(vtt) { cueEnd = null, cueText = null; + /** + * Append current caption + */ function appendCurrentCaption() { if (cueStart && cueEnd && cueText) { let newCaption = { @@ -1143,7 +1328,7 @@ function ParseAndLoadWebVTT(vtt) { caption: cueText.trim(), }; captionsArray.push(newCaption); - CreateCaptionBlock(newCaption); + createCaptionBlock(newCaption); } cueStart = cueEnd = cueText = null; } @@ -1155,22 +1340,22 @@ function ParseAndLoadWebVTT(vtt) { } if (!cueStart && !cueEnd && !cueText && vttLines[i].indexOf("-->") == -1) { - // this is a cue identifier we're ignoring + // this is a cue identifier we're ignoring continue; } var timeMatch = rxTimeLine.exec(vttLines[i]); if (timeMatch) { appendCurrentCaption(); - cueStart = ParseTime(timeMatch[1]); + cueStart = parseTime(timeMatch[1]); if (cueStart == 0) cueStart = "0.0"; - cueEnd = ParseTime(timeMatch[2]); + cueEnd = parseTime(timeMatch[2]); continue; } var captionMatch = rxCaptionLine.exec(vttLines[i]); if (captionMatch && cueStart && cueEnd) { - // captionMatch[1] is the optional voice (speaker) we're ignoring + // captionMatch[1] is the optional voice (speaker) we're ignoring var capLine = captionMatch[2].replace(rxMarkup, ""); if (cueText) cueText += " " + capLine; else { @@ -1189,11 +1374,19 @@ var clearVideoRegion; const registerPlugin = videojs.registerPlugin || videojs.plugin; +/** + * On player ready Event + * @param {[type]} player [description] + * @param {[type]} options [description] + */ const onPlayerReady = function (player, options) { let startKeyframe; let endKeyframe; let regionHighlight; + /** + * Clear video region + */ const clearVideoRegion = () => { startKeyframe?.remove(); @@ -1204,6 +1397,11 @@ const onPlayerReady = function (player, options) { player.userActive(false); }; + /** + * Highlight video region + * @param {[type]} startTime [description] + * @param {[type]} endTime [description] + */ highlightVideoRegion = function (startTime, endTime) { clearVideoRegion(); player.userActive(true); @@ -1223,8 +1421,8 @@ const onPlayerReady = function (player, options) { element.parentNode.insertBefore(startKeyframe, element); regionHighlight = "
"; - regionHighlight.style = "left: " + `${startPercent}%`; - regionHighlight.style = "width:" + `${endPercent - startPercent}%`; + regionHighlight.style.left = `${startPercent}%`; + regionHighlight.style.width = `${endPercent - startPercent}%`; startKeyframe.after(regionHighlight); @@ -1235,22 +1433,34 @@ const onPlayerReady = function (player, options) { regionHighlight.after(endKeyframe); }; + /** + * Seek video player to absolute `time`. + * @param {[type]} time [description] + */ seekVideoTo = function (time) { player.userActive(true); player.currentTime(time); }; - seekVideo = function (time) { + /** + * Seek video player to relative `time`. + * @param {[type]} time [description] + */ + seekVideo = function (time) { player.userActive(true); player.currentTime(player.currentTime() + time); }; }; -const timelineRegions = function (options) { +/** + * Timeline regions + * @param {[type]} options [description] + */ +function timelineRegions(options) { this.ready(function () { onPlayerReady(this, options); }); -}; +} registerPlugin("timelineRegions", timelineRegions); diff --git a/pod/completion/templates/video_caption_maker.html b/pod/completion/templates/video_caption_maker.html index c86f707410..0b44717dc3 100644 --- a/pod/completion/templates/video_caption_maker.html +++ b/pod/completion/templates/video_caption_maker.html @@ -84,7 +84,7 @@
- +
-

{% trans "No captions" %}

-
@@ -218,11 +218,6 @@
+ {% include "notification_toast.html" %} - + {% endblock content %} {% if not request.GET.is_iframe %}