Compare commits

...

1 Commits

Author SHA1 Message Date
77519e6d52 first 2024-01-06 18:09:23 -05:00
12 changed files with 576 additions and 530 deletions

2
app.js
View File

@ -39,7 +39,7 @@ app.onListen.push(function(){
app.contollers.pubsub.subscribe(/./g, function(data, topic){ app.contollers.pubsub.subscribe(/./g, function(data, topic){
app.io.emit('P2PSub', { topic, data }); app.io.emit('P2PSub', { topic, data });
}); });
app.io.on('connection', (socket) => { app.io.on('connection', (socket) => {
// console.log('socket', socket) // console.log('socket', socket)

View File

@ -1,419 +1,56 @@
var app = {}; // socket
app.pubsub = (function(){ // api
app.topics = {};
app.subscribe = function(topic, listener) { // auth
if(topic instanceof RegExp){
listener.match = topic;
topic = "__REGEX__";
}
// create the topic if not yet created // user
if(!app.topics[topic]) app.topics[topic] = [];
// add the listener // group
app.topics[topic].push(listener);
}
app.matchTopics = function(topic){ "use strict";
topic = topic || ''; /* globals jQuery, Mustache, XRegExp, $, app */
var matches = [... app.topics[topic] ? app.topics[topic] : []]; var app = app || {};
if(!app.topics['__REGEX__']) return matches; ( function($){
for(var listener of app.topics['__REGEX__']){ /*
if(topic.match(listener.match)) matches.push(listener); delay calling document.ready until app is loaded.
} */
jQuery.holdReady(true);
return matches; app.includeScrip = function(path, base){
} path = (base || JQapp_BASE_PATH || '') + path;
app.publish = function(topic, data) { jQuery.ajax({
url: path,
// send the event to all listeners dataType: 'script',
app.matchTopics(topic).forEach(function(listener) { async: false
setTimeout(function(data, topic){
listener(data || {}, topic);
}, 0, data, topic);
}); });
}
return this;
})(app);
app.socket = (function(app){
// $.getScript('/socket.io/socket.io.js')
// <script type="text/javascript" src="/socket.io/socket.io.js"></script>
var socket;
$(document).ready(function(){
socket = io({
auth: {
token: app.auth.getToken()
}
});
// socket.emit('chat message', $('#m').val());
socket.on('P2PSub', function(msg){
msg.data.__noSocket = true;
app.publish(msg.topic, msg.data);
});
app.subscribe(/./g, function(data, topic){
// console.log('local_pubs', data, topic)
if(data.__noSocket) return;
// console.log('local_pubs 2', data, topic)
socket.emit('P2PSub', { topic, data });
});
})
return socket;
})(app);
app.api = (function(app){
var baseURL = '/__api/'
$( document ).on( "ajaxError", function(event, res, req) {
console.log('bad!', `app:api:error:`, res.status);
app.publish(`app:api:error:${res.status}`, {res, res});
} );
function post(url, data, callback){
callback = callback || app.util.emptyFuction;
$.ajax({
type: 'POST',
url: baseURL+url,
headers:{
'auth-token': app.auth.getToken()
},
data: JSON.stringify(data),
contentType: "application/json; charset=utf-8",
dataType: "json",
complete: function(res, text){
callback(
text !== 'success' ? res.statusText : null,
JSON.parse(res.responseText),
res.status
)
}
});
}
function put(url, data, callback){
$.ajax({
type: 'PUT',
url: baseURL+url,
headers:{
'auth-token': app.auth.getToken()
},
data: JSON.stringify(data),
contentType: "application/json; charset=utf-8",
dataType: "json",
complete: function(res, text){
callback(
text !== 'success' ? res.statusText : null,
JSON.parse(res.responseText),
res.status
)
}
});
}
function remove(url, callback, callback2){
if(!$.isFunction(callback)) callback = callback2;
$.ajax({
type: 'delete',
url: baseURL+url,
headers:{
'auth-token': app.auth.getToken()
},
contentType: "application/json; charset=utf-8",
dataType: "json",
complete: function(res, text){
callback(
text !== 'success' ? res.statusText : null,
JSON.parse(res.responseText),
res.status
)
}
});
}
function get(url, callback){
$.ajax({
type: 'GET',
url: baseURL+url,
headers:{
'auth-token': app.auth.getToken()
},
contentType: "application/json; charset=utf-8",
dataType: "json",
complete: function(res, text){
callback(
text !== 'success' ? res.statusText : null,
JSON.parse(res.responseText),
res.status
)
}
});
}
return {post: post, get: get, put: put, delete: remove}
})(app)
app.auth = (function(app) {
var user = {}
function setToken(token){
localStorage.setItem('APIToken', token);
}
function getToken(){
return localStorage.getItem('APIToken');
}
function isLoggedIn(callback){
if(getToken()){
return app.api.get('user/me', function(error, data){
if(error === 'Unauthorized') logOut();
if(!error) app.auth.user = data;
return callback(error, data);
});
}else{
callback(null, false);
}
}
function logIn(args, callback){
app.api.post('auth/login', args, function(error, data){
if(data.login){
setToken(data.token);
}
callback(error, !!data.token);
});
}
function logOut(callback){
callback = callback || app.util.emptyFuction;
localStorage.removeItem('APIToken');
callback();
}
function makeUserFromInvite(args, callback){
app.api.post('auth/invite/'+ args.token, args, function(error, data){
if(data.login){
callback(null, data);
setToken(data.token);
}
callback(error, !!data.token);
});
}
function forceLogin(){
$.holdReady( true );
app.auth.isLoggedIn(function(error, isLoggedIn){
if(error || !isLoggedIn){
app.auth.logOut(function(){})
location.replace(`/login${location.href.replace(location.origin, '')}`);
}else{
$.holdReady( false );
}
});
}
function logInRedirect(){
window.location.href = location.href.replace(location.origin+'/login', '') || '/'
}
$( document ).ready( function(){
isLoggedIn(function(error, isLoggedIn){
if(!error && isLoggedIn){
$('.tbp_proxy_is_authed').show();
$('.tbp_proxy_not_authed').hide();
}else{
$('.tbp_proxy_is_authed').hide();
$('.tbp_proxy_not_authed').show();
}
});
});
return {
getToken: getToken,
setToken: setToken,
isLoggedIn: isLoggedIn,
logIn: logIn,
logOut: logOut,
makeUserFromInvite: makeUserFromInvite,
forceLogin,
logInRedirect,
}
})(app);
app.util = (function(app){
function getUrlParameter(name) {
name = name.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]');
var regex = new RegExp('[\\?&]' + name + '=([^&#]*)');
var results = regex.exec(location.search);
return results === null ? '' : decodeURIComponent(results[1].replace(/\+/g, ' '));
}; };
function actionMessage(message, $target, type, callback){ app.include = function(scripts, base){
message = message || ''; scripts = $.isArray(scripts) ? scripts : [scripts];
$target = $target.closest('div.card').find('.actionMessage'); for(let script of scripts){
type = type || 'info'; app.includeScrip(script, base)
callback = callback || function(){};
if($target.html() === message) return;
if($target.html()){
$target.slideUp('fast', function(){
$target.html('')
$target.removeClass (function (index, className) {
return (className.match (/(^|\s)ui-\S+/g) || []).join(' ');
});
if(message) return actionMessage(message, $target, type, callback);
$target.hide()
})
}else{
if(type) $target.addClass('ui-' + type);
$target.html(message).slideDown('fast');
} }
setTimeout(callback,10)
} }
})(jQuery);
$.fn.serializeObject = function() { app.include([
var '/utils.js',
arr = $(this).serializeArray(), '/pubsub.js',
obj = {}; '/api.js',
'/socket.js',
for(var i = 0; i < arr.length; i++) { '/user.js',
if(obj[arr[i].name] === undefined) { '/group.js',
obj[arr[i].name] = arr[i].value; '/auth.js',
} else { ], JQapp_BASE_PATH)
if(!(obj[arr[i].name] instanceof Array)) {
obj[arr[i].name] = [obj[arr[i].name]];
}
obj[arr[i].name].push(arr[i].value);
}
}
return obj;
};
return { /*
getUrlParameter: getUrlParameter, when the DOM is finished, start the app
actionMessage: actionMessage, */
emptyFuction: function(){}, jQuery(document).on("DOMContentLoaded", function(event) {
app.publish("__dom-content-loaded-start");
} app.publish("__dom-content-loaded-end");
})(app); });
app.user = (function(app){
function list(callback){
app.api.get('user/?detail=true', function(error, data){
callback(error, data);
})
}
function add(args, callback){
app.api.post('user/', args, function(error, data){
callback(error, data);
});
}
function remove(args, callback){
if(!confirm('Delete '+ args.uid+ 'user?')) return false;
app.api.delete('user/'+ args.uid, function(error, data){
callback(error, data);
});
}
function changePassword(args, callback){
app.api.put('users/'+ arg.uid || '', args, function(error, data){
callback(error, data);
});
}
function createInvite(callback){
app.api.post('user/invite', {}, function(error, data, status){
callback(error, data);
});
}
function consumeInvite(args){
app.api.post('/auth/invite/'+args.token, args, function(error, data){
if(data.token){
app.auth.setToken(data.token)
return callback(null, true)
}
callback(error)
});
}
return {list, remove, createInvite};
})(app);
app.group = (function(app){
function list(callback){
app.api.get('group?detail=true', function(error, data){
callback(error, data);
});
}
function remove(args, callback){
app.api.delete('group/'+args.cn, function(error, data){
callback(error, data);
});
}
return {list, remove}
})(app);
$( document ).ready( function () {
$( 'div.row' ).fadeIn( 'slow' ); //show the page
//panel button's
$( '.fa-arrows-v' ).click( function () {
$( this ).closest( '.card' ).find( '.card-body' ).slideToggle( 'fast' );
});
$('.actionMessage').on('click', 'button.action-close', function(event){
app.util.actionMessage(null, $(this));
})
});
//ajax form submit
function formAJAX( btn, del ) {
event.preventDefault(); // avoid to execute the actual submit of the form.
var $form = $(btn).closest( '[action]' ); // gets the 'form' parent
var formData = $form.find( '[name]' ).serializeObject(); // builds query formDataing
var method = $form.attr('method') || 'post';
// if( !$form.validate()) {
// app.util.actionMessage('Please fix the form errors.', $form, 'danger')
// return false;
// }
app.util.actionMessage(
'<div class="spinner-border" role="status"><span class="sr-only">Loading...</span></div>',
$form,
'state-highlight'
);
app.api[method]($form.attr('action'), formData, function(error, data){
app.util.actionMessage(data.message, $form, error ? 'state-error' : 'priority-primary'); //re-populate table
if(!error){
$form.trigger("reset");
eval($form.attr('evalAJAX')); //gets JS to run after completion
}
});
}

91
public/js/app/api.js Normal file
View File

@ -0,0 +1,91 @@
app.api = (function(app){
var baseURL = '/__api/'
$( document ).on( "ajaxError", function(event, res, req) {
console.log('bad!', `app:api:error:`, res.status);
app.publish(`app:api:error:${res.status}`, {res, res});
} );
function post(url, data, callback){
callback = callback || app.util.emptyFuction;
$.ajax({
type: 'POST',
url: baseURL+url,
headers:{
'auth-token': app.auth.getToken()
},
data: JSON.stringify(data),
contentType: "application/json; charset=utf-8",
dataType: "json",
complete: function(res, text){
callback(
text !== 'success' ? res.statusText : null,
JSON.parse(res.responseText),
res.status
)
}
});
}
function put(url, data, callback){
$.ajax({
type: 'PUT',
url: baseURL+url,
headers:{
'auth-token': app.auth.getToken()
},
data: JSON.stringify(data),
contentType: "application/json; charset=utf-8",
dataType: "json",
complete: function(res, text){
callback(
text !== 'success' ? res.statusText : null,
JSON.parse(res.responseText),
res.status
)
}
});
}
function remove(url, callback, callback2){
if(!$.isFunction(callback)) callback = callback2;
$.ajax({
type: 'delete',
url: baseURL+url,
headers:{
'auth-token': app.auth.getToken()
},
contentType: "application/json; charset=utf-8",
dataType: "json",
complete: function(res, text){
callback(
text !== 'success' ? res.statusText : null,
JSON.parse(res.responseText),
res.status
)
}
});
}
function get(url, callback){
$.ajax({
type: 'GET',
url: baseURL+url,
headers:{
'auth-token': app.auth.getToken()
},
contentType: "application/json; charset=utf-8",
dataType: "json",
complete: function(res, text){
callback(
text !== 'success' ? res.statusText : null,
JSON.parse(res.responseText),
res.status
)
}
});
}
return {post: post, get: get, put: put, delete: remove}
})(app);

87
public/js/app/auth.js Normal file
View File

@ -0,0 +1,87 @@
app.auth = (function(app) {
var user = {}
function setToken(token){
localStorage.setItem('APIToken', token);
}
function getToken(){
return localStorage.getItem('APIToken');
}
function isLoggedIn(callback){
if(getToken()){
return app.api.get('user/me', function(error, data){
if(error === 'Unauthorized') logOut();
if(!error) app.auth.user = data;
return callback(error, data);
});
}else{
callback(null, false);
}
}
function logIn(args, callback){
app.api.post('auth/login', args, function(error, data){
if(data.login){
setToken(data.token);
}
callback(error, !!data.token);
});
}
function logOut(callback){
callback = callback || app.util.emptyFuction;
localStorage.removeItem('APIToken');
callback();
}
function makeUserFromInvite(args, callback){
app.api.post('auth/invite/'+ args.token, args, function(error, data){
if(data.login){
callback(null, data);
setToken(data.token);
}
callback(error, !!data.token);
});
}
function forceLogin(){
$.holdReady( true );
app.auth.isLoggedIn(function(error, isLoggedIn){
if(error || !isLoggedIn){
app.auth.logOut(function(){})
location.replace(`/login${location.href.replace(location.origin, '')}`);
}else{
$.holdReady( false );
}
});
}
function logInRedirect(){
window.location.href = location.href.replace(location.origin+'/login', '') || '/'
}
$( document ).ready( function(){
isLoggedIn(function(error, isLoggedIn){
if(!error && isLoggedIn){
$('.tbp_proxy_is_authed').show();
$('.tbp_proxy_not_authed').hide();
}else{
$('.tbp_proxy_is_authed').hide();
$('.tbp_proxy_not_authed').show();
}
});
});
return {
getToken: getToken,
setToken: setToken,
isLoggedIn: isLoggedIn,
logIn: logIn,
logOut: logOut,
makeUserFromInvite: makeUserFromInvite,
forceLogin,
logInRedirect,
}
})(app);

15
public/js/app/group.js Normal file
View File

@ -0,0 +1,15 @@
app.group = (function(app){
function list(callback){
app.api.get('group?detail=true', function(error, data){
callback(error, data);
});
}
function remove(args, callback){
app.api.delete('group/'+args.cn, function(error, data){
callback(error, data);
});
}
return {list, remove}
})(app);

41
public/js/app/pubsub.js Normal file
View File

@ -0,0 +1,41 @@
app.pubsub = (function(){
app.topics = {};
app.subscribe = function(topic, listener) {
if(topic instanceof RegExp){
listener.match = topic;
topic = "__REGEX__";
}
// create the topic if not yet created
if(!app.topics[topic]) app.topics[topic] = [];
// add the listener
app.topics[topic].push(listener);
}
app.matchTopics = function(topic){
topic = topic || '';
var matches = [... app.topics[topic] ? app.topics[topic] : []];
if(!app.topics['__REGEX__']) return matches;
for(var listener of app.topics['__REGEX__']){
if(topic.match(listener.match)) matches.push(listener);
}
return matches;
}
app.publish = function(topic, data) {
// send the event to all listeners
app.matchTopics(topic).forEach(function(listener) {
setTimeout(function(data, topic){
listener(data || {}, topic);
}, 0, data, topic);
});
}
return this;
})(app);

28
public/js/app/socket.js Normal file
View File

@ -0,0 +1,28 @@
app.socket = (function(app){
// $.getScript('/socket.io/socket.io.js')
// <script type="text/javascript" src="/socket.io/socket.io.js"></script>
var socket;
$(document).ready(function(){
socket = io({
auth: {
token: app.auth.getToken()
}
});
// socket.emit('chat message', $('#m').val());
socket.on('P2PSub', function(msg){
msg.data.__noSocket = true;
app.publish(msg.topic, msg.data);
});
app.subscribe(/./g, function(data, topic){
// console.log('local_pubs', data, topic)
if(data.__noSocket) return;
// console.log('local_pubs 2', data, topic)
socket.emit('P2PSub', { topic, data });
});
})
return socket;
})(app);

122
public/js/app/torrent.js Normal file
View File

@ -0,0 +1,122 @@
app.torrent = (function(app){
let isDown = false;
$( document ).on( "ajaxSend", function(event, ajax, res, ...args) {
console.log('right?', res.url, res.url.startsWith('/__api/torrent'), app.torrent.isDown)
if(res.url.startsWith('/__api/torrent') && isDown){
ajax.abort()
}
// $( ".log" ).text( "Triggered ajaxStart handler." );
// throw new Error('go')
} );
statusMap = [
'Inactive', // 0
'CHECK_WAIT', // 1
'Verifying', // 2
'DOWNLOAD_WAIT', // 3
'Downloading', // 4
'SEED_WAIT', // 5
'Seeding', // 6
'ISOLATED', // 7
'Unknown', // 8
];
function list(callback, username) {
app.api.get('torrent', function(error, data){
if(error) return;
callback(null, data)
});
}
function get(callback, id, forceUpdate){
app.api.get(`torrent/${id}?${forceUpdate ? 'latest': '' }`, function(error, data){
if(error) return;
callback(null, data)
});
}
function start(id, callback){
app.api.post(`torrent/${id}/start`, function(error, data){
if(error) return;
callback(null, data)
});
}
function stop(id, callback){
app.api.post(`torrent/${id}/stop`, function(error, data){
if(error) return;
callback(null, data)
});
}
function destroy(id, callback){
app.api.delete(`torrent/${id}`, function(error, data){
if(error) return;
callback(null, data)
});
}
function parseServerStatus(data){
return {
...data,
"downloadSpeed": humanFileSize(data.downloadSpeed)+'/s',
"uploadSpeed": humanFileSize(data.uploadSpeed)+'/s',
/* "activeTorrentCount": 11,
"cumulative-stats": {
"downloadedBytes": 2925927098021,
"filesAdded": 80609,
"secondsActive": 12136579,
"sessionCount": 21,
"uploadedBytes": 107123787853
},
"current-stats": {
"downloadedBytes": 48440590262,
"filesAdded": 544,
"secondsActive": 111907,
"sessionCount": 1,
"uploadedBytes": 461874022
},
"pausedTorrentCount": 462,
"torrentCount": 473,
"__noSocket": true*/
}
}
function parseTorrnetItem(torrent){
let percentDone = (torrent.percentDone || 0)*100;
return {
...torrent,
"eta": torrent.eta > 0 ? moment().seconds(torrent.eta).fromNow() : 'Unknown',
"rateDownload": `${humanFileSize(torrent.rateDownload)}/s`,
"sizeWhenDone": humanFileSize(torrent.sizeWhenDone),
"percentDone": percentDone,
"statusText": statusMap[torrent.status],
"isActive": [3, 4, 5, 6].includes(torrent.status), // DOWNLOAD_WAIT ,DOWNLOAD, SEED_WAIT, SEED
"isFinished": torrent.isFinished || percentDone === 100,
"createdAtString": moment(torrent.createdAt).fromNow(),
// "isFinished": false,
// "isStalled": false,
// "name": "reacher.s02e06.1080p.web.h264-successfulcrab[EZTVx.to].mkv",
// "hashString": "4794a0915cada6c491eb5c910e1f4a0da727cac8",
// "status": 4,
// "id": 1,
// "peersConnected": 50,
// "added_by": "wmantly",
// "errorString": "",
// "downloadDir": "/media/torrents",
// "files": [],
// "peers": [],
// "magnetLink": "magnet:?xt=urn:btih:4794A0915CADA6C491EB5C910E1F4A0DA727CAC8&dn=Reacher+S02E06+1080p+WEB+H264-SuccessfulCrab&tr=http%3A%2F%2Fp4p.arenabg.com%3A1337%2Fannounce&tr=udp%3A%2F%2F47.ip-51-68-199.eu%3A6969%2Fannounce&tr=udp%3A%2F%2F9.rarbg.me%3A2780%2Fannounce&tr=udp%3A%2F%2F9.rarbg.to%3A2710%2Fannounce&tr=udp%3A%2F%2F9.rarbg.to%3A2730%2Fannounce&tr=udp%3A%2F%2F9.rarbg.to%3A2920%2Fannounce&tr=udp%3A%2F%2Fopen.stealth.si%3A80%2Fannounce&tr=udp%3A%2F%2Fopentracker.i2p.rocks%3A6969%2Fannounce&tr=udp%3A%2F%2Ftracker.coppersurfer.tk%3A6969%2Fannounce&tr=udp%3A%2F%2Ftracker.cyberia.is%3A6969%2Fannounce&tr=udp%3A%2F%2Ftracker.dler.org%3A6969%2Fannounce&tr=udp%3A%2F%2Ftracker.internetwarriors.net%3A1337%2Fannounce&tr=udp%3A%2F%2Ftracker.leechers-paradise.org%3A6969%2Fannounce&tr=udp%3A%2F%2Ftracker.openbittorrent.com%3A6969%2Fannounce&tr=udp%3A%2F%2Ftracker.opentrackr.org%3A1337&tr=udp%3A%2F%2Ftracker.pirateparty.gr%3A6969%2Fannounce&tr=udp%3A%2F%2Ftracker.tiny-vps.com%3A6969%2Fannounce&tr=udp%3A%2F%2Ftracker.torrent.eu.org%3A451%2Fannounce",
// "isPrivate": false,
// "createdAt": "2024-01-05T21:18:30.607Z",
// "updatedAt": "2024-01-05T21:32:54.493Z"
// "torrent_id": "454",
}
}
return {list, get, start, stop, destroy, parseTorrnetItem, parseServerStatus, isDown};
})(app);

44
public/js/app/user.js Normal file
View File

@ -0,0 +1,44 @@
app.user = (function(app){
function list(callback){
app.api.get('user/?detail=true', function(error, data){
callback(error, data);
})
}
function add(args, callback){
app.api.post('user/', args, function(error, data){
callback(error, data);
});
}
function remove(args, callback){
if(!confirm('Delete '+ args.uid+ 'user?')) return false;
app.api.delete('user/'+ args.uid, function(error, data){
callback(error, data);
});
}
function changePassword(args, callback){
app.api.put('users/'+ arg.uid || '', args, function(error, data){
callback(error, data);
});
}
function createInvite(callback){
app.api.post('user/invite', {}, function(error, data, status){
callback(error, data);
});
}
function consumeInvite(args){
app.api.post('/auth/invite/'+args.token, args, function(error, data){
if(data.token){
app.auth.setToken(data.token)
return callback(null, true)
}
callback(error)
});
}
return {list, remove, createInvite};
})(app);

96
public/js/app/utils.js Normal file
View File

@ -0,0 +1,96 @@
app.util = (function(app){
function getUrlParameter(name) {
name = name.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]');
var regex = new RegExp('[\\?&]' + name + '=([^&#]*)');
var results = regex.exec(location.search);
return results === null ? '' : decodeURIComponent(results[1].replace(/\+/g, ' '));
};
function actionMessage(message, $target, type, callback){
message = message || '';
$target = $target.closest('div.card').find('.actionMessage');
type = type || 'info';
callback = callback || function(){};
if($target.html() === message) return;
if($target.html()){
$target.slideUp('fast', function(){
$target.html('')
$target.removeClass (function (index, className) {
return (className.match (/(^|\s)ui-\S+/g) || []).join(' ');
});
if(message) return actionMessage(message, $target, type, callback);
$target.hide()
})
}else{
if(type) $target.addClass('ui-' + type);
$target.html(message).slideDown('fast');
}
setTimeout(callback,10)
}
$( document ).ready( function () {
$('.actionMessage').on('click', 'button.action-close', function(event){
app.util.actionMessage(null, $(this));
});
});
$.fn.serializeObject = function() {
var
arr = $(this).serializeArray(),
obj = {};
for(var i = 0; i < arr.length; i++) {
if(obj[arr[i].name] === undefined) {
obj[arr[i].name] = arr[i].value;
} else {
if(!(obj[arr[i].name] instanceof Array)) {
obj[arr[i].name] = [obj[arr[i].name]];
}
obj[arr[i].name].push(arr[i].value);
}
}
return obj;
};
function formAJAX( btn, del ) {
event.preventDefault(); // avoid to execute the actual submit of the form.
var $form = $(btn).closest( '[action]' ); // gets the 'form' parent
var formData = $form.find( '[name]' ).serializeObject(); // builds query formDataing
var method = $form.attr('method') || 'post';
// if( !$form.validate()) {
// app.util.actionMessage('Please fix the form errors.', $form, 'danger')
// return false;
// }
app.util.actionMessage(
'<div class="spinner-border" role="status"><span class="sr-only">Loading...</span></div>',
$form,
'state-highlight'
);
app.api[method]($form.attr('action'), formData, function(error, data){
app.util.actionMessage(data.message, $form, error ? 'state-error' : 'priority-primary'); //re-populate table
if(!error){
$form.trigger("reset");
eval($form.attr('evalAJAX')); //gets JS to run after completion
}
});
}
function humanFileSize(size) {
var i = size == 0 ? 0 : Math.floor(Math.log(size) / Math.log(1024));
return (size / Math.pow(1024, i)).toFixed(2) * 1 + ' ' + ['B', 'kB', 'MB', 'GB', 'TB'][i];
}
return {
emptyFuction: function(){},
getUrlParameter,
actionMessage,
humanFileSize,
formAJAX,
}
})(app);

View File

@ -1,3 +1,6 @@
<script type="text/javascript">
var JQapp_BASE_PATH = '/__static/js/app';
</script>
<link rel="stylesheet" href="/__static-modules/jquery-ui/dist/themes/smoothness/jquery-ui.css"> <link rel="stylesheet" href="/__static-modules/jquery-ui/dist/themes/smoothness/jquery-ui.css">
<script type="text/javascript" src="/socket.io/socket.io.js"></script> <script type="text/javascript" src="/socket.io/socket.io.js"></script>
@ -6,6 +9,10 @@
<script src="/__static-modules/moment/min/moment-with-locales.min.js"></script> <script src="/__static-modules/moment/min/moment-with-locales.min.js"></script>
<script src="/__static-modules/jquery-ui/dist/jquery-ui.min.js"></script> <script src="/__static-modules/jquery-ui/dist/jquery-ui.min.js"></script>
<script src="/__static/js/app.js"></script> <script src="/__static/js/app.js"></script>
<script>
console.log("here", app)
app.include('/torrent.js');
</script>
<style type="text/css"> <style type="text/css">
.ui-dialog .ui-dialog-title{ .ui-dialog .ui-dialog-title{
@ -353,128 +360,4 @@
} }
} }
app.torrent = (function(app){
let isDown = false;
$( document ).on( "ajaxSend", function(event, ajax, res, ...args) {
console.log('right?', res.url, res.url.startsWith('/__api/torrent'), app.torrent.isDown)
if(res.url.startsWith('/__api/torrent') && isDown){
ajax.abort()
}
// $( ".log" ).text( "Triggered ajaxStart handler." );
// throw new Error('go')
} );
statusMap = [
'Inactive', // 0
'CHECK_WAIT', // 1
'Verifying', // 2
'DOWNLOAD_WAIT', // 3
'Downloading', // 4
'SEED_WAIT', // 5
'Seeding', // 6
'ISOLATED', // 7
'Unknown', // 8
];
function list(callback, username) {
app.api.get('torrent', function(error, data){
if(error) return;
callback(null, data)
});
}
function get(callback, id, forceUpdate){
app.api.get(`torrent/${id}?${forceUpdate ? 'latest': '' }`, function(error, data){
if(error) return;
callback(null, data)
});
}
function start(id, callback){
app.api.post(`torrent/${id}/start`, function(error, data){
if(error) return;
callback(null, data)
});
}
function stop(id, callback){
app.api.post(`torrent/${id}/stop`, function(error, data){
if(error) return;
callback(null, data)
});
}
function destroy(id, callback){
app.api.delete(`torrent/${id}`, function(error, data){
if(error) return;
callback(null, data)
});
}
function parseServerStatus(data){
return {
...data,
"downloadSpeed": humanFileSize(data.downloadSpeed)+'/s',
"uploadSpeed": humanFileSize(data.uploadSpeed)+'/s',
/* "activeTorrentCount": 11,
"cumulative-stats": {
"downloadedBytes": 2925927098021,
"filesAdded": 80609,
"secondsActive": 12136579,
"sessionCount": 21,
"uploadedBytes": 107123787853
},
"current-stats": {
"downloadedBytes": 48440590262,
"filesAdded": 544,
"secondsActive": 111907,
"sessionCount": 1,
"uploadedBytes": 461874022
},
"pausedTorrentCount": 462,
"torrentCount": 473,
"__noSocket": true*/
}
}
function parseTorrnetItem(torrent){
let percentDone = (torrent.percentDone || 0)*100;
return {
...torrent,
"eta": torrent.eta > 0 ? moment().seconds(torrent.eta).fromNow() : 'Unknown',
"rateDownload": `${humanFileSize(torrent.rateDownload)}/s`,
"sizeWhenDone": humanFileSize(torrent.sizeWhenDone),
"percentDone": percentDone,
"statusText": statusMap[torrent.status],
"isActive": [3, 4, 5, 6].includes(torrent.status), // DOWNLOAD_WAIT ,DOWNLOAD, SEED_WAIT, SEED
"isFinished": torrent.isFinished || percentDone === 100,
"createdAtString": moment(torrent.createdAt).fromNow(),
// "isFinished": false,
// "isStalled": false,
// "name": "reacher.s02e06.1080p.web.h264-successfulcrab[EZTVx.to].mkv",
// "hashString": "4794a0915cada6c491eb5c910e1f4a0da727cac8",
// "status": 4,
// "id": 1,
// "peersConnected": 50,
// "added_by": "wmantly",
// "errorString": "",
// "downloadDir": "/media/torrents",
// "files": [],
// "peers": [],
// "magnetLink": "magnet:?xt=urn:btih:4794A0915CADA6C491EB5C910E1F4A0DA727CAC8&dn=Reacher+S02E06+1080p+WEB+H264-SuccessfulCrab&tr=http%3A%2F%2Fp4p.arenabg.com%3A1337%2Fannounce&tr=udp%3A%2F%2F47.ip-51-68-199.eu%3A6969%2Fannounce&tr=udp%3A%2F%2F9.rarbg.me%3A2780%2Fannounce&tr=udp%3A%2F%2F9.rarbg.to%3A2710%2Fannounce&tr=udp%3A%2F%2F9.rarbg.to%3A2730%2Fannounce&tr=udp%3A%2F%2F9.rarbg.to%3A2920%2Fannounce&tr=udp%3A%2F%2Fopen.stealth.si%3A80%2Fannounce&tr=udp%3A%2F%2Fopentracker.i2p.rocks%3A6969%2Fannounce&tr=udp%3A%2F%2Ftracker.coppersurfer.tk%3A6969%2Fannounce&tr=udp%3A%2F%2Ftracker.cyberia.is%3A6969%2Fannounce&tr=udp%3A%2F%2Ftracker.dler.org%3A6969%2Fannounce&tr=udp%3A%2F%2Ftracker.internetwarriors.net%3A1337%2Fannounce&tr=udp%3A%2F%2Ftracker.leechers-paradise.org%3A6969%2Fannounce&tr=udp%3A%2F%2Ftracker.openbittorrent.com%3A6969%2Fannounce&tr=udp%3A%2F%2Ftracker.opentrackr.org%3A1337&tr=udp%3A%2F%2Ftracker.pirateparty.gr%3A6969%2Fannounce&tr=udp%3A%2F%2Ftracker.tiny-vps.com%3A6969%2Fannounce&tr=udp%3A%2F%2Ftracker.torrent.eu.org%3A451%2Fannounce",
// "isPrivate": false,
// "createdAt": "2024-01-05T21:18:30.607Z",
// "updatedAt": "2024-01-05T21:32:54.493Z"
// "torrent_id": "454",
}
}
return {list, get, start, stop, destroy, parseTorrnetItem, parseServerStatus, isDown};
})(app);
</script> </script>

View File

@ -7,8 +7,10 @@ router.get('/', async function(req, res, next){
try{ try{
res.json({results: await Torrent.findAll({ res.json({results: await Torrent.findAll({
where:{added_by: req.query.username || req.user.username}, where:{added_by: req.query.username || req.user.username},
limit: req.query.limit, // limit: req.query.limit,
offset: req.query.offset // offset: req.query.offset,
// order: [[req.query.orderKey || "created_at", (req.query.asc && "ASC")]],
// from: {$between: [startDate, endDate]}
})}); })});
}catch(error){ }catch(error){
next(error); next(error);