Compare commits

..

41 Commits

Author SHA1 Message Date
Markos Gogoulos
b3f7669f53 a 2026-03-15 17:59:04 +02:00
Markos Gogoulos
a09c5904e1 a 2026-03-15 17:52:47 +02:00
Markos Gogoulos
875f5f90d1 v 2026-03-15 17:51:34 +02:00
Markos Gogoulos
133c80ed7b a 2026-03-15 17:48:34 +02:00
Markos Gogoulos
3c8b83480f a 2026-03-15 17:40:45 +02:00
Markos Gogoulos
a79acb5ab0 all 2026-03-15 17:09:51 +02:00
Markos Gogoulos
c1ce525f24 all 2026-03-15 17:08:57 +02:00
Markos Gogoulos
10cc4eb069 1 2026-03-14 16:29:54 +02:00
Markos Gogoulos
715e6dec72 a 2026-03-14 16:00:35 +02:00
Markos Gogoulos
b157ecf5d3 al 2026-03-14 16:00:26 +02:00
Markos Gogoulos
e33144b8d0 all 2026-03-13 20:16:17 +02:00
Markos Gogoulos
6279f8bd60 w 2026-03-13 19:27:23 +02:00
Markos Gogoulos
0e0ab6e22c all 2026-03-13 19:27:16 +02:00
Markos Gogoulos
a40a0037bd a 2026-03-13 18:54:51 +02:00
Markos Gogoulos
04693f11c8 a 2026-03-13 18:44:21 +02:00
Markos Gogoulos
fb71e1ead4 all 2026-03-13 18:44:07 +02:00
Markos Gogoulos
cb9b4df3f6 wtv 2026-03-13 15:08:14 +02:00
Markos Gogoulos
22c9c391f5 foo 2026-03-13 15:08:01 +02:00
Markos Gogoulos
f3bc24a7a2 foo 2026-03-13 15:01:54 +02:00
Markos Gogoulos
d27c245f58 a 2026-03-13 14:45:57 +02:00
Markos Gogoulos
633e666cea all 2026-03-13 14:45:04 +02:00
Markos Gogoulos
0954b3ff0d a 2026-03-13 14:14:04 +02:00
Markos Gogoulos
8d0f4827ed f 2026-03-13 10:09:29 +02:00
Markos Gogoulos
e1e04ea93a new 2026-03-13 09:51:43 +02:00
Markos Gogoulos
0c8a464845 d 2026-03-09 20:27:32 +02:00
Markos Gogoulos
e0974433a4 a 2026-03-09 20:09:20 +02:00
Markos Gogoulos
e130c7403c py 2026-03-09 19:58:14 +02:00
Markos Gogoulos
182fb9599a st 2026-03-09 19:57:46 +02:00
Markos Gogoulos
eadaffb27c a 2026-03-06 18:30:34 +02:00
Markos Gogoulos
27bba37a55 wtv 2026-03-06 17:56:56 +02:00
Markos Gogoulos
90b480b4f8 nces 2026-03-06 17:56:27 +02:00
Markos Gogoulos
583a8c4512 chec 2026-03-06 17:19:05 +02:00
Markos Gogoulos
b806ffd7f5 a 2026-03-06 17:01:15 +02:00
Markos Gogoulos
a6f7ce71c6 a 2026-03-06 16:56:29 +02:00
Markos Gogoulos
ab5f86ee4d e 2026-03-06 16:30:29 +02:00
Markos Gogoulos
216365fdb6 a 2026-03-06 16:29:51 +02:00
Markos Gogoulos
66b19b99f2 all 2026-03-04 13:27:42 +02:00
Markos Gogoulos
692b6b5f09 fix 2026-03-04 13:09:19 +02:00
Markos Gogoulos
814a7d3cee all 2026-03-04 09:12:45 +02:00
Markos Gogoulos
31571fc4cb stf 2026-03-04 09:02:01 +02:00
Markos Gogoulos
edd40d45b4 all 2026-03-03 23:07:09 +02:00
108 changed files with 2208 additions and 1748 deletions

1
LTI_README.md Normal file
View File

@@ -0,0 +1 @@
Django admin → /admin/lti/ltiplatform/ --> Change to: https://YOUR_MOODLE/filter/mediacms/lti_auth.php

View File

@@ -1 +1 @@
VERSION = "7.ki"
VERSION = "8.93"

View File

@@ -73,3 +73,8 @@ Can be set through the SAML Configurations tab:
3. **Group Role Mapping**: Maps the role returned by SAML (as set in the SAML Configuration tab) with the role in groups that user will be added
4. **Group mapping**: This creates groups associated with this IDP. Group ids as they come from SAML, associated with MediaCMS groups
5. **Category Mapping**: This maps a group id (from SAML response) with a category in MediaCMS
## More options
USER_SEARCH_FIELD = "name_username_email"
ALLOW_MEDIA_REPLACEMENT = True

View File

@@ -5,7 +5,7 @@ from django import forms
from django.conf import settings
from .methods import get_next_state, is_mediacms_editor
from .models import MEDIA_STATES, Category, Media, Subtitle
from .models import MEDIA_STATES, Category, Media, Subtitle, Tag
from .widgets import CategoryModalWidget
@@ -123,6 +123,7 @@ class MediaPublishForm(forms.ModelForm):
widgets = {
"category": CategoryModalWidget(),
"state": forms.RadioSelect(),
}
def __init__(self, user, *args, **kwargs):
@@ -293,6 +294,10 @@ class MediaPublishForm(forms.ModelForm):
media = super(MediaPublishForm, self).save(*args, **kwargs)
for course in media.category.filter(is_lms_course=True):
tag, _ = Tag.objects.get_or_create(title=course.title[:100])
media.tags.add(tag)
return media

View File

@@ -57,4 +57,4 @@ def translate_string(language_code, string):
if not check_language_code(language_code):
return string
return translation_strings[language_code].get(string, string)
return translation_strings[language_code].get(string) or string

View File

@@ -48,6 +48,7 @@ translation_strings = {
"DELETE MEDIA": "حذف الوسائط",
"DOWNLOAD": "تحميل",
"DURATION": "المدة",
"Delete Comments": "",
"Delete Media": "حذف الوسائط",
"Delete media": "حذف الوسائط",
"Disable Comments": "تعطيل التعليقات",
@@ -70,6 +71,7 @@ translation_strings = {
"Failed to change owner. Please try again.": "فشل تغيير المالك. يرجى المحاولة مرة أخرى.",
"Failed to copy media.": "فشل نسخ الوسائط.",
"Failed to create playlist": "فشل إنشاء قائمة التشغيل",
"Failed to delete comments.": "",
"Failed to delete media. Please try again.": "فشل حذف الوسائط. يرجى المحاولة مرة أخرى.",
"Failed to disable comments.": "فشل تعطيل التعليقات.",
"Failed to disable download.": "فشل تعطيل التنزيل.",
@@ -101,6 +103,9 @@ translation_strings = {
"Filter existing users...": "تصفية المستخدمين الموجودين...",
"Filter playlists...": "تصفية قوائم التشغيل...",
"Filters": "الفلاتر",
"Give users editor permissions to your media by adding them to the below list.": "",
"Give users owner permissions to your media, except for deleting the media, by adding them to the below list.": "",
"Give users viewer permissions to your media by adding them to the below list.": "",
"Go": "اذهب",
"History": "التاريخ",
"Home": "الرئيسية",
@@ -121,6 +126,7 @@ translation_strings = {
"Manage comments": "إدارة التعليقات",
"Manage media": "إدارة الوسائط",
"Manage users": "إدارة المستخدمين",
"Management": "",
"Media": "وسائط",
"Media I own": "الوسائط التي أمتلكها",
"Media was edited": "تم تعديل الوسائط",
@@ -137,6 +143,7 @@ translation_strings = {
"No results for": "لا توجد نتائج لـ",
"No tags": "لا توجد علامات",
"No users to add": "لا يوجد مستخدمون لإضافتهم",
"Organization": "",
"PLAYLISTS": "قوائم التشغيل",
"PUBLISH STATE": "حالة النشر",
"Pdf": "PDF",
@@ -156,12 +163,17 @@ translation_strings = {
"Published on": "نشر في",
"Recent uploads": "التحميلات الأخيرة",
"Recommended": "موصى به",
"Record": "",
"Record Screen": "تسجيل الشاشة",
"Record Screen with Audio": "",
"Register": "تسجيل",
"Remove category": "إزالة الفئة",
"Remove from list": "إزالة من القائمة",
"Remove tag": "إزالة العلامة",
"Remove user": "إزالة المستخدم",
"Remove users from the list to remove editor permissions": "",
"Remove users from the list to remove owner permissions": "",
"Remove users from the list to remove viewer permissions": "",
"Replace": "",
"SAVE": "حفظ",
"SEARCH": "بحث",
@@ -178,14 +190,22 @@ translation_strings = {
"Select all media": "تحديد جميع الوسائط",
"Select publish state:": "اختر حالة النشر:",
"Selected": "محدد",
"Settings": "",
"Share with": "",
"Share with Co-Editors": "",
"Share with Co-Owners": "",
"Share with Co-Viewers": "",
"Share with Course Members": "",
"Shared by me": "مشاركة مني",
"Shared with me": "مشاركة معي",
"Sharing": "",
"Sign in": "تسجيل الدخول",
"Sign out": "تسجيل الخروج",
"Sort By": "ترتيب حسب",
"Start Recording": "بدء التسجيل",
"Start uploading media and sharing your work. Media that you upload will show up here.": "ابدأ في تحميل الوسائط ومشاركة عملك. ستظهر الوسائط التي تحملها هنا.",
"Stop Recording": "إيقاف التسجيل",
"Students will get viewer permissions, while lecturers will get co-owner permissions (same as owner, but cannot delete the media)": "",
"Submit": "إرسال",
"Subtitle was added": "تمت إضافة الترجمة",
"Subtitles": "ترجمات",
@@ -196,6 +216,7 @@ translation_strings = {
"Successfully Enabled comments": "تم تفعيل التعليقات بنجاح",
"Successfully changed owner": "تم تغيير المالك بنجاح",
"Successfully deleted": "تم الحذف بنجاح",
"Successfully deleted comments": "",
"Successfully updated": "تم التحديث بنجاح",
"Successfully updated categories": "تم تحديث الفئات بنجاح",
"Successfully updated playlist membership": "تم تحديث عضوية قائمة التشغيل بنجاح",
@@ -232,6 +253,9 @@ translation_strings = {
"Upload media": "رفع الوسائط",
"Uploads": "التحميلات",
"Users": "المستخدمون",
"Users can edit your media via: My Media > Shared with Me > particular media > Edit...": "",
"Users can manage your media via: My Media > Shared with Me > particular media > ...": "",
"Users can view your media via: My Media > Shared with Me > particular media > ...": "",
"VIEW ALL": "عرض الكل",
"Video": "فيديو",
"View all": "عرض الكل",
@@ -240,6 +264,7 @@ translation_strings = {
"Welcome": "مرحباً",
"You are going to copy": "سوف تقوم بالنسخ",
"You are going to delete": "سوف تقوم بالحذف",
"You are going to delete all comments from": "",
"You are going to disable comments to": "سوف تقوم بتعطيل التعليقات لـ",
"You are going to disable download for": "سوف تقوم بتعطيل التنزيل لـ",
"You are going to enable comments to": "سوف تقوم بتفعيل التعليقات لـ",

View File

@@ -48,6 +48,7 @@ translation_strings = {
"DELETE MEDIA": "মিডিয়া মুছুন",
"DOWNLOAD": "ডাউনলোড",
"DURATION": "সময়কাল",
"Delete Comments": "",
"Delete Media": "",
"Delete media": "মিডিয়া মুছুন",
"Disable Comments": "",
@@ -70,6 +71,7 @@ translation_strings = {
"Failed to change owner. Please try again.": "",
"Failed to copy media.": "মিডিয়া কপি করতে ব্যর্থ হয়েছে।",
"Failed to create playlist": "",
"Failed to delete comments.": "",
"Failed to delete media. Please try again.": "মিডিয়া মুছতে ব্যর্থ হয়েছে। দয়া করে আবার চেষ্টা করুন।",
"Failed to disable comments.": "মন্তব্য নিষ্ক্রিয় করতে ব্যর্থ হয়েছে।",
"Failed to disable download.": "ডাউনলোড নিষ্ক্রিয় করতে ব্যর্থ হয়েছে।",
@@ -101,6 +103,9 @@ translation_strings = {
"Filter existing users...": "",
"Filter playlists...": "",
"Filters": "ফিল্টার",
"Give users editor permissions to your media by adding them to the below list.": "",
"Give users owner permissions to your media, except for deleting the media, by adding them to the below list.": "",
"Give users viewer permissions to your media by adding them to the below list.": "",
"Go": "যাও",
"History": "ইতিহাস",
"Home": "বাড়ি",
@@ -121,6 +126,7 @@ translation_strings = {
"Manage comments": "মন্তব্য পরিচালনা করুন",
"Manage media": "মিডিয়া পরিচালনা করুন",
"Manage users": "ব্যবহারকারীদের পরিচালনা করুন",
"Management": "",
"Media": "মিডিয়া",
"Media I own": "",
"Media was edited": "মিডিয়া সম্পাদিত হয়েছে",
@@ -137,6 +143,7 @@ translation_strings = {
"No results for": "এর জন্য কোন ফলাফল নেই",
"No tags": "",
"No users to add": "",
"Organization": "",
"PLAYLISTS": "প্লেলিস্ট",
"PUBLISH STATE": "প্রকাশের অবস্থা",
"Pdf": "PDF",
@@ -156,12 +163,17 @@ translation_strings = {
"Published on": "প্রকাশিত",
"Recent uploads": "সাম্প্রতিক আপলোড",
"Recommended": "প্রস্তাবিত",
"Record": "",
"Record Screen": "স্ক্রিন রেকর্ড করুন",
"Record Screen with Audio": "",
"Register": "নিবন্ধন করুন",
"Remove category": "",
"Remove from list": "",
"Remove tag": "",
"Remove user": "",
"Remove users from the list to remove editor permissions": "",
"Remove users from the list to remove owner permissions": "",
"Remove users from the list to remove viewer permissions": "",
"Replace": "",
"SAVE": "সংরক্ষণ করুন",
"SEARCH": "অনুসন্ধান",
@@ -178,14 +190,22 @@ translation_strings = {
"Select all media": "",
"Select publish state:": "",
"Selected": "",
"Settings": "",
"Share with": "",
"Share with Co-Editors": "",
"Share with Co-Owners": "",
"Share with Co-Viewers": "",
"Share with Course Members": "",
"Shared by me": "আমার দ্বারা শেয়ার করা",
"Shared with me": "আমার সাথে শেয়ার করা",
"Sharing": "",
"Sign in": "সাইন ইন করুন",
"Sign out": "সাইন আউট করুন",
"Sort By": "সাজান",
"Start Recording": "রেকর্ডিং শুরু করুন",
"Start uploading media and sharing your work. Media that you upload will show up here.": "মিডিয়া আপলোড করা এবং আপনার কাজ শেয়ার করা শুরু করুন। আপনি যে মিডিয়া আপলোড করবেন তা এখানে প্রদর্শিত হবে।",
"Stop Recording": "রেকর্ডিং বন্ধ করুন",
"Students will get viewer permissions, while lecturers will get co-owner permissions (same as owner, but cannot delete the media)": "",
"Submit": "",
"Subtitle was added": "সাবটাইটেল যোগ করা হয়েছে",
"Subtitles": "সাবটাইটেল",
@@ -196,6 +216,7 @@ translation_strings = {
"Successfully Enabled comments": "মন্তব্য সফলভাবে সক্রিয় হয়েছে",
"Successfully changed owner": "",
"Successfully deleted": "সফলভাবে মুছে ফেলা হয়েছে",
"Successfully deleted comments": "",
"Successfully updated": "",
"Successfully updated categories": "",
"Successfully updated playlist membership": "",
@@ -232,6 +253,9 @@ translation_strings = {
"Upload media": "মিডিয়া আপলোড করুন",
"Uploads": "আপলোডসমূহ",
"Users": "",
"Users can edit your media via: My Media > Shared with Me > particular media > Edit...": "",
"Users can manage your media via: My Media > Shared with Me > particular media > ...": "",
"Users can view your media via: My Media > Shared with Me > particular media > ...": "",
"VIEW ALL": "সব দেখুন",
"Video": "ভিডিও",
"View all": "সব দেখুন",
@@ -240,6 +264,7 @@ translation_strings = {
"Welcome": "স্বাগতম",
"You are going to copy": "আপনি কপি করতে চলেছেন",
"You are going to delete": "আপনি মুছে ফেলতে চলেছেন",
"You are going to delete all comments from": "",
"You are going to disable comments to": "আপনি মন্তব্য নিষ্ক্রিয় করতে চলেছেন",
"You are going to disable download for": "আপনি ডাউনলোড নিষ্ক্রিয় করতে চলেছেন",
"You are going to enable comments to": "আপনি মন্তব্য সক্রিয় করতে চলেছেন",

View File

@@ -48,6 +48,7 @@ translation_strings = {
"DELETE MEDIA": "SLET MEDIE",
"DOWNLOAD": "HENT",
"DURATION": "VARIGHED",
"Delete Comments": "",
"Delete Media": "Slet Medie",
"Delete media": "Slet medie",
"Disable Comments": "Deaktiver Kommentarer",
@@ -70,6 +71,7 @@ translation_strings = {
"Failed to change owner. Please try again.": "Ændring af ejer mislykkedes. Prøv venligst igen.",
"Failed to copy media.": "Kopiering af medie mislykkedes.",
"Failed to create playlist": "Oprettelse af playliste mislykkedes",
"Failed to delete comments.": "",
"Failed to delete media. Please try again.": "Sletning af medie mislykkedes. Prøv venligst igen.",
"Failed to disable comments.": "Deaktivering af kommentarer mislykkedes.",
"Failed to disable download.": "Deaktivering af download mislykkedes.",
@@ -101,6 +103,9 @@ translation_strings = {
"Filter existing users...": "Filtrer eksisterende brugere...",
"Filter playlists...": "Filtrer playlister...",
"Filters": "Filtre",
"Give users editor permissions to your media by adding them to the below list.": "",
"Give users owner permissions to your media, except for deleting the media, by adding them to the below list.": "",
"Give users viewer permissions to your media by adding them to the below list.": "",
"Go": "Vælg",
"History": "Historik",
"Home": "Hjem",
@@ -121,6 +126,7 @@ translation_strings = {
"Manage comments": "Administrer kommentarer",
"Manage media": "Administrer medier",
"Manage users": "Administrer brugere",
"Management": "",
"Media": "Medier",
"Media I own": "Medier jeg ejer",
"Media was edited": "Mediet er blevet redigeret",
@@ -137,6 +143,7 @@ translation_strings = {
"No results for": "Ingen resultater for",
"No tags": "Ingen tags",
"No users to add": "Ingen brugere at tilføje",
"Organization": "",
"PLAYLISTS": "PLAYLISTER",
"PUBLISH STATE": "PUBLICERINGSSTATUS",
"Pdf": "PDF",
@@ -156,12 +163,17 @@ translation_strings = {
"Published on": "Udgivet på",
"Recent uploads": "Nylige uploads",
"Recommended": "Anbefalet",
"Record": "",
"Record Screen": "Optag skærm",
"Record Screen with Audio": "",
"Register": "Registrer",
"Remove category": "Fjern kategori",
"Remove from list": "Fjern fra liste",
"Remove tag": "Fjern tag",
"Remove user": "Fjern bruger",
"Remove users from the list to remove editor permissions": "",
"Remove users from the list to remove owner permissions": "",
"Remove users from the list to remove viewer permissions": "",
"Replace": "",
"SAVE": "GEM",
"SEARCH": "SØG",
@@ -178,14 +190,22 @@ translation_strings = {
"Select all media": "Vælg alle medier",
"Select publish state:": "Vælg publiceringsstatus:",
"Selected": "Valgt",
"Settings": "",
"Share with": "",
"Share with Co-Editors": "",
"Share with Co-Owners": "",
"Share with Co-Viewers": "",
"Share with Course Members": "",
"Shared by me": "Delt af mig",
"Shared with me": "Delt med mig",
"Sharing": "",
"Sign in": "Log ind",
"Sign out": "Log ud",
"Sort By": "Sorter efter",
"Start Recording": "Start optagelse",
"Start uploading media and sharing your work. Media that you upload will show up here.": "Begynd at uploade medier og dele dit arbejde. Medier, du uploader, vil blive vist her.",
"Stop Recording": "Stop optagelse",
"Students will get viewer permissions, while lecturers will get co-owner permissions (same as owner, but cannot delete the media)": "",
"Submit": "Indsend",
"Subtitle was added": "Undertekster tilføjet",
"Subtitles": "Undertekster",
@@ -196,6 +216,7 @@ translation_strings = {
"Successfully Enabled comments": "Kommentarer aktiveret med succes",
"Successfully changed owner": "Ejer ændret med succes",
"Successfully deleted": "Slettet med succes",
"Successfully deleted comments": "",
"Successfully updated": "Opdateret med succes",
"Successfully updated categories": "Kategorier opdateret med succes",
"Successfully updated playlist membership": "Playlistemedlemskab opdateret med succes",
@@ -232,6 +253,9 @@ translation_strings = {
"Upload media": "Upload medie",
"Uploads": "Uploads",
"Users": "Brugere",
"Users can edit your media via: My Media > Shared with Me > particular media > Edit...": "",
"Users can manage your media via: My Media > Shared with Me > particular media > ...": "",
"Users can view your media via: My Media > Shared with Me > particular media > ...": "",
"VIEW ALL": "SE ALLE",
"Video": "Video",
"View all": "Se alle",
@@ -240,6 +264,7 @@ translation_strings = {
"Welcome": "Velkommen",
"You are going to copy": "Du er ved at kopiere",
"You are going to delete": "Du er ved at slette",
"You are going to delete all comments from": "",
"You are going to disable comments to": "Du er ved at deaktivere kommentarer til",
"You are going to disable download for": "Du er ved at deaktivere download for",
"You are going to enable comments to": "Du er ved at aktivere kommentarer til",

View File

@@ -48,6 +48,7 @@ translation_strings = {
"DELETE MEDIA": "MEDIEN LÖSCHEN",
"DOWNLOAD": "HERUNTERLADEN",
"DURATION": "DAUER",
"Delete Comments": "",
"Delete Media": "Medien löschen",
"Delete media": "Medien löschen",
"Disable Comments": "Kommentare deaktivieren",
@@ -70,6 +71,7 @@ translation_strings = {
"Failed to change owner. Please try again.": "Fehler beim Ändern des Eigentümers. Bitte versuchen Sie es erneut.",
"Failed to copy media.": "Fehler beim Kopieren der Medien.",
"Failed to create playlist": "Fehler beim Erstellen der Playlist",
"Failed to delete comments.": "",
"Failed to delete media. Please try again.": "Fehler beim Löschen der Medien. Bitte versuchen Sie es erneut.",
"Failed to disable comments.": "Fehler beim Deaktivieren der Kommentare.",
"Failed to disable download.": "Fehler beim Deaktivieren des Downloads.",
@@ -101,6 +103,9 @@ translation_strings = {
"Filter existing users...": "Vorhandene Benutzer filtern...",
"Filter playlists...": "Playlists filtern...",
"Filters": "Filter",
"Give users editor permissions to your media by adding them to the below list.": "",
"Give users owner permissions to your media, except for deleting the media, by adding them to the below list.": "",
"Give users viewer permissions to your media by adding them to the below list.": "",
"Go": "Los",
"History": "Verlauf",
"Home": "Startseite",
@@ -121,6 +126,7 @@ translation_strings = {
"Manage comments": "Kommentare verwalten",
"Manage media": "Medien verwalten",
"Manage users": "Benutzer verwalten",
"Management": "",
"Media": "Medien",
"Media I own": "Medien, die mir gehören",
"Media was edited": "Medien wurden bearbeitet",
@@ -137,6 +143,7 @@ translation_strings = {
"No results for": "Keine Ergebnisse für",
"No tags": "Keine Tags",
"No users to add": "Keine Benutzer hinzuzufügen",
"Organization": "",
"PLAYLISTS": "PLAYLISTS",
"PUBLISH STATE": "VERÖFFENTLICHUNGSSTATUS",
"Pdf": "PDF",
@@ -156,12 +163,17 @@ translation_strings = {
"Published on": "Veröffentlicht am",
"Recent uploads": "Neue Uploads",
"Recommended": "Empfohlen",
"Record": "",
"Record Screen": "Bildschirm aufnehmen",
"Record Screen with Audio": "",
"Register": "Registrieren",
"Remove category": "Kategorie entfernen",
"Remove from list": "Aus Liste entfernen",
"Remove tag": "Tag entfernen",
"Remove user": "Benutzer entfernen",
"Remove users from the list to remove editor permissions": "",
"Remove users from the list to remove owner permissions": "",
"Remove users from the list to remove viewer permissions": "",
"Replace": "",
"SAVE": "SPEICHERN",
"SEARCH": "SUCHE",
@@ -178,14 +190,22 @@ translation_strings = {
"Select all media": "Alle Medien auswählen",
"Select publish state:": "Veröffentlichungsstatus auswählen:",
"Selected": "Ausgewählt",
"Settings": "",
"Share with": "",
"Share with Co-Editors": "",
"Share with Co-Owners": "",
"Share with Co-Viewers": "",
"Share with Course Members": "",
"Shared by me": "Von mir geteilt",
"Shared with me": "Mit mir geteilt",
"Sharing": "",
"Sign in": "Anmelden",
"Sign out": "Abmelden",
"Sort By": "Sortieren nach",
"Start Recording": "Aufnahme starten",
"Start uploading media and sharing your work. Media that you upload will show up here.": "Beginnen Sie mit dem Hochladen von Medien und dem Teilen Ihrer Arbeit. Hochgeladene Medien werden hier angezeigt.",
"Stop Recording": "Aufnahme stoppen",
"Students will get viewer permissions, while lecturers will get co-owner permissions (same as owner, but cannot delete the media)": "",
"Submit": "Absenden",
"Subtitle was added": "Untertitel wurde hinzugefügt",
"Subtitles": "Untertitel",
@@ -196,6 +216,7 @@ translation_strings = {
"Successfully Enabled comments": "Kommentare erfolgreich aktiviert",
"Successfully changed owner": "Eigentümer erfolgreich geändert",
"Successfully deleted": "Erfolgreich gelöscht",
"Successfully deleted comments": "",
"Successfully updated": "Erfolgreich aktualisiert",
"Successfully updated categories": "Kategorien erfolgreich aktualisiert",
"Successfully updated playlist membership": "Playlist-Mitgliedschaft erfolgreich aktualisiert",
@@ -232,6 +253,9 @@ translation_strings = {
"Upload media": "Medien hochladen",
"Uploads": "Uploads",
"Users": "Benutzer",
"Users can edit your media via: My Media > Shared with Me > particular media > Edit...": "",
"Users can manage your media via: My Media > Shared with Me > particular media > ...": "",
"Users can view your media via: My Media > Shared with Me > particular media > ...": "",
"VIEW ALL": "ALLE ANZEIGEN",
"Video": "Video",
"View all": "Alle anzeigen",
@@ -240,6 +264,7 @@ translation_strings = {
"Welcome": "Willkommen",
"You are going to copy": "Sie werden kopieren",
"You are going to delete": "Sie werden löschen",
"You are going to delete all comments from": "",
"You are going to disable comments to": "Sie werden Kommentare deaktivieren für",
"You are going to disable download for": "Sie werden Download deaktivieren für",
"You are going to enable comments to": "Sie werden Kommentare aktivieren für",

View File

@@ -48,6 +48,7 @@ translation_strings = {
"DELETE MEDIA": "ΔΙΑΓΡΑΦΗ ΑΡΧΕΙΟΥ",
"DOWNLOAD": "ΚΑΤΕΒΑΣΜΑ",
"DURATION": "ΔΙΑΡΚΕΙΑ",
"Delete Comments": "",
"Delete Media": "Διαγραφή Αρχείου",
"Delete media": "Διαγραφή αρχείου",
"Disable Comments": "Απενεργοποίηση Σχολίων",
@@ -70,6 +71,7 @@ translation_strings = {
"Failed to change owner. Please try again.": "Αποτυχία αλλαγής ιδιοκτήτη. Παρακαλώ δοκιμάστε ξανά.",
"Failed to copy media.": "Αποτυχία αντιγραφής αρχείου.",
"Failed to create playlist": "Αποτυχία δημιουργίας λίστας",
"Failed to delete comments.": "",
"Failed to delete media. Please try again.": "Αποτυχία διαγραφής αρχείου. Παρακαλώ δοκιμάστε ξανά.",
"Failed to disable comments.": "Αποτυχία απενεργοποίησης σχολίων.",
"Failed to disable download.": "Αποτυχία απενεργοποίησης λήψης.",
@@ -101,6 +103,9 @@ translation_strings = {
"Filter existing users...": "Φιλτράρισμα υπαρχόντων χρηστών...",
"Filter playlists...": "Φιλτράρισμα λιστών...",
"Filters": "Φίλτρα",
"Give users editor permissions to your media by adding them to the below list.": "",
"Give users owner permissions to your media, except for deleting the media, by adding them to the below list.": "",
"Give users viewer permissions to your media by adding them to the below list.": "",
"Go": "Μετάβαση",
"History": "Ιστορικό",
"Home": "Αρχική",
@@ -121,6 +126,7 @@ translation_strings = {
"Manage comments": "Διαχείριση σχολίων",
"Manage media": "Διαχείριση αρχείων",
"Manage users": "Διαχείριση χρηστών",
"Management": "",
"Media": "Αρχεία",
"Media I own": "Δικά μου αρχεία",
"Media was edited": "Το αρχείο επεξεργάστηκε",
@@ -137,6 +143,7 @@ translation_strings = {
"No results for": "Δεν υπάρχουν αποτελέσματα για",
"No tags": "Δεν υπάρχουν ετικέτες",
"No users to add": "Δεν υπάρχουν χρήστες για προσθήκη",
"Organization": "",
"PLAYLISTS": "ΛΙΣΤΕΣ",
"PUBLISH STATE": "ΚΑΤΑΣΤΑΣΗ ΔΗΜΟΣΙΕΥΣΗΣ",
"Pdf": "PDF",
@@ -156,12 +163,17 @@ translation_strings = {
"Published on": "Δημοσιεύτηκε στις",
"Recent uploads": "Πρόσφατα ανεβάσματα",
"Recommended": "Προτεινόμενα",
"Record": "",
"Record Screen": "Καταγραφή οθόνης",
"Record Screen with Audio": "",
"Register": "Εγγραφή",
"Remove category": "Αφαίρεση κατηγορίας",
"Remove from list": "Αφαίρεση από λίστα",
"Remove tag": "Αφαίρεση ετικέτας",
"Remove user": "Αφαίρεση χρήστη",
"Remove users from the list to remove editor permissions": "",
"Remove users from the list to remove owner permissions": "",
"Remove users from the list to remove viewer permissions": "",
"Replace": "",
"SAVE": "ΑΠΟΘΗΚΕΥΣΗ",
"SEARCH": "ΑΝΑΖΗΤΗΣΗ",
@@ -178,14 +190,22 @@ translation_strings = {
"Select all media": "Επιλογή όλων των αρχείων",
"Select publish state:": "Επιλέξτε κατάσταση δημοσίευσης:",
"Selected": "Επιλεγμένα",
"Settings": "",
"Share with": "",
"Share with Co-Editors": "",
"Share with Co-Owners": "",
"Share with Co-Viewers": "",
"Share with Course Members": "",
"Shared by me": "Κοινοποιήθηκαν από εμένα",
"Shared with me": "Κοινοποιήθηκαν σε εμένα",
"Sharing": "",
"Sign in": "Σύνδεση",
"Sign out": "Αποσύνδεση",
"Sort By": "Ταξινόμηση",
"Start Recording": "Έναρξη εγγραφής",
"Start uploading media and sharing your work. Media that you upload will show up here.": "Ξεκινήστε να ανεβάζετε αρχεία και να κοινοποιείτε τη δουλειά σας. Τα αρχεία που ανεβάζετε θα εμφανίζονται εδώ.",
"Stop Recording": "Διακοπή εγγραφής",
"Students will get viewer permissions, while lecturers will get co-owner permissions (same as owner, but cannot delete the media)": "",
"Submit": "Υποβολή",
"Subtitle was added": "Οι υπότιτλοι προστέθηκαν",
"Subtitles": "Υπότιτλοι",
@@ -196,6 +216,7 @@ translation_strings = {
"Successfully Enabled comments": "Τα σχόλια ενεργοποιήθηκαν με επιτυχία",
"Successfully changed owner": "Ο ιδιοκτήτης άλλαξε με επιτυχία",
"Successfully deleted": "Διαγράφηκε με επιτυχία",
"Successfully deleted comments": "",
"Successfully updated": "Ενημερώθηκε με επιτυχία",
"Successfully updated categories": "Οι κατηγορίες ενημερώθηκαν με επιτυχία",
"Successfully updated playlist membership": "Η συμμετοχή στη λίστα ενημερώθηκε με επιτυχία",
@@ -232,6 +253,9 @@ translation_strings = {
"Upload media": "Ανέβασμα αρχείων",
"Uploads": "Ανεβάσματα",
"Users": "Χρήστες",
"Users can edit your media via: My Media > Shared with Me > particular media > Edit...": "",
"Users can manage your media via: My Media > Shared with Me > particular media > ...": "",
"Users can view your media via: My Media > Shared with Me > particular media > ...": "",
"VIEW ALL": "ΔΕΣ ΤΑ ΟΛΑ",
"Video": "Βίντεο",
"View all": "Δες τα όλα",
@@ -240,6 +264,7 @@ translation_strings = {
"Welcome": "Καλώς ήρθατε",
"You are going to copy": "Πρόκειται να αντιγράψετε",
"You are going to delete": "Πρόκειται να διαγράψετε",
"You are going to delete all comments from": "",
"You are going to disable comments to": "Πρόκειται να απενεργοποιήσετε τα σχόλια για",
"You are going to disable download for": "Πρόκειται να απενεργοποιήσετε τη λήψη για",
"You are going to enable comments to": "Πρόκειται να ενεργοποιήσετε τα σχόλια για",

View File

@@ -48,6 +48,7 @@ translation_strings = {
"DELETE": "",
"DELETE MEDIA": "",
"Delete media": "",
"Delete Comments": "",
"Delete Media": "",
"Disable Comments": "",
"Disable Download": "",
@@ -71,6 +72,7 @@ translation_strings = {
"Failed to change owner. Please try again.": "",
"Failed to copy media.": "",
"Failed to create playlist": "",
"Failed to delete comments.": "",
"Failed to delete media. Please try again.": "",
"Failed to disable comments.": "",
"Failed to disable download.": "",
@@ -102,6 +104,9 @@ translation_strings = {
"Filter existing users...": "",
"Filter playlists...": "",
"Filters": "",
"Give users editor permissions to your media by adding them to the below list.": "",
"Give users owner permissions to your media, except for deleting the media, by adding them to the below list.": "",
"Give users viewer permissions to your media by adding them to the below list.": "",
"Go": "",
"History": "",
"Home": "",
@@ -117,6 +122,7 @@ translation_strings = {
"Loading existing users...": "",
"Loading playlists...": "",
"Loading tags...": "",
"Management": "",
"Manage": "",
"Manage comments": "",
"Manage media": "",
@@ -143,6 +149,7 @@ translation_strings = {
"No results for": "",
"No tags": "",
"No users to add": "",
"Organization": "",
"or": "",
"Pdf": "",
"PLAYLISTS": "",
@@ -162,8 +169,13 @@ translation_strings = {
"Published": "",
"Published on": "",
"Recent uploads": "",
"Remove users from the list to remove editor permissions": "",
"Remove users from the list to remove owner permissions": "",
"Remove users from the list to remove viewer permissions": "",
"Recommended": "",
"Record": "",
"Record Screen": "",
"Record Screen with Audio": "",
"Register": "",
"Replace": "",
"Remove category": "",
@@ -171,6 +183,7 @@ translation_strings = {
"Remove tag": "",
"Remove user": "",
"results for": "",
"Settings": "",
"SAVE": "",
"SEARCH": "",
"Search": "",
@@ -184,6 +197,12 @@ translation_strings = {
"Selected": "",
"selected": "",
"SHARE": "",
"Share with Co-Editors": "",
"Share with Co-Owners": "",
"Share with Co-Viewers": "",
"Share with Course Members": "",
"Sharing": "",
"Share with": "",
"Shared by me": "",
"Shared with me": "",
"SHOW MORE": "",
@@ -194,6 +213,7 @@ translation_strings = {
"Start Recording": "",
"Start uploading media and sharing your work. Media that you upload will show up here.": "",
"Stop Recording": "",
"Students will get viewer permissions, while lecturers will get co-owner permissions (same as owner, but cannot delete the media)": "",
"SUBMIT": "",
"Submit": "",
"Subtitle was added": "",
@@ -201,6 +221,7 @@ translation_strings = {
"Successfully changed owner": "",
"Successfully Copied": "",
"Successfully deleted": "",
"Successfully deleted comments": "",
"Successfully Disabled comments": "",
"Successfully Disabled Download": "",
"Successfully Enabled comments": "",
@@ -240,6 +261,9 @@ translation_strings = {
"UPLOAD MEDIA": "",
"Upload media": "",
"Uploads": "",
"Users can edit your media via: My Media > Shared with Me > particular media > Edit...": "",
"Users can manage your media via: My Media > Shared with Me > particular media > ...": "",
"Users can view your media via: My Media > Shared with Me > particular media > ...": "",
"Users": "",
"Video": "",
"view": "",
@@ -252,6 +276,7 @@ translation_strings = {
"yet": "",
"You are going to copy": "",
"You are going to delete": "",
"You are going to delete all comments from": "",
"You are going to disable comments to": "",
"You are going to disable download for": "",
"You are going to enable comments to": "",

View File

@@ -48,6 +48,7 @@ translation_strings = {
"DELETE MEDIA": "ELIMINAR MEDIOS",
"DOWNLOAD": "DESCARGAR",
"DURATION": "DURACIÓN",
"Delete Comments": "",
"Delete Media": "Eliminar Medio",
"Delete media": "Eliminar medios",
"Disable Comments": "Deshabilitar Comentarios",
@@ -70,6 +71,7 @@ translation_strings = {
"Failed to change owner. Please try again.": "Error al cambiar propietario. Por favor, inténtelo de nuevo.",
"Failed to copy media.": "Error al copiar medios.",
"Failed to create playlist": "Error al crear lista de reproducción",
"Failed to delete comments.": "",
"Failed to delete media. Please try again.": "Error al eliminar medios. Por favor, inténtelo de nuevo.",
"Failed to disable comments.": "Error al deshabilitar comentarios.",
"Failed to disable download.": "Error al deshabilitar descarga.",
@@ -101,6 +103,9 @@ translation_strings = {
"Filter existing users...": "Filtrar usuarios existentes...",
"Filter playlists...": "Filtrar listas de reproducción...",
"Filters": "Filtros",
"Give users editor permissions to your media by adding them to the below list.": "",
"Give users owner permissions to your media, except for deleting the media, by adding them to the below list.": "",
"Give users viewer permissions to your media by adding them to the below list.": "",
"Go": "Ir",
"History": "Historial",
"Home": "Inicio",
@@ -121,6 +126,7 @@ translation_strings = {
"Manage comments": "Gestionar comentarios",
"Manage media": "Gestionar medios",
"Manage users": "Gestionar usuarios",
"Management": "",
"Media": "Medios",
"Media I own": "Medios que poseo",
"Media was edited": "El medio fue editado",
@@ -137,6 +143,7 @@ translation_strings = {
"No results for": "No hay resultados para",
"No tags": "Sin etiquetas",
"No users to add": "No hay usuarios para agregar",
"Organization": "",
"PLAYLISTS": "LISTAS DE REPRODUCCIÓN",
"PUBLISH STATE": "ESTADO DE PUBLICACIÓN",
"Pdf": "PDF",
@@ -156,12 +163,17 @@ translation_strings = {
"Published on": "Publicado en",
"Recent uploads": "Subidas recientes",
"Recommended": "Recomendado",
"Record": "",
"Record Screen": "Grabar pantalla",
"Record Screen with Audio": "",
"Register": "Registrarse",
"Remove category": "Eliminar categoría",
"Remove from list": "Eliminar de la lista",
"Remove tag": "Eliminar etiqueta",
"Remove user": "Eliminar usuario",
"Remove users from the list to remove editor permissions": "",
"Remove users from the list to remove owner permissions": "",
"Remove users from the list to remove viewer permissions": "",
"Replace": "",
"SAVE": "GUARDAR",
"SEARCH": "BUSCAR",
@@ -178,14 +190,22 @@ translation_strings = {
"Select all media": "Seleccionar todos los medios",
"Select publish state:": "Seleccionar estado de publicación:",
"Selected": "Seleccionado",
"Settings": "",
"Share with": "",
"Share with Co-Editors": "",
"Share with Co-Owners": "",
"Share with Co-Viewers": "",
"Share with Course Members": "",
"Shared by me": "Compartido por mí",
"Shared with me": "Compartido conmigo",
"Sharing": "",
"Sign in": "Iniciar sesión",
"Sign out": "Cerrar sesión",
"Sort By": "Ordenar por",
"Start Recording": "Iniciar grabación",
"Start uploading media and sharing your work. Media that you upload will show up here.": "Comience a subir medios y compartir su trabajo. Los medios que suba aparecerán aquí.",
"Stop Recording": "Detener grabación",
"Students will get viewer permissions, while lecturers will get co-owner permissions (same as owner, but cannot delete the media)": "",
"Submit": "Enviar",
"Subtitle was added": "El subtítulo fue agregado",
"Subtitles": "Subtítulos",
@@ -196,6 +216,7 @@ translation_strings = {
"Successfully Enabled comments": "Comentarios habilitados exitosamente",
"Successfully changed owner": "Propietario cambiado exitosamente",
"Successfully deleted": "Eliminado exitosamente",
"Successfully deleted comments": "",
"Successfully updated": "Actualizado exitosamente",
"Successfully updated categories": "Categorías actualizadas exitosamente",
"Successfully updated playlist membership": "Membresía de lista de reproducción actualizada exitosamente",
@@ -232,6 +253,9 @@ translation_strings = {
"Upload media": "Subir medios",
"Uploads": "Subidas",
"Users": "Usuarios",
"Users can edit your media via: My Media > Shared with Me > particular media > Edit...": "",
"Users can manage your media via: My Media > Shared with Me > particular media > ...": "",
"Users can view your media via: My Media > Shared with Me > particular media > ...": "",
"VIEW ALL": "VER TODO",
"Video": "Video",
"View all": "Ver todo",
@@ -240,6 +264,7 @@ translation_strings = {
"Welcome": "Bienvenido",
"You are going to copy": "Vas a copiar",
"You are going to delete": "Vas a eliminar",
"You are going to delete all comments from": "",
"You are going to disable comments to": "Vas a deshabilitar comentarios de",
"You are going to disable download for": "Vas a deshabilitar descarga de",
"You are going to enable comments to": "Vas a habilitar comentarios de",

View File

@@ -49,6 +49,7 @@ translation_strings = {
"DELETE MEDIA": "SUPPRIMER LE MÉDIA",
"DOWNLOAD": "TÉLÉCHARGER",
"DURATION": "DURÉE",
"Delete Comments": "",
"Delete Media": "Supprimer le média",
"Delete media": "Supprimer le média",
"Disable Comments": "Désactiver les commentaires",
@@ -71,6 +72,7 @@ translation_strings = {
"Failed to change owner. Please try again.": "Échec du changement de propriétaire. Veuillez réessayer.",
"Failed to copy media.": "Échec de la copie du média.",
"Failed to create playlist": "Échec de la création de la playlist",
"Failed to delete comments.": "",
"Failed to delete media. Please try again.": "Échec de la suppression du média. Veuillez réessayer.",
"Failed to disable comments.": "Échec de la désactivation des commentaires.",
"Failed to disable download.": "Échec de la désactivation du téléchargement.",
@@ -102,6 +104,9 @@ translation_strings = {
"Filter existing users...": "Filtrer les utilisateurs existants...",
"Filter playlists...": "Filtrer les playlists...",
"Filters": "Filtres",
"Give users editor permissions to your media by adding them to the below list.": "",
"Give users owner permissions to your media, except for deleting the media, by adding them to the below list.": "",
"Give users viewer permissions to your media by adding them to the below list.": "",
"Go": "Aller",
"History": "Historique",
"Home": "Accueil",
@@ -122,6 +127,7 @@ translation_strings = {
"Manage comments": "Gérer les commentaires",
"Manage media": "Gérer les médias",
"Manage users": "Gérer les utilisateurs",
"Management": "",
"Media": "Média",
"Media I own": "Médias que je possède",
"Media was edited": "Le média a été modifié",
@@ -138,6 +144,7 @@ translation_strings = {
"No results for": "Aucun résultat pour",
"No tags": "Aucun tag",
"No users to add": "Aucun utilisateur à ajouter",
"Organization": "",
"PLAYLISTS": "PLAYLISTS",
"PUBLISH STATE": "ÉTAT DE PUBLICATION",
"Pdf": "PDF",
@@ -157,12 +164,17 @@ translation_strings = {
"Published on": "Publié le",
"Recent uploads": "Téléchargements récents",
"Recommended": "Recommandé",
"Record": "",
"Record Screen": "Enregistrer l'écran",
"Record Screen with Audio": "",
"Register": "S'inscrire",
"Remove category": "Supprimer la catégorie",
"Remove from list": "Supprimer de la liste",
"Remove tag": "Supprimer le tag",
"Remove user": "Supprimer l'utilisateur",
"Remove users from the list to remove editor permissions": "",
"Remove users from the list to remove owner permissions": "",
"Remove users from the list to remove viewer permissions": "",
"Replace": "",
"SAVE": "ENREGISTRER",
"SEARCH": "RECHERCHER",
@@ -179,14 +191,22 @@ translation_strings = {
"Select all media": "Sélectionner tous les médias",
"Select publish state:": "Sélectionner l'état de publication:",
"Selected": "Sélectionné",
"Settings": "",
"Share with": "",
"Share with Co-Editors": "",
"Share with Co-Owners": "",
"Share with Co-Viewers": "",
"Share with Course Members": "",
"Shared by me": "Partagé par moi",
"Shared with me": "Partagé avec moi",
"Sharing": "",
"Sign in": "Se connecter",
"Sign out": "Se déconnecter",
"Sort By": "Trier par",
"Start Recording": "Commencer l'enregistrement",
"Start uploading media and sharing your work. Media that you upload will show up here.": "Commencez à télécharger des médias et à partager votre travail. Les médias que vous téléchargez apparaîtront ici.",
"Stop Recording": "Arrêter l'enregistrement",
"Students will get viewer permissions, while lecturers will get co-owner permissions (same as owner, but cannot delete the media)": "",
"Submit": "Soumettre",
"Subtitle was added": "Le sous-titre a été ajouté",
"Subtitles": "Sous-titres",
@@ -197,6 +217,7 @@ translation_strings = {
"Successfully Enabled comments": "Commentaires activés avec succès",
"Successfully changed owner": "Propriétaire changé avec succès",
"Successfully deleted": "Supprimé avec succès",
"Successfully deleted comments": "",
"Successfully updated": "Mis à jour avec succès",
"Successfully updated categories": "Catégories mises à jour avec succès",
"Successfully updated playlist membership": "Adhésion à la playlist mise à jour avec succès",
@@ -233,6 +254,9 @@ translation_strings = {
"Upload media": "Télécharger des médias",
"Uploads": "Téléchargements",
"Users": "Utilisateurs",
"Users can edit your media via: My Media > Shared with Me > particular media > Edit...": "",
"Users can manage your media via: My Media > Shared with Me > particular media > ...": "",
"Users can view your media via: My Media > Shared with Me > particular media > ...": "",
"VIEW ALL": "VOIR TOUT",
"Video": "Vidéo",
"View all": "Voir tout",
@@ -241,6 +265,7 @@ translation_strings = {
"Welcome": "Bienvenue",
"You are going to copy": "Vous allez copier",
"You are going to delete": "Vous allez supprimer",
"You are going to delete all comments from": "",
"You are going to disable comments to": "Vous allez désactiver les commentaires de",
"You are going to disable download for": "Vous allez désactiver le téléchargement de",
"You are going to enable comments to": "Vous allez activer les commentaires de",

View File

@@ -48,6 +48,7 @@ translation_strings = {
"DELETE MEDIA": "מחק מדיה",
"DOWNLOAD": "הורד",
"DURATION": "משך",
"Delete Comments": "",
"Delete Media": "",
"Delete media": "מחק מדיה",
"Disable Comments": "",
@@ -70,6 +71,7 @@ translation_strings = {
"Failed to change owner. Please try again.": "",
"Failed to copy media.": "העתקת המדיה נכשלה.",
"Failed to create playlist": "",
"Failed to delete comments.": "",
"Failed to delete media. Please try again.": "מחיקת המדיה נכשלה. אנא נסה שוב.",
"Failed to disable comments.": "ביטול התגובות נכשל.",
"Failed to disable download.": "ביטול ההורדה נכשל.",
@@ -101,6 +103,9 @@ translation_strings = {
"Filter existing users...": "",
"Filter playlists...": "",
"Filters": "מסננים",
"Give users editor permissions to your media by adding them to the below list.": "",
"Give users owner permissions to your media, except for deleting the media, by adding them to the below list.": "",
"Give users viewer permissions to your media by adding them to the below list.": "",
"Go": "בצע",
"History": "היסטוריה",
"Home": "דף הבית",
@@ -121,6 +126,7 @@ translation_strings = {
"Manage comments": "ניהול תגובות",
"Manage media": "ניהול מדיה",
"Manage users": "ניהול משתמשים",
"Management": "",
"Media": "מדיה",
"Media I own": "",
"Media was edited": "המדיה נערכה",
@@ -137,6 +143,7 @@ translation_strings = {
"No results for": "אין תוצאות עבור",
"No tags": "",
"No users to add": "",
"Organization": "",
"PLAYLISTS": "פלייליסטים",
"PUBLISH STATE": "מצב פרסום",
"Pdf": "PDF",
@@ -156,12 +163,17 @@ translation_strings = {
"Published on": "פורסם בתאריך",
"Recent uploads": "העלאות אחרונות",
"Recommended": "מומלץ",
"Record": "",
"Record Screen": "הקלטת מסך",
"Record Screen with Audio": "",
"Register": "הרשמה",
"Remove category": "",
"Remove from list": "",
"Remove tag": "",
"Remove user": "",
"Remove users from the list to remove editor permissions": "",
"Remove users from the list to remove owner permissions": "",
"Remove users from the list to remove viewer permissions": "",
"Replace": "",
"SAVE": "שמור",
"SEARCH": "חפש",
@@ -178,14 +190,22 @@ translation_strings = {
"Select all media": "",
"Select publish state:": "",
"Selected": "",
"Settings": "",
"Share with": "",
"Share with Co-Editors": "",
"Share with Co-Owners": "",
"Share with Co-Viewers": "",
"Share with Course Members": "",
"Shared by me": "שותף על ידי",
"Shared with me": "שותף איתי",
"Sharing": "",
"Sign in": "התחבר",
"Sign out": "התנתק",
"Sort By": "מיין לפי",
"Start Recording": "התחל הקלטה",
"Start uploading media and sharing your work. Media that you upload will show up here.": "התחל להעלות מדיה ולשתף את עבודתך. המדיה שתעלה תופיע כאן.",
"Stop Recording": "עצור הקלטה",
"Students will get viewer permissions, while lecturers will get co-owner permissions (same as owner, but cannot delete the media)": "",
"Submit": "",
"Subtitle was added": "הכתובית נוספה",
"Subtitles": "כתוביות",
@@ -196,6 +216,7 @@ translation_strings = {
"Successfully Enabled comments": "התגובות הופעלו בהצלחה",
"Successfully changed owner": "",
"Successfully deleted": "נמחק בהצלחה",
"Successfully deleted comments": "",
"Successfully updated": "",
"Successfully updated categories": "",
"Successfully updated playlist membership": "",
@@ -232,6 +253,9 @@ translation_strings = {
"Upload media": "העלה מדיה",
"Uploads": "העלאות",
"Users": "",
"Users can edit your media via: My Media > Shared with Me > particular media > Edit...": "",
"Users can manage your media via: My Media > Shared with Me > particular media > ...": "",
"Users can view your media via: My Media > Shared with Me > particular media > ...": "",
"VIEW ALL": "הצג הכל",
"Video": "וידאו",
"View all": "הצג הכל",
@@ -240,6 +264,7 @@ translation_strings = {
"Welcome": "ברוך הבא",
"You are going to copy": "אתה עומד להעתיק",
"You are going to delete": "אתה עומד למחוק",
"You are going to delete all comments from": "",
"You are going to disable comments to": "אתה עומד לבטל תגובות ל",
"You are going to disable download for": "אתה עומד לבטל הורדה עבור",
"You are going to enable comments to": "אתה עומד להפעיל תגובות ל",

View File

@@ -48,6 +48,7 @@ translation_strings = {
"DELETE MEDIA": "मीडिया हटाएं",
"DOWNLOAD": "डाउनलोड करें",
"DURATION": "अवधि",
"Delete Comments": "",
"Delete Media": "मीडिया हटाएं",
"Delete media": "मीडिया हटाएं",
"Disable Comments": "टिप्पणियां अक्षम करें",
@@ -70,6 +71,7 @@ translation_strings = {
"Failed to change owner. Please try again.": "स्वामी बदलने में विफल। कृपया पुनः प्रयास करें।",
"Failed to copy media.": "मीडिया कॉपी करने में विफल।",
"Failed to create playlist": "प्लेलिस्ट बनाने में विफल",
"Failed to delete comments.": "",
"Failed to delete media. Please try again.": "मीडिया हटाने में विफल। कृपया पुनः प्रयास करें।",
"Failed to disable comments.": "टिप्पणियों को अक्षम करने में विफल।",
"Failed to disable download.": "डाउनलोड अक्षम करने में विफल।",
@@ -101,6 +103,9 @@ translation_strings = {
"Filter existing users...": "मौजूदा उपयोगकर्ताओं को फ़िल्टर करें...",
"Filter playlists...": "प्लेलिस्ट फ़िल्टर करें...",
"Filters": "फ़िल्टर",
"Give users editor permissions to your media by adding them to the below list.": "",
"Give users owner permissions to your media, except for deleting the media, by adding them to the below list.": "",
"Give users viewer permissions to your media by adding them to the below list.": "",
"Go": "जाएं",
"History": "इतिहास",
"Home": "मुख्य पृष्ठ",
@@ -121,6 +126,7 @@ translation_strings = {
"Manage comments": "टिप्पणियाँ प्रबंधित करें",
"Manage media": "मीडिया प्रबंधित करें",
"Manage users": "उपयोगकर्ताओं को प्रबंधित करें",
"Management": "",
"Media": "मीडिया",
"Media I own": "मेरे स्वामित्व वाली मीडिया",
"Media was edited": "मीडिया संपादित किया गया था",
@@ -137,6 +143,7 @@ translation_strings = {
"No results for": "के लिए कोई परिणाम नहीं",
"No tags": "कोई टैग नहीं",
"No users to add": "जोड़ने के लिए कोई उपयोगकर्ता नहीं",
"Organization": "",
"PLAYLISTS": "प्लेलिस्ट",
"PUBLISH STATE": "प्रकाशन स्थिति",
"Pdf": "PDF",
@@ -156,12 +163,17 @@ translation_strings = {
"Published on": "पर प्रकाशित",
"Recent uploads": "हाल के अपलोड",
"Recommended": "अनुशंसित",
"Record": "",
"Record Screen": "स्क्रीन रिकॉर्ड करें",
"Record Screen with Audio": "",
"Register": "पंजीकरण करें",
"Remove category": "श्रेणी हटाएं",
"Remove from list": "सूची से हटाएं",
"Remove tag": "टैग हटाएं",
"Remove user": "उपयोगकर्ता हटाएं",
"Remove users from the list to remove editor permissions": "",
"Remove users from the list to remove owner permissions": "",
"Remove users from the list to remove viewer permissions": "",
"Replace": "",
"SAVE": "सहेजें",
"SEARCH": "खोजें",
@@ -178,14 +190,22 @@ translation_strings = {
"Select all media": "सभी मीडिया चुनें",
"Select publish state:": "प्रकाशन स्थिति चुनें:",
"Selected": "चयनित",
"Settings": "",
"Share with": "",
"Share with Co-Editors": "",
"Share with Co-Owners": "",
"Share with Co-Viewers": "",
"Share with Course Members": "",
"Shared by me": "मेरे द्वारा साझा किया गया",
"Shared with me": "मेरे साथ साझा किया गया",
"Sharing": "",
"Sign in": "साइन इन करें",
"Sign out": "साइन आउट करें",
"Sort By": "इसके अनुसार क्रमबद्ध करें",
"Start Recording": "रिकॉर्डिंग प्रारंभ करें",
"Start uploading media and sharing your work. Media that you upload will show up here.": "मीडिया अपलोड करना और अपना काम साझा करना शुरू करें। आपके द्वारा अपलोड किया गया मीडिया यहां दिखाई देगा।",
"Stop Recording": "रिकॉर्डिंग रोकें",
"Students will get viewer permissions, while lecturers will get co-owner permissions (same as owner, but cannot delete the media)": "",
"Submit": "प्रस्तुत करें",
"Subtitle was added": "उपशीर्षक जोड़ा गया",
"Subtitles": "उपशीर्षक",
@@ -196,6 +216,7 @@ translation_strings = {
"Successfully Enabled comments": "टिप्पणियां सफलतापूर्वक सक्षम की गईं",
"Successfully changed owner": "स्वामी सफलतापूर्वक बदला गया",
"Successfully deleted": "सफलतापूर्वक हटाया गया",
"Successfully deleted comments": "",
"Successfully updated": "सफलतापूर्वक अपडेट किया गया",
"Successfully updated categories": "श्रेणियां सफलतापूर्वक अपडेट की गईं",
"Successfully updated playlist membership": "प्लेलिस्ट सदस्यता सफलतापूर्वक अपडेट की गई",
@@ -232,6 +253,9 @@ translation_strings = {
"Upload media": "मीडिया अपलोड करें",
"Uploads": "अपलोड",
"Users": "उपयोगकर्ता",
"Users can edit your media via: My Media > Shared with Me > particular media > Edit...": "",
"Users can manage your media via: My Media > Shared with Me > particular media > ...": "",
"Users can view your media via: My Media > Shared with Me > particular media > ...": "",
"VIEW ALL": "सभी देखें",
"Video": "वीडियो",
"View all": "सभी देखें",
@@ -240,6 +264,7 @@ translation_strings = {
"Welcome": "स्वागत है",
"You are going to copy": "आप कॉपी करने जा रहे हैं",
"You are going to delete": "आप हटाने जा रहे हैं",
"You are going to delete all comments from": "",
"You are going to disable comments to": "आप टिप्पणियों को अक्षम करने जा रहे हैं",
"You are going to disable download for": "आप डाउनलोड को अक्षम करने जा रहे हैं",
"You are going to enable comments to": "आप टिप्पणियों को सक्षम करने जा रहे हैं",

View File

@@ -48,6 +48,7 @@ translation_strings = {
"DELETE MEDIA": "HAPUS MEDIA",
"DOWNLOAD": "UNDUH",
"DURATION": "DURASI",
"Delete Comments": "",
"Delete Media": "Hapus Media",
"Delete media": "Hapus media",
"Disable Comments": "Nonaktifkan Komentar",
@@ -70,6 +71,7 @@ translation_strings = {
"Failed to change owner. Please try again.": "Gagal mengganti pemilik. Silakan coba lagi.",
"Failed to copy media.": "Gagal menyalin media.",
"Failed to create playlist": "Gagal membuat daftar putar",
"Failed to delete comments.": "",
"Failed to delete media. Please try again.": "Gagal menghapus media. Silakan coba lagi.",
"Failed to disable comments.": "Gagal menonaktifkan komentar.",
"Failed to disable download.": "Gagal menonaktifkan unduhan.",
@@ -101,6 +103,9 @@ translation_strings = {
"Filter existing users...": "Filter pengguna yang ada...",
"Filter playlists...": "Filter daftar putar...",
"Filters": "Filter",
"Give users editor permissions to your media by adding them to the below list.": "",
"Give users owner permissions to your media, except for deleting the media, by adding them to the below list.": "",
"Give users viewer permissions to your media by adding them to the below list.": "",
"Go": "Pergi",
"History": "Riwayat",
"Home": "Beranda",
@@ -121,6 +126,7 @@ translation_strings = {
"Manage comments": "Kelola komentar",
"Manage media": "Kelola media",
"Manage users": "Kelola pengguna",
"Management": "",
"Media": "Media",
"Media I own": "Media yang saya miliki",
"Media was edited": "Media telah diedit",
@@ -137,6 +143,7 @@ translation_strings = {
"No results for": "Tidak ada hasil untuk",
"No tags": "Tidak ada tag",
"No users to add": "Tidak ada pengguna untuk ditambahkan",
"Organization": "",
"PLAYLISTS": "DAFTAR PUTAR",
"PUBLISH STATE": "STATUS PUBLIKASI",
"Pdf": "PDF",
@@ -156,12 +163,17 @@ translation_strings = {
"Published on": "Diterbitkan pada",
"Recent uploads": "Unggahan terbaru",
"Recommended": "Direkomendasikan",
"Record": "",
"Record Screen": "Rekam Layar",
"Record Screen with Audio": "",
"Register": "Daftar",
"Remove category": "Hapus kategori",
"Remove from list": "Hapus dari daftar",
"Remove tag": "Hapus tag",
"Remove user": "Hapus pengguna",
"Remove users from the list to remove editor permissions": "",
"Remove users from the list to remove owner permissions": "",
"Remove users from the list to remove viewer permissions": "",
"Replace": "",
"SAVE": "SIMPAN",
"SEARCH": "CARI",
@@ -178,14 +190,22 @@ translation_strings = {
"Select all media": "Pilih semua media",
"Select publish state:": "Pilih status publikasi:",
"Selected": "Dipilih",
"Settings": "",
"Share with": "",
"Share with Co-Editors": "",
"Share with Co-Owners": "",
"Share with Co-Viewers": "",
"Share with Course Members": "",
"Shared by me": "Dibagikan oleh saya",
"Shared with me": "Dibagikan dengan saya",
"Sharing": "",
"Sign in": "Masuk",
"Sign out": "Keluar",
"Sort By": "Urutkan Berdasarkan",
"Start Recording": "Mulai Merekam",
"Start uploading media and sharing your work. Media that you upload will show up here.": "Mulai mengunggah media dan berbagi karya Anda. Media yang Anda unggah akan muncul di sini.",
"Stop Recording": "Hentikan Perekaman",
"Students will get viewer permissions, while lecturers will get co-owner permissions (same as owner, but cannot delete the media)": "",
"Submit": "Kirim",
"Subtitle was added": "Subtitle telah ditambahkan",
"Subtitles": "Subtitel",
@@ -196,6 +216,7 @@ translation_strings = {
"Successfully Enabled comments": "Komentar berhasil diaktifkan",
"Successfully changed owner": "Berhasil mengganti pemilik",
"Successfully deleted": "Berhasil dihapus",
"Successfully deleted comments": "",
"Successfully updated": "Berhasil diperbarui",
"Successfully updated categories": "Kategori berhasil diperbarui",
"Successfully updated playlist membership": "Keanggotaan daftar putar berhasil diperbarui",
@@ -232,6 +253,9 @@ translation_strings = {
"Upload media": "Unggah media",
"Uploads": "Unggahan",
"Users": "Pengguna",
"Users can edit your media via: My Media > Shared with Me > particular media > Edit...": "",
"Users can manage your media via: My Media > Shared with Me > particular media > ...": "",
"Users can view your media via: My Media > Shared with Me > particular media > ...": "",
"VIEW ALL": "LIHAT SEMUA",
"Video": "Video",
"View all": "Lihat semua",
@@ -240,6 +264,7 @@ translation_strings = {
"Welcome": "Selamat datang",
"You are going to copy": "Anda akan menyalin",
"You are going to delete": "Anda akan menghapus",
"You are going to delete all comments from": "",
"You are going to disable comments to": "Anda akan menonaktifkan komentar untuk",
"You are going to disable download for": "Anda akan menonaktifkan unduhan untuk",
"You are going to enable comments to": "Anda akan mengaktifkan komentar untuk",

View File

@@ -49,6 +49,7 @@ translation_strings = {
"DELETE MEDIA": "ELIMINA MEDIA",
"DOWNLOAD": "SCARICA",
"DURATION": "DURATA",
"Delete Comments": "",
"Delete Media": "Elimina Media",
"Delete media": "Elimina media",
"Disable Comments": "Disabilita Commenti",
@@ -71,6 +72,7 @@ translation_strings = {
"Failed to change owner. Please try again.": "Impossibile cambiare proprietario. Riprova.",
"Failed to copy media.": "Impossibile copiare il media.",
"Failed to create playlist": "Impossibile creare playlist",
"Failed to delete comments.": "",
"Failed to delete media. Please try again.": "Impossibile eliminare il media. Riprova.",
"Failed to disable comments.": "Impossibile disabilitare i commenti.",
"Failed to disable download.": "Impossibile disabilitare il download.",
@@ -102,6 +104,9 @@ translation_strings = {
"Filter existing users...": "Filtra utenti esistenti...",
"Filter playlists...": "Filtra playlist...",
"Filters": "Filtri",
"Give users editor permissions to your media by adding them to the below list.": "",
"Give users owner permissions to your media, except for deleting the media, by adding them to the below list.": "",
"Give users viewer permissions to your media by adding them to the below list.": "",
"Go": "Vai",
"History": "Cronologia",
"Home": "Home",
@@ -122,6 +127,7 @@ translation_strings = {
"Manage comments": "Gestisci i commenti",
"Manage media": "Gestisci i media",
"Manage users": "Gestisci gli utenti",
"Management": "",
"Media": "Media",
"Media I own": "Media di mia proprietà",
"Media was edited": "Il media è stato modificato",
@@ -138,6 +144,7 @@ translation_strings = {
"No results for": "Nessun risultato per",
"No tags": "Nessun tag",
"No users to add": "Nessun utente da aggiungere",
"Organization": "",
"PLAYLISTS": "PLAYLIST",
"PUBLISH STATE": "STATO DI PUBBLICAZIONE",
"Pdf": "PDF",
@@ -157,12 +164,17 @@ translation_strings = {
"Published on": "Pubblicato il",
"Recent uploads": "Caricamenti recenti",
"Recommended": "Raccomandati",
"Record": "",
"Record Screen": "Registra schermo",
"Record Screen with Audio": "",
"Register": "Registrati",
"Remove category": "Rimuovi categoria",
"Remove from list": "Rimuovi dalla lista",
"Remove tag": "Rimuovi tag",
"Remove user": "Rimuovi utente",
"Remove users from the list to remove editor permissions": "",
"Remove users from the list to remove owner permissions": "",
"Remove users from the list to remove viewer permissions": "",
"Replace": "",
"SAVE": "SALVA",
"SEARCH": "CERCA",
@@ -179,14 +191,22 @@ translation_strings = {
"Select all media": "Seleziona tutti i media",
"Select publish state:": "Seleziona stato di pubblicazione:",
"Selected": "Selezionato",
"Settings": "",
"Share with": "",
"Share with Co-Editors": "",
"Share with Co-Owners": "",
"Share with Co-Viewers": "",
"Share with Course Members": "",
"Shared by me": "Condiviso da me",
"Shared with me": "Condiviso con me",
"Sharing": "",
"Sign in": "Login",
"Sign out": "Logout",
"Sort By": "Ordina per",
"Start Recording": "Inizia registrazione",
"Start uploading media and sharing your work. Media that you upload will show up here.": "Inizia a caricare media e condividere il tuo lavoro. I media caricati appariranno qui.",
"Stop Recording": "Interrompi registrazione",
"Students will get viewer permissions, while lecturers will get co-owner permissions (same as owner, but cannot delete the media)": "",
"Submit": "Invia",
"Subtitle was added": "I sottotitoli sono stati aggiunti",
"Subtitles": "Sottotitoli",
@@ -197,6 +217,7 @@ translation_strings = {
"Successfully Enabled comments": "Commenti abilitati con successo",
"Successfully changed owner": "Proprietario cambiato con successo",
"Successfully deleted": "Eliminato con successo",
"Successfully deleted comments": "",
"Successfully updated": "Aggiornato con successo",
"Successfully updated categories": "Categorie aggiornate con successo",
"Successfully updated playlist membership": "Appartenenza alla playlist aggiornata con successo",
@@ -233,6 +254,9 @@ translation_strings = {
"Upload media": "Carica i media",
"Uploads": "Caricamenti",
"Users": "Utenti",
"Users can edit your media via: My Media > Shared with Me > particular media > Edit...": "",
"Users can manage your media via: My Media > Shared with Me > particular media > ...": "",
"Users can view your media via: My Media > Shared with Me > particular media > ...": "",
"VIEW ALL": "MOSTRA TUTTI",
"Video": "Video",
"View all": "Mostra tutti",
@@ -241,6 +265,7 @@ translation_strings = {
"Welcome": "Benvenuto",
"You are going to copy": "Stai per copiare",
"You are going to delete": "Stai per eliminare",
"You are going to delete all comments from": "",
"You are going to disable comments to": "Stai per disabilitare i commenti di",
"You are going to disable download for": "Stai per disabilitare il download di",
"You are going to enable comments to": "Stai per abilitare i commenti di",

View File

@@ -48,6 +48,7 @@ translation_strings = {
"DELETE MEDIA": "メディアを削除",
"DOWNLOAD": "ダウンロード",
"DURATION": "期間",
"Delete Comments": "",
"Delete Media": "メディアを削除",
"Delete media": "メディアを削除",
"Disable Comments": "コメントを無効化",
@@ -70,6 +71,7 @@ translation_strings = {
"Failed to change owner. Please try again.": "所有者の変更に失敗しました。もう一度お試しください。",
"Failed to copy media.": "メディアのコピーに失敗しました。",
"Failed to create playlist": "プレイリストの作成に失敗しました",
"Failed to delete comments.": "",
"Failed to delete media. Please try again.": "メディアの削除に失敗しました。もう一度お試しください。",
"Failed to disable comments.": "コメントの無効化に失敗しました。",
"Failed to disable download.": "ダウンロードの無効化に失敗しました。",
@@ -101,6 +103,9 @@ translation_strings = {
"Filter existing users...": "既存ユーザーをフィルター...",
"Filter playlists...": "プレイリストをフィルター...",
"Filters": "フィルター",
"Give users editor permissions to your media by adding them to the below list.": "",
"Give users owner permissions to your media, except for deleting the media, by adding them to the below list.": "",
"Give users viewer permissions to your media by adding them to the below list.": "",
"Go": "行く",
"History": "履歴",
"Home": "ホーム",
@@ -121,6 +126,7 @@ translation_strings = {
"Manage comments": "コメントを管理",
"Manage media": "メディアを管理",
"Manage users": "ユーザーを管理",
"Management": "",
"Media": "メディア",
"Media I own": "自分が所有するメディア",
"Media was edited": "メディアが編集されました",
@@ -137,6 +143,7 @@ translation_strings = {
"No results for": "の結果はありません",
"No tags": "タグなし",
"No users to add": "追加するユーザーなし",
"Organization": "",
"PLAYLISTS": "プレイリスト",
"PUBLISH STATE": "公開状態",
"Pdf": "PDF",
@@ -156,12 +163,17 @@ translation_strings = {
"Published on": "公開日",
"Recent uploads": "最近のアップロード",
"Recommended": "おすすめ",
"Record": "",
"Record Screen": "画面を録画",
"Record Screen with Audio": "",
"Register": "登録",
"Remove category": "カテゴリーを削除",
"Remove from list": "リストから削除",
"Remove tag": "タグを削除",
"Remove user": "ユーザーを削除",
"Remove users from the list to remove editor permissions": "",
"Remove users from the list to remove owner permissions": "",
"Remove users from the list to remove viewer permissions": "",
"Replace": "",
"SAVE": "保存",
"SEARCH": "検索",
@@ -178,14 +190,22 @@ translation_strings = {
"Select all media": "すべてのメディアを選択",
"Select publish state:": "公開状態を選択:",
"Selected": "選択済み",
"Settings": "",
"Share with": "",
"Share with Co-Editors": "",
"Share with Co-Owners": "",
"Share with Co-Viewers": "",
"Share with Course Members": "",
"Shared by me": "自分が共有",
"Shared with me": "共有されたもの",
"Sharing": "",
"Sign in": "サインイン",
"Sign out": "サインアウト",
"Sort By": "並び替え",
"Start Recording": "録画開始",
"Start uploading media and sharing your work. Media that you upload will show up here.": "メディアをアップロードして作品を共有しましょう。アップロードしたメディアはここに表示されます。",
"Stop Recording": "録画停止",
"Students will get viewer permissions, while lecturers will get co-owner permissions (same as owner, but cannot delete the media)": "",
"Submit": "送信",
"Subtitle was added": "字幕が追加されました",
"Subtitles": "字幕",
@@ -196,6 +216,7 @@ translation_strings = {
"Successfully Enabled comments": "コメントが正常に有効化されました",
"Successfully changed owner": "所有者が正常に変更されました",
"Successfully deleted": "正常に削除されました",
"Successfully deleted comments": "",
"Successfully updated": "正常に更新されました",
"Successfully updated categories": "カテゴリーが正常に更新されました",
"Successfully updated playlist membership": "プレイリストメンバーシップが正常に更新されました",
@@ -232,6 +253,9 @@ translation_strings = {
"Upload media": "メディアをアップロード",
"Uploads": "アップロード",
"Users": "ユーザー",
"Users can edit your media via: My Media > Shared with Me > particular media > Edit...": "",
"Users can manage your media via: My Media > Shared with Me > particular media > ...": "",
"Users can view your media via: My Media > Shared with Me > particular media > ...": "",
"VIEW ALL": "すべて表示",
"Video": "ビデオ",
"View all": "すべて表示",
@@ -240,6 +264,7 @@ translation_strings = {
"Welcome": "ようこそ",
"You are going to copy": "コピーします",
"You are going to delete": "削除します",
"You are going to delete all comments from": "",
"You are going to disable comments to": "コメントを無効化します",
"You are going to disable download for": "ダウンロードを無効化します",
"You are going to enable comments to": "コメントを有効化します",

View File

@@ -48,6 +48,7 @@ translation_strings = {
"DELETE MEDIA": "미디어 삭제",
"DOWNLOAD": "다운로드",
"DURATION": "재생 시간",
"Delete Comments": "",
"Delete Media": "미디어 삭제",
"Delete media": "미디어 삭제",
"Disable Comments": "댓글 비활성화",
@@ -70,6 +71,7 @@ translation_strings = {
"Failed to change owner. Please try again.": "소유자 변경에 실패했습니다. 다시 시도해주세요.",
"Failed to copy media.": "미디어 복사에 실패했습니다.",
"Failed to create playlist": "재생 목록 만들기 실패",
"Failed to delete comments.": "",
"Failed to delete media. Please try again.": "미디어 삭제에 실패했습니다. 다시 시도해주세요.",
"Failed to disable comments.": "댓글 비활성화에 실패했습니다.",
"Failed to disable download.": "다운로드 비활성화에 실패했습니다.",
@@ -101,6 +103,9 @@ translation_strings = {
"Filter existing users...": "기존 사용자 필터링...",
"Filter playlists...": "재생 목록 필터링...",
"Filters": "필터",
"Give users editor permissions to your media by adding them to the below list.": "",
"Give users owner permissions to your media, except for deleting the media, by adding them to the below list.": "",
"Give users viewer permissions to your media by adding them to the below list.": "",
"Go": "이동",
"History": "기록",
"Home": "",
@@ -121,6 +126,7 @@ translation_strings = {
"Manage comments": "댓글 관리",
"Manage media": "미디어 관리",
"Manage users": "사용자 관리",
"Management": "",
"Media": "미디어",
"Media I own": "내가 소유한 미디어",
"Media was edited": "미디어가 편집되었습니다",
@@ -137,6 +143,7 @@ translation_strings = {
"No results for": "결과 없음",
"No tags": "태그 없음",
"No users to add": "추가할 사용자 없음",
"Organization": "",
"PLAYLISTS": "재생 목록",
"PUBLISH STATE": "게시 상태",
"Pdf": "PDF",
@@ -156,12 +163,17 @@ translation_strings = {
"Published on": "게시일",
"Recent uploads": "최근 업로드",
"Recommended": "추천",
"Record": "",
"Record Screen": "화면 녹화",
"Record Screen with Audio": "",
"Register": "등록",
"Remove category": "카테고리 제거",
"Remove from list": "목록에서 제거",
"Remove tag": "태그 제거",
"Remove user": "사용자 제거",
"Remove users from the list to remove editor permissions": "",
"Remove users from the list to remove owner permissions": "",
"Remove users from the list to remove viewer permissions": "",
"Replace": "",
"SAVE": "저장",
"SEARCH": "검색",
@@ -178,14 +190,22 @@ translation_strings = {
"Select all media": "모든 미디어 선택",
"Select publish state:": "게시 상태 선택:",
"Selected": "선택됨",
"Settings": "",
"Share with": "",
"Share with Co-Editors": "",
"Share with Co-Owners": "",
"Share with Co-Viewers": "",
"Share with Course Members": "",
"Shared by me": "내가 공유함",
"Shared with me": "나와 공유됨",
"Sharing": "",
"Sign in": "로그인",
"Sign out": "로그아웃",
"Sort By": "정렬",
"Start Recording": "녹화 시작",
"Start uploading media and sharing your work. Media that you upload will show up here.": "미디어를 업로드하고 작업을 공유하세요. 업로드한 미디어가 여기에 표시됩니다.",
"Stop Recording": "녹화 중지",
"Students will get viewer permissions, while lecturers will get co-owner permissions (same as owner, but cannot delete the media)": "",
"Submit": "제출",
"Subtitle was added": "자막이 추가되었습니다",
"Subtitles": "자막",
@@ -196,6 +216,7 @@ translation_strings = {
"Successfully Enabled comments": "댓글이 활성화되었습니다",
"Successfully changed owner": "소유자가 변경되었습니다",
"Successfully deleted": "삭제 성공",
"Successfully deleted comments": "",
"Successfully updated": "업데이트 성공",
"Successfully updated categories": "카테고리가 업데이트되었습니다",
"Successfully updated playlist membership": "재생 목록 멤버십이 업데이트되었습니다",
@@ -232,6 +253,9 @@ translation_strings = {
"Upload media": "미디어 업로드",
"Uploads": "업로드",
"Users": "사용자",
"Users can edit your media via: My Media > Shared with Me > particular media > Edit...": "",
"Users can manage your media via: My Media > Shared with Me > particular media > ...": "",
"Users can view your media via: My Media > Shared with Me > particular media > ...": "",
"VIEW ALL": "모두 보기",
"Video": "비디오",
"View all": "모두 보기",
@@ -240,6 +264,7 @@ translation_strings = {
"Welcome": "환영합니다",
"You are going to copy": "복사하려고 합니다",
"You are going to delete": "삭제하려고 합니다",
"You are going to delete all comments from": "",
"You are going to disable comments to": "댓글을 비활성화하려고 합니다",
"You are going to disable download for": "다운로드를 비활성화하려고 합니다",
"You are going to enable comments to": "댓글을 활성화하려고 합니다",

View File

@@ -48,6 +48,7 @@ translation_strings = {
"DELETE MEDIA": "MEDIA VERWIJDEREN",
"DOWNLOAD": "DOWNLOADEN",
"DURATION": "DUUR",
"Delete Comments": "",
"Delete Media": "Media verwijderen",
"Delete media": "Media verwijderen",
"Disable Comments": "Reacties uitschakelen",
@@ -70,6 +71,7 @@ translation_strings = {
"Failed to change owner. Please try again.": "Eigenaar wijzigen mislukt. Probeer het opnieuw.",
"Failed to copy media.": "Media kopiëren mislukt.",
"Failed to create playlist": "Afspeellijst maken mislukt",
"Failed to delete comments.": "",
"Failed to delete media. Please try again.": "Media verwijderen mislukt. Probeer het opnieuw.",
"Failed to disable comments.": "Reacties uitschakelen mislukt.",
"Failed to disable download.": "Download uitschakelen mislukt.",
@@ -101,6 +103,9 @@ translation_strings = {
"Filter existing users...": "Filter bestaande gebruikers...",
"Filter playlists...": "Filter afspeellijsten...",
"Filters": "Filters",
"Give users editor permissions to your media by adding them to the below list.": "",
"Give users owner permissions to your media, except for deleting the media, by adding them to the below list.": "",
"Give users viewer permissions to your media by adding them to the below list.": "",
"Go": "Ga",
"History": "Geschiedenis",
"Home": "Home",
@@ -121,6 +126,7 @@ translation_strings = {
"Manage comments": "Reacties beheren",
"Manage media": "Media beheren",
"Manage users": "Gebruikers beheren",
"Management": "",
"Media": "Media",
"Media I own": "Media die ik bezit",
"Media was edited": "Media is bewerkt",
@@ -137,6 +143,7 @@ translation_strings = {
"No results for": "Geen resultaten voor",
"No tags": "Geen tags",
"No users to add": "Geen gebruikers om toe te voegen",
"Organization": "",
"PLAYLISTS": "AFSPEELLIJSTEN",
"PUBLISH STATE": "PUBLICATIESTATUS",
"Pdf": "PDF",
@@ -156,12 +163,17 @@ translation_strings = {
"Published on": "Gepubliceerd op",
"Recent uploads": "Recente uploads",
"Recommended": "Aanbevolen",
"Record": "",
"Record Screen": "Scherm opnemen",
"Record Screen with Audio": "",
"Register": "Registreren",
"Remove category": "Categorie verwijderen",
"Remove from list": "Verwijderen uit lijst",
"Remove tag": "Tag verwijderen",
"Remove user": "Gebruiker verwijderen",
"Remove users from the list to remove editor permissions": "",
"Remove users from the list to remove owner permissions": "",
"Remove users from the list to remove viewer permissions": "",
"Replace": "",
"SAVE": "OPSLAAN",
"SEARCH": "ZOEKEN",
@@ -178,14 +190,22 @@ translation_strings = {
"Select all media": "Alle media selecteren",
"Select publish state:": "Selecteer publicatiestatus:",
"Selected": "Geselecteerd",
"Settings": "",
"Share with": "",
"Share with Co-Editors": "",
"Share with Co-Owners": "",
"Share with Co-Viewers": "",
"Share with Course Members": "",
"Shared by me": "Gedeeld door mij",
"Shared with me": "Gedeeld met mij",
"Sharing": "",
"Sign in": "Inloggen",
"Sign out": "Uitloggen",
"Sort By": "Sorteer op",
"Start Recording": "Opname starten",
"Start uploading media and sharing your work. Media that you upload will show up here.": "Begin met het uploaden van media en het delen van uw werk. Media die u uploadt, verschijnt hier.",
"Stop Recording": "Opname stoppen",
"Students will get viewer permissions, while lecturers will get co-owner permissions (same as owner, but cannot delete the media)": "",
"Submit": "Indienen",
"Subtitle was added": "Ondertitel is toegevoegd",
"Subtitles": "Ondertitels",
@@ -196,6 +216,7 @@ translation_strings = {
"Successfully Enabled comments": "Reacties succesvol ingeschakeld",
"Successfully changed owner": "Eigenaar succesvol gewijzigd",
"Successfully deleted": "Succesvol verwijderd",
"Successfully deleted comments": "",
"Successfully updated": "Succesvol bijgewerkt",
"Successfully updated categories": "Categorieën succesvol bijgewerkt",
"Successfully updated playlist membership": "Afspeellijstlidmaatschap succesvol bijgewerkt",
@@ -232,6 +253,9 @@ translation_strings = {
"Upload media": "Media uploaden",
"Uploads": "Uploads",
"Users": "Gebruikers",
"Users can edit your media via: My Media > Shared with Me > particular media > Edit...": "",
"Users can manage your media via: My Media > Shared with Me > particular media > ...": "",
"Users can view your media via: My Media > Shared with Me > particular media > ...": "",
"VIEW ALL": "BEKIJK ALLES",
"Video": "Video",
"View all": "Bekijk alles",
@@ -240,6 +264,7 @@ translation_strings = {
"Welcome": "Welkom",
"You are going to copy": "Je gaat kopiëren",
"You are going to delete": "Je gaat verwijderen",
"You are going to delete all comments from": "",
"You are going to disable comments to": "Je gaat reacties uitschakelen voor",
"You are going to disable download for": "Je gaat download uitschakelen voor",
"You are going to enable comments to": "Je gaat reacties inschakelen voor",

View File

@@ -48,6 +48,7 @@ translation_strings = {
"DELETE MEDIA": "EXCLUIR MÍDIA",
"DOWNLOAD": "BAIXAR",
"DURATION": "DURAÇÃO",
"Delete Comments": "",
"Delete Media": "Excluir mídia",
"Delete media": "Excluir mídia",
"Disable Comments": "Desativar comentários",
@@ -70,6 +71,7 @@ translation_strings = {
"Failed to change owner. Please try again.": "Falha ao mudar proprietário. Por favor, tente novamente.",
"Failed to copy media.": "Falha ao copiar mídia.",
"Failed to create playlist": "Falha ao criar playlist",
"Failed to delete comments.": "",
"Failed to delete media. Please try again.": "Falha ao excluir mídia. Por favor, tente novamente.",
"Failed to disable comments.": "Falha ao desativar comentários.",
"Failed to disable download.": "Falha ao desativar download.",
@@ -101,6 +103,9 @@ translation_strings = {
"Filter existing users...": "Filtrar usuários existentes...",
"Filter playlists...": "Filtrar playlists...",
"Filters": "Filtros",
"Give users editor permissions to your media by adding them to the below list.": "",
"Give users owner permissions to your media, except for deleting the media, by adding them to the below list.": "",
"Give users viewer permissions to your media by adding them to the below list.": "",
"Go": "Ir",
"History": "Histórico",
"Home": "Início",
@@ -121,6 +126,7 @@ translation_strings = {
"Manage comments": "Gerenciar comentários",
"Manage media": "Gerenciar mídia",
"Manage users": "Gerenciar usuários",
"Management": "",
"Media": "Mídia",
"Media I own": "Mídia que possuo",
"Media was edited": "Mídia foi editada",
@@ -137,6 +143,7 @@ translation_strings = {
"No results for": "Nenhum resultado para",
"No tags": "Nenhuma tag",
"No users to add": "Nenhum usuário para adicionar",
"Organization": "",
"PLAYLISTS": "PLAYLISTS",
"PUBLISH STATE": "ESTADO DE PUBLICAÇÃO",
"Pdf": "PDF",
@@ -156,12 +163,17 @@ translation_strings = {
"Published on": "Publicado em",
"Recent uploads": "Uploads recentes",
"Recommended": "Recomendado",
"Record": "",
"Record Screen": "Gravar tela",
"Record Screen with Audio": "",
"Register": "Registrar",
"Remove category": "Remover categoria",
"Remove from list": "Remover da lista",
"Remove tag": "Remover tag",
"Remove user": "Remover usuário",
"Remove users from the list to remove editor permissions": "",
"Remove users from the list to remove owner permissions": "",
"Remove users from the list to remove viewer permissions": "",
"Replace": "",
"SAVE": "SALVAR",
"SEARCH": "PESQUISAR",
@@ -178,14 +190,22 @@ translation_strings = {
"Select all media": "Selecionar todas as mídias",
"Select publish state:": "Selecionar estado de publicação:",
"Selected": "Selecionado",
"Settings": "",
"Share with": "",
"Share with Co-Editors": "",
"Share with Co-Owners": "",
"Share with Co-Viewers": "",
"Share with Course Members": "",
"Shared by me": "Compartilhado por mim",
"Shared with me": "Compartilhado comigo",
"Sharing": "",
"Sign in": "Entrar",
"Sign out": "Sair",
"Sort By": "Ordenar por",
"Start Recording": "Iniciar gravação",
"Start uploading media and sharing your work. Media that you upload will show up here.": "Comece a fazer upload de mídia e compartilhar seu trabalho. A mídia que você fizer upload aparecerá aqui.",
"Stop Recording": "Parar gravação",
"Students will get viewer permissions, while lecturers will get co-owner permissions (same as owner, but cannot delete the media)": "",
"Submit": "Enviar",
"Subtitle was added": "Legenda foi adicionada",
"Subtitles": "Legendas",
@@ -196,6 +216,7 @@ translation_strings = {
"Successfully Enabled comments": "Comentários ativados com sucesso",
"Successfully changed owner": "Proprietário alterado com sucesso",
"Successfully deleted": "Excluído com sucesso",
"Successfully deleted comments": "",
"Successfully updated": "Atualizado com sucesso",
"Successfully updated categories": "Categorias atualizadas com sucesso",
"Successfully updated playlist membership": "Associação da playlist atualizada com sucesso",
@@ -232,6 +253,9 @@ translation_strings = {
"Upload media": "Carregar mídia",
"Uploads": "Uploads",
"Users": "Usuários",
"Users can edit your media via: My Media > Shared with Me > particular media > Edit...": "",
"Users can manage your media via: My Media > Shared with Me > particular media > ...": "",
"Users can view your media via: My Media > Shared with Me > particular media > ...": "",
"VIEW ALL": "VER TODOS",
"Video": "Vídeo",
"View all": "Ver todos",
@@ -240,6 +264,7 @@ translation_strings = {
"Welcome": "Bem-vindo",
"You are going to copy": "Você vai copiar",
"You are going to delete": "Você vai excluir",
"You are going to delete all comments from": "",
"You are going to disable comments to": "Você vai desativar comentários de",
"You are going to disable download for": "Você vai desativar download de",
"You are going to enable comments to": "Você vai ativar comentários de",

View File

@@ -48,6 +48,7 @@ translation_strings = {
"DELETE MEDIA": "УДАЛИТЬ МЕДИА",
"DOWNLOAD": "СКАЧАТЬ",
"DURATION": "ДЛИТЕЛЬНОСТЬ",
"Delete Comments": "",
"Delete Media": "Удалить медиа",
"Delete media": "Удалить медиа",
"Disable Comments": "Отключить комментарии",
@@ -70,6 +71,7 @@ translation_strings = {
"Failed to change owner. Please try again.": "Не удалось изменить владельца. Пожалуйста, попробуйте снова.",
"Failed to copy media.": "Не удалось скопировать медиа.",
"Failed to create playlist": "Не удалось создать плейлист",
"Failed to delete comments.": "",
"Failed to delete media. Please try again.": "Не удалось удалить медиа. Пожалуйста, попробуйте снова.",
"Failed to disable comments.": "Не удалось отключить комментарии.",
"Failed to disable download.": "Не удалось отключить загрузку.",
@@ -101,6 +103,9 @@ translation_strings = {
"Filter existing users...": "Фильтровать существующих пользователей...",
"Filter playlists...": "Фильтровать плейлисты...",
"Filters": "Фильтры",
"Give users editor permissions to your media by adding them to the below list.": "",
"Give users owner permissions to your media, except for deleting the media, by adding them to the below list.": "",
"Give users viewer permissions to your media by adding them to the below list.": "",
"Go": "Перейти",
"History": "История",
"Home": "Главная",
@@ -121,6 +126,7 @@ translation_strings = {
"Manage comments": "Управление комментариями",
"Manage media": "Управление медиа",
"Manage users": "Управление пользователями",
"Management": "",
"Media": "Медиа",
"Media I own": "Медиа, которыми я владею",
"Media was edited": "Медиа было отредактировано",
@@ -137,6 +143,7 @@ translation_strings = {
"No results for": "Нет результатов для",
"No tags": "Нет тегов",
"No users to add": "Нет пользователей для добавления",
"Organization": "",
"PLAYLISTS": "ПЛЕЙЛИСТЫ",
"PUBLISH STATE": "СОСТОЯНИЕ ПУБЛИКАЦИИ",
"Pdf": "PDF",
@@ -156,12 +163,17 @@ translation_strings = {
"Published on": "Опубликовано",
"Recent uploads": "Недавние загрузки",
"Recommended": "Рекомендуемое",
"Record": "",
"Record Screen": "Запись экрана",
"Record Screen with Audio": "",
"Register": "Регистрация",
"Remove category": "Удалить категорию",
"Remove from list": "Удалить из списка",
"Remove tag": "Удалить тег",
"Remove user": "Удалить пользователя",
"Remove users from the list to remove editor permissions": "",
"Remove users from the list to remove owner permissions": "",
"Remove users from the list to remove viewer permissions": "",
"Replace": "",
"SAVE": "СОХРАНИТЬ",
"SEARCH": "ПОИСК",
@@ -178,14 +190,22 @@ translation_strings = {
"Select all media": "Выбрать все медиа",
"Select publish state:": "Выберите состояние публикации:",
"Selected": "Выбрано",
"Settings": "",
"Share with": "",
"Share with Co-Editors": "",
"Share with Co-Owners": "",
"Share with Co-Viewers": "",
"Share with Course Members": "",
"Shared by me": "Мной поделено",
"Shared with me": "Поделено со мной",
"Sharing": "",
"Sign in": "Войти",
"Sign out": "Выйти",
"Sort By": "Сортировать по",
"Start Recording": "Начать запись",
"Start uploading media and sharing your work. Media that you upload will show up here.": "Начните загружать медиа и делиться своей работой. Загруженные медиа появятся здесь.",
"Stop Recording": "Остановить запись",
"Students will get viewer permissions, while lecturers will get co-owner permissions (same as owner, but cannot delete the media)": "",
"Submit": "Отправить",
"Subtitle was added": "Субтитры были добавлены",
"Subtitles": "Субтитры",
@@ -196,6 +216,7 @@ translation_strings = {
"Successfully Enabled comments": "Комментарии успешно включены",
"Successfully changed owner": "Владелец успешно изменен",
"Successfully deleted": "Успешно удалено",
"Successfully deleted comments": "",
"Successfully updated": "Успешно обновлено",
"Successfully updated categories": "Категории успешно обновлены",
"Successfully updated playlist membership": "Членство в плейлисте успешно обновлено",
@@ -232,6 +253,9 @@ translation_strings = {
"Upload media": "Загрузить медиа",
"Uploads": "Загрузки",
"Users": "Пользователи",
"Users can edit your media via: My Media > Shared with Me > particular media > Edit...": "",
"Users can manage your media via: My Media > Shared with Me > particular media > ...": "",
"Users can view your media via: My Media > Shared with Me > particular media > ...": "",
"VIEW ALL": "ПОКАЗАТЬ ВСЕ",
"Video": "Видео",
"View all": "Показать все",
@@ -240,6 +264,7 @@ translation_strings = {
"Welcome": "Добро пожаловать",
"You are going to copy": "Вы собираетесь скопировать",
"You are going to delete": "Вы собираетесь удалить",
"You are going to delete all comments from": "",
"You are going to disable comments to": "Вы собираетесь отключить комментарии для",
"You are going to disable download for": "Вы собираетесь отключить загрузку для",
"You are going to enable comments to": "Вы собираетесь включить комментарии для",

View File

@@ -48,6 +48,7 @@ translation_strings = {
"DELETE MEDIA": "IZBRIŠI MEDIJ",
"DOWNLOAD": "PRENESI",
"DURATION": "TRAJANJE",
"Delete Comments": "",
"Delete Media": "Izbriši Medij",
"Delete media": "Izbriši medij",
"Disable Comments": "Onemogoči Komentarje",
@@ -70,6 +71,7 @@ translation_strings = {
"Failed to change owner. Please try again.": "Spreminjanje lastnika ni uspelo. Prosim poskusite ponovno.",
"Failed to copy media.": "Kopiranje medija ni uspelo.",
"Failed to create playlist": "Ustvarjanje seznama predvajanja ni uspelo",
"Failed to delete comments.": "",
"Failed to delete media. Please try again.": "Brisanje medija ni uspelo. Prosim poskusite ponovno.",
"Failed to disable comments.": "Onemogočanje komentarjev ni uspelo.",
"Failed to disable download.": "Onemogočanje prenosa ni uspelo.",
@@ -101,6 +103,9 @@ translation_strings = {
"Filter existing users...": "Filtriraj obstoječe uporabnike...",
"Filter playlists...": "Filtriraj sezname predvajanja...",
"Filters": "Filtri",
"Give users editor permissions to your media by adding them to the below list.": "",
"Give users owner permissions to your media, except for deleting the media, by adding them to the below list.": "",
"Give users viewer permissions to your media by adding them to the below list.": "",
"Go": "Pojdi",
"History": "Zgodovina",
"Home": "Domov",
@@ -121,6 +126,7 @@ translation_strings = {
"Manage comments": "Upravljaj komentarje",
"Manage media": "Upravljaj medije",
"Manage users": "Upravljaj uporabnike",
"Management": "",
"Media": "Mediji",
"Media I own": "Mediji, ki jih posedujam",
"Media was edited": "Medij je bil urejen",
@@ -137,6 +143,7 @@ translation_strings = {
"No results for": "Ni rezultatov za",
"No tags": "Brez oznak",
"No users to add": "Ni uporabnikov za dodajanje",
"Organization": "",
"PLAYLISTS": "SEZNAMI PREDVAJANJA",
"PUBLISH STATE": "STANJE OBJAVE",
"Pdf": "PDF",
@@ -156,12 +163,17 @@ translation_strings = {
"Published on": "Objavljeno",
"Recent uploads": "Nedavne naložitve",
"Recommended": "Priporočeno",
"Record": "",
"Record Screen": "Snemanje zaslona",
"Record Screen with Audio": "",
"Register": "Registracija",
"Remove category": "Odstrani kategorijo",
"Remove from list": "Odstrani s seznama",
"Remove tag": "Odstrani oznako",
"Remove user": "Odstrani uporabnika",
"Remove users from the list to remove editor permissions": "",
"Remove users from the list to remove owner permissions": "",
"Remove users from the list to remove viewer permissions": "",
"Replace": "",
"SAVE": "SHRANI",
"SEARCH": "ISKANJE",
@@ -178,14 +190,22 @@ translation_strings = {
"Select all media": "Izberi vse medije",
"Select publish state:": "Izberi stanje objave:",
"Selected": "Izbrano",
"Settings": "",
"Share with": "",
"Share with Co-Editors": "",
"Share with Co-Owners": "",
"Share with Co-Viewers": "",
"Share with Course Members": "",
"Shared by me": "Deljeno z moje strani",
"Shared with me": "Deljeno z mano",
"Sharing": "",
"Sign in": "Prijava",
"Sign out": "Odjava",
"Sort By": "Razvrsti po",
"Start Recording": "Začni snemanje",
"Start uploading media and sharing your work. Media that you upload will show up here.": "Začnite nalagati medije in deliti svoje delo. Mediji, ki jih naložite, bodo prikazani tukaj.",
"Stop Recording": "Ustavi snemanje",
"Students will get viewer permissions, while lecturers will get co-owner permissions (same as owner, but cannot delete the media)": "",
"Submit": "Pošlji",
"Subtitle was added": "Podnapisi so bili dodani",
"Subtitles": "Podnapisi",
@@ -196,6 +216,7 @@ translation_strings = {
"Successfully Enabled comments": "Komentarji uspešno omogočeni",
"Successfully changed owner": "Lastnik uspešno spremenjen",
"Successfully deleted": "Uspešno izbrisano",
"Successfully deleted comments": "",
"Successfully updated": "Uspešno posodobljeno",
"Successfully updated categories": "Kategorije uspešno posodobljene",
"Successfully updated playlist membership": "Članstvo seznama predvajanja uspešno posodobljeno",
@@ -232,6 +253,9 @@ translation_strings = {
"Upload media": "Naloži medij",
"Uploads": "Naloženi",
"Users": "Uporabniki",
"Users can edit your media via: My Media > Shared with Me > particular media > Edit...": "",
"Users can manage your media via: My Media > Shared with Me > particular media > ...": "",
"Users can view your media via: My Media > Shared with Me > particular media > ...": "",
"VIEW ALL": "PRIKAŽI VSE",
"Video": "Video",
"View all": "Prikaži vse",
@@ -240,6 +264,7 @@ translation_strings = {
"Welcome": "Dobrodošli",
"You are going to copy": "Kopirate",
"You are going to delete": "Brišete",
"You are going to delete all comments from": "",
"You are going to disable comments to": "Onemogočate komentarje za",
"You are going to disable download for": "Onemogočate prenos za",
"You are going to enable comments to": "Omogočate komentarje za",

View File

@@ -48,6 +48,7 @@ translation_strings = {
"DELETE MEDIA": "MEDYAYI SİL",
"DOWNLOAD": "İNDİR",
"DURATION": "SÜRE",
"Delete Comments": "",
"Delete Media": "Medyayı Sil",
"Delete media": "Medyayı sil",
"Disable Comments": "Yorumları Devre Dışı Bırak",
@@ -70,6 +71,7 @@ translation_strings = {
"Failed to change owner. Please try again.": "Sahip değiştirilemedi. Lütfen tekrar deneyin.",
"Failed to copy media.": "Medya kopyalanamadı.",
"Failed to create playlist": "Çalma listesi oluşturulamadı",
"Failed to delete comments.": "",
"Failed to delete media. Please try again.": "Medya silinemedi. Lütfen tekrar deneyin.",
"Failed to disable comments.": "Yorumlar devre dışı bırakılamadı.",
"Failed to disable download.": "İndirme devre dışı bırakılamadı.",
@@ -101,6 +103,9 @@ translation_strings = {
"Filter existing users...": "Mevcut kullanıcıları filtrele...",
"Filter playlists...": "Çalma listelerini filtrele...",
"Filters": "Filtreler",
"Give users editor permissions to your media by adding them to the below list.": "",
"Give users owner permissions to your media, except for deleting the media, by adding them to the below list.": "",
"Give users viewer permissions to your media by adding them to the below list.": "",
"Go": "Git",
"History": "Geçmiş",
"Home": "Ana Sayfa",
@@ -121,6 +126,7 @@ translation_strings = {
"Manage comments": "Yorumları yönet",
"Manage media": "Medyayı yönet",
"Manage users": "Kullanıcıları yönet",
"Management": "",
"Media": "Medya",
"Media I own": "Sahip olduğum medya",
"Media was edited": "Medya düzenlendi",
@@ -137,6 +143,7 @@ translation_strings = {
"No results for": "Sonuç bulunamadı",
"No tags": "Etiket yok",
"No users to add": "Eklenecek kullanıcı yok",
"Organization": "",
"PLAYLISTS": "ÇALMA LİSTELERİ",
"PUBLISH STATE": "YAYINLANMA DURUMU",
"Pdf": "PDF",
@@ -156,12 +163,17 @@ translation_strings = {
"Published on": "Yayınlanma tarihi",
"Recent uploads": "Son yüklemeler",
"Recommended": "Önerilen",
"Record": "",
"Record Screen": "Ekranı Kaydet",
"Record Screen with Audio": "",
"Register": "Kayıt Ol",
"Remove category": "Kategoriyi kaldır",
"Remove from list": "Listeden kaldır",
"Remove tag": "Etiketi kaldır",
"Remove user": "Kullanıcıyı kaldır",
"Remove users from the list to remove editor permissions": "",
"Remove users from the list to remove owner permissions": "",
"Remove users from the list to remove viewer permissions": "",
"Replace": "",
"SAVE": "KAYDET",
"SEARCH": "ARA",
@@ -178,14 +190,22 @@ translation_strings = {
"Select all media": "Tüm medyayı seç",
"Select publish state:": "Yayınlanma durumunu seç:",
"Selected": "Seçildi",
"Settings": "",
"Share with": "",
"Share with Co-Editors": "",
"Share with Co-Owners": "",
"Share with Co-Viewers": "",
"Share with Course Members": "",
"Shared by me": "Paylaştıklarım",
"Shared with me": "Benimle paylaşılanlar",
"Sharing": "",
"Sign in": "Giriş Yap",
"Sign out": "Çıkış Yap",
"Sort By": "Sırala",
"Start Recording": "Kaydı Başlat",
"Start uploading media and sharing your work. Media that you upload will show up here.": "Medya yüklemeye ve çalışmanızı paylaşmaya başlayın. Yüklediğiniz medya burada görünecektir.",
"Stop Recording": "Kaydı Durdur",
"Students will get viewer permissions, while lecturers will get co-owner permissions (same as owner, but cannot delete the media)": "",
"Submit": "Gönder",
"Subtitle was added": "Alt yazı eklendi",
"Subtitles": "Altyazılar",
@@ -196,6 +216,7 @@ translation_strings = {
"Successfully Enabled comments": "Yorumlar başarıyla etkinleştirildi",
"Successfully changed owner": "Sahip başarıyla değiştirildi",
"Successfully deleted": "Başarıyla silindi",
"Successfully deleted comments": "",
"Successfully updated": "Başarıyla güncellendi",
"Successfully updated categories": "Kategoriler başarıyla güncellendi",
"Successfully updated playlist membership": "Çalma listesi üyeliği başarıyla güncellendi",
@@ -232,6 +253,9 @@ translation_strings = {
"Upload media": "Medya yükle",
"Uploads": "Yüklemeler",
"Users": "Kullanıcılar",
"Users can edit your media via: My Media > Shared with Me > particular media > Edit...": "",
"Users can manage your media via: My Media > Shared with Me > particular media > ...": "",
"Users can view your media via: My Media > Shared with Me > particular media > ...": "",
"VIEW ALL": "HEPSİNİ GÖR",
"Video": "Video",
"View all": "Hepsini gör",
@@ -240,6 +264,7 @@ translation_strings = {
"Welcome": "Hoş geldiniz",
"You are going to copy": "Kopyalayacaksınız",
"You are going to delete": "Sileceksiniz",
"You are going to delete all comments from": "",
"You are going to disable comments to": "Yorumları devre dışı bırakacaksınız",
"You are going to disable download for": "İndirmeyi devre dışı bırakacaksınız",
"You are going to enable comments to": "Yorumları etkinleştireceksiniz",

View File

@@ -48,6 +48,7 @@ translation_strings = {
"DELETE MEDIA": "میڈیا حذف کریں",
"DOWNLOAD": "ڈاؤن لوڈ",
"DURATION": "دورانیہ",
"Delete Comments": "",
"Delete Media": "میڈیا حذف کریں",
"Delete media": "میڈیا حذف کریں",
"Disable Comments": "تبصرے غیر فعال کریں",
@@ -70,6 +71,7 @@ translation_strings = {
"Failed to change owner. Please try again.": "مالک تبدیل کرنے میں ناکام۔ براہ کرم دوبارہ کوشش کریں۔",
"Failed to copy media.": "میڈیا کاپی کرنے میں ناکام۔",
"Failed to create playlist": "پلے لسٹ بنانے میں ناکام",
"Failed to delete comments.": "",
"Failed to delete media. Please try again.": "میڈیا حذف کرنے میں ناکام۔ براہ کرم دوبارہ کوشش کریں۔",
"Failed to disable comments.": "تبصرے غیر فعال کرنے میں ناکام۔",
"Failed to disable download.": "ڈاؤن لوڈ غیر فعال کرنے میں ناکام۔",
@@ -101,6 +103,9 @@ translation_strings = {
"Filter existing users...": "موجودہ صارفین فلٹر کریں...",
"Filter playlists...": "پلے لسٹس فلٹر کریں...",
"Filters": "فلٹرز",
"Give users editor permissions to your media by adding them to the below list.": "",
"Give users owner permissions to your media, except for deleting the media, by adding them to the below list.": "",
"Give users viewer permissions to your media by adding them to the below list.": "",
"Go": "جائیں",
"History": "تاریخ",
"Home": "ہوم",
@@ -121,6 +126,7 @@ translation_strings = {
"Manage comments": "تبصرے منظم کریں",
"Manage media": "میڈیا منظم کریں",
"Manage users": "صارفین منظم کریں",
"Management": "",
"Media": "میڈیا",
"Media I own": "",
"Media was edited": "میڈیا ترمیم کیا گیا",
@@ -137,6 +143,7 @@ translation_strings = {
"No results for": "کے لئے کوئی نتائج نہیں",
"No tags": "کوئی ٹیگز نہیں",
"No users to add": "شامل کرنے کے لیے کوئی صارف نہیں",
"Organization": "",
"PLAYLISTS": "پلے لسٹس",
"PUBLISH STATE": "اشاعت کی حالت",
"Pdf": "PDF",
@@ -156,12 +163,17 @@ translation_strings = {
"Published on": "پر شائع ہوا",
"Recent uploads": "حالیہ اپ لوڈز",
"Recommended": "تجویز کردہ",
"Record": "",
"Record Screen": "اسکرین ریکارڈ کریں",
"Record Screen with Audio": "",
"Register": "رجسٹر کریں",
"Remove category": "قسم ہٹائیں",
"Remove from list": "فہرست سے ہٹائیں",
"Remove tag": "ٹیگ ہٹائیں",
"Remove user": "صارف ہٹائیں",
"Remove users from the list to remove editor permissions": "",
"Remove users from the list to remove owner permissions": "",
"Remove users from the list to remove viewer permissions": "",
"Replace": "",
"SAVE": "محفوظ کریں",
"SEARCH": "تلاش کریں",
@@ -178,14 +190,22 @@ translation_strings = {
"Select all media": "تمام میڈیا منتخب کریں",
"Select publish state:": "اشاعت کی حالت منتخب کریں:",
"Selected": "منتخب شدہ",
"Settings": "",
"Share with": "",
"Share with Co-Editors": "",
"Share with Co-Owners": "",
"Share with Co-Viewers": "",
"Share with Course Members": "",
"Shared by me": "میری طرف سے شیئر کیا گیا",
"Shared with me": "میرے ساتھ شیئر کیا گیا",
"Sharing": "",
"Sign in": "سائن ان کریں",
"Sign out": "سائن آؤٹ کریں",
"Sort By": "ترتیب دیں",
"Start Recording": "ریکارڈنگ شروع کریں",
"Start uploading media and sharing your work. Media that you upload will show up here.": "میڈیا اپ لوڈ کرنا اور اپنا کام شیئر کرنا شروع کریں۔ آپ جو میڈیا اپ لوڈ کرتے ہیں وہ یہاں ظاہر ہوگا۔",
"Stop Recording": "ریکارڈنگ روکیں",
"Students will get viewer permissions, while lecturers will get co-owner permissions (same as owner, but cannot delete the media)": "",
"Submit": "جمع کرائیں",
"Subtitle was added": "سب ٹائٹل شامل کیا گیا",
"Subtitles": "سب ٹائٹلز",
@@ -196,6 +216,7 @@ translation_strings = {
"Successfully Enabled comments": "تبصرے کامیابی سے فعال ہو گئے",
"Successfully changed owner": "مالک کامیابی سے تبدیل ہو گیا",
"Successfully deleted": "کامیابی سے حذف ہو گیا",
"Successfully deleted comments": "",
"Successfully updated": "کامیابی سے اپ ڈیٹ ہو گیا",
"Successfully updated categories": "اقسام کامیابی سے اپ ڈیٹ ہو گئیں",
"Successfully updated playlist membership": "پلے لسٹ ممبرشپ کامیابی سے اپ ڈیٹ ہو گئی",
@@ -232,6 +253,9 @@ translation_strings = {
"Upload media": "میڈیا اپ لوڈ کریں",
"Uploads": "اپ لوڈز",
"Users": "صارفین",
"Users can edit your media via: My Media > Shared with Me > particular media > Edit...": "",
"Users can manage your media via: My Media > Shared with Me > particular media > ...": "",
"Users can view your media via: My Media > Shared with Me > particular media > ...": "",
"VIEW ALL": "سب دیکھیں",
"Video": "ویڈیو",
"View all": "سب دیکھیں",
@@ -240,6 +264,7 @@ translation_strings = {
"Welcome": "خوش آمدید",
"You are going to copy": "آپ کاپی کرنے جا رہے ہیں",
"You are going to delete": "آپ حذف کرنے جا رہے ہیں",
"You are going to delete all comments from": "",
"You are going to disable comments to": "آپ تبصرے غیر فعال کرنے جا رہے ہیں",
"You are going to disable download for": "آپ ڈاؤن لوڈ غیر فعال کرنے جا رہے ہیں",
"You are going to enable comments to": "آپ تبصرے فعال کرنے جا رہے ہیں",

View File

@@ -48,6 +48,7 @@ translation_strings = {
"DELETE MEDIA": "删除媒体",
"DOWNLOAD": "下载",
"DURATION": "时长",
"Delete Comments": "",
"Delete Media": "",
"Delete media": "删除媒体",
"Disable Comments": "",
@@ -70,6 +71,7 @@ translation_strings = {
"Failed to change owner. Please try again.": "",
"Failed to copy media.": "复制媒体失败。",
"Failed to create playlist": "",
"Failed to delete comments.": "",
"Failed to delete media. Please try again.": "删除媒体失败。请重试。",
"Failed to disable comments.": "禁用评论失败。",
"Failed to disable download.": "禁用下载失败。",
@@ -101,6 +103,9 @@ translation_strings = {
"Filter existing users...": "",
"Filter playlists...": "",
"Filters": "筛选",
"Give users editor permissions to your media by adding them to the below list.": "",
"Give users owner permissions to your media, except for deleting the media, by adding them to the below list.": "",
"Give users viewer permissions to your media by adding them to the below list.": "",
"Go": "",
"History": "历史",
"Home": "主页",
@@ -121,6 +126,7 @@ translation_strings = {
"Manage comments": "管理评论",
"Manage media": "管理媒体",
"Manage users": "管理用户",
"Management": "",
"Media": "媒体",
"Media I own": "",
"Media was edited": "媒体已编辑",
@@ -137,6 +143,7 @@ translation_strings = {
"No results for": "没有结果",
"No tags": "",
"No users to add": "",
"Organization": "",
"PLAYLISTS": "播放列表",
"PUBLISH STATE": "发布状态",
"Pdf": "PDF",
@@ -156,12 +163,17 @@ translation_strings = {
"Published on": "发布于",
"Recent uploads": "最近上传",
"Recommended": "推荐",
"Record": "",
"Record Screen": "录制屏幕",
"Record Screen with Audio": "",
"Register": "注册",
"Remove category": "",
"Remove from list": "",
"Remove tag": "",
"Remove user": "",
"Remove users from the list to remove editor permissions": "",
"Remove users from the list to remove owner permissions": "",
"Remove users from the list to remove viewer permissions": "",
"Replace": "",
"SAVE": "保存",
"SEARCH": "搜索",
@@ -178,14 +190,22 @@ translation_strings = {
"Select all media": "",
"Select publish state:": "",
"Selected": "",
"Settings": "",
"Share with": "",
"Share with Co-Editors": "",
"Share with Co-Owners": "",
"Share with Co-Viewers": "",
"Share with Course Members": "",
"Shared by me": "我分享的",
"Shared with me": "分享给我的",
"Sharing": "",
"Sign in": "登录",
"Sign out": "登出",
"Sort By": "排序方式",
"Start Recording": "开始录制",
"Start uploading media and sharing your work. Media that you upload will show up here.": "开始上传媒体并分享您的作品。您上传的媒体将显示在这里。",
"Stop Recording": "停止录制",
"Students will get viewer permissions, while lecturers will get co-owner permissions (same as owner, but cannot delete the media)": "",
"Submit": "",
"Subtitle was added": "字幕已添加",
"Subtitles": "字幕",
@@ -196,6 +216,7 @@ translation_strings = {
"Successfully Enabled comments": "评论已成功启用",
"Successfully changed owner": "",
"Successfully deleted": "删除成功",
"Successfully deleted comments": "",
"Successfully updated": "",
"Successfully updated categories": "",
"Successfully updated playlist membership": "",
@@ -232,6 +253,9 @@ translation_strings = {
"Upload media": "上传媒体",
"Uploads": "上传",
"Users": "",
"Users can edit your media via: My Media > Shared with Me > particular media > Edit...": "",
"Users can manage your media via: My Media > Shared with Me > particular media > ...": "",
"Users can view your media via: My Media > Shared with Me > particular media > ...": "",
"VIEW ALL": "查看全部",
"Video": "视频",
"View all": "查看全部",
@@ -240,6 +264,7 @@ translation_strings = {
"Welcome": "欢迎",
"You are going to copy": "您将复制",
"You are going to delete": "您将删除",
"You are going to delete all comments from": "",
"You are going to disable comments to": "您将禁用评论",
"You are going to disable download for": "您将禁用下载",
"You are going to enable comments to": "您将启用评论",

View File

@@ -48,6 +48,7 @@ translation_strings = {
"DELETE MEDIA": "刪除影片",
"DOWNLOAD": "下載",
"DURATION": "時長",
"Delete Comments": "",
"Delete Media": "",
"Delete media": "刪除媒體",
"Disable Comments": "",
@@ -70,6 +71,7 @@ translation_strings = {
"Failed to change owner. Please try again.": "",
"Failed to copy media.": "複製媒體失敗。",
"Failed to create playlist": "",
"Failed to delete comments.": "",
"Failed to delete media. Please try again.": "刪除媒體失敗。請再試一次。",
"Failed to disable comments.": "停用留言失敗。",
"Failed to disable download.": "停用下載失敗。",
@@ -101,6 +103,9 @@ translation_strings = {
"Filter existing users...": "",
"Filter playlists...": "",
"Filters": "篩選器",
"Give users editor permissions to your media by adding them to the below list.": "",
"Give users owner permissions to your media, except for deleting the media, by adding them to the below list.": "",
"Give users viewer permissions to your media by adding them to the below list.": "",
"Go": "執行",
"History": "觀看紀錄",
"Home": "首頁",
@@ -121,6 +126,7 @@ translation_strings = {
"Manage comments": "留言管理",
"Manage media": "媒體管理",
"Manage users": "使用者管理",
"Management": "",
"Media": "媒體",
"Media I own": "",
"Media was edited": "媒體已更新",
@@ -137,6 +143,7 @@ translation_strings = {
"No results for": "查無相關結果:",
"No tags": "",
"No users to add": "",
"Organization": "",
"PLAYLISTS": "播放清單",
"PUBLISH STATE": "發布狀態",
"Pdf": "PDF",
@@ -156,12 +163,17 @@ translation_strings = {
"Published on": "發布日期為",
"Recent uploads": "最近上傳",
"Recommended": "推薦內容",
"Record": "",
"Record Screen": "螢幕錄製",
"Record Screen with Audio": "",
"Register": "註冊",
"Remove category": "",
"Remove from list": "",
"Remove tag": "",
"Remove user": "",
"Remove users from the list to remove editor permissions": "",
"Remove users from the list to remove owner permissions": "",
"Remove users from the list to remove viewer permissions": "",
"Replace": "",
"SAVE": "儲存",
"SEARCH": "搜尋",
@@ -178,14 +190,22 @@ translation_strings = {
"Select all media": "",
"Select publish state:": "",
"Selected": "",
"Settings": "",
"Share with": "",
"Share with Co-Editors": "",
"Share with Co-Owners": "",
"Share with Co-Viewers": "",
"Share with Course Members": "",
"Shared by me": "我分享的",
"Shared with me": "與我分享",
"Sharing": "",
"Sign in": "登入",
"Sign out": "登出",
"Sort By": "排序方式",
"Start Recording": "開始錄製",
"Start uploading media and sharing your work. Media that you upload will show up here.": "開始上傳媒體並分享您的作品。您上傳的媒體將顯示在此處。",
"Stop Recording": "停止錄製",
"Students will get viewer permissions, while lecturers will get co-owner permissions (same as owner, but cannot delete the media)": "",
"Submit": "",
"Subtitle was added": "字幕已新增",
"Subtitles": "字幕",
@@ -196,6 +216,7 @@ translation_strings = {
"Successfully Enabled comments": "成功啟用留言",
"Successfully changed owner": "",
"Successfully deleted": "成功刪除",
"Successfully deleted comments": "",
"Successfully updated": "",
"Successfully updated categories": "",
"Successfully updated playlist membership": "",
@@ -232,6 +253,9 @@ translation_strings = {
"Upload media": "上傳媒體",
"Uploads": "上傳內容",
"Users": "",
"Users can edit your media via: My Media > Shared with Me > particular media > Edit...": "",
"Users can manage your media via: My Media > Shared with Me > particular media > ...": "",
"Users can view your media via: My Media > Shared with Me > particular media > ...": "",
"VIEW ALL": "查看全部",
"Video": "影片",
"View all": "瀏覽全部",
@@ -240,6 +264,7 @@ translation_strings = {
"Welcome": "歡迎",
"You are going to copy": "您即將複製",
"You are going to delete": "您即將刪除",
"You are going to delete all comments from": "",
"You are going to disable comments to": "您即將停用留言",
"You are going to disable download for": "您即將停用下載",
"You are going to enable comments to": "您即將啟用留言",

View File

@@ -2,7 +2,7 @@ from datetime import datetime, timedelta
from django.conf import settings
from django.contrib.postgres.search import SearchQuery
from django.db.models import Count, Q
from django.db.models import Count, Prefetch, Q, prefetch_related_objects
from django.shortcuts import get_object_or_404
from drf_yasg import openapi
from drf_yasg.utils import swagger_auto_schema
@@ -35,6 +35,7 @@ from ..methods import (
)
from ..models import (
Category,
Comment,
EncodeProfile,
Media,
MediaPermission,
@@ -112,6 +113,8 @@ class MediaList(APIView):
upload_date = params.get('upload_date', '').strip()
duration = params.get('duration', '').strip()
publish_state = params.get('publish_state', '').strip()
shared_user = params.get('shared_user', '').strip()
shared_group = params.get('shared_group', '').strip()
query = params.get("q", "").strip().lower()
parsed_combined = False
@@ -152,6 +155,7 @@ class MediaList(APIView):
gte = datetime(year, 1, 1)
already_sorted = False
include_sharing_info = False
pagination_class = api_settings.DEFAULT_PAGINATION_CLASS
if show_param == "recommended":
@@ -164,7 +168,15 @@ class MediaList(APIView):
if not self.request.user.is_authenticated:
media = Media.objects.none()
else:
media = Media.objects.filter(permissions__owner_user=self.request.user).prefetch_related("user", "tags").distinct()
base_queryset = Media.objects.prefetch_related("user", "tags")
conditions = Q(permissions__owner_user=self.request.user)
if getattr(settings, 'USE_RBAC', False):
rbac_categories = request.user.get_rbac_categories_as_contributor()
conditions |= Q(category__in=rbac_categories, user=self.request.user)
media = base_queryset.filter(conditions).distinct()
include_sharing_info = True
elif show_param == "shared_with_me":
if not self.request.user.is_authenticated:
media = Media.objects.none()
@@ -184,6 +196,8 @@ class MediaList(APIView):
user = get_object_or_404(user_queryset, username=author_param)
if self.request.user == user or is_mediacms_editor(self.request.user):
media = Media.objects.filter(user=user).prefetch_related("user", "tags")
if self.request.user == user:
include_sharing_info = True
else:
media = self._get_media_queryset(request, user)
already_sorted = True
@@ -234,6 +248,12 @@ class MediaList(APIView):
elif publish_state in ['private', 'public', 'unlisted']:
media = media.filter(state=publish_state)
if shared_user and include_sharing_info:
media = media.filter(permissions__user__username=shared_user).distinct()
if shared_group and include_sharing_info:
media = media.filter(category__is_rbac_category=True, category__rbac_groups__name=shared_group).distinct()
if not already_sorted:
media = media.order_by(f"{ordering}{sort_by}")
@@ -243,6 +263,15 @@ class MediaList(APIView):
page = paginator.paginate_queryset(media, request)
prefetch_related_objects(page, 'tags')
if include_sharing_info:
prefetch_related_objects(
page,
Prefetch('permissions', queryset=MediaPermission.objects.select_related('user')),
Prefetch('category', queryset=Category.objects.filter(is_rbac_category=True).prefetch_related('rbac_groups'), to_attr='rbac_categories_prefetched'),
)
serializer = MediaSerializer(page, many=True, context={"request": request})
tags_set = set()
@@ -253,6 +282,19 @@ class MediaList(APIView):
response = paginator.get_paginated_response(serializer.data)
response.data['tags'] = tags
if include_sharing_info:
shared_users = {}
shared_groups = {}
for media_obj in page:
for perm in media_obj.permissions.all():
shared_users[perm.user.username] = {"username": perm.user.username, "name": perm.user.name or perm.user.username}
for cat in getattr(media_obj, 'rbac_categories_prefetched', []):
for group in cat.rbac_groups.all():
shared_groups[group.name] = {"name": group.name}
response.data['shared_users'] = list(shared_users.values())
response.data['shared_groups'] = list(shared_groups.values())
return response
@swagger_auto_schema(
@@ -295,6 +337,7 @@ class MediaBulkUserActions(APIView):
enum=[
"enable_comments",
"disable_comments",
"delete_comments",
"delete_media",
"enable_download",
"disable_download",
@@ -379,6 +422,10 @@ class MediaBulkUserActions(APIView):
media.update(enable_comments=False)
return Response({"detail": f"Comments disabled for {media.count()} media items"})
elif action == "delete_comments":
deleted_count, _ = Comment.objects.filter(media__in=media).delete()
return Response({"detail": f"{deleted_count} comments deleted"})
elif action == "delete_media":
count = media.count()
media.delete()
@@ -492,8 +539,9 @@ class MediaBulkUserActions(APIView):
users = (
MediaPermission.objects.filter(media__in=media, permission=ownership_type)
.exclude(user=request.user)
.values('user__name', 'user__username')
.annotate(media_count=Count('media', distinct=True))
.annotate(media_count=Count('media'))
.filter(media_count=media_count)
)
@@ -601,11 +649,17 @@ class MediaBulkUserActions(APIView):
return Response({"detail": "No matching categories found or access denied"}, status=status.HTTP_400_BAD_REQUEST)
added_count = 0
tag = None
for category in categories:
if category.is_lms_course:
tag, _ = Tag.objects.get_or_create(title=category.title[:100])
for m in media:
if not m.category.filter(uid=category.uid).exists():
m.category.add(category)
added_count += 1
if tag:
m.tags.add(tag)
return Response({"detail": f"Added {added_count} media items to {categories.count()} categories"})
@@ -619,11 +673,17 @@ class MediaBulkUserActions(APIView):
return Response({"detail": "No matching categories found"}, status=status.HTTP_400_BAD_REQUEST)
removed_count = 0
tag = None
for category in categories:
if category.is_lms_course:
tag = Tag.objects.filter(title=category.title[:100]).first()
for m in media:
if m.category.filter(uid=category.uid).exists():
m.category.remove(category)
removed_count += 1
if tag:
m.tags.remove(tag)
return Response({"detail": f"Removed {removed_count} media items from {categories.count()} categories"})

View File

@@ -54,7 +54,7 @@
.category-modal-header {
display: flex;
justify-content: space-between;
align-items: center;
align-items: flex-start;
padding: 20px 24px;
border-bottom: 1px solid #e0e0e0;
@@ -74,6 +74,19 @@
}
}
.category-modal-subtitle {
display: flex;
align-items: center;
gap: 8px;
margin-top: 6px;
font-size: 13px;
color: #777;
.dark_theme & {
color: #aaa;
}
}
.category-modal-close {
background: none;
border: none;

View File

@@ -193,7 +193,14 @@ export const BulkActionCategoryModal: React.FC<BulkActionCategoryModalProps> = (
<div className="category-modal-overlay">
<div className="category-modal">
<div className="category-modal-header">
<div>
<h2>{isLmsMode ? translateString('Share with Course') : translateString('Add / Remove from Categories')}</h2>
{isLmsMode && (
<div className="category-modal-subtitle">
<span>{translateString('Students will get viewer permissions, while lecturers will get co-owner permissions (same as owner, but cannot delete the media)')}</span>
</div>
)}
</div>
<button className="category-modal-close" onClick={onCancel}>
×
</button>

View File

@@ -47,7 +47,7 @@ export const BulkActionChangeOwnerModal: React.FC<BulkActionChangeOwnerModalProp
}
try {
const response = await fetch(`/api/v1/users?name=${encodeURIComponent(name)}`);
const response = await fetch(`/api/v1/users?name=${encodeURIComponent(name)}&exclude_self=True`);
if (!response.ok) {
throw new Error(translateString('Failed to search users'));
}

View File

@@ -54,7 +54,7 @@
.permission-modal-header {
display: flex;
justify-content: space-between;
align-items: center;
align-items: flex-start;
padding: 20px 24px;
border-bottom: 1px solid #e0e0e0;
@@ -102,6 +102,19 @@
}
}
.permission-modal-subtitle {
display: flex;
align-items: center;
gap: 8px;
margin-top: 6px;
font-size: 13px;
color: #777;
.dark_theme & {
color: #aaa;
}
}
.permission-modal-content {
display: flex;
gap: 24px;

View File

@@ -226,7 +226,42 @@ export const BulkActionPermissionModal: React.FC<BulkActionPermissionModalProps>
<div className="permission-modal-overlay">
<div className="permission-modal">
<div className="permission-modal-header">
<h2>{translateString('Manage')} {permissionLabel}</h2>
<div>
<h2>{translateString('Share with')} {permissionLabel}</h2>
{permissionType === 'viewer' && (
<div className="permission-modal-subtitle">
<span>{translateString('Give users viewer permissions to your media by adding them to the below list.')}</span>
<span
className="info-tooltip"
title={translateString("Users can view your media via: My Media > Shared with Me > particular media > ...")}
>
i
</span>
</div>
)}
{permissionType === 'editor' && (
<div className="permission-modal-subtitle">
<span>{translateString('Give users editor permissions to your media by adding them to the below list.')}</span>
<span
className="info-tooltip"
title={translateString("Users can edit your media via: My Media > Shared with Me > particular media > Edit...")}
>
i
</span>
</div>
)}
{permissionType === 'owner' && (
<div className="permission-modal-subtitle">
<span>{translateString('Give users owner permissions to your media, except for deleting the media, by adding them to the below list.')}</span>
<span
className="info-tooltip"
title={translateString("Users can manage your media via: My Media > Shared with Me > particular media > ...")}
>
i
</span>
</div>
)}
</div>
<button className="permission-modal-close" onClick={onCancel}>
×
</button>
@@ -284,6 +319,21 @@ export const BulkActionPermissionModal: React.FC<BulkActionPermissionModalProps>
?
</span>
)}
{permissionType === 'viewer' && (
<span className="info-tooltip" title={translateString('Remove users from the list to remove viewer permissions')}>
i
</span>
)}
{permissionType === 'editor' && (
<span className="info-tooltip" title={translateString('Remove users from the list to remove editor permissions')}>
i
</span>
)}
{permissionType === 'owner' && (
<span className="info-tooltip" title={translateString('Remove users from the list to remove owner permissions')}>
i
</span>
)}
</h3>
<div className="search-box">
<input

View File

@@ -40,6 +40,12 @@
color: #666;
}
optgroup {
color: #000;
font-weight: 700;
background-color: white;
}
option {
padding: 10px;
font-weight: normal;
@@ -77,6 +83,11 @@
color: #aaa;
}
optgroup {
color: #fff;
background-color: #2a2a2a;
}
option {
background-color: #2a2a2a;
color: #fff;

View File

@@ -8,24 +8,57 @@ interface BulkActionsDropdownProps {
onActionSelect: (action: string) => void;
}
const BULK_ACTIONS = [
{ value: 'add-remove-coviewers', label: translateString('Add / Remove Co-Viewers'), enabled: true },
{ value: 'add-remove-coeditors', label: translateString('Add / Remove Co-Editors'), enabled: true },
{ value: 'add-remove-coowners', label: translateString('Add / Remove Co-Owners'), enabled: true },
interface BulkAction {
value: string;
label: string;
enabled: boolean;
}
interface BulkActionGroup {
label: string;
actions: BulkAction[];
}
export const BulkActionsDropdown: React.FC<BulkActionsDropdownProps> = ({ selectedCount, onActionSelect }) => {
const isLmsMode = inEmbeddedApp();
const BULK_ACTION_GROUPS: BulkActionGroup[] = [
{
label: translateString('Sharing'),
actions: [
{ value: 'add-remove-coviewers', label: translateString('Share with Co-Viewers'), enabled: true },
{ value: 'add-remove-coeditors', label: translateString('Share with Co-Editors'), enabled: true },
{ value: 'add-remove-coowners', label: translateString('Share with Co-Owners'), enabled: true },
{ value: 'add-remove-category', label: isLmsMode ? translateString('Share with Course Members') : translateString('Add / Remove from Categories'), enabled: true },
],
},
{
label: translateString('Organization'),
actions: [
{ value: 'add-remove-playlist', label: translateString('Add to / Remove from Playlist'), enabled: true },
{ value: 'add-remove-category', label: inEmbeddedApp() ? translateString('Share with Course') : translateString('Add to / Remove from Category'), enabled: true },
{ value: 'add-remove-tags', label: translateString('Add / Remove Tags'), enabled: true },
],
},
{
label: translateString('Settings'),
actions: [
{ value: 'enable-comments', label: translateString('Enable Comments'), enabled: true },
{ value: 'disable-comments', label: translateString('Disable Comments'), enabled: true },
{ value: 'delete-comments', label: translateString('Delete Comments'), enabled: true },
{ value: 'enable-download', label: translateString('Enable Download'), enabled: true },
{ value: 'disable-download', label: translateString('Disable Download'), enabled: true },
],
},
{
label: translateString('Management'),
actions: [
{ value: 'publish-state', label: translateString('Publish State'), enabled: true },
{ value: 'change-owner', label: translateString('Change Owner'), enabled: true },
{ value: 'copy-media', label: translateString('Copy Media'), enabled: true },
{ value: 'delete-media', label: translateString('Delete Media'), enabled: true },
];
export const BulkActionsDropdown: React.FC<BulkActionsDropdownProps> = ({ selectedCount, onActionSelect }) => {
],
},
];
const noSelection = selectedCount === 0;
@@ -59,11 +92,15 @@ export const BulkActionsDropdown: React.FC<BulkActionsDropdownProps> = ({ select
<option value="" disabled>
{displayText}
</option>
{BULK_ACTIONS.map((action) => (
{BULK_ACTION_GROUPS.map((group) => (
<optgroup key={group.label} label={group.label}>
{group.actions.map((action) => (
<option key={action.value} value={action.value} disabled={noSelection || !action.enabled}>
{action.label}
</option>
))}
</optgroup>
))}
</select>
</div>
);

View File

@@ -16,8 +16,17 @@
margin-bottom: 16px;
.add-media-button {
position: relative;
margin-left: auto;
.popup {
position: absolute;
top: 100%;
right: 0;
margin-top: 8px;
z-index: 99;
}
a {
display: flex;
align-items: center;

View File

@@ -2,8 +2,9 @@ import React from 'react';
import { MediaListRow } from './MediaListRow';
import { BulkActionsDropdown } from './BulkActionsDropdown';
import { SelectAllCheckbox } from './SelectAllCheckbox';
import { CircleIconButton, MaterialIcon } from './_shared';
import { CircleIconButton, MaterialIcon, PopupMain, NavigationMenuList } from './_shared';
import { LinksConsumer } from '../utils/contexts';
import { usePopup } from '../utils/hooks';
import { translateString } from '../utils/helpers/';
import './MediaListWrapper.scss';
@@ -37,12 +38,29 @@ export const MediaListWrapper: React.FC<MediaListWrapperProps> = ({
onSelectAll = () => {},
onDeselectAll = () => {},
showAddMediaButton = false,
}) => (
}) => {
const [popupContentRef, PopupContent, PopupTrigger] = usePopup() as [any, any, any];
return (
<div className={(className ? className + ' ' : '') + 'media-list-wrapper'} style={style}>
<MediaListRow title={title} viewAllLink={viewAllLink} viewAllText={viewAllText}>
{showBulkActions && (
<LinksConsumer>
{(links) => (
{(links) => {
const uploadMenuItems = [
{
link: links.user.addMedia,
icon: 'upload',
text: translateString('Upload'),
},
{
link: '/record_screen',
icon: 'videocam',
text: translateString('Record'),
},
];
return (
<div className="bulk-actions-container">
<div style={{ display: 'flex', alignItems: 'center', gap: '10px' }}>
<BulkActionsDropdown selectedCount={selectedCount} onActionSelect={onBulkAction} />
@@ -55,18 +73,25 @@ export const MediaListWrapper: React.FC<MediaListWrapperProps> = ({
</div>
{showAddMediaButton && (
<div className="add-media-button">
<a href={links.user.addMedia} title={translateString('Add media')}>
<CircleIconButton>
<PopupTrigger contentRef={popupContentRef}>
<CircleIconButton title={translateString('Add media')}>
<MaterialIcon type="video_call" />
</CircleIconButton>
</a>
</PopupTrigger>
<PopupContent contentRef={popupContentRef}>
<PopupMain>
<NavigationMenuList items={uploadMenuItems} />
</PopupMain>
</PopupContent>
</div>
)}
</div>
)}
);
}}
</LinksConsumer>
)}
{children || null}
</MediaListRow>
</div>
);
);
};

View File

@@ -513,12 +513,6 @@
}
}
.embedded-app {
.viewer-container,
.viewer-info {
width: 100%;
}
}
.viewer-image-container {
position: relative;

View File

@@ -183,8 +183,7 @@ export default class ViewerInfoTitleBanner extends React.PureComponent {
{MemberContext._currentValue.can.shareMedia ? <MediaShareButton isVideo={false} /> : null}
{!MemberContext._currentValue.is.anonymous &&
MemberContext._currentValue.can.saveMedia &&
-1 < PlaylistsContext._currentValue.mediaTypes.indexOf(MediaPageStore.get('media-type')) ? (
MemberContext._currentValue.can.saveMedia ? (
<MediaSaveButton />
) : null}

View File

@@ -95,10 +95,8 @@ export default class ViewerInfoVideoTitleBanner extends ViewerInfoTitleBanner {
<MediaShareButton isVideo={true} />
) : null}
{!inEmbeddedApp() &&
!MemberContext._currentValue.is.anonymous &&
MemberContext._currentValue.can.saveMedia &&
-1 < PlaylistsContext._currentValue.mediaTypes.indexOf(MediaPageStore.get('media-type')) ? (
{!MemberContext._currentValue.is.anonymous &&
MemberContext._currentValue.can.saveMedia ? (
<MediaSaveButton />
) : null}

View File

@@ -1,7 +1,4 @@
import React from 'react';
import { MediaPageStore } from '../../utils/stores/';
import { AutoPlay } from './AutoPlay';
import { RelatedMedia } from './RelatedMedia';
import PlaylistView from './PlaylistView';
export default class ViewerSidebar extends React.PureComponent {
@@ -12,8 +9,6 @@ export default class ViewerSidebar extends React.PureComponent {
playlistData: props.playlistData,
isPlaylistPage: !!props.playlistData,
activeItem: 0,
mediaType: MediaPageStore.get('media-type'),
chapters: MediaPageStore.get('media-data')?.chapters
};
if (props.playlistData) {
@@ -28,18 +23,6 @@ export default class ViewerSidebar extends React.PureComponent {
}
}
this.onMediaLoad = this.onMediaLoad.bind(this);
}
componentDidMount() {
MediaPageStore.on('loaded_media_data', this.onMediaLoad);
}
onMediaLoad() {
this.setState({
mediaType: MediaPageStore.get('media-type'),
chapters: MediaPageStore.get('media-data')?.chapter_data || []
});
}
render() {
@@ -47,10 +30,7 @@ export default class ViewerSidebar extends React.PureComponent {
<div className="viewer-sidebar">
{this.state.isPlaylistPage ? (
<PlaylistView activeItem={this.state.activeItem} playlistData={this.props.playlistData} />
) : 'video' === this.state.mediaType || 'audio' === this.state.mediaType ? (
<AutoPlay />
) : null}
<RelatedMedia hideFirst={!this.state.isPlaylistPage} />
</div>
);
}

View File

@@ -88,7 +88,7 @@ function UploadMediaButton({ user, links }) {
{
link: '/record_screen',
icon: 'videocam',
text: translateString('Record Screen'),
text: translateString('Record'),
},
];

View File

@@ -576,6 +576,7 @@
// Ensure icon buttons are visible on mobile
&.media-search,
&.media-filters-toggle,
&.media-sharing-toggle,
&.media-tags-toggle,
&.media-sorting-toggle {
@media screen and (max-width: 768px) {
@@ -901,6 +902,13 @@ $-max-width: $-hor-spaces + ( 2 * $item-width ) - 1;
}
}
.mi-sharing-filter-options {
> .active button,
> * button:hover {
background-color: #3b82f6 !important;
}
}
$-hor-spaces: 2 * $side-empty-space;
$-max-width: $-hor-spaces + ( 2 * $item-width ) - 1;

View File

@@ -491,6 +491,39 @@ class NavMenuInlineTabs extends React.PureComponent {
</span>
</li>
) : null}
{this.props.onToggleSharingClick &&
['media', 'shared_by_me'].includes(this.props.type) ? (
<li className="media-sharing-toggle">
<span
style={{
display: 'flex',
alignItems: 'center',
cursor: 'pointer',
position: 'relative',
}}
onClick={this.props.onToggleSharingClick}
title={translateString('Shared with')}
>
<CircleIconButton buttonShadow={false}>
<i className="material-icons">people</i>
</CircleIconButton>
{this.props.hasActiveSharing ? (
<span
style={{
position: 'absolute',
top: '8px',
right: '8px',
width: '8px',
height: '8px',
borderRadius: '50%',
backgroundColor: 'var(--default-theme-color)',
border: '2px solid white',
}}
></span>
) : null}
</span>
</li>
) : null}
{this.props.onToggleTagsClick &&
['media', 'shared_by_me', 'shared_with_me'].includes(this.props.type) ? (
<li className="media-tags-toggle">
@@ -570,9 +603,11 @@ NavMenuInlineTabs.propTypes = {
type: PropTypes.string.isRequired,
onQueryChange: PropTypes.func,
onToggleFiltersClick: PropTypes.func,
onToggleSharingClick: PropTypes.func,
onToggleTagsClick: PropTypes.func,
onToggleSortingClick: PropTypes.func,
hasActiveFilters: PropTypes.bool,
hasActiveSharing: PropTypes.bool,
hasActiveTags: PropTypes.bool,
hasActiveSort: PropTypes.bool,
};
@@ -776,9 +811,11 @@ export default function ProfilePagesHeader(props) {
type={props.type}
onQueryChange={props.onQueryChange}
onToggleFiltersClick={props.onToggleFiltersClick}
onToggleSharingClick={userIsAuthor ? props.onToggleSharingClick : undefined}
onToggleTagsClick={props.onToggleTagsClick}
onToggleSortingClick={props.onToggleSortingClick}
hasActiveFilters={props.hasActiveFilters}
hasActiveSharing={props.hasActiveSharing}
hasActiveTags={props.hasActiveTags}
hasActiveSort={props.hasActiveSort}
/>
@@ -792,9 +829,11 @@ ProfilePagesHeader.propTypes = {
type: PropTypes.string.isRequired,
onQueryChange: PropTypes.func,
onToggleFiltersClick: PropTypes.func,
onToggleSharingClick: PropTypes.func,
onToggleTagsClick: PropTypes.func,
onToggleSortingClick: PropTypes.func,
hasActiveFilters: PropTypes.bool,
hasActiveSharing: PropTypes.bool,
hasActiveTags: PropTypes.bool,
hasActiveSort: PropTypes.bool,
};

View File

@@ -0,0 +1,101 @@
import React, { useState, useEffect, useRef } from 'react';
import PropTypes from 'prop-types';
import { PageStore } from '../../utils/stores/';
import { FilterOptions } from '../_shared';
import { translateString } from '../../utils/helpers/';
import '../management-table/ManageItemList-filters.scss';
export function ProfileMediaSharing(props) {
const [isHidden, setIsHidden] = useState(props.hidden);
const containerRef = useRef(null);
const innerContainerRef = useRef(null);
function onWindowResize() {
if (!isHidden && containerRef.current && innerContainerRef.current) {
containerRef.current.style.height = 24 + innerContainerRef.current.offsetHeight + 'px';
}
}
useEffect(() => {
setIsHidden(props.hidden);
onWindowResize();
}, [props.hidden, props.sharedUsers, props.sharedGroups]);
useEffect(() => {
PageStore.on('window_resize', onWindowResize);
return () => PageStore.removeListener('window_resize', onWindowResize);
}, []);
function onUserSelect(ev) {
const username = ev.currentTarget.getAttribute('value');
const newValue = (username === 'all' || username === props.selectedSharingValue) ? null : username;
props.onSharingSelect(newValue ? 'user' : null, newValue);
}
function onGroupSelect(ev) {
const name = ev.currentTarget.getAttribute('value');
const newValue = (name === 'all' || name === props.selectedSharingValue) ? null : name;
props.onSharingSelect(newValue ? 'group' : null, newValue);
}
const hasUsers = props.sharedUsers && props.sharedUsers.length > 0;
const hasGroups = props.sharedGroups && props.sharedGroups.length > 0;
const usersOptions = [
{ id: 'all', title: translateString('All') },
...(props.sharedUsers || []).map((u) => ({ id: u.username, title: u.name })),
];
const groupsOptions = [
{ id: 'all', title: translateString('All') },
...(props.sharedGroups || []).map((g) => ({ id: g.name, title: g.name })),
];
const selectedUser = props.selectedSharingType === 'user' ? props.selectedSharingValue : 'all';
const selectedGroup = props.selectedSharingType === 'group' ? props.selectedSharingValue : 'all';
return (
<div ref={containerRef} className={'mi-filters-row' + (isHidden ? ' hidden' : '')}>
<div ref={innerContainerRef} className="mi-filters-row-inner">
{hasUsers ? (
<div className="mi-filter mi-filter-full-width">
<div className="mi-filter-title">{translateString('SHARED WITH USERS')}</div>
<div className="mi-filter-options mi-filter-options-horizontal mi-sharing-filter-options">
<FilterOptions id="shared_user" options={usersOptions} selected={selectedUser} onSelect={onUserSelect} />
</div>
</div>
) : null}
{hasGroups ? (
<div className="mi-filter mi-filter-full-width">
<div className="mi-filter-title">{translateString('SHARED WITH GROUPS')}</div>
<div className="mi-filter-options mi-filter-options-horizontal mi-sharing-filter-options">
<FilterOptions id="shared_group" options={groupsOptions} selected={selectedGroup} onSelect={onGroupSelect} />
</div>
</div>
) : null}
{!hasUsers && !hasGroups ? (
<div className="mi-filter mi-filter-full-width">
<div className="mi-filter-title">{translateString('NOT SHARED WITH ANYONE')}</div>
</div>
) : null}
</div>
</div>
);
}
ProfileMediaSharing.propTypes = {
hidden: PropTypes.bool,
sharedUsers: PropTypes.array,
sharedGroups: PropTypes.array,
onSharingSelect: PropTypes.func,
selectedSharingType: PropTypes.string,
selectedSharingValue: PropTypes.string,
};
ProfileMediaSharing.defaultProps = {
hidden: false,
sharedUsers: [],
sharedGroups: [],
selectedSharingType: null,
selectedSharingValue: null,
};

View File

@@ -8,7 +8,7 @@ import { PageStore, ProfilePageStore } from '../utils/stores/';
import ProfilePagesHeader from '../components/profile-page/ProfilePagesHeader';
import ProfilePagesContent from '../components/profile-page/ProfilePagesContent';
import { MediaListRow } from '../components/MediaListRow';
import { ProfileMediaPage } from './ProfileMediaPage';
import { ProfileMediaPageBase } from './ProfileMediaPage';
class ChannelContactForm extends React.PureComponent {
constructor(props) {
@@ -149,7 +149,7 @@ class ChannelContactForm extends React.PureComponent {
}
}
export class ProfileAboutPage extends ProfileMediaPage {
export class ProfileAboutPage extends ProfileMediaPageBase {
constructor(props) {
super(props, 'author-about');

View File

@@ -7,9 +7,9 @@ import { MediaListWrapper } from '../components/MediaListWrapper';
import ProfilePagesHeader from '../components/profile-page/ProfilePagesHeader';
import ProfilePagesContent from '../components/profile-page/ProfilePagesContent';
import { LazyLoadItemListAsync } from '../components/item-list/LazyLoadItemListAsync.jsx';
import { ProfileMediaPage } from './ProfileMediaPage';
import { ProfileMediaPageBase } from './ProfileMediaPage';
export class ProfileHistoryPage extends ProfileMediaPage {
export class ProfileHistoryPage extends ProfileMediaPageBase {
constructor(props) {
super(props, 'author-history');

View File

@@ -7,9 +7,9 @@ import { MediaListWrapper } from '../components/MediaListWrapper';
import ProfilePagesHeader from '../components/profile-page/ProfilePagesHeader';
import ProfilePagesContent from '../components/profile-page/ProfilePagesContent';
import { LazyLoadItemListAsync } from '../components/item-list/LazyLoadItemListAsync';
import { ProfileMediaPage } from './ProfileMediaPage';
import { ProfileMediaPageBase } from './ProfileMediaPage';
export class ProfileLikedPage extends ProfileMediaPage {
export class ProfileLikedPage extends ProfileMediaPageBase {
constructor(props) {
super(props, 'author-liked');

File diff suppressed because it is too large Load Diff

View File

@@ -6,9 +6,9 @@ import { MediaListWrapper } from '../components/MediaListWrapper';
import ProfilePagesHeader from '../components/profile-page/ProfilePagesHeader';
import ProfilePagesContent from '../components/profile-page/ProfilePagesContent';
import { LazyLoadItemListAsync } from '../components/item-list/LazyLoadItemListAsync.jsx';
import { ProfileMediaPage } from './ProfileMediaPage';
import { ProfileMediaPageBase } from './ProfileMediaPage';
export class ProfilePlaylistsPage extends ProfileMediaPage {
export class ProfilePlaylistsPage extends ProfileMediaPageBase {
constructor(props) {
super(props, 'author-playlists');

View File

@@ -9,6 +9,7 @@ import ProfilePagesContent from '../components/profile-page/ProfilePagesContent'
import { LazyLoadItemListAsync } from '../components/item-list/LazyLoadItemListAsync';
import { ProfileMediaFilters } from '../components/search-filters/ProfileMediaFilters';
import { ProfileMediaTags } from '../components/search-filters/ProfileMediaTags';
import { ProfileMediaSharing } from '../components/search-filters/ProfileMediaSharing';
import { ProfileMediaSorting } from '../components/search-filters/ProfileMediaSorting';
import { BulkActionsModals } from '../components/BulkActionsModals';
import { inEmbeddedApp, inSelectMediaEmbedMode } from '../utils/helpers';
@@ -47,11 +48,16 @@ class ProfileSharedByMePage extends Page {
hiddenFilters: true,
hiddenTags: true,
hiddenSorting: true,
hiddenSharing: true,
filterArgs: '',
availableTags: [],
selectedTag: 'all',
selectedSort: 'date_added_desc',
selectedMedia: new Set(), // For select media mode
sharedUsers: [],
sharedGroups: [],
selectedSharingType: null,
selectedSharingValue: null,
};
this.authorDataLoad = this.authorDataLoad.bind(this);
@@ -61,9 +67,11 @@ class ProfileSharedByMePage extends Page {
this.onToggleFiltersClick = this.onToggleFiltersClick.bind(this);
this.onToggleTagsClick = this.onToggleTagsClick.bind(this);
this.onToggleSortingClick = this.onToggleSortingClick.bind(this);
this.onToggleSharingClick = this.onToggleSharingClick.bind(this);
this.onFiltersUpdate = this.onFiltersUpdate.bind(this);
this.onTagSelect = this.onTagSelect.bind(this);
this.onSortSelect = this.onSortSelect.bind(this);
this.onSharingSelect = this.onSharingSelect.bind(this);
this.onResponseDataLoaded = this.onResponseDataLoaded.bind(this);
this.handleMediaSelection = this.handleMediaSelection.bind(this);
@@ -177,6 +185,7 @@ class ProfileSharedByMePage extends Page {
hiddenFilters: !this.state.hiddenFilters,
hiddenTags: true,
hiddenSorting: true,
hiddenSharing: true,
});
}
@@ -185,6 +194,7 @@ class ProfileSharedByMePage extends Page {
hiddenFilters: true,
hiddenTags: !this.state.hiddenTags,
hiddenSorting: true,
hiddenSharing: true,
});
}
@@ -193,6 +203,16 @@ class ProfileSharedByMePage extends Page {
hiddenFilters: true,
hiddenTags: true,
hiddenSorting: !this.state.hiddenSorting,
hiddenSharing: true,
});
}
onToggleSharingClick() {
this.setState({
hiddenFilters: true,
hiddenTags: true,
hiddenSorting: true,
hiddenSharing: !this.state.hiddenSharing,
});
}
@@ -205,6 +225,8 @@ class ProfileSharedByMePage extends Page {
publish_state: this.state.filterArgs.match(/publish_state=([^&]+)/)?.[1],
sort_by: this.state.selectedSort,
tag: tag,
sharing_type: this.state.selectedSharingType,
sharing_value: this.state.selectedSharingValue,
});
});
}
@@ -218,6 +240,23 @@ class ProfileSharedByMePage extends Page {
publish_state: this.state.filterArgs.match(/publish_state=([^&]+)/)?.[1],
sort_by: sortBy,
tag: this.state.selectedTag,
sharing_type: this.state.selectedSharingType,
sharing_value: this.state.selectedSharingValue,
});
});
}
onSharingSelect(type, value) {
this.setState({ selectedSharingType: type, selectedSharingValue: value }, () => {
this.onFiltersUpdate({
media_type: this.state.filterArgs.match(/media_type=([^&]+)/)?.[1],
upload_date: this.state.filterArgs.match(/upload_date=([^&]+)/)?.[1],
duration: this.state.filterArgs.match(/duration=([^&]+)/)?.[1],
publish_state: this.state.filterArgs.match(/publish_state=([^&]+)/)?.[1],
sort_by: this.state.selectedSort,
tag: this.state.selectedTag,
sharing_type: type,
sharing_value: value,
});
});
}
@@ -231,6 +270,8 @@ class ProfileSharedByMePage extends Page {
sort_by: null,
ordering: null,
t: null,
shared_user: null,
shared_group: null,
};
switch (updatedArgs.media_type) {
@@ -292,6 +333,12 @@ class ProfileSharedByMePage extends Page {
args.t = updatedArgs.tag;
}
if (updatedArgs.sharing_type === 'user' && updatedArgs.sharing_value) {
args.shared_user = updatedArgs.sharing_value;
} else if (updatedArgs.sharing_type === 'group' && updatedArgs.sharing_value) {
args.shared_group = updatedArgs.sharing_value;
}
const newArgs = [];
for (let arg in args) {
@@ -343,6 +390,12 @@ class ProfileSharedByMePage extends Page {
.filter((tag) => tag);
this.setState({ availableTags: tags });
}
if (responseData && responseData.shared_users !== undefined) {
this.setState({
sharedUsers: responseData.shared_users || [],
sharedGroups: responseData.shared_groups || [],
});
}
}
handleMediaSelection(mediaId, isSelected) {
@@ -413,9 +466,11 @@ class ProfileSharedByMePage extends Page {
onToggleFiltersClick={this.onToggleFiltersClick}
onToggleTagsClick={this.onToggleTagsClick}
onToggleSortingClick={this.onToggleSortingClick}
onToggleSharingClick={this.onToggleSharingClick}
hasActiveFilters={hasActiveFilters}
hasActiveTags={this.state.selectedTag !== 'all'}
hasActiveSort={this.state.selectedSort !== 'date_added_desc'}
hasActiveSharing={!!this.state.selectedSharingValue}
hideChannelBanner={inEmbeddedApp()}
/>
) : null,
@@ -443,6 +498,14 @@ class ProfileSharedByMePage extends Page {
onTagSelect={this.onTagSelect}
/>
<ProfileMediaSorting hidden={this.state.hiddenSorting} onSortSelect={this.onSortSelect} />
<ProfileMediaSharing
hidden={this.state.hiddenSharing}
sharedUsers={this.state.sharedUsers}
sharedGroups={this.state.sharedGroups}
onSharingSelect={this.onSharingSelect}
selectedSharingType={this.state.selectedSharingType}
selectedSharingValue={this.state.selectedSharingValue}
/>
<LazyLoadItemListAsync
key={isSelectMediaMode ? this.state.requestUrl : `${this.state.requestUrl}-${this.props.bulkActions.listKey}`}
requestUrl={this.state.requestUrl}

View File

@@ -1,7 +1,6 @@
import React from 'react';
import { PageStore, MediaPageStore } from '../utils/stores/';
import { MediaPageActions } from '../utils/actions/';
import { inEmbeddedApp } from '../utils/helpers/';
import ViewerError from '../components/media-page/ViewerError';
import ViewerInfo from '../components/media-page/ViewerInfo';
import ViewerSidebar from '../components/media-page/ViewerSidebar';
@@ -87,22 +86,18 @@ export class _MediaPage extends Page {
{!this.state.infoAndSidebarViewType
? [
<ViewerInfo key="viewer-info" />,
!inEmbeddedApp() && this.state.pagePlaylistLoaded ? (
<ViewerSidebar
key="viewer-sidebar"
mediaId={MediaPageStore.get('media-id')}
playlistData={MediaPageStore.get('playlist-data')}
/>
) : null,
/>,
]
: [
!inEmbeddedApp() && this.state.pagePlaylistLoaded ? (
<ViewerSidebar
key="viewer-sidebar"
mediaId={MediaPageStore.get('media-id')}
playlistData={MediaPageStore.get('playlist-data')}
/>
) : null,
/>,
<ViewerInfo key="viewer-info" />,
]}
</div>

View File

@@ -2,7 +2,6 @@ import React from 'react';
// FIXME: 'VideoViewerStore' is used only in case of video media, but is included in every media page code.
import { PageStore, MediaPageStore, VideoViewerStore } from '../utils/stores/';
import { MediaPageActions } from '../utils/actions/';
import { inEmbeddedApp } from '../utils/helpers/';
import ViewerInfoVideo from '../components/media-page/ViewerInfoVideo';
import ViewerError from '../components/media-page/ViewerError';
import ViewerSidebar from '../components/media-page/ViewerSidebar';
@@ -104,7 +103,7 @@ export class _VideoMediaPage extends Page {
{!this.state.wideLayout || (this.state.isVideoMedia && this.state.theaterMode)
? [
<ViewerInfoVideo key="viewer-info" />,
!inEmbeddedApp() && this.state.pagePlaylistLoaded ? (
this.state.pagePlaylistLoaded ? (
<ViewerSidebar
key="viewer-sidebar"
mediaId={MediaPageStore.get('media-id')}
@@ -113,7 +112,7 @@ export class _VideoMediaPage extends Page {
) : null,
]
: [
!inEmbeddedApp() && this.state.pagePlaylistLoaded ? (
this.state.pagePlaylistLoaded ? (
<ViewerSidebar
key="viewer-sidebar"
mediaId={MediaPageStore.get('media-id')}

View File

@@ -45,12 +45,14 @@ export const LayoutProvider = ({ children }) => {
const site = useContext(SiteContext);
const cache = new BrowserCache('MediaCMS[' + site.id + '][layout]', 86400);
const isMediaPage = useMemo(() => PageStore.get('current-page') === 'media', []);
const isMediaPage = useMemo(() => PageStore.get('current-page') === 'media' || window.MediaCMS?.mediaId !== undefined, []);
const isEmbeddedApp = useMemo(() => inEmbeddedApp(), []);
const enabledSidebar = Boolean(document.getElementById('app-sidebar') || document.querySelector('.page-sidebar'));
const [visibleSidebar, setVisibleSidebar] = useState(cache.get('visible-sidebar'));
const [visibleSidebar, setVisibleSidebar] = useState(
isMediaPage || isEmbeddedApp ? false : cache.get('visible-sidebar')
);
const [visibleMobileSearch, setVisibleMobileSearch] = useState(false);
const toggleMobileSearch = () => {

View File

@@ -1,5 +1,5 @@
// check templates/config/installation/translations.html for more
export function translateString(str) {
return window.TRANSLATION?.[str] ?? str;
return window.TRANSLATION?.[str] || str;
}

View File

@@ -111,6 +111,10 @@ export function useBulkActions() {
setShowConfirmModal(true);
setPendingAction(action);
setConfirmMessage(translateString('You are going to disable comments to') + ` ${selectedCount} ` + translateString('media, are you sure?'));
} else if (action === 'delete-comments') {
setShowConfirmModal(true);
setPendingAction(action);
setConfirmMessage(translateString('You are going to delete all comments from') + ` ${selectedCount} ` + translateString('media, are you sure?'));
} else if (action === 'enable-download') {
setShowConfirmModal(true);
setPendingAction(action);
@@ -165,6 +169,8 @@ export function useBulkActions() {
executeEnableComments();
} else if (action === 'disable-comments') {
executeDisableComments();
} else if (action === 'delete-comments') {
executeDeleteComments();
} else if (action === 'enable-download') {
executeEnableDownload();
} else if (action === 'disable-download') {
@@ -271,6 +277,37 @@ export function useBulkActions() {
});
};
// Execute delete comments
const executeDeleteComments = () => {
const selectedIds = Array.from(selectedMedia);
fetch('/api/v1/media/user/bulk_actions', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': getCsrfToken(),
},
body: JSON.stringify({
action: 'delete_comments',
media_ids: selectedIds,
}),
})
.then((response) => {
if (!response.ok) {
throw new Error('Failed to delete comments');
}
return response.json();
})
.then((data) => {
showNotificationMessage(translateString('Successfully deleted comments'));
clearSelection();
})
.catch((error) => {
showNotificationMessage(translateString('Failed to delete comments.'), 'error');
clearSelection();
});
};
// Execute enable download
const executeEnableDownload = () => {
const selectedIds = Array.from(selectedMedia);

View File

@@ -1,34 +1,26 @@
# MediaCMS for Moodle
**Version:** 1.0.0 | **Release Date:** 2026-02-12 | **Moodle:** 4.5+
Version: 1.0.0, tested on Moodle 5
This package provides complete MediaCMS integration for Moodle, consisting of two plugins that work together with **unified settings**:
This plugin provides complete MediaCMS integration for Moodle, consisting of two plugins that work together with unified settings:
1. **Filter Plugin (filter_mediacms):**
* Handles LTI 1.3 authentication and secure video launches
* Auto-converts MediaCMS URLs to embedded players
* **Provides core settings** (MediaCMS URL, LTI Tool ID) used by both plugins
* **Location:** `filter/mediacms`
* **Location:** Admin, Plugins, Manage filters, MediaCMS
2. **Editor Plugin (tiny_mediacms):**
* Adds MediaCMS button to TinyMCE editor
* Browse authenticated video library via LTI Deep Linking
* Configure embed options (dimensions, display, start time)
* **Reads core settings** from filter plugin
* **Location:** `lib/editor/tiny/plugins/mediacms`
* **Location:** Admin, Plugins, TinyMCE, MediaCMS
## Installation
This package is distributed as a single repository but contains two distinct Moodle plugins that must be installed in their respective directories.
### 1. Copy Files
Copy the directories into your Moodle installation as follows (example assuming Moodle is at `/var/www/moodle/public`):
* Copy `filter/mediacms` to `/var/www/moodle/public/filter/mediacms`.
* Copy `tiny/mediacms` to `/var/www/moodle/public/lib/editor/tiny/plugins/mediacms`.
### 2. Set Permissions
Upload the plugin in Moodle's public directory and unzip
# cd /var/www/moodle/public ; cp /root/mediacms-moodle-v1.0.0.zip . && unzip mediacms-moodle-v1.0.0.zip
Ensure the web server user (typically `www-data`) has ownership of the new directories:
@@ -88,3 +80,31 @@ Configure default display options for auto-converted URLs:
### For Students (Display)
When content is viewed, the Filter will ensure the video is loaded securely via LTI 1.3, authenticating the user with MediaCMS automatically.
## Build instructions / Developing with the plugin
two types of changes: php (no build), js (build with npx grunt amd)
needs moodle/
npx version, dependencies etc
1. make changes here in lms-plugins/mediacms-moodle
2. copy to moodle
3. run `npx grunt amd` in moodle to build the JS files
4. from moodle copy back
sudo cp -r ~/mediacms/lms-plugins/mediacms-moodle/tiny/mediacms/ -r ~/mediacms/moodle/public/lib/editor/tiny/plugins/
5. cd ~/mediacms/moodle/public/lib/editor/tiny/plugins/mediacms/
npx grunt amd
6.
cp files back...
sudo cp -r /home/user/mediacms/moodle/public/lib/editor/tiny/plugins/mediacms /home/user/mediacms/lms-plugins/mediacms-moodle/tiny/
php admin/cli/purge_caches.php after
### Troubleshooting
Admin, advanced theme settings, add `My Media|/filter/mediacms/my_media.php` in case the position is not workin

View File

@@ -1,49 +0,0 @@
<?php
/**
* Hook listener for filter_mediacms navigation hooks (Moodle 4.3+)
*
* @package filter_mediacms
* @copyright 2026 MediaCMS
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace filter_mediacms;
/**
* Extends the primary (top) navigation bar with a My Media link.
*/
class hook_listener {
/**
* Called by the \core\hook\navigation\primary_extend hook.
* Adds the My Media link to the primary nav bar when placement = 'top'.
*/
public static function extend_primary_navigation(
\core\hook\navigation\primary_extend $hook
): void {
$placement = get_config('filter_mediacms', 'mymedia_placement');
if ($placement !== 'top') {
return;
}
if (!isloggedin() || isguestuser()) {
return;
}
$url = new \moodle_url('/filter/mediacms/my_media.php');
$node = \navigation_node::create(
get_string('mymedia', 'filter_mediacms'),
$url,
\navigation_node::TYPE_CUSTOM,
null,
'mediacms_mymedia',
new \pix_icon('i/media', '')
);
$primarynav = $hook->get_primarynav();
if ($primarynav === null) {
return;
}
$primarynav->add_node($node);
}
}

View File

@@ -0,0 +1,57 @@
<?php
/**
* Hook callbacks for filter_mediacms.
*
* @package filter_mediacms
* @copyright 2026 MediaCMS
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace filter_mediacms;
defined('MOODLE_INTERNAL') || die();
class hooks {
/**
* Appends the My Media link to the custom menus after configuration is loaded.
*
* @param \core\hook\after_config $hook
*/
public static function append_my_media_link(\core\hook\after_config $hook): void {
global $CFG;
$navposition = get_config('filter_mediacms', 'mymedia_nav_position');
// MEDIACMS_NAV_PLACEMENT_NONE = 2
if ($navposition == 2) {
return;
}
if (!get_string_manager()->string_exists('mymedia', 'filter_mediacms')) {
return;
}
$linktext = get_string('mymedia', 'filter_mediacms');
$linkurl = '/filter/mediacms/my_media.php';
$menuitem = "\n{$linktext}|{$linkurl}";
// MEDIACMS_NAV_PLACEMENT_PROFILE = 1
if ($navposition == 1) {
// Add to User Profile Menu
if (!isset($CFG->customusermenuitems)) {
$CFG->customusermenuitems = '';
}
if (strpos($CFG->customusermenuitems, $linktext) === false) {
$CFG->customusermenuitems .= $menuitem;
}
} else {
// Default to Top Navigation Menu (MEDIACMS_NAV_PLACEMENT_TOP = 0)
if (!isset($CFG->custommenuitems)) {
$CFG->custommenuitems = '';
}
if (strpos($CFG->custommenuitems, $linktext) === false) {
$CFG->custommenuitems .= $menuitem;
}
}
}
}

View File

@@ -185,7 +185,7 @@ class text_filter extends \core_filters\text_filter {
* @return string Transformed HTML (or original if token cannot be extracted)
*/
private function transform_textlink($anchor_html) {
global $COURSE, $PAGE;
global $COURSE;
// Extract href.
if (!preg_match('/href=["\']([^"\']+)["\']/', $anchor_html, $href_matches)) {
@@ -205,36 +205,15 @@ class text_filter extends \core_filters\text_filter {
return $anchor_html;
}
$launch_url = new moodle_url('/filter/mediacms/launch.php', [
$view_url = new moodle_url('/filter/mediacms/my_media.php', [
'token' => $token,
'courseid' => isset($COURSE->id) ? (int)$COURSE->id : 0,
'show_media_page' => 'true',
]);
if (!self::$textlink_js_added) {
self::$textlink_js_added = true;
$PAGE->requires->js_init_code(
'document.addEventListener("click",function(e){'
. 'var a=e.target.closest("a.mediacms-textlink-launch");if(!a)return;'
. 'e.preventDefault();'
. 'var f=document.createElement("iframe");'
. 'f.src=a.dataset.launchUrl;'
. 'f.style.cssText="width:100%;height:480px;border:none;display:block;";'
. 'f.allowFullscreen=true;'
. 'f.setAttribute("allow","autoplay *; fullscreen *; encrypted-media *;");'
. 'a.parentNode.replaceChild(f,a);'
. '});',
false
);
}
return html_writer::tag('a', $text_matches[1], [
'href' => '#',
'class' => 'mediacms-textlink-launch',
'data-launch-url' => $launch_url->out(false),
'href' => $view_url->out(false),
'target' => '_blank',
'rel' => 'noopener noreferrer',
]);
}
/** @var bool Whether the inline-iframe JS has already been added to the page. */
private static $textlink_js_added = false;
}

View File

@@ -1,7 +1,6 @@
<?php
/**
* Hook registrations for filter_mediacms.
* Primary navigation is handled via extend_navigation() in lib.php instead.
*
* @package filter_mediacms
* @copyright 2026 MediaCMS
@@ -10,4 +9,10 @@
defined('MOODLE_INTERNAL') || die();
$callbacks = [];
$callbacks = [
[
'hook' => \core\hook\after_config::class,
'callback' => [\filter_mediacms\hooks::class, 'append_my_media_link'],
'priority' => 100,
],
];

View File

@@ -18,12 +18,13 @@ $string['enableautoconvert'] = 'Auto-convert URLs';
$string['enableautoconvert_desc'] = 'Automatically convert MediaCMS URLs (e.g., /view?m=xyz) in text to embedded players.';
$string['privacy:metadata'] = 'The MediaCMS filter does not store any personal data.';
// My Media page.
$string['mymedia'] = 'My Media';
$string['mymedia_placement'] = 'My Media link placement';
$string['mymedia_placement_desc'] = 'Where to display the My Media link in the Moodle interface.';
$string['mymedia_placement_top'] = 'Top navigation';
$string['mymedia_placement_user'] = 'User navigation';
$string['notconfigured'] = 'MediaCMS is not fully configured. Please set the MediaCMS URL and LTI Tool in Site Administration → Plugins → Filters → MediaCMS.';
$string['ltitoolnotfound'] = 'The configured LTI tool could not be found. Please check the MediaCMS filter settings.';
$string['cannotcreatedummyactivity'] = 'Could not create the MediaCMS launcher activity. Please check course permissions.';
$string['mymediaposition'] = 'My Media Link Position';
$string['mymediaposition_desc'] = 'Select where the "My Media" link should appear in the Moodle interface.';
$string['pos_topbar'] = 'Top Navigation Bar';
$string['pos_userdrop'] = 'User Profile Dropdown';
$string['pos_none'] = 'None (Do not display)';

View File

@@ -10,10 +10,8 @@
require_once(__DIR__ . '/../../config.php');
require_once($CFG->dirroot . '/mod/lti/lib.php');
require_once($CFG->dirroot . '/mod/lti/locallib.php');
require_once($CFG->dirroot . '/course/modlib.php');
require_once(__DIR__ . '/locallib.php');
global $SITE, $DB, $PAGE, $OUTPUT, $CFG;
global $SITE, $DB, $PAGE, $OUTPUT, $CFG, $SESSION;
require_login();
@@ -34,18 +32,14 @@ $show_media_page = optional_param('show_media_page', '', PARAM_TEXT);
$mediacmsurl = get_config('filter_mediacms', 'mediacmsurl');
$ltitoolid = get_config('filter_mediacms', 'ltitoolid');
// No default dimensions - use what's provided or nothing
if (empty($mediacmsurl)) {
die('MediaCMS URL not configured');
}
// Tool Selection Logic
$type = false;
if (!empty($ltitoolid)) {
$type = $DB->get_record('lti_types', ['id' => $ltitoolid]);
}
if (!$type) {
die('LTI tool not found or not configured.');
}
@@ -59,22 +53,9 @@ if ($courseid && $courseid != SITEID) {
$course = $SITE;
}
// Get or create the dummy activity (visible, non-stealth).
try {
$dummy_cmid = filter_mediacms_get_dummy_activity($courseid, $type->id);
} catch (Exception $e) {
if (!has_capability('moodle/course:manageactivities', $context)) {
die('No MediaCMS activity found. Please ask a teacher to add one first.');
}
throw $e;
}
$cm = get_coursemodule_from_id('lti', $dummy_cmid, 0, false, MUST_EXIST);
$instance = $DB->get_record('lti', ['id' => $cm->instance], '*', MUST_EXIST);
// Build custom params for this video embed.
$custom_params = ["media_friendly_token=" . $mediatoken];
// Add embed parameters if provided (check !== '' instead of !empty() because '0' is a valid value)
if ($showTitle !== '') {
$custom_params[] = "embed_show_title=" . $showTitle;
}
@@ -94,9 +75,6 @@ if ($show_media_page === 'true') {
$custom_params[] = "show_media_page=true";
}
$instance->instructorcustomparameters = implode("\n", $custom_params);
$instance->name = 'MediaCMS Video: ' . $mediatoken;
// Set up page
$page_params = [
'token' => $mediatoken,
@@ -105,7 +83,6 @@ $page_params = [
'height' => $height
];
// Add embed parameters to page URL if provided (check !== '' because '0' is valid)
if ($showTitle !== '') {
$page_params['showTitle'] = $showTitle;
}
@@ -130,17 +107,20 @@ $PAGE->set_context($context);
$PAGE->set_pagelayout('embedded');
$PAGE->set_title('MediaCMS');
// Get type config
$typeconfig = lti_get_type_type_config($type->id);
// Initiate LTI Login with proper cmid (for permissions) and custom token
$content = lti_initiate_login($course->id, $dummy_cmid, $instance, $typeconfig, null, $instance->name);
// Build the OIDC login request params directly so we can capture the launchid.
// This avoids a shared SESSION key, which would cause a race condition when
// multiple videos are embedded on the same page and load simultaneously.
$oidc_params = lti_build_login_request($course->id, 0, null, $typeconfig, null, 0, 'MediaCMS Video');
// CRITICAL: Inject media_token and embed parameters as hidden fields in OIDC form
// MediaCMS will encode them in state and inject into custom claims (fallback mechanism)
// Key the custom params by launchid — lti_auth.php retrieves them the same way.
$hint = json_decode($oidc_params['lti_message_hint']);
$SESSION->{'mediacms_cp_' . $hint->launchid} = implode("\n", $custom_params);
// Build the fallback hidden fields (MediaCMS encodes them in state as a secondary mechanism).
$hidden_fields = '<input type="hidden" name="media_token" value="' . htmlspecialchars($mediatoken, ENT_QUOTES) . '" />';
// Add embed parameters as hidden fields
if ($showTitle !== '') {
$hidden_fields .= '<input type="hidden" name="embed_show_title" value="' . htmlspecialchars($showTitle, ENT_QUOTES) . '" />';
}
@@ -166,7 +146,22 @@ if ($height) {
$hidden_fields .= '<input type="hidden" name="embed_height" value="' . htmlspecialchars($height, ENT_QUOTES) . '" />';
}
$content = str_replace('</form>', $hidden_fields . '</form>', $content);
// Produce the OIDC login form (mirrors lti_initiate_login output).
$content = '<form action="' . htmlspecialchars($typeconfig->lti_initiatelogin, ENT_COMPAT)
. '" name="ltiInitiateLoginForm" id="ltiInitiateLoginForm"'
. ' method="post" encType="application/x-www-form-urlencoded">' . "\n";
foreach ($oidc_params as $key => $value) {
$key = htmlspecialchars($key, ENT_COMPAT);
$value = htmlspecialchars($value, ENT_COMPAT);
$content .= " <input type=\"hidden\" name=\"{$key}\" value=\"{$value}\"/>\n";
}
$content .= $hidden_fields . "\n";
$content .= "</form>\n";
$content .= "<script type=\"text/javascript\">\n"
. "//<![CDATA[\n"
. "document.ltiInitiateLoginForm.submit();\n"
. "//]]>\n"
. "</script>\n";
echo $OUTPUT->header();
echo $content;

View File

@@ -1,72 +1,7 @@
<?php
/**
* Navigation callbacks for filter_mediacms
*
* @package filter_mediacms
* @copyright 2026 MediaCMS
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* Add My Media to the global / flat navigation (nav drawer).
* Fires on every page when placement is set to 'top'.
* In Moodle 4.x Boost the nav drawer is opened via the hamburger icon
* and the node appears as a top-level item alongside Home / My courses.
*/
function filter_mediacms_extend_navigation(global_navigation $navigation): void {
$placement = get_config('filter_mediacms', 'mymedia_placement');
if ($placement !== 'top') {
return;
}
if (!isloggedin() || isguestuser()) {
return;
}
$url = new moodle_url('/filter/mediacms/my_media.php');
$node = navigation_node::create(
get_string('mymedia', 'filter_mediacms'),
$url,
navigation_node::TYPE_CUSTOM,
null,
'mediacms_mymedia',
new pix_icon('i/media', '')
);
// showinflatnavigation = true makes it visible in the Boost nav drawer.
$node->showinflatnavigation = true;
$navigation->add_node($node);
}
/**
* Add My Media to the user account / settings navigation.
* Fires when placement is set to 'user'.
* In Moodle 4.x Boost this section is reachable via avatar → Preferences.
*/
function filter_mediacms_extend_navigation_user_settings(
navigation_node $navigation,
stdClass $user,
context_user $usercontext,
stdClass $course,
context_course $coursecontext
): void {
$placement = get_config('filter_mediacms', 'mymedia_placement');
if ($placement !== 'user') {
return;
}
if (!isloggedin() || isguestuser()) {
return;
}
$url = new moodle_url('/filter/mediacms/my_media.php');
$navigation->add(
get_string('mymedia', 'filter_mediacms'),
$url,
navigation_node::TYPE_SETTING,
null,
'mediacms_mymedia',
new pix_icon('i/media', '')
);
}
define('MEDIACMS_NAV_PLACEMENT_TOP', 0);
define('MEDIACMS_NAV_PLACEMENT_PROFILE', 1);
define('MEDIACMS_NAV_PLACEMENT_NONE', 2);

View File

@@ -8,57 +8,3 @@
*/
defined('MOODLE_INTERNAL') || die();
/**
* Find the first LTI activity for the MediaCMS tool in a course, or create a
* visible dummy one if none exists. Repairs any existing stealth/hidden activity.
*
* @param int $courseid
* @param int $typeid LTI tool type ID
* @return int course-module ID
*/
function filter_mediacms_get_dummy_activity($courseid, $typeid) {
global $DB;
$sql = "SELECT cm.id
FROM {course_modules} cm
JOIN {modules} m ON m.id = cm.module
JOIN {lti} lti ON lti.id = cm.instance
WHERE cm.course = :courseid
AND m.name = 'lti'
AND lti.typeid = :typeid
AND cm.deletioninprogress = 0
ORDER BY cm.visible DESC, cm.visibleoncoursepage DESC
LIMIT 1";
$existing = $DB->get_record_sql($sql, ['courseid' => $courseid, 'typeid' => $typeid]);
if ($existing) {
return $existing->id;
}
// Create the dummy activity then immediately force visibleoncoursepage=0,
// because add_moduleinfo() always defaults it to 1.
$moduleinfo = new stdClass();
$moduleinfo->course = $courseid;
$moduleinfo->module = $DB->get_field('modules', 'id', ['name' => 'lti']);
$moduleinfo->modulename = 'lti';
$moduleinfo->section = 0;
$moduleinfo->visible = 1;
$moduleinfo->visibleoncoursepage = 1;
$moduleinfo->availability = null;
$moduleinfo->showdescription = 0;
$moduleinfo->name = 'My Media';
$moduleinfo->intro = '';
$moduleinfo->introformat = FORMAT_HTML;
$moduleinfo->typeid = $typeid;
$moduleinfo->instructorchoiceacceptgrades = 0;
$moduleinfo->grade = 0;
$moduleinfo->instructorchoicesendname = 1;
$moduleinfo->instructorchoicesendemailaddr = 1;
$moduleinfo->launchcontainer = LTI_LAUNCH_CONTAINER_EMBED_NO_BLOCKS;
$moduleinfo->instructorcustomparameters = '';
$result = add_moduleinfo($moduleinfo, get_course($courseid));
return $result->coursemodule;
}

View File

@@ -0,0 +1,196 @@
<?php
/**
* MediaCMS custom LTI 1.3 auth endpoint.
*
* Functionally identical to /mod/lti/auth.php except the no-activity (id=0)
* branch only requires the user to be logged in — not moodle/course:manageactivities.
*
* Custom params (publishdata, redirect_path) are read from the PHP session
* where lti_launch.php / select_media_picker.php store them before starting
* the OIDC flow.
*
* Setup required:
* 1. MediaCMS admin → LTI Platforms → edit Moodle record:
* set "Auth login url" to https://YOUR_MOODLE/filter/mediacms/lti_auth.php
* 2. Moodle admin → Site admin → Plugins → Activity modules → External tool
* → Manage tools → MediaCMS tool → edit → add to "Redirection URIs":
* https://YOUR_MOODLE/filter/mediacms/lti_auth.php
*
* @package filter_mediacms
* @copyright 2026 MediaCMS
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
require_once(__DIR__ . '/../../config.php');
require_once($CFG->dirroot . '/mod/lti/locallib.php');
global $_POST, $_SERVER, $SESSION;
if (!isloggedin() && empty($_POST['repost'])) {
header_remove("Set-Cookie");
$PAGE->set_pagelayout('popup');
$PAGE->set_context(context_system::instance());
$output = $PAGE->get_renderer('mod_lti');
$page = new \mod_lti\output\repost_crosssite_page($_SERVER['REQUEST_URI'], $_POST);
echo $output->header();
echo $output->render($page);
echo $output->footer();
return;
}
$scope = optional_param('scope', '', PARAM_TEXT);
$responsetype = optional_param('response_type', '', PARAM_TEXT);
$clientid = optional_param('client_id', '', PARAM_TEXT);
$redirecturi = optional_param('redirect_uri', '', PARAM_URL);
$loginhint = optional_param('login_hint', '', PARAM_TEXT);
$ltimessagehintenc = optional_param('lti_message_hint', '', PARAM_TEXT);
$state = optional_param('state', '', PARAM_TEXT);
$responsemode = optional_param('response_mode', '', PARAM_TEXT);
$nonce = optional_param('nonce', '', PARAM_TEXT);
$prompt = optional_param('prompt', '', PARAM_TEXT);
$ok = !empty($scope) && !empty($responsetype) && !empty($clientid) &&
!empty($redirecturi) && !empty($loginhint) && !empty($nonce);
if (!$ok) {
$error = 'invalid_request';
}
$ltimessagehint = json_decode($ltimessagehintenc);
$ok = $ok && isset($ltimessagehint->launchid);
if (!$ok) {
$error = 'invalid_request';
$desc = 'No launch id in LTI hint';
}
if ($ok && ($scope !== 'openid')) {
$ok = false;
$error = 'invalid_scope';
}
if ($ok && ($responsetype !== 'id_token')) {
$ok = false;
$error = 'unsupported_response_type';
}
if ($ok) {
$launchid = $ltimessagehint->launchid;
list($courseid, $typeid, $id, $messagetype, $foruserid, $titleb64, $textb64) =
explode(',', $SESSION->$launchid, 7);
unset($SESSION->$launchid);
$config = lti_get_type_type_config($typeid);
$ok = ($clientid === $config->lti_clientid);
if (!$ok) {
$error = 'unauthorized_client';
}
}
if ($ok && ($loginhint !== $USER->id)) {
$ok = false;
$error = 'access_denied';
}
if (empty($config)) {
throw new moodle_exception('invalidrequest', 'error');
} else {
$uris = array_map('trim', explode("\n", $config->lti_redirectionuris));
if (!in_array($redirecturi, $uris)) {
throw new moodle_exception('invalidrequest', 'error');
}
}
if ($ok) {
if (isset($responsemode)) {
$ok = ($responsemode === 'form_post');
if (!$ok) {
$error = 'invalid_request';
$desc = 'Invalid response_mode';
}
} else {
$ok = false;
$error = 'invalid_request';
$desc = 'Missing response_mode';
}
}
if ($ok && !empty($prompt) && ($prompt !== 'none')) {
$ok = false;
$error = 'invalid_request';
$desc = 'Invalid prompt';
}
if ($ok) {
$course = $DB->get_record('course', ['id' => $courseid], '*', MUST_EXIST);
if ($id) {
// Activity-based launch — identical to auth.php's if ($id) branch.
$cm = get_coursemodule_from_id('lti', $id, 0, false, MUST_EXIST);
$context = context_module::instance($cm->id);
require_login($course, true, $cm);
require_capability('mod/lti:view', $context);
$lti = $DB->get_record('lti', ['id' => $cm->instance], '*', MUST_EXIST);
$lti->cmid = $cm->id;
list($endpoint, $params) = lti_get_launch_data($lti, $nonce, $messagetype, $foruserid);
} else {
// No-activity launch — student-accessible.
// Custom params (publishdata / redirect_path) were stored in the session
// by lti_launch.php or select_media_picker.php before initiating the OIDC flow.
require_login($course);
// launch.php keys params by launchid (safe for concurrent embeds on one page).
// lti_launch.php and select_media_picker.php use the fixed key (single-use pages).
$customparams = '';
$cpkey = 'mediacms_cp_' . $launchid;
if (!empty($SESSION->$cpkey)) {
$customparams = $SESSION->$cpkey;
unset($SESSION->$cpkey);
} elseif (!empty($SESSION->mediacms_launch_customparams)) {
$customparams = $SESSION->mediacms_launch_customparams;
unset($SESSION->mediacms_launch_customparams);
}
// Minimal LTI instance object — enough for lti_get_launch_data to sign the JWT.
$lti = new stdClass();
$lti->id = 0;
$lti->typeid = (int) $typeid;
$lti->course = (int) $courseid;
$lti->cmid = 0;
$lti->name = 'MediaCMS';
$lti->toolurl = '';
$lti->securetoolurl = '';
$lti->instructorcustomparameters = $customparams;
$lti->instructorchoicesendname = LTI_SETTING_ALWAYS;
$lti->instructorchoicesendemailaddr = LTI_SETTING_ALWAYS;
$lti->instructorchoiceacceptgrades = LTI_SETTING_NEVER;
$lti->instructorchoiceallowroster = null;
$lti->launchcontainer = LTI_LAUNCH_CONTAINER_EMBED_NO_BLOCKS;
$lti->resourcekey = '';
$lti->password = '';
$lti->servicesalt = '';
$lti->resource_link_id = 'mediacms_' . $typeid;
list($endpoint, $params) = lti_get_launch_data(
$lti,
$nonce,
$messagetype ?: 'basic-lti-launch-request',
$foruserid
);
}
} else {
$params['error'] = $error;
if (!empty($desc)) {
$params['error_description'] = $desc;
}
}
if (isset($state)) {
$params['state'] = $state;
}
unset($SESSION->lti_message_hint);
$r = '<form action="' . $redirecturi . "\" name=\"ltiAuthForm\" id=\"ltiAuthForm\" " .
"method=\"post\" enctype=\"application/x-www-form-urlencoded\">\n";
foreach ($params as $key => $value) {
$key = htmlspecialchars($key, ENT_COMPAT);
$value = htmlspecialchars($value, ENT_COMPAT);
$r .= " <input type=\"hidden\" name=\"{$key}\" value=\"{$value}\"/>\n";
}
$r .= "</form>\n";
$r .= "<script type=\"text/javascript\">\n" .
"//<![CDATA[\n" .
"document.ltiAuthForm.submit();\n" .
"//]]>\n" .
"</script>\n";
echo $r;

View File

@@ -5,6 +5,13 @@
* Builds custom_publishdata (enrolled courses + roles) and initiates
* the LTI 1.3 OIDC login flow, outputting the auto-submit form directly.
*
* No dummy LTI activity is created. The publishdata is stored in the PHP
* session and picked up by lti_auth.php during the OIDC callback.
*
* Edge case: if the user is not enrolled in any course the launch still
* proceeds using the site course (SITEID). MediaCMS will receive an empty
* publishdata array and can decide how to handle it (e.g. show a message).
*
* @package filter_mediacms
* @copyright 2026 MediaCMS
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
@@ -13,10 +20,8 @@
require_once(__DIR__ . '/../../config.php');
require_once($CFG->dirroot . '/mod/lti/lib.php');
require_once($CFG->dirroot . '/mod/lti/locallib.php');
require_once($CFG->dirroot . '/course/modlib.php');
require_once(__DIR__ . '/locallib.php');
global $SITE, $DB, $CFG, $USER;
global $SITE, $DB, $CFG, $USER, $SESSION;
require_login();
@@ -32,7 +37,7 @@ if (!$type) {
throw new moodle_exception('ltitoolnotfound', 'filter_mediacms');
}
// Build custom_publishdata: all courses the user is enrolled in + role.
// Build publishdata: all courses the user is enrolled in + role.
$enrolled_courses = enrol_get_users_courses($USER->id, true, ['id', 'shortname', 'fullname']);
$publish_data = [];
@@ -60,8 +65,8 @@ foreach ($enrolled_courses as $enrolled_course) {
$publishdata_b64 = base64_encode(json_encode($publish_data));
// Use a course the user is actually enrolled in so they have mod/lti:view during
// the OIDC flow. Fall back to SITEID only for admins with no course enrolments.
// Use a course the user is actually enrolled in so they pass require_login
// in lti_auth.php. Fall back to SITEID for admins with no course enrolments.
$launch_courseid = SITEID;
$launch_course = $SITE;
foreach ($enrolled_courses as $ec) {
@@ -72,26 +77,10 @@ foreach ($enrolled_courses as $ec) {
}
}
// Get or create the dummy activity (visible, non-stealth).
try {
$dummy_cmid = filter_mediacms_get_dummy_activity($launch_courseid, $type->id);
} catch (Exception $e) {
throw new moodle_exception('cannotcreatedummyactivity', 'filter_mediacms');
}
$cm = get_coursemodule_from_id('lti', $dummy_cmid, 0, false, MUST_EXIST);
$instance = $DB->get_record('lti', ['id' => $cm->instance], '*', MUST_EXIST);
// DEBUG: log enrolled courses retrieved.
error_log('MediaCMS My Media publishdata courses (' . count($publish_data) . '): ' . json_encode($publish_data));
// Write publishdata to DB — Moodle's auth.php re-reads the instance from DB
// when building the LTI launch JWT, so in-memory changes are ignored.
$DB->set_field('lti', 'instructorcustomparameters', 'publishdata=' . $publishdata_b64, ['id' => $cm->instance]);
$instance->instructorcustomparameters = 'publishdata=' . $publishdata_b64;
$instance->name = 'MediaCMS My Media';
// Store publishdata in session — lti_auth.php picks it up after the OIDC roundtrip.
$SESSION->mediacms_launch_customparams = 'publishdata=' . $publishdata_b64;
$typeconfig = lti_get_type_type_config($type->id);
$content = lti_initiate_login($launch_course->id, $dummy_cmid, $instance, $typeconfig, null, $instance->name);
$content = lti_initiate_login($launch_courseid, 0, null, $typeconfig, null, 'MediaCMS My Media');
echo $content;

View File

@@ -9,28 +9,45 @@
require_once(__DIR__ . '/../../config.php');
global $SITE, $PAGE, $OUTPUT, $USER;
global $SITE, $PAGE, $OUTPUT, $USER, $COURSE;
require_login();
$context = context_system::instance();
$token = optional_param('token', '', PARAM_ALPHANUMEXT);
$courseid = optional_param('courseid', 0, PARAM_INT);
$context = context_system::instance();
$PAGE->set_context($context);
$PAGE->set_url(new moodle_url('/filter/mediacms/my_media.php'));
$PAGE->set_course($SITE);
$PAGE->set_pagelayout('mydashboard');
$PAGE->set_title(get_string('mymedia', 'filter_mediacms'));
$PAGE->set_heading(get_string('mymedia', 'filter_mediacms'));
if ($token) {
$PAGE->set_url(new moodle_url('/filter/mediacms/my_media.php', ['token' => $token]));
$PAGE->set_title('MediaCMS');
$PAGE->set_heading('MediaCMS');
$launch_params = [
'token' => $token,
'courseid' => $courseid ?: ($COURSE->id ?? 0),
'show_media_page' => 'true',
];
$src = (new moodle_url('/filter/mediacms/launch.php', $launch_params))->out(false);
} else {
$PAGE->set_url(new moodle_url('/filter/mediacms/my_media.php'));
$PAGE->set_title(get_string('mymedia', 'filter_mediacms'));
$PAGE->set_heading(get_string('mymedia', 'filter_mediacms'));
$src = (new moodle_url('/filter/mediacms/lti_launch.php'))->out(false);
}
echo $OUTPUT->header();
$attr = [
echo html_writer::tag('iframe', '', [
'id' => 'contentframe',
'src' => (new moodle_url('/filter/mediacms/lti_launch.php'))->out(false),
'src' => $src,
'allowfullscreen' => 'true',
'allow' => 'autoplay *; fullscreen *; encrypted-media *; camera *; microphone *;',
'allow' => 'autoplay *; fullscreen *; encrypted-media *; camera *; microphone *; display-capture *;',
'style' => 'border:none;display:block;width:100%;height:calc(100vh - 120px);',
];
echo html_writer::tag('iframe', '', $attr);
]);
echo $OUTPUT->footer();

View File

@@ -0,0 +1,82 @@
<?php
/**
* Student-accessible MediaCMS media picker launcher.
*
* Initiates a no-activity LTI 1.3 OIDC login that routes to MediaCMS's
* /lti/select-media/ UI. No LTI activity is created in the course.
*
* The redirect_path custom param is stored in the PHP session and injected
* by lti_auth.php during the OIDC callback, so MediaCMS routes to the
* media-picker rather than the default My Media page.
*
* Flow:
* 1. TinyMCE plugin opens this URL in an iframe (contentItemUrl).
* 2. We store redirect_path in session and start the OIDC flow.
* 3. lti_auth.php processes the OIDC callback (no manageactivities check).
* 4. MediaCMS receives redirect_path=/lti/select-media/?mode=lms_embed_mode.
* 5. User picks a video; MediaCMS sends postMessage({type:'videoSelected',...})
* which iframeembed.js already handles.
*
* @package filter_mediacms
* @copyright 2026 MediaCMS
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
require_once(__DIR__ . '/../../config.php');
require_once($CFG->dirroot . '/mod/lti/lib.php');
require_once($CFG->dirroot . '/mod/lti/locallib.php');
global $DB, $PAGE, $OUTPUT, $SITE, $USER, $SESSION;
require_login();
$courseid = required_param('courseid', PARAM_INT);
$action = optional_param('action', '', PARAM_TEXT);
$ltitoolid = get_config('filter_mediacms', 'ltitoolid');
if (empty($ltitoolid)) {
die('MediaCMS LTI tool not configured.');
}
$type = $DB->get_record('lti_types', ['id' => $ltitoolid]);
if (!$type) {
die('LTI tool not found.');
}
// Resolve course — fall back to the user's first enrolled course if needed.
if ($courseid && $courseid != SITEID) {
$course = get_course($courseid);
$context = context_course::instance($courseid);
} else {
$course = $SITE;
$context = context_system::instance();
foreach (enrol_get_users_courses($USER->id, true, ['id']) as $ec) {
if ((int)$ec->id !== SITEID) {
$course = get_course($ec->id);
$context = context_course::instance($ec->id);
break;
}
}
}
require_login($course);
$PAGE->set_url(new moodle_url('/filter/mediacms/select_media_picker.php', ['courseid' => $course->id]));
$PAGE->set_context($context);
$PAGE->set_pagelayout('embedded');
$PAGE->set_title('MediaCMS Select Media');
$typeconfig = lti_get_type_type_config($type->id);
// Store redirect_path in session — lti_auth.php picks it up after the OIDC roundtrip.
if ($action === 'upload') {
$SESSION->mediacms_launch_customparams = 'redirect_path=/upload?action=select_media';
} else {
$SESSION->mediacms_launch_customparams = 'redirect_path=/lti/select-media/?mode=lms_embed_mode';
}
$content = lti_initiate_login($course->id, 0, null, $typeconfig, null, 'MediaCMS Select Media');
echo $OUTPUT->header();
echo $content;
echo $OUTPUT->footer();

View File

@@ -1,15 +1,27 @@
<?php
defined('MOODLE_INTERNAL') || die;
require_once($CFG->dirroot . '/filter/mediacms/lib.php');
if ($ADMIN->fulltree) {
// Info heading
$settings->add(new admin_setting_heading(
'filter_mediacms/coresettings',
get_string('coresettings', 'filter_mediacms'),
get_string('coresettings_desc', 'filter_mediacms')
));
// MediaCMS URL
$settings->add(new admin_setting_configselect(
'filter_mediacms/mymedia_nav_position',
get_string('mymediaposition', 'filter_mediacms'),
get_string('mymediaposition_desc', 'filter_mediacms'),
MEDIACMS_NAV_PLACEMENT_TOP,
array(
MEDIACMS_NAV_PLACEMENT_TOP => 'Top Navigation Bar',
MEDIACMS_NAV_PLACEMENT_PROFILE => 'User Profile Dropdown',
MEDIACMS_NAV_PLACEMENT_NONE => 'None (Do not display)'
)
));
$settings->add(new admin_setting_configtext(
'filter_mediacms/mediacmsurl',
get_string('mediacmsurl', 'filter_mediacms'),
@@ -18,7 +30,6 @@ if ($ADMIN->fulltree) {
PARAM_URL
));
// LTI Tool Selector
$ltioptions = [0 => get_string('noltitoolsfound', 'filter_mediacms')];
try {
$tools = $DB->get_records('lti_types', null, 'name ASC', 'id, name, baseurl');
@@ -29,7 +40,6 @@ if ($ADMIN->fulltree) {
}
}
} catch (Exception $e) {
// Database might not be ready during install
}
$settings->add(new admin_setting_configselect(
@@ -39,16 +49,4 @@ if ($ADMIN->fulltree) {
0,
$ltioptions
));
// My Media link placement.
$settings->add(new admin_setting_configselect(
'filter_mediacms/mymedia_placement',
get_string('mymedia_placement', 'filter_mediacms'),
get_string('mymedia_placement_desc', 'filter_mediacms'),
'top',
[
'top' => get_string('mymedia_placement_top', 'filter_mediacms'),
'user' => get_string('mymedia_placement_user', 'filter_mediacms'),
]
));
}

View File

@@ -1,7 +1,7 @@
<?php
defined('MOODLE_INTERNAL') || die();
$plugin->version = 2026021200; // 2026-02-12
$plugin->version = 2026021202; // 2026-02-12
$plugin->requires = 2024100700; // Requires Moodle 4.5+
$plugin->component = 'filter_mediacms';
$plugin->maturity = MATURITY_STABLE;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,3 +1,3 @@
define("tiny_mediacms/selectors",["exports"],(function(_exports){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0;return _exports.default={IMAGE:{actions:{submit:".tiny_imagecms_urlentrysubmit",imageBrowser:".openimagecmsbrowser",addUrl:".tiny_imagecms_addurl",deleteImage:".tiny_imagecms_deleteicon"},elements:{form:"form.tiny_imagecms_form",alignSettings:".tiny_imagecms_button",alt:".tiny_imagecms_altentry",altWarning:".tiny_imagecms_altwarning",height:".tiny_imagecms_heightentry",width:".tiny_imagecms_widthentry",url:".tiny_imagecms_urlentry",urlWarning:".tiny_imagecms_urlwarning",size:".tiny_imagecms_size",presentation:".tiny_imagecms_presentation",constrain:".tiny_imagecms_constrain",customStyle:".tiny_imagecms_customstyle",preview:".tiny_imagecms_preview",previewBox:".tiny_imagecms_preview_box",loaderIcon:".tiny_imagecms_loader",loaderIconContainer:".tiny_imagecms_loader_container",insertImage:".tiny_imagecms_insert_image",modalFooter:".modal-footer",dropzoneContainer:".tiny_imagecms_dropzone_container",fileInput:"#tiny_imagecms_fileinput",fileNameLabel:".tiny_imagecms_filename",sizeOriginal:".tiny_imagecms_sizeoriginal",sizeCustom:".tiny_imagecms_sizecustom",properties:".tiny_imagecms_properties"},styles:{responsive:"img-fluid"}},EMBED:{actions:{submit:".tiny_mediacms_submit",mediaBrowser:".openmediacmsbrowser"},elements:{form:"form.tiny_mediacms_form",source:".tiny_mediacms_source",track:".tiny_mediacms_track",mediaSource:".tiny_mediacms_media_source",linkSource:".tiny_mediacms_link_source",linkSize:".tiny_mediacms_link_size",posterSource:".tiny_mediacms_poster_source",posterSize:".tiny_mediacms_poster_size",displayOptions:".tiny_mediacms_display_options",name:".tiny_mediacms_name_entry",title:".tiny_mediacms_title_entry",url:".tiny_mediacms_url_entry",width:".tiny_mediacms_width_entry",height:".tiny_mediacms_height_entry",trackSource:".tiny_mediacms_track_source",trackKind:".tiny_mediacms_track_kind_entry",trackLabel:".tiny_mediacms_track_label_entry",trackLang:".tiny_mediacms_track_lang_entry",trackDefault:".tiny_mediacms_track_default",mediaControl:".tiny_mediacms_controls",mediaAutoplay:".tiny_mediacms_autoplay",mediaMute:".tiny_mediacms_mute",mediaLoop:".tiny_mediacms_loop",advancedSettings:".tiny_mediacms_advancedsettings",linkTab:'li[data-medium-type="link"]',videoTab:'li[data-medium-type="video"]',audioTab:'li[data-medium-type="audio"]',linkPane:'.tab-pane[data-medium-type="link"]',videoPane:'.tab-pane[data-medium-type="video"]',audioPane:'.tab-pane[data-medium-type="audio"]',trackSubtitlesTab:'li[data-track-kind="subtitles"]',trackCaptionsTab:'li[data-track-kind="captions"]',trackDescriptionsTab:'li[data-track-kind="descriptions"]',trackChaptersTab:'li[data-track-kind="chapters"]',trackMetadataTab:'li[data-track-kind="metadata"]',trackSubtitlesPane:'.tab-pane[data-track-kind="subtitles"]',trackCaptionsPane:'.tab-pane[data-track-kind="captions"]',trackDescriptionsPane:'.tab-pane[data-track-kind="descriptions"]',trackChaptersPane:'.tab-pane[data-track-kind="chapters"]',trackMetadataPane:'.tab-pane[data-track-kind="metadata"]'},mediaTypes:{link:"LINK",video:"VIDEO",audio:"AUDIO"},trackKinds:{subtitles:"SUBTITLES",captions:"CAPTIONS",descriptions:"DESCRIPTIONS",chapters:"CHAPTERS",metadata:"METADATA"}},IFRAME:{actions:{remove:'[data-action="remove"]'},elements:{form:"form.tiny_iframecms_form",url:".tiny_iframecms_url",urlWarning:".tiny_iframecms_url_warning",showTitle:".tiny_iframecms_showtitle",linkTitle:".tiny_iframecms_linktitle",showRelated:".tiny_iframecms_showrelated",showUserAvatar:".tiny_iframecms_showuseravatar",textLinkOnly:".tiny_iframecms_textlinkonly",startAt:".tiny_iframecms_startat",startAtEnabled:".tiny_iframecms_startat_enabled",aspectRatio:".tiny_iframecms_aspectratio",width:".tiny_iframecms_width",height:".tiny_iframecms_height",preview:".tiny_iframecms_preview",previewContainer:".tiny_iframecms_preview_container",tabs:".tiny_iframecms_tabs",tabUrlBtn:".tiny_iframecms_tab_url_btn",tabIframeLibraryBtn:".tiny_iframecms_tab_iframe_library_btn",paneUrl:".tiny_iframecms_pane_url",paneIframeLibrary:".tiny_iframecms_pane_iframe_library",iframeLibraryContainer:".tiny_iframecms_iframe_library_container",iframeLibraryPlaceholder:".tiny_iframecms_iframe_library_placeholder",iframeLibraryLoading:".tiny_iframecms_iframe_library_loading",iframeLibraryFrame:".tiny_iframecms_iframe_library_frame"},aspectRatios:{"16:9":{width:560,height:315},"4:3":{width:560,height:420},"1:1":{width:400,height:400},custom:null}}},_exports.default}));
define("tiny_mediacms/selectors",["exports"],(function(_exports){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0;return _exports.default={IMAGE:{actions:{submit:".tiny_imagecms_urlentrysubmit",imageBrowser:".openimagecmsbrowser",addUrl:".tiny_imagecms_addurl",deleteImage:".tiny_imagecms_deleteicon"},elements:{form:"form.tiny_imagecms_form",alignSettings:".tiny_imagecms_button",alt:".tiny_imagecms_altentry",altWarning:".tiny_imagecms_altwarning",height:".tiny_imagecms_heightentry",width:".tiny_imagecms_widthentry",url:".tiny_imagecms_urlentry",urlWarning:".tiny_imagecms_urlwarning",size:".tiny_imagecms_size",presentation:".tiny_imagecms_presentation",constrain:".tiny_imagecms_constrain",customStyle:".tiny_imagecms_customstyle",preview:".tiny_imagecms_preview",previewBox:".tiny_imagecms_preview_box",loaderIcon:".tiny_imagecms_loader",loaderIconContainer:".tiny_imagecms_loader_container",insertImage:".tiny_imagecms_insert_image",modalFooter:".modal-footer",dropzoneContainer:".tiny_imagecms_dropzone_container",fileInput:"#tiny_imagecms_fileinput",fileNameLabel:".tiny_imagecms_filename",sizeOriginal:".tiny_imagecms_sizeoriginal",sizeCustom:".tiny_imagecms_sizecustom",properties:".tiny_imagecms_properties"},styles:{responsive:"img-fluid"}},EMBED:{actions:{submit:".tiny_mediacms_submit",mediaBrowser:".openmediacmsbrowser"},elements:{form:"form.tiny_mediacms_form",source:".tiny_mediacms_source",track:".tiny_mediacms_track",mediaSource:".tiny_mediacms_media_source",linkSource:".tiny_mediacms_link_source",linkSize:".tiny_mediacms_link_size",posterSource:".tiny_mediacms_poster_source",posterSize:".tiny_mediacms_poster_size",displayOptions:".tiny_mediacms_display_options",name:".tiny_mediacms_name_entry",title:".tiny_mediacms_title_entry",url:".tiny_mediacms_url_entry",width:".tiny_mediacms_width_entry",height:".tiny_mediacms_height_entry",trackSource:".tiny_mediacms_track_source",trackKind:".tiny_mediacms_track_kind_entry",trackLabel:".tiny_mediacms_track_label_entry",trackLang:".tiny_mediacms_track_lang_entry",trackDefault:".tiny_mediacms_track_default",mediaControl:".tiny_mediacms_controls",mediaAutoplay:".tiny_mediacms_autoplay",mediaMute:".tiny_mediacms_mute",mediaLoop:".tiny_mediacms_loop",advancedSettings:".tiny_mediacms_advancedsettings",linkTab:'li[data-medium-type="link"]',videoTab:'li[data-medium-type="video"]',audioTab:'li[data-medium-type="audio"]',linkPane:'.tab-pane[data-medium-type="link"]',videoPane:'.tab-pane[data-medium-type="video"]',audioPane:'.tab-pane[data-medium-type="audio"]',trackSubtitlesTab:'li[data-track-kind="subtitles"]',trackCaptionsTab:'li[data-track-kind="captions"]',trackDescriptionsTab:'li[data-track-kind="descriptions"]',trackChaptersTab:'li[data-track-kind="chapters"]',trackMetadataTab:'li[data-track-kind="metadata"]',trackSubtitlesPane:'.tab-pane[data-track-kind="subtitles"]',trackCaptionsPane:'.tab-pane[data-track-kind="captions"]',trackDescriptionsPane:'.tab-pane[data-track-kind="descriptions"]',trackChaptersPane:'.tab-pane[data-track-kind="chapters"]',trackMetadataPane:'.tab-pane[data-track-kind="metadata"]'},mediaTypes:{link:"LINK",video:"VIDEO",audio:"AUDIO"},trackKinds:{subtitles:"SUBTITLES",captions:"CAPTIONS",descriptions:"DESCRIPTIONS",chapters:"CHAPTERS",metadata:"METADATA"}},IFRAME:{actions:{remove:'[data-action="remove"]'},elements:{form:"form.tiny_iframecms_form",url:".tiny_iframecms_url",urlWarning:".tiny_iframecms_url_warning",showTitle:".tiny_iframecms_showtitle",linkTitle:".tiny_iframecms_linktitle",showRelated:".tiny_iframecms_showrelated",showUserAvatar:".tiny_iframecms_showuseravatar",textLinkOnly:".tiny_iframecms_textlinkonly",startAt:".tiny_iframecms_startat",startAtEnabled:".tiny_iframecms_startat_enabled",aspectRatio:".tiny_iframecms_aspectratio",width:".tiny_iframecms_width",height:".tiny_iframecms_height",preview:".tiny_iframecms_preview",previewContainer:".tiny_iframecms_preview_container",tabs:".tiny_iframecms_tabs",tabUrlBtn:".tiny_iframecms_tab_url_btn",tabIframeLibraryBtn:".tiny_iframecms_tab_iframe_library_btn",tabUploadMediaBtn:".tiny_iframecms_upload_media_btn",paneUrl:".tiny_iframecms_pane_url",paneIframeLibrary:".tiny_iframecms_pane_iframe_library",iframeLibraryContainer:".tiny_iframecms_iframe_library_container",iframeLibraryPlaceholder:".tiny_iframecms_iframe_library_placeholder",iframeLibraryLoading:".tiny_iframecms_iframe_library_loading",iframeLibraryFrame:".tiny_iframecms_iframe_library_frame"},aspectRatios:{"16:9":{width:560,height:315},"4:3":{width:560,height:420},"1:1":{width:400,height:400},custom:null}}},_exports.default}));
//# sourceMappingURL=selectors.min.js.map

File diff suppressed because one or more lines are too long

View File

@@ -143,6 +143,7 @@ export default {
tabs: '.tiny_iframecms_tabs',
tabUrlBtn: '.tiny_iframecms_tab_url_btn',
tabIframeLibraryBtn: '.tiny_iframecms_tab_iframe_library_btn',
tabUploadMediaBtn: '.tiny_iframecms_upload_media_btn',
paneUrl: '.tiny_iframecms_pane_url',
paneIframeLibrary: '.tiny_iframecms_pane_iframe_library',
// Iframe library elements

View File

@@ -161,16 +161,14 @@ class plugininfo extends plugin implements plugin_with_buttons, plugin_with_menu
$courseid = $COURSE->id;
}
// Build the content item URL for LTI Deep Linking.
// This URL initiates the LTI Deep Linking flow which allows users
// to select content (like videos) from the tool provider.
// Build the URL for the student-accessible media picker.
// Uses /filter/mediacms/select_media_picker.php instead of the standard
// /mod/lti/contentitem.php, which requires moodle/course:manageactivities
// and therefore fails for students.
$contentitemurl = '';
if (!empty($ltitoolid) && $courseid > 0) {
$contentitemurl = (new moodle_url('/mod/lti/contentitem.php', [
'id' => $ltitoolid,
'course' => $courseid,
'title' => 'MediaCMS Library',
'return_types' => 1 // LTI_DEEPLINKING_RETURN_TYPE_LTI_LINK
$contentitemurl = (new moodle_url('/filter/mediacms/select_media_picker.php', [
'courseid' => $courseid,
]))->out(false);
}

View File

@@ -149,9 +149,9 @@ $string['librarysortnewest'] = 'Newest first';
$string['librarysortoldest'] = 'Oldest first';
$string['librarysorttitle'] = 'Title A-Z';
$string['librarysortviews'] = 'Most views';
$string['libraryloading'] = 'Loading videos...';
$string['libraryempty'] = 'No videos found';
$string['libraryerror'] = 'Failed to load videos';
$string['libraryloading'] = 'Loading...';
$string['libraryempty'] = 'Not found';
$string['libraryerror'] = 'Failed to load';
$string['libraryretry'] = 'Retry';
$string['libraryprev'] = 'Previous';
$string['librarynext'] = 'Next';

View File

@@ -47,6 +47,12 @@
{{#str}} tabembedurl, tiny_mediacms {{/str}}
</button>
</li>
<!-- Upload media button -->
<li class="nav-item ms-auto ml-auto" role="presentation">
<button class="btn btn-outline-secondary btn-sm mt-1 me-2 mr-2 tiny_iframecms_upload_media_btn" type="button" title="Upload media">
<svg xmlns="http://www.w3.org/2000/svg" height="18px" viewBox="0 -960 960 960" width="18px" fill="currentColor" style="vertical-align: text-bottom; margin-right: 4px;"><path d="M440-440H280v-80h160v-160h80v160h160v80H520v160h-80v-160ZM160-160q-33 0-56.5-23.5T80-240v-480q0-33 23.5-56.5T160-800h480q33 0 56.5 23.5T720-720v180l160-160v440L720-420v180q0 33-23.5 56.5T640-160H160Zm0-80h480v-480H160v480Zm0 0v-480 480Z"/></svg>Upload media
</button>
</li>
</ul>
<!-- Tab Content -->

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Some files were not shown because too many files have changed in this diff Show More