Fixed issues with IA utils, continued work on playlist mgmt UI
This commit is contained in:
parent
3da88aea2a
commit
f4db10fbc3
|
|
@ -46,6 +46,7 @@ playlistMediaProperties.pre('save', async function (next){
|
||||||
});
|
});
|
||||||
|
|
||||||
//methods
|
//methods
|
||||||
|
//Rehydrate to a full phat media object
|
||||||
playlistMediaProperties.methods.rehydrate = function(){
|
playlistMediaProperties.methods.rehydrate = function(){
|
||||||
//Return item as a full phat, standard media object
|
//Return item as a full phat, standard media object
|
||||||
return new media(
|
return new media(
|
||||||
|
|
@ -58,4 +59,14 @@ playlistMediaProperties.methods.rehydrate = function(){
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Dehydrate to minified flat network-friendly object
|
||||||
|
playlistMediaProperties.methods.dehydrate = function(){
|
||||||
|
return {
|
||||||
|
title: this.title,
|
||||||
|
url: this.url,
|
||||||
|
duration: this.duration,
|
||||||
|
uuid: this.uuid.toString()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = mediaSchema.discriminator('saved', playlistMediaProperties);
|
module.exports = mediaSchema.discriminator('saved', playlistMediaProperties);
|
||||||
|
|
@ -41,11 +41,7 @@ playlistSchema.methods.dehydrate = function(){
|
||||||
|
|
||||||
//Fill media array
|
//Fill media array
|
||||||
for(let media of this.media){
|
for(let media of this.media){
|
||||||
mediaArray.push({
|
mediaArray.push(media.dehydrate());
|
||||||
title: media.title,
|
|
||||||
url: media.url,
|
|
||||||
duration: media.duration
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//return dehydrated playlist
|
//return dehydrated playlist
|
||||||
|
|
|
||||||
|
|
@ -16,11 +16,13 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.*/
|
||||||
|
|
||||||
//Node Imports
|
//Node Imports
|
||||||
const url = require("node:url");
|
const url = require("node:url");
|
||||||
|
const validator = require('validator');
|
||||||
|
|
||||||
//Local Imports
|
//Local Imports
|
||||||
const regexUtils = require('../regexUtils');
|
const regexUtils = require('../regexUtils');
|
||||||
|
const media = require('../../app/channel/media/media');
|
||||||
|
|
||||||
module.exports.fetchMetadata = async function(link){
|
module.exports.fetchMetadata = async function(link, title){
|
||||||
//Parse link
|
//Parse link
|
||||||
const parsedLink = new url.URL(link);
|
const parsedLink = new url.URL(link);
|
||||||
//Split link path
|
//Split link path
|
||||||
|
|
@ -31,6 +33,10 @@ module.exports.fetchMetadata = async function(link){
|
||||||
splitPath.splice(0,3)
|
splitPath.splice(0,3)
|
||||||
//Join remaining link path back together to get requested file path within the given archive.org upload
|
//Join remaining link path back together to get requested file path within the given archive.org upload
|
||||||
const requestedPath = decodeURIComponent(splitPath.join('/'));
|
const requestedPath = decodeURIComponent(splitPath.join('/'));
|
||||||
|
//Create empty list to hold media objects
|
||||||
|
const mediaList = [];
|
||||||
|
//Create empty variable to hold return data object
|
||||||
|
let data;
|
||||||
|
|
||||||
//Create metadata link from itemID
|
//Create metadata link from itemID
|
||||||
const metadataLink = `https://archive.org/metadata/${itemID}`;
|
const metadataLink = `https://archive.org/metadata/${itemID}`;
|
||||||
|
|
@ -55,23 +61,48 @@ module.exports.fetchMetadata = async function(link){
|
||||||
//Filter out any in-compatible files
|
//Filter out any in-compatible files
|
||||||
const compatibleFiles = rawMetadata.files.filter(compatibilityFilter);
|
const compatibleFiles = rawMetadata.files.filter(compatibilityFilter);
|
||||||
|
|
||||||
|
|
||||||
//If we're requesting an empty path
|
//If we're requesting an empty path
|
||||||
if(requestedPath == ''){
|
if(requestedPath == ''){
|
||||||
//Return item metadata and compatible files
|
//Return item metadata and compatible files
|
||||||
return {
|
data = {
|
||||||
files: compatibleFiles,
|
files: compatibleFiles,
|
||||||
metadata: rawMetadata.metadata
|
metadata: rawMetadata.metadata
|
||||||
}
|
}
|
||||||
//Other wise
|
//Other wise
|
||||||
}else{
|
}else{
|
||||||
//Return item metadata and matching compatible files
|
//Return item metadata and matching compatible files
|
||||||
return {
|
data = {
|
||||||
//Filter files out that don't match requested path and return remaining list
|
//Filter files out that don't match requested path and return remaining list
|
||||||
files: compatibleFiles.filter(pathFilter),
|
files: compatibleFiles.filter(pathFilter),
|
||||||
metadata: rawMetadata.metadata
|
metadata: rawMetadata.metadata
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//for every compatible and relevant file returned from IA
|
||||||
|
for(let file of data.files){
|
||||||
|
//Split file path by directories
|
||||||
|
const path = file.name.split('/');
|
||||||
|
|
||||||
|
//pull filename from path and escape in-case someone put something nasty in there
|
||||||
|
const name = validator.escape(validator.trim(path[path.length - 1]));
|
||||||
|
|
||||||
|
//Construct link from pulled info
|
||||||
|
const link = `https://archive.org/download/${data.metadata.identifier}/${file.name}`;
|
||||||
|
|
||||||
|
//if we where handed a null title
|
||||||
|
if(title == null || title == ''){
|
||||||
|
//Create new media object from file info substituting filename for title
|
||||||
|
mediaList.push(new media(name, name, link, link, 'ia', Number(file.length)));
|
||||||
|
}else{
|
||||||
|
//Create new media object from file info
|
||||||
|
mediaList.push(new media(title, name, link, link, 'ia', Number(file.length)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//return media object list
|
||||||
|
return mediaList;
|
||||||
|
|
||||||
function compatibilityFilter(file){
|
function compatibilityFilter(file){
|
||||||
//return true for all files that match for web-safe formats
|
//return true for all files that match for web-safe formats
|
||||||
return file.format == "h.264 IA" || file.format == "h.264" || file.format == "Ogg Video" || file.format.match("MPEG4");
|
return file.format == "h.264 IA" || file.format == "h.264" || file.format == "Ogg Video" || file.format.match("MPEG4");
|
||||||
|
|
|
||||||
|
|
@ -19,41 +19,17 @@ const validator = require('validator');//No express here, so regular validator i
|
||||||
|
|
||||||
//local import
|
//local import
|
||||||
const iaUtil = require('./internetArchiveUtils');
|
const iaUtil = require('./internetArchiveUtils');
|
||||||
const media = require('../../app/channel/media/media');
|
|
||||||
|
|
||||||
module.exports.yankMedia = async function(url, title){
|
module.exports.yankMedia = async function(url, title){
|
||||||
|
//Get pull type
|
||||||
const pullType = await this.getMediaType(url);
|
const pullType = await this.getMediaType(url);
|
||||||
|
|
||||||
if(pullType == 'ia'){
|
//Check pull type
|
||||||
//Create empty list to hold media objects
|
switch(pullType){
|
||||||
const mediaList = [];
|
case "ia":
|
||||||
//Pull metadata from IA
|
//return media object list from IA module
|
||||||
const mediaInfo = await iaUtil.fetchMetadata(url);
|
return await iaUtil.fetchMetadata(url, title);
|
||||||
|
default:
|
||||||
//for every compatible and relevant file returned from IA
|
|
||||||
for(let file of mediaInfo.files){
|
|
||||||
//Split file path by directories
|
|
||||||
const path = file.name.split('/');
|
|
||||||
|
|
||||||
//pull filename from path
|
|
||||||
const name = path[path.length - 1];
|
|
||||||
|
|
||||||
//Construct link from pulled info
|
|
||||||
const link = `https://archive.org/download/${mediaInfo.metadata.identifier}/${file.name}`;
|
|
||||||
|
|
||||||
//if we where handed a null title
|
|
||||||
if(title == null || title == ''){
|
|
||||||
//Create new media object from file info substituting filename for title
|
|
||||||
mediaList.push(new media(name, name, link, link, 'ia', Number(file.length)));
|
|
||||||
}else{
|
|
||||||
//Create new media object from file info
|
|
||||||
mediaList.push(new media(title, name, link, link, 'ia', Number(file.length)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//return media object list
|
|
||||||
return mediaList;
|
|
||||||
}else{
|
|
||||||
//return null to signify a bad url
|
//return null to signify a bad url
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
@ -69,7 +45,6 @@ module.exports.getMediaType = async function(url){
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//If we have link to a resource from archive.org
|
//If we have link to a resource from archive.org
|
||||||
if(url.match(/^https\:\/\/archive.org\//g)){
|
if(url.match(/^https\:\/\/archive.org\//g)){
|
||||||
//return internet archive code
|
//return internet archive code
|
||||||
|
|
|
||||||
|
|
@ -164,10 +164,7 @@ div.dragging-queue-entry{
|
||||||
|
|
||||||
.queue-playlist-span{
|
.queue-playlist-span{
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
}
|
padding: 0 0.2em;
|
||||||
|
|
||||||
.queue-playlist-div{
|
|
||||||
padding: 0 0.15em;
|
|
||||||
margin: 0 0.15em;
|
margin: 0 0.15em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -182,10 +179,27 @@ div.dragging-queue-entry{
|
||||||
user-select: none;
|
user-select: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.queue-playlist-title-span{
|
||||||
|
text-wrap: nowrap;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
|
||||||
.queue-playlist-count{
|
.queue-playlist-count{
|
||||||
font-size: 0.8em;
|
font-size: 0.8em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.queue-playlist-media-container-div{
|
||||||
|
resize: vertical;
|
||||||
|
overflow: scroll;
|
||||||
|
height: 5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.queue-playlist-media-container-div p{
|
||||||
|
margin: 0;
|
||||||
|
font-size: 0.8em;
|
||||||
|
}
|
||||||
|
|
||||||
#queue-create-playlist-popup-div{
|
#queue-create-playlist-popup-div{
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
|
||||||
|
|
@ -546,7 +546,13 @@ div.archived p{
|
||||||
border-block: var(--accent1) solid 1px;
|
border-block: var(--accent1) solid 1px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.not-first-queue-playlist-div{
|
|
||||||
|
.queue-playlist-media-container-div{
|
||||||
|
background-color: var(--bg1-alt0);
|
||||||
|
border-block: var(--accent1) solid 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.queue-playlist-span.not-first{
|
||||||
border-top: var(--bg1-alt0) solid 1px;
|
border-top: var(--bg1-alt0) solid 1px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1103,24 +1103,27 @@ class playlistManager{
|
||||||
//Set playlist div dataset
|
//Set playlist div dataset
|
||||||
playlistDiv.dataset.name = playlist.name;
|
playlistDiv.dataset.name = playlist.name;
|
||||||
|
|
||||||
//If this isn't our first rodeo
|
|
||||||
if(playlistIndex != 0){
|
|
||||||
//make note
|
|
||||||
playlistDiv.classList.add('not-first-queue-playlist-div');
|
|
||||||
}
|
|
||||||
|
|
||||||
//Create span to hold playlist entry line contents
|
//Create span to hold playlist entry line contents
|
||||||
const playlistSpan = document.createElement('span');
|
const playlistSpan = document.createElement('span');
|
||||||
//Set classes
|
//Set classes
|
||||||
playlistSpan.classList.add('queue-playlist-span');
|
playlistSpan.classList.add('queue-playlist-span');
|
||||||
|
|
||||||
|
//If this isn't our first rodeo
|
||||||
|
if(playlistIndex != 0){
|
||||||
|
//make note
|
||||||
|
playlistSpan.classList.add('not-first');
|
||||||
|
}
|
||||||
|
|
||||||
|
//pre-render and keep this so we can use it later
|
||||||
|
const mediaContainer = renderMedia();
|
||||||
|
|
||||||
//Append items to playlist entry line
|
//Append items to playlist entry line
|
||||||
playlistSpan.appendChild(renderLabels());
|
playlistSpan.appendChild(renderLabels());
|
||||||
playlistSpan.appendChild(renderControls());
|
playlistSpan.appendChild(renderControls());
|
||||||
|
|
||||||
//Append items to playlist div
|
//Append items to playlist div
|
||||||
playlistDiv.appendChild(playlistSpan);
|
playlistDiv.appendChild(playlistSpan);
|
||||||
playlistDiv.appendChild(renderMedia());
|
playlistDiv.appendChild(mediaContainer);
|
||||||
|
|
||||||
//Append current playlist div to the channel playlists div
|
//Append current playlist div to the channel playlists div
|
||||||
this.channelPlaylistDiv.appendChild(playlistDiv);
|
this.channelPlaylistDiv.appendChild(playlistDiv);
|
||||||
|
|
@ -1132,6 +1135,16 @@ class playlistManager{
|
||||||
//Set it's class
|
//Set it's class
|
||||||
playlistLabels.classList.add('queue-playlist-labels-span');
|
playlistLabels.classList.add('queue-playlist-labels-span');
|
||||||
|
|
||||||
|
//create playlist title span
|
||||||
|
const playlistTitleSpan = document.createElement('span');
|
||||||
|
//Set class
|
||||||
|
playlistTitleSpan.classList.add('queue-playlist-title-span', 'interactive');
|
||||||
|
|
||||||
|
//Create playlist title caret
|
||||||
|
const playlistTitleCaret = document.createElement('i');
|
||||||
|
//Set class
|
||||||
|
playlistTitleCaret.classList.add('bi-caret-right-fill');
|
||||||
|
|
||||||
//Create playlist title label
|
//Create playlist title label
|
||||||
const playlistTitle = document.createElement('p');
|
const playlistTitle = document.createElement('p');
|
||||||
//Set it's class
|
//Set it's class
|
||||||
|
|
@ -1139,6 +1152,10 @@ class playlistManager{
|
||||||
//Unescape Sanatized Enteties and safely inject as plaintext
|
//Unescape Sanatized Enteties and safely inject as plaintext
|
||||||
playlistTitle.innerText = utils.unescapeEntities(playlist.name);
|
playlistTitle.innerText = utils.unescapeEntities(playlist.name);
|
||||||
|
|
||||||
|
//Construct playlist title span
|
||||||
|
playlistTitleSpan.appendChild(playlistTitleCaret);
|
||||||
|
playlistTitleSpan.appendChild(playlistTitle);
|
||||||
|
|
||||||
//Create playlist count label
|
//Create playlist count label
|
||||||
const playlistCount = document.createElement('p');
|
const playlistCount = document.createElement('p');
|
||||||
//Set it's class
|
//Set it's class
|
||||||
|
|
@ -1147,11 +1164,33 @@ class playlistManager{
|
||||||
playlistCount.innerText = `Count: ${playlist.media.length}`;
|
playlistCount.innerText = `Count: ${playlist.media.length}`;
|
||||||
|
|
||||||
//Append items to playlist labels span
|
//Append items to playlist labels span
|
||||||
playlistLabels.appendChild(playlistTitle);
|
playlistLabels.appendChild(playlistTitleSpan);
|
||||||
playlistLabels.appendChild(playlistCount);
|
playlistLabels.appendChild(playlistCount);
|
||||||
|
|
||||||
|
//Define input listeners
|
||||||
|
playlistTitleSpan.addEventListener('click', toggleMedia.bind(this));
|
||||||
|
|
||||||
//return playlistLabels
|
//return playlistLabels
|
||||||
return playlistLabels;
|
return playlistLabels;
|
||||||
|
|
||||||
|
function toggleMedia(){
|
||||||
|
//If the div is hidden
|
||||||
|
if(mediaContainer.style.display == 'none'){
|
||||||
|
//Light up the button
|
||||||
|
playlistTitleSpan.classList.add('positive');
|
||||||
|
//Flip the caret
|
||||||
|
playlistTitleCaret.classList.replace('bi-caret-right-fill', 'bi-caret-down-fill');
|
||||||
|
//Show the div
|
||||||
|
mediaContainer.style.display = '';
|
||||||
|
}else{
|
||||||
|
//Unlight the button
|
||||||
|
playlistTitleSpan.classList.remove('positive');
|
||||||
|
//Flip the caret
|
||||||
|
playlistTitleCaret.classList.replace('bi-caret-down-fill', 'bi-caret-right-fill');
|
||||||
|
//Hide the div
|
||||||
|
mediaContainer.style.display = 'none';
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderControls(){
|
function renderControls(){
|
||||||
|
|
@ -1195,14 +1234,28 @@ class playlistManager{
|
||||||
//Create media container div
|
//Create media container div
|
||||||
const mediaContainer = document.createElement('div');
|
const mediaContainer = document.createElement('div');
|
||||||
//Set classes
|
//Set classes
|
||||||
mediaContainer.classList.add('queue-playlist-media-div');
|
mediaContainer.classList.add('queue-playlist-media-container-div');
|
||||||
|
//Auto-hide media container
|
||||||
|
mediaContainer.style.display = 'none';
|
||||||
|
|
||||||
for(let media of playlist.media){
|
for(let media of playlist.media){
|
||||||
|
//Create media div
|
||||||
|
const mediaDiv = document.createElement('div');
|
||||||
|
//Set class
|
||||||
|
mediaDiv.classList.add('queue-playlist-media-div');
|
||||||
|
|
||||||
//Create media title
|
//Create media title
|
||||||
const mediaTitle = document.createElement('p');
|
const mediaTitle = document.createElement('p');
|
||||||
//Set class
|
//Set class
|
||||||
mediaTitle.classList.add('queue-playlist-media-title');
|
mediaTitle.classList.add('queue-playlist-media-title');
|
||||||
|
//Inject text content
|
||||||
|
mediaTitle.innerText = utils.unescapeEntities(media.title);
|
||||||
|
|
||||||
|
//Append items to media div
|
||||||
|
mediaDiv.appendChild(mediaTitle);
|
||||||
|
|
||||||
|
//Append media div to media container
|
||||||
|
mediaContainer.appendChild(mediaDiv);
|
||||||
}
|
}
|
||||||
|
|
||||||
//return media container
|
//return media container
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue