Added stream URL to channel settings.
This commit is contained in:
parent
e4bebce431
commit
93265b7890
|
|
@ -64,6 +64,10 @@ const channelSchema = new mongoose.Schema({
|
||||||
required: true,
|
required: true,
|
||||||
default: true
|
default: true
|
||||||
},
|
},
|
||||||
|
streamURL: {
|
||||||
|
type: mongoose.SchemaTypes.String,
|
||||||
|
default: ''
|
||||||
|
}
|
||||||
},
|
},
|
||||||
permissions: {
|
permissions: {
|
||||||
type: channelPermissionSchema,
|
type: channelPermissionSchema,
|
||||||
|
|
|
||||||
|
|
@ -32,8 +32,15 @@ module.exports.yankMedia = async function(url, title){
|
||||||
//return media object list from IA module
|
//return media object list from IA module
|
||||||
return await iaUtil.fetchMetadata(pullType.id, title);
|
return await iaUtil.fetchMetadata(pullType.id, title);
|
||||||
case "yt":
|
case "yt":
|
||||||
//return mediao object list from the YT-DLP module's youtube function
|
//return media object list from the YT-DLP module's youtube function
|
||||||
return await ytdlpUtil.fetchYoutubeMetadata(pullType.id, title);
|
return await ytdlpUtil.fetchYoutubeMetadata(pullType.id, title);
|
||||||
|
case "ytp":
|
||||||
|
//return media object list from YT-DLP module's youtube playlist function
|
||||||
|
//return await ytdlpUtil.fetchYoutubePlaylistMetadata(pullType.id, title);
|
||||||
|
//Holding off on this since YT-DLP takes 10 years to do a playlist as it needs to pull each and every video one-by-one
|
||||||
|
//Maybe in the future a piped alternative might be in order, however this would most likely require us to host our own local instance.
|
||||||
|
//Though it could give us added resistance against youtube/google's rolling IP bans
|
||||||
|
return null;
|
||||||
case "dm":
|
case "dm":
|
||||||
//return mediao object list from the YT-DLP module's dailymotion function
|
//return mediao object list from the YT-DLP module's dailymotion function
|
||||||
return await ytdlpUtil.fetchDailymotionMetadata(pullType.id, title);
|
return await ytdlpUtil.fetchDailymotionMetadata(pullType.id, title);
|
||||||
|
|
@ -85,7 +92,7 @@ module.exports.getMediaType = async function(url){
|
||||||
|
|
||||||
//If we have link to a resource from archive.org
|
//If we have link to a resource from archive.org
|
||||||
if(match = url.match(/archive\.org\/(?:details|download)\/([a-zA-Z0-9\/._-\s\%]+)/)){
|
if(match = url.match(/archive\.org\/(?:details|download)\/([a-zA-Z0-9\/._-\s\%]+)/)){
|
||||||
//return internet archive code
|
//return internet archive upload id and filepath
|
||||||
return {
|
return {
|
||||||
type: "ia",
|
type: "ia",
|
||||||
id: match[1]
|
id: match[1]
|
||||||
|
|
@ -101,6 +108,15 @@ module.exports.getMediaType = async function(url){
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//If we have a match to a youtube playlist
|
||||||
|
if((match = url.match(/youtube\.com\/playlist\?list=([a-zA-Z0-9_-]{34})/)) || (match = url.match(/youtu\.be\/playlist\?list=([a-zA-Z0-9_-]{34})/))){
|
||||||
|
//return youtube playlist id
|
||||||
|
return {
|
||||||
|
type: "ytp",
|
||||||
|
id: match[1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//If we have a match to a dailymotion video
|
//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-z0-9]{7})/)){
|
||||||
return {
|
return {
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,28 @@ const loggerUtils = require('../loggerUtils.js')
|
||||||
module.exports.fetchYoutubeMetadata = async function(id, title){
|
module.exports.fetchYoutubeMetadata = async function(id, title){
|
||||||
try{
|
try{
|
||||||
//Try to pull media from youtube id
|
//Try to pull media from youtube id
|
||||||
const media = await fetchMetadata(`https://youtu.be/${id}`, title, 'yt');
|
const media = await fetchVideoMetadata(`https://youtu.be/${id}`, title, 'yt');
|
||||||
|
|
||||||
|
//Return found media
|
||||||
|
return media;
|
||||||
|
//If something went wrong
|
||||||
|
}catch(err){
|
||||||
|
//If our IP was banned by youtube
|
||||||
|
if(err.message.match("Sign in to confirm you’re not a bot.")){
|
||||||
|
//Make our own error with blackjack and hookers
|
||||||
|
throw loggerUtils.exceptionSmith("The server's IP address has been banned by youtube. Please contact your server's administrator.", "queue");
|
||||||
|
//Otherwise if we don't have a good way to handle it
|
||||||
|
}else{
|
||||||
|
//toss it back up
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports.fetchYoutubePlaylistMetadata = async function(id, title){
|
||||||
|
try{
|
||||||
|
//Try to pull media from youtube id
|
||||||
|
const media = await fetchPlaylistMetadata(`https://youtu.be/playlist?list=${id}`, title, 'yt');
|
||||||
|
|
||||||
//Return found media
|
//Return found media
|
||||||
return media;
|
return media;
|
||||||
|
|
@ -52,22 +73,19 @@ module.exports.fetchYoutubeMetadata = async function(id, title){
|
||||||
|
|
||||||
module.exports.fetchDailymotionMetadata = async function(id, title){
|
module.exports.fetchDailymotionMetadata = async function(id, title){
|
||||||
//Pull media from dailymotion link
|
//Pull media from dailymotion link
|
||||||
const media = await fetchMetadata(`https://dailymotion.com/video/${id}`, title, 'dm');
|
const media = await fetchVideoMetadata(`https://dailymotion.com/video/${id}`, title, 'dm');
|
||||||
|
|
||||||
//Return found media;
|
//Return found media;
|
||||||
return media;
|
return media;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Generic YTDLP function meant to be used by service-sepecific fetchers which will then be used to fetch video metadata
|
//Generic single video YTDLP function meant to be used by service-sepecific fetchers which will then be used to fetch video metadata
|
||||||
async function fetchMetadata(link, title, type, format = 'b'){
|
async function fetchVideoMetadata(link, title, type, format = 'b'){
|
||||||
//Create media list
|
//Create media list
|
||||||
const mediaList = [];
|
const mediaList = [];
|
||||||
|
|
||||||
//Pull raw metadata
|
//Pull raw metadata from YT-DLP
|
||||||
const rawMetadata = await ytdlp(link, {
|
const rawMetadata = await ytdlpFetch(link, format);
|
||||||
dumpSingleJson: true,
|
|
||||||
format
|
|
||||||
});
|
|
||||||
|
|
||||||
//Pull data from rawMetadata, sanatizing title to prevent XSS
|
//Pull data from rawMetadata, sanatizing title to prevent XSS
|
||||||
const name = validator.escape(validator.trim(rawMetadata.title));
|
const name = validator.escape(validator.trim(rawMetadata.title));
|
||||||
|
|
@ -86,3 +104,16 @@ async function fetchMetadata(link, title, type, format = 'b'){
|
||||||
//Return list of media
|
//Return list of media
|
||||||
return mediaList;
|
return mediaList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//YT-DLP takes forever to handle playlists, we'll handle this via piped in the future perhaps
|
||||||
|
/*async function fetchPlaylistMetadata(link, title, type, format = 'b'){
|
||||||
|
}*/
|
||||||
|
|
||||||
|
//Wrapper function for YT-DLP NPM package with pre-set cli-flags
|
||||||
|
async function ytdlpFetch(link, format = 'b'){
|
||||||
|
//return promise from ytdlp
|
||||||
|
return ytdlp(link, {
|
||||||
|
dumpSingleJson: true,
|
||||||
|
format
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
@ -80,6 +80,11 @@ module.exports.settingsMap = function(){
|
||||||
optional: true,
|
optional: true,
|
||||||
isBoolean: true,
|
isBoolean: true,
|
||||||
errorMessage: "Bad channel settings map."
|
errorMessage: "Bad channel settings map."
|
||||||
|
},
|
||||||
|
'settingsMap.streamURL': {
|
||||||
|
optional: true,
|
||||||
|
isURL: true,
|
||||||
|
errorMessage: "Invalid Stream URL"
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,14 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. %>
|
||||||
<% Object.keys(channel.settings).forEach((key) => { %>
|
<% Object.keys(channel.settings).forEach((key) => { %>
|
||||||
<span class="admin-list-field-container">
|
<span class="admin-list-field-container">
|
||||||
<label class="admin-list-label"><%- key %>:</label>
|
<label class="admin-list-label"><%- key %>:</label>
|
||||||
|
<% switch(typeof channel.settings[key]){
|
||||||
|
case "string": %>
|
||||||
|
<input id=<%- `channel-preference-${key}` %> class="channel-preference-list-item" value="<%- channel.settings[key] %>">
|
||||||
|
<% break;
|
||||||
|
default: %>
|
||||||
<input id=<%- `channel-preference-${key}` %> class="channel-preference-list-item" type="checkbox" <% if(channel.settings[key]){ %> checked <% } %>>
|
<input id=<%- `channel-preference-${key}` %> class="channel-preference-list-item" type="checkbox" <% if(channel.settings[key]){ %> checked <% } %>>
|
||||||
|
<% break;
|
||||||
|
} %>
|
||||||
</span>
|
</span>
|
||||||
<% }); %>
|
<% }); %>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
||||||
|
|
@ -235,13 +235,28 @@ class prefrenceList{
|
||||||
}
|
}
|
||||||
|
|
||||||
async submitUpdate(event){
|
async submitUpdate(event){
|
||||||
|
//Get key from event target
|
||||||
const key = event.target.id.replace("channel-preference-","");
|
const key = event.target.id.replace("channel-preference-","");
|
||||||
const value = event.target.checked;
|
|
||||||
|
//Pull value from event target
|
||||||
|
let value = event.target.value;
|
||||||
|
|
||||||
|
//If this is a checkmark
|
||||||
|
if(event.target.type == "checkbox"){
|
||||||
|
//Use the .checked property instead of .value
|
||||||
|
value = event.target.checked;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Create settings map
|
||||||
const settingsMap = new Map([
|
const settingsMap = new Map([
|
||||||
[key, value]
|
[key, value]
|
||||||
]);
|
]);
|
||||||
|
|
||||||
this.handleUpdate(await utils.ajax.setChannelSetting(this.channel, settingsMap), event.target, key);
|
//Send update and collect results
|
||||||
|
const update = await utils.ajax.setChannelSetting(this.channel, settingsMap);
|
||||||
|
|
||||||
|
//Handle update from server
|
||||||
|
this.handleUpdate(update, event.target, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleUpdate(data, target, key){
|
handleUpdate(data, target, key){
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue