diff --git a/src/utils/media/yanker.js b/src/utils/media/yanker.js
index 02f9193..1aaef04 100644
--- a/src/utils/media/yanker.js
+++ b/src/utils/media/yanker.js
@@ -118,7 +118,7 @@ module.exports.getMediaType = async function(url){
}
//If we have a match to a dailymotion video
- if(match = url.match(/dailymotion\.com\/video\/([a-z0-9]{7})/)){
+ if(match = url.match(/dailymotion\.com\/video\/([a-zA-Z0-9]+)/)){
return {
type: "dm",
id: match[1]
diff --git a/src/views/channelSettings.ejs b/src/views/channelSettings.ejs
index a32e53d..5a2780d 100644
--- a/src/views/channelSettings.ejs
+++ b/src/views/channelSettings.ejs
@@ -26,6 +26,7 @@ along with this program. If not, see . %>
<%- include('partial/navbar', {user}); %>
<%- channel.name %> - Channel Settings
+ <%- include('partial/channelSettings/description.ejs', {channel}); %>
<%- include('partial/channelSettings/userList.ejs'); %>
<%- include('partial/channelSettings/banList.ejs'); %>
<%- include('partial/channelSettings/settings.ejs'); %>
diff --git a/src/views/partial/channelSettings/description.ejs b/src/views/partial/channelSettings/description.ejs
new file mode 100644
index 0000000..a2f073f
--- /dev/null
+++ b/src/views/partial/channelSettings/description.ejs
@@ -0,0 +1,31 @@
+<%# Canopy - The next generation of stoner streaming software
+Copyright (C) 2024-2025 Rainbownapkin and the TTN Community
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program. If not, see . %>
+
+
Channel Info:
+
+
+
Thumbnail:
+
+
+
+
+
+
+
Description:
+
<%= channel.description %>
+
+
+
\ No newline at end of file
diff --git a/www/css/adminPanel.css b/www/css/adminPanel.css
index 25b3676..b570a16 100644
--- a/www/css/adminPanel.css
+++ b/www/css/adminPanel.css
@@ -58,6 +58,39 @@ img.admin-list-entry-item{
text-align: center;
}
+#channel-info-div{
+ display: flex;
+ justify-content: space-evenly;
+ padding: 0.3em 0;
+}
+
+.channel-info-span p{
+ margin: 0;
+}
+
+#channel-info-thumbnail-span div{
+ position: relative;
+}
+
+#channel-info-description-span{
+ flex: 0.5;
+}
+
+#channel-info-thumbnail-prompt{
+ position: absolute;
+ width: 8em;
+ top: 3em;
+ left: calc(50% - 4.5em);
+}
+
+
+#channel-info-description-prompt{
+ resize: vertical;
+ width: 100%;
+ min-height: 2em;
+ max-height: 8em;
+}
+
#channel-rank-title{
margin-bottom: 0;
}
diff --git a/www/css/theme/movie-night.css b/www/css/theme/movie-night.css
index de764eb..d7443ae 100644
--- a/www/css/theme/movie-night.css
+++ b/www/css/theme/movie-night.css
@@ -302,6 +302,11 @@ p.channel-guide-entry-item{
background-color: var(--bg1-alt0);
}
+/* channel settings */
+.channel-info-label{
+ color: var(--accent1-alt0);
+}
+
/* channel */
#media-panel-div{
background-color: black;
diff --git a/www/js/channel/player.js b/www/js/channel/player.js
index dac0a13..2b7ccd1 100644
--- a/www/js/channel/player.js
+++ b/www/js/channel/player.js
@@ -99,6 +99,8 @@ class player{
}else if(data.media.type == "livehls"){
//Create a new HLS Livestream Handler for it
this.mediaHandler = new hlsLiveStreamHandler(this.client, this, data.media);
+ }else if(data.media.type == 'dm'){
+ this.mediaHandler = new hlsDailymotionHandler(this.client, this, data.media);
//Otherwise, if we have a raw-file compatible source
}else if(data.media.type == 'ia' || data.media.type == 'raw' || data.media.type == 'yt' || data.media.type == 'dm'){
//Create a new raw file handler for it
diff --git a/www/js/channelSettings.js b/www/js/channelSettings.js
index 980b1cb..1713335 100644
--- a/www/js/channelSettings.js
+++ b/www/js/channelSettings.js
@@ -19,6 +19,7 @@ class channelSettingsPage{
//Get channel name off of the URL
this.channel = window.location.pathname.slice(3).replace('/settings','');
//Instantiate UX handling objects, making sure to pass the channel name.
+ this.chanInfo = new chanInfo(this.channel);
this.rankList = new rankList(this.channel);
this.banList = new banList(this.channel);
this.permList = new permList(this.channel);
@@ -29,6 +30,81 @@ class channelSettingsPage{
}
}
+class chanInfo{
+ constructor(channel){
+ //Define channel
+ this.channel = channel;
+ //Define UX elements
+ this.thumbnail = document.querySelector("#channel-info-thumbnail");
+ this.thumbnailInput = document.querySelector("#channel-info-thumbnail-prompt");
+ this.description = document.querySelector("#channel-info-description");
+ //Create description prompt
+ this.descriptionInput = document.createElement("textarea");
+ this.descriptionInput.id = "channel-info-description-prompt";
+
+ //Setup Input Event Handlers
+ this.setupInput();
+ }
+
+ setupInput(){
+ this.thumbnail.addEventListener('click', ()=>{this.toggleThumbnailPrompt(true)});
+ this.thumbnailInput.addEventListener('keydown', this.submitThumbnail.bind(this));
+
+ this.description.addEventListener('click', ()=>{this.toggleDescriptionPrompt(true)})
+ this.descriptionInput.addEventListener('keydown', this.submitDescription.bind(this));
+ }
+
+ toggleThumbnailPrompt(enabled){
+ this.thumbnailInput.style.display = enabled ? "" : "none";
+
+ if(enabled){
+ this.thumbnail.classList.remove('interactive');
+ }else{
+ this.thumbnail.classList.add('interactive');
+ }
+ }
+
+ submitThumbnail(event){
+ //If we hit didnt hit enter or escape
+ if(!(event.key == "Enter" || event.key == "Escape") && event.key != null){
+ //bail!
+ return;
+ }
+
+ //Toggle prompt
+ this.toggleThumbnailPrompt(false);
+
+ //Only returns after this point
+ if(event.key != "Enter" && event.key != null){
+ return;
+ }
+ }
+
+ toggleDescriptionPrompt(enabled){
+ if(enabled){
+ this.description.replaceWith(this.descriptionInput);
+ }else{
+ this.descriptionInput.replaceWith(this.description);
+ }
+ }
+
+ submitDescription(event){
+ //If we hit didnt hit enter (without shift) or escape
+ if(!((event.key == "Enter" && !event.shiftKey) || event.key == "Escape") && event.key != null){
+ //bail!
+ return;
+ }
+
+ //Toggle prompt
+ this.toggleDescriptionPrompt(false);
+
+ //Only returns after this point
+ if(event.key != "Enter" && !event.shiftKey && event.key != null){
+ return;
+ }
+ }
+}
+
class rankList{
constructor(channel){
this.channel = channel
@@ -52,7 +128,7 @@ class rankList{
}
async submitNewRank(event){
- if(event.key != "Enter" && event.key != null){
+ if((event.key != "Enter" ) && event.key != null){
//Bail out if we didn't hit enter
return;
}