Finished up with internet archive api utility.

This commit is contained in:
rainbow napkin 2025-01-12 16:39:03 -05:00
parent 4c1d3c9db5
commit b443840c29
9 changed files with 241 additions and 43 deletions

View file

@ -23,6 +23,7 @@ const loggerUtils = require('../../utils/loggerUtils');
const csrfUtils = require('../../utils/csrfUtils');
const activeChannel = require('./activeChannel');
const chatHandler = require('./chatHandler');
const mediaYanker = require('./media/yanker');
module.exports = class{
constructor(io){
@ -34,6 +35,7 @@ module.exports = class{
//Load server components
this.chatHandler = new chatHandler(this);
this.mediaYanker = new mediaYanker(this);
//Handle connections from socket.io
io.on("connection", this.handleConnection.bind(this) );
@ -71,6 +73,7 @@ module.exports = class{
//Define listeners
this.defineListeners(socket);
this.chatHandler.defineListeners(socket);
this.mediaYanker.defineListeners(socket);
//Connect the socket to it's given channel
//Lil' hacky to pass chanDB like that, but why double up on DB calls?
@ -127,7 +130,7 @@ module.exports = class{
}
async getActiveChan(socket){
socket.chan = socket.handshake.headers.referer.split('/c/')[1];
socket.chan = socket.handshake.headers.referer.split('/c/')[1].split('/')[0];
const chanDB = (await channelModel.findOne({name: socket.chan}))
//Check if channel exists

View file

@ -33,7 +33,7 @@ module.exports = class commandPreprocessor{
async preprocess(socket, data){
//Set command object
let commandObj = {
const commandObj = {
socket,
sendFlag: true,
rawData: data,

View file

@ -18,8 +18,9 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.*/
const crypto = require('node:crypto');
module.exports = class{
constructor(title, id, type, duration){
constructor(title, fileName, id, type, duration){
this.title = title;
this.fileName = fileName
this.id = id;
this.type = type;
this.duration = duration;

View file

@ -0,0 +1,87 @@
/*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 <https://www.gnu.org/licenses/>.*/
//NPM Imports
const validator = require('validator');//No express here, so regular validator it is!
//local import
const loggerUtils = require('../../../utils/loggerUtils');
const iaUtil = require('../../../utils/media/internetArchiveUtils');
const media = require('./media');
module.exports = class{
constructor(server){
this.server = server;
}
defineListeners(socket){
socket.on("yank", (data) => {this.testYank(socket, data)});
}
async testYank(socket, data){
try{
console.log(await this.yankMedia(data.url));
}catch(err){
return loggerUtils.socketExceptionHandler(socket, err);
}
}
async yankMedia(url){
const pullType = await this.getMediaType(url)
if(pullType == 'ia'){
//Create empty list to hold media objects
const mediaList = []
//Pull metadata from IA
const mediaInfo = await iaUtil.fetchMetadata(url);
//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}`
//Create new media object from file info
mediaList.push(new media(name, name, link, 'ia', file.length));
}
//return media object list
return mediaList
}else{
//return null to signify a bad url
return null
}
}
async getMediaType(url){
//Check if we have a valid url
if(!validator.isURL(url)){
//If not toss the fucker out
return null
}
//If we have link to a resource from archive.org
if(url.match(/^https\:\/\/archive.org\//g)){
//return internet archive code
return "ia";
}
return null;
}
}

View file

@ -0,0 +1,84 @@
/*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 <https://www.gnu.org/licenses/>.*/
//Node Imports
const url = require("node:url");
//Local Imports
const regexUtils = require('../regexUtils');
module.exports.fetchMetadata = async function(link){
//Parse link
const parsedLink = new url.URL(link);
//Split link path
const splitPath = parsedLink.pathname.split('/');
//Get ItemID from link path
const itemID = splitPath[2]
//Splice the empty string, request type, and item ID out from link path
splitPath.splice(0,3)
//Join remaining link path back together to get requested file path within the given archive.org upload
const requestedPath = decodeURIComponent(splitPath.join('/'));
//Create metadata link from itemID
const metadataLink = `https://archive.org/metadata/${itemID}`;
//Fetch item metadata from the internet archive
const response = await fetch(metadataLink,
{
method: "GET"
}
);
//If we hit a snag
if(!response.ok){
//Scream and shout
const errorBody = await response.text();
throw new Error(`Internet Archive Error '${response.status}': ${errorBody}`);
}
//Collect our metadata
const rawMetadata = await response.json();
//Filter out any in-compatible files
const compatibleFiles = rawMetadata.files.filter(compatibilityFilter);
//If we're requesting an empty path
if(requestedPath == ''){
//Return item metadata and compatible files
return {
files: compatibleFiles,
metadata: rawMetadata.metadata
}
//Other wise
}else{
//Return item metadata and matching compatible files
return {
//Filter files out that don't match requested path and return remaining list
files: compatibleFiles.filter(pathFilter),
metadata: rawMetadata.metadata
}
}
function compatibilityFilter(file){
//return true for all files that match for web-safe formats
return file.format == "h.264"
}
function pathFilter(file){
//return true for all file names which match the given requested file path
return file.name.match(`^${regexUtils.escapeRegex(requestedPath)}`);
}
}

23
src/utils/regexUtils.js Normal file
View file

@ -0,0 +1,23 @@
/*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 <https://www.gnu.org/licenses/>.*/
module.exports.escapeRegex = function(string){
/* I won't lie this line was whole-sale ganked from stack overflow like a fucking skid
In my defense I only did it because js-runtime-devs are taking fucking eons to implement RegExp.escape()
This should be replaced once that function becomes available in mainline versions of node.js:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/escape */
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}