diff --git a/README.md b/README.md index 01d6a08..4d64e84 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,4 @@ # BinBin -Simple Database Website +Personal Drive Web App + +This web application acts as a web interface for a cloud storage service. Users are assigned drives with permissions to read and/or write. There are two types of drives: real and virtual. A real drive is a physical folder on the host, with all subdirectories of the drive correlating to real subdirectories. A virtual drive is an emulated storage space, with all files being stored under a single directory, and a directory layout is mapped internally in the database. diff --git a/binbin.py b/binbin.py index 634d968..a25c6f4 100644 --- a/binbin.py +++ b/binbin.py @@ -1,8 +1,10 @@ import sys, os, time, hashlib, uuid, threading, atexit, flask, \ - configparser as cp + configparser as cp, magic from flask import Flask, render_template, url_for, request, session, \ - send_from_directory, send_file, redirect + send_from_directory, send_file, redirect, abort, Response from flask_pymongo import PyMongo, ObjectId +from apscheduler.schedulers.background import BackgroundScheduler +from pytz import utc FILTERS = { 'name': 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz' + @@ -22,17 +24,31 @@ def apply_config(): else: app.config[k] = v +def expire(): + links = LINKS.find() + for l in links: + if l['expiry'] < time.time(): + print(l['expiry']) + print(time.time()) + print("deleted") + LINKS.delete_one({'_id': l['_id']}) + + os.chdir(os.path.dirname(__file__)) app = Flask(__name__) apply_config() mongo = PyMongo(app) + +scheduler = BackgroundScheduler(timezone=utc) +scheduler.add_job(expire, 'interval', seconds=20) +scheduler.start() +atexit.register(lambda: scheduler.shutdown()) + USERS, DRIVES, LINKS = mongo.db['users'], mongo.db['drives'], \ mongo.db['links'] -CHECK_PERIOD = 60 -expire_thread = threading.Thread() @app.route('/') def index(): @@ -41,10 +57,12 @@ def index(): else: return render_template('index.html') + @app.route('/main/') def main(method): return render_template(method+'.html') + @app.route('/login', methods=['POST']) def login(): error = None @@ -56,11 +74,13 @@ def login(): else: return flask.jsonify(False) + @app.route('/logout') def logout(): session.pop('username', None) return redirect(url_for('index')) + @app.route('/mydrives') def mydrives(): if 'username' not in session: @@ -94,56 +114,89 @@ def mydrives(): return flask.jsonify(info) -@app.route('/files', methods=['POST']) -def files(): + +@app.route('/files/', methods=['POST']) +def files(method): + err_msgs = { + 'list': 'Error: This directory does not exist.', + 'zip': 'Error: Folder downloading not supported.' + } check = verify_data('files', request.form, session) - if not check[0]: return check[1] + if not check[0]: return check[1], 400 form = check[1] - if form['is_fol']: # If request is a folder. + if method == 'list': + if not form['is_fol']: return err_msgs['list'] info = dir_info(form['path'], form['drive']['type'], \ form['drive']['_id']) return flask.jsonify(info) - else: # If request is a file. - if form['drive']['type'] == 'real': - link = LINKS.insert_one({ - 'path': form['path'], - 'name': form['path'].split("/")[-1], - 'shared': [get_user(session)['_id']], - 'expiry': -1 - }).inserted_id - elif form['drive']['type'] == 'virtual': - r_path = form['drive']['path'] + '/' + form['real_file'] - link = LINKS.insert_one({ - 'path': r_path, - 'name': form['path'].split("/")[-1], - 'shared': [get_user(session)['_id']], - 'expiry': -1 - }).inserted_id - else: - raise Exception("Invalid method for file link creation.") - ### QUEUE DELETION - return str(link) + + elif method == 'download' or method == 'stream': + if form['is_fol']: + return err_msgs['zip'] + else: + link_uuid = str(uuid.uuid4()).replace("-","") + if method == 'download': + expire = -1 + else: + expire = time.time() + 20*60 # 20 minutes + + if form['drive']['type'] == 'real': + link = LINKS.insert_one({ + 'path': form['path'], + 'uuid': link_uuid, + 'name': form['path'].split("/")[-1], + 'shared': [get_user(session)['_id']],\ + 'expiry': expire + }) + elif form['drive']['type'] == 'virtual': + r_path = form['drive']['path'] + '/' \ + + form['real_file'] + link = LINKS.insert_one({ + 'path': r_path, + 'uuid': link_uuid, + 'name': form['path'].split("/")[-1], + 'shared': [get_user(session)['_id']], + 'expiry': expire + }) + else: + raise Exception('Drive not real or virtual.') + return link_uuid + else: + return redirect(url_for('index')) -@app.route('/d/<_id>') -def download(_id): +@app.route('/d/') +def download(uuid): if 'username' not in session: return redirect(url_for('index')) + uuid = uuid.split('.')[0] try: - link = LINKS.find_one({'_id': ObjectId(_id)}) + link = LINKS.find_one({'uuid': uuid}) except: return redirect(url_for('index')) if link == None: return redirect(url_for('index')) if get_user(session)['_id'] not in link['shared']: return redirect(url_for('index')) + + if link['expiry'] == -1: + LINKS.delete_one({'uuid': uuid}) + else: + LINKS.update_one({'uuid': uuid}, { + '$set': {'expiry': time.time() + 20*60} + }) + + if 'pdf' in magic.from_file(link['path'], mime=True): + r = send_file(link['path']) + header = 'inline; filename=\"' + link['name'] + '\"' + r.headers['Content-Disposition'] = header + return r else: - if link['expiry'] == -1: - LINKS.delete_one({'_id': ObjectId(_id)}) return send_file(link['path'], as_attachment=True, - attachment_filename=link['name']) + attachment_filename=link['name'], + conditional=True) @app.route('/users/', methods=['POST']) @@ -155,7 +208,7 @@ def users(method): if method == 'create': check = verify_data('users.create', request.form, session) - if not check[0]: return check[1] + if not check[0]: return check[1], 400 form = check[1] salt = uuid.uuid4().hex @@ -171,7 +224,7 @@ def users(method): elif method == 'delete': check = verify_data('users.delete', request.form, session) - if not check[0]: return check[1] + if not check[0]: return check[1], 400 form = check[1] USERS.delete_one({'username': form['username']}) @@ -183,6 +236,7 @@ def users(method): def drive_path(): pass + @app.errorhandler(404) def page_not_found(e): return render_template('404.html'), 404 @@ -201,6 +255,10 @@ def js(path): def assets(path): return send_from_directory('assets', path) +@app.route('/test/') +def test(path): + return send_from_directory('test', path) + # End temporary def get_user(sess): @@ -217,15 +275,15 @@ def validate_login(u, p): def sizeof_fmt(num, suffix='B'): - for unit in ['','K','M','G','T','P','E','Z']: - if abs(num) < 1024.0: - return '%3.1f%s%s' % (num, unit, suffix) - num /= 1024.0 - return '%.1f%s%s' % (num, 'Y', suffix) + for unit in ['','K','M','G','T','P','E','Z']: + if abs(num) < 1024.0: + return '%3.1f%s%s' % (num, unit, suffix) + num /= 1024.0 + return '%.1f%s%s' % (num, 'Y', suffix) def dir_info(path, t, drive_id): - def info_dict(item, stats, is_fol): + def info_dict(item, stats, is_fol, filetype): if is_fol: my_item = ({ 'folder': True, @@ -233,12 +291,12 @@ def dir_info(path, t, drive_id): }) else: my_item = ({ - 'folder': False, 'name': item, 'date': time.strftime('%Y-%m-%d %H:%M:%S UTC', \ time.gmtime(stats[8])), 'size': sizeof_fmt(stats[6]), - 'real_size': stats[6] + 'real_size': stats[6], + 'filetype': filetype }) return my_item full_items = [] @@ -246,9 +304,15 @@ def dir_info(path, t, drive_id): if t == 'real': items = os.listdir(path) for item in items: - stats = list(os.stat(path + '/' + item)) - is_fol = os.path.isdir(path + '/' + item) - full_items.append(info_dict(item, stats, is_fol)) + f_path = path + '/' + item + stats = list(os.stat(f_path)) + is_fol = os.path.isdir(f_path) + if not is_fol: + kind = magic.from_file(f_path, mime=True) + else: + kind = None + + full_items.append(info_dict(item, stats, is_fol, kind)) elif t == 'virtual': drives = DRIVES.find_one({'_id': drive_id}) @@ -260,11 +324,14 @@ def dir_info(path, t, drive_id): for k,v in tree.items(): is_fol = type(v).__name__ != 'str' if is_fol: - stats = None + stats, kind = None, None else: stats = list(os.stat(drives['path'] + '/' + v)) + kind = magic.from_file(drives['path'] + '/' + v, + mime=True) + full_items.append(info_dict(k.replace(':','.'), \ - stats, is_fol)) + stats, is_fol, kind)) return full_items @@ -451,11 +518,5 @@ def create_drive(method, owner, form=None): return 'Operation completed.' -def manage_expiry(): - links = LINKS.find() - #print(links) - - - if __name__ == '__main__': app.run(debug=True) \ No newline at end of file diff --git a/css/desktop.css b/css/desktop.css index 06fbc27..8f1d7fa 100644 --- a/css/desktop.css +++ b/css/desktop.css @@ -31,12 +31,6 @@ html { height: 100%; width: 100%; - -webkit-touch-callout: none; - -webkit-user-select: none; - -khtml-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; } body { @@ -64,6 +58,15 @@ a { -ms-transition: all 0.3s cubic-bezier(.25, .8, .25, 1); } +.noSelect { + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + #header1 { display: grid; background-color: #1b1a1a; @@ -332,11 +335,11 @@ canvas { margin: auto; } -.fileIcon .fa { +.fileIcon i { padding: .6em; } -.fileIcon .fa:hover { +.fileIcon i:hover { color: #fff; } @@ -371,10 +374,6 @@ canvas { display: inline-block; } -#directoryLocation i { - font-size: 150%; -} - .subdir:hover { background-color: rgba(255,255,255, 0.1); } @@ -386,10 +385,6 @@ canvas { background-color: rgba(255,255,255,0.1); } -audio { - display: none; -} - #playback div { display: grid; } diff --git a/css/mobile.css b/css/mobile.css index dfbfdb8..ffa4555 100644 --- a/css/mobile.css +++ b/css/mobile.css @@ -198,7 +198,7 @@ a { margin: auto auto auto 0 !important; } -.item div .fa { +.item div i { padding: 1.5vh; } diff --git a/js/alert.js b/js/alert.js index dc4b47c..99991c1 100644 --- a/js/alert.js +++ b/js/alert.js @@ -1,38 +1,38 @@ // Loads alert box into HTML first. -var box = document.createElement("div"); -var p = document.createElement("p"); +var box = document.createElement('div'); +var p = document.createElement('p'); -box.id = "alert"; -box.style.position = "absolute"; -box.style.top = "-4em"; -box.style.width = "100%"; -box.style.color = "#fefefe"; -box.style.textAlign = "center"; +box.id = 'alert'; +box.style.position = 'absolute'; +box.style.top = '-4em'; +box.style.width = '100%'; +box.style.color = '#fefefe'; +box.style.textAlign = 'center'; -box.style.setProperty("-webkit-transition", " top 0.3s cubic-bezier(.25, .8, .25, 1)"); -box.style.setProperty("transition:", "top 0.3s cubic-bezier(.25, .8, .25, 1)"); -box.style.setProperty("-moz-transition", " top 0.3s cubic-bezier(.25, .8, .25, 1)"); -box.style.setProperty("-ms-transition", " top 0.3s cubic-bezier(.25, .8, .25, 1)"); +box.style.setProperty('-webkit-transition', ' top 0.3s cubic-bezier(.25, .8, .25, 1)'); +box.style.setProperty('transition:', 'top 0.3s cubic-bezier(.25, .8, .25, 1)'); +box.style.setProperty('-moz-transition', ' top 0.3s cubic-bezier(.25, .8, .25, 1)'); +box.style.setProperty('-ms-transition', ' top 0.3s cubic-bezier(.25, .8, .25, 1)'); -p.style.backgroundColor = "#000"; -p.style.display = "inline"; -p.style.padding = "1em"; -p.style.borderRadius = "4px"; +p.style.backgroundColor = '#000'; +p.style.display = 'inline'; +p.style.padding = '1em'; +p.style.borderRadius = '4px'; box.appendChild(p); -get("body").appendChild(box); +get('body').appendChild(box); function alertBox(s, type) { colors = { - "error": "#d24242", - "msg": "#4d9e53" + 'error': '#d24242', + 'msg': '#4d9e53' }; box.childNodes[0].textContent = s; box.childNodes[0].style.backgroundColor = colors[type]; - box.style.top = "2em"; + box.style.top = '2em'; setTimeout(function() { - box.style.top = "-4em"; - }, 1000); + box.style.top = '-4em'; + }, 2500); } diff --git a/js/desktop.js b/js/desktop.js index ec477c5..ee7434a 100644 --- a/js/desktop.js +++ b/js/desktop.js @@ -8,8 +8,8 @@ var navSelect; // Stores current selected sidebar option. var clickable = true; // Prevents actions being run more than once. var selectDiv; // Stores selected file or folder div. var currDir = ''; // Stores the current directory. +var version = 'desktop'; -// FIX THE DATE function sortFiles(type, direction) { if(type === 'name') data[0] = sortSection(type, direction, data[0]); data[1] = sortSection(type, direction, data[1]); @@ -39,124 +39,6 @@ function sortFiles(type, direction) { } }; -function dispDir() { - updateLocation(); - try { - get('#directory').removeChild(get('#directoryCont')); - } catch(err) {} - - var cont = element('div', { - id: 'directoryCont', - class: 'transition', - style: 'opacity:0' - }); - - if(data[0].length === 0 && data[1].length === 0) { - cont.appendChild(element('p', { - text: 'Nothing here!', - style: 'font-weight: 100' - })); - } - - for(var i = 0; i < data.length; i++) { - for(var j = 0; j < data[i].length; j++) { - var itemInfo = data[i][j]; - - var ext = (itemInfo.folder) ? "fol" : - itemInfo.name.substring( - itemInfo.name.lastIndexOf(".") + 1, - itemInfo.name.length) - .toLowerCase(); - - var item = element('div', { - class: 'item transition', - ext: ext, - filename: itemInfo.name - }); - - item.appendChild(element('p', { - class: 'name', - text: itemInfo.name - })); - - item.appendChild(element('p', { - class: 'modified', - text: (itemInfo.folder) ? "----" : dateStr(itemInfo.date) - })); - - item.appendChild(element('p', { - class: 'size', - text: itemInfo.size || "----" - })); - - if(!itemInfo.folder) { - var a = element('div', { - onclick: function() { - console.log("generating download link"); - // DO EXPIRY LINKS HERE - // update link to get('copy') and copy - } - }); - - a.appendChild(element('i', { - class: 'fa fa-files-o transition' - })); - - item.appendChild(a); - } - - var ico = element('div', { - class: 'fileIcon', - }); - - ico.appendChild(element('i', { - class: `fa fa-${(faIcons[ext] || faIcons["other"])}` - })); - - item.appendChild(ico); - - item.onclick = function() { - if(!clickable) return; - // DO WITH SHIFT AND CONTROL LATER. - - if(this.className.search( 'selectedItem') === -1) { - get('.item').forEach(function(ele) { - ele.style.backgroundColor = ""; - ele.className = ele.className.replace(' selectedItem', - ''); - }); - this.className += ' selectedItem'; - this.style.backgroundColor = "rgba(255,255,255,0.2)"; - return; - } - - // Below executes only after user has clicked twice. - var name = this.getAttribute('filename'); - var ext = this.getAttribute('ext'); - - clickable = false; - if(ext == 'fol') { - clearTbl(); - setTimeout(function() { - currDir += '/' + name; - listDir(currDir, 0); - }, 300); - } else { - downloadFile(currDir + "/" + name); - } - clickable = true; - - } - cont.appendChild(item); - } - } - - get('#directory').appendChild(cont); - setTimeout(function() { - get('#directoryCont').style.opacity = "1"; - }, 100); -}; - function updateLocation() { var loc = get('#directoryLocation'); while(loc.firstChild) loc.removeChild(loc.firstChild); @@ -176,7 +58,7 @@ function updateLocation() { currDir = ''; } else { currDir = subdir.slice(0, subdirNum+1) - .reduce(function(a,b) { return a + '/' + b; }) + '/'; + .reduce(function(a,b) { return a + '/' + b; }); } listDir(currDir, 0); } @@ -184,7 +66,7 @@ function updateLocation() { if(i > 0) { loc.appendChild(element('i', { - class: 'fa fa-angle-right' + class: 'fas fa-chevron-right' })); } loc.appendChild(p); diff --git a/js/index.js b/js/index.js index 4d2cfa9..33fa671 100644 --- a/js/index.js +++ b/js/index.js @@ -3,32 +3,32 @@ var t = 0; function login(form) { u = form.username.value; p = form.password.value; - uEmpty = u === "", pEmpty = p === ""; + uEmpty = u === '', pEmpty = p === ''; if(uEmpty && pEmpty) { - alertBox("Please enter a username and password!", "error"); + alertBox('Please enter a username and password!', 'error'); return; } else if (uEmpty && !pEmpty) { - alertBox("Please enter a username!", "error"); + alertBox('Please enter a username!', 'error'); return; } else if (!uEmpty && pEmpty) { - alertBox("Please enter a password!", "error"); + alertBox('Please enter a password!', 'error'); return; } data = {username: u, password: p} - $.post("./login", data).done(function(data) { + $.post('./login', data).done(function(data) { if(data) { location.reload(true); } else { - alertBox("Wrong username or password!"); + alertBox('Wrong username or password!'); } }); } function drawCanvas() { - var el = get("canvas") - var c = el.getContext("2d") + var el = get('canvas') + var c = el.getContext('2d') var block = 10, space = 2, size = block+space; var period = 100, freq = 2*Math.PI/period, step = 1.4, base = 0.05; @@ -44,7 +44,7 @@ function drawCanvas() { el.width = w, el.height = h; - c.fillStyle = "#0e0e0e"; + c.fillStyle = '#0e0e0e'; c.fillRect(0, 0, w, h); for(var i = 0; i < x+1; i++) { for(var j = 0; j < y+1; j++) { @@ -87,12 +87,12 @@ function drawCanvas() { drawCanvas(); -inputs = get("input"), button = get("button") +inputs = get('input'), button = get('button') -inputs[0].addEventListener("keyup", function(e) { +inputs[0].addEventListener('keyup', function(e) { if(e.keyCode === 13) button.click(); }); -inputs[1].addEventListener("keyup", function(e) { +inputs[1].addEventListener('keyup', function(e) { if(e.keyCode === 13) button.click(); }); \ No newline at end of file diff --git a/js/mobile.js b/js/mobile.js index f8ee60c..e1fd992 100644 --- a/js/mobile.js +++ b/js/mobile.js @@ -8,6 +8,7 @@ var navSelect; // Stores current selected sidebar option. var clickable = true; // Prevents actions being run more than once. var selectDiv; // Stores selected file or folder div. var currDir = ''; // Stores the current directory. +var version = 'mobile'; function sortFiles(type, direction) { if(type === 'name') data[0] = sortSection(type, direction, data[0]); diff --git a/js/overlay.temp.js b/js/overlay.temp.js deleted file mode 100644 index f7555f0..0000000 --- a/js/overlay.temp.js +++ /dev/null @@ -1,100 +0,0 @@ -function videoOverlay(url) { - var overlay = getDefaultOverlay(); - - var video = document.createElement("video"); - video.onclick = function() {event.stopPropagation();} - video.src = url; - video.controls = true; - video.autoplay = true; - video.type = "video/mp4"; - - video.style.margin = "auto"; - video.style.backgroundColor = "black"; - - video.onloadedmetadata = function() { - if((video.videoHeight/video.videoWidth) > (window.innerHeight/window.innerWidth)) { - video.style.height = (window.innerHeight * 0.9).toString() + "px"; - } else { - video.style.width = (window.innerWidth * 0.9).toString() + "px"; - } - } - - var div = document.createElement("div"); - div.style.margin = "auto"; - div.style.gridRow = "1"; - div.style.gridColumn = "1"; - div.appendChild(video); - overlay.appendChild(div); - - var close = getClose(); - overlay.appendChild(close); - - document.getElementsByTagName("body")[0].appendChild(overlay); - setTimeout(function() { - overlay.style.opacity = "1"; - }, 10); -} - -function audioOverlay(url) { - var overlay = getDefaultOverlay(); - var audio = document.createElement("audio"); - audio.onclick = function() {event.stopPropagation();} - audio.src = url; - audio.controls = true; - audio.autoplay = true; - - audio.style.margin = "auto"; - audio.style.width = (window.innerWidth * 0.9).toString() + "px"; - - var div = document.createElement("div"); - div.style.margin = "auto"; - div.style.gridRow = "1"; - div.style.gridColumn = "1"; - div.appendChild(audio); - overlay.appendChild(div); - - var close = getClose(); - overlay.appendChild(close); - - document.getElementsByTagName("body")[0].appendChild(overlay); - setTimeout(function() { - overlay.style.opacity = "1"; - }, 10); -} - - -function imageOverlay(url) { - var overlay = getDefaultOverlay(); - var img = new Image(); - img.src = url; - img.style.margin = "auto"; - - var image = document.createElement("img"); - image.src = url; - img.onload = function() { - var height = img.height; - var width = img.width; - - - if((height/width) > (window.innerHeight/window.innerWidth)) { - image.style.height = (window.innerHeight * 0.9).toString() + "px"; - } else { - image.style.width = (window.innerWidth * 0.9).toString() + "px"; - } - }; - - var div = document.createElement("div"); - div.style.margin = "auto"; - div.style.gridRow = "1"; - div.style.gridColumn = "1"; - div.appendChild(image); - overlay.appendChild(div); - - var close = getClose(); - overlay.appendChild(close); - - document.getElementsByTagName("body")[0].appendChild(overlay); - setTimeout(function() { - overlay.style.opacity = "1"; - }, 10); -} \ No newline at end of file diff --git a/js/tools.js b/js/tools.js index aeea1aa..c3b946f 100644 --- a/js/tools.js +++ b/js/tools.js @@ -5,12 +5,13 @@ var themeColors = { // For reference and for quick changing if need-be. }; var faIcons = { - 'fol': 'folder', - 'mp3': 'music', - 'ogg': 'music', - 'mp4': 'video-camera', - 'zip': 'file-zip-o', - 'other': 'file-o' + 'fol': 'fas fa-folder', + 'audio': 'fas fa-file-audio', + 'video': 'fas fa-file-video', + 'image': 'fas fa-file-image', + 'zip': 'fas fa-file-archive', + 'pdf': 'fas fa-file-pdf', + 'other': 'fas fa-file' }; var sort = { // Default sorting directions. @@ -30,8 +31,8 @@ var navi = [ // Necessary arguments: id, alias, fa | Optional arguments: subnav. */ function get(name) { - ele = document.querySelectorAll(name) - return (ele.length === 1) ? ele[0] : ele; + ele = document.querySelectorAll(name) + return (ele.length === 1) ? ele[0] : ele; }; function element(type, dict) { @@ -61,8 +62,7 @@ function getDrives() { 'onclick': function() { if(this.id === navSelect) return; updateNav(this.id); - sidebar = get('.closeable'); - if(sidebar) moveSidebar('close'); + if(version === 'mobile') moveSidebar('close'); currDir = ''; listDir(currDir, 0); } @@ -74,6 +74,10 @@ function getDrives() { navLayout(); updateNav(navSelect); listDir(currDir, 0); + }) + .fail(function(e) { + alertBox(e.responseText, 'error'); + console.log(e.responseText); }); }; @@ -81,7 +85,7 @@ function getDrives() { // if files need to be split up into sections. function listDir(dir, sec) { - $.post('./files', {'drive_id': navSelect, 'path': currDir}) + $.post('./files/list', {'drive_id': navSelect, 'path': currDir}) .done(function(d) { data = [[],[]]; for(var i = 0; i < d.length; i++) { @@ -94,13 +98,43 @@ function listDir(dir, sec) { } sortFiles('name', -1); clickable = true; + }) + .fail(function(e) { + alertBox(e.responseText, 'error'); + console.log(e.responseText); }); }; -function downloadFile(path) { +function downloadFile(type, ext, path) { alertBox('Downloading file...', 'msg'); - $.post('./files', {'drive_id': navSelect, 'path': path}).done(function(d) { - window.location = './d/' + d; + $.post('./files/download', {'drive_id': navSelect, 'path': path}) + .done(function(d) { + if(type === 'download') { + if(ext.includes('pdf')) { + window.open('./d/' + d); + } else { + window.location = './d/' + d; + } + } else if(type === 'image') { + overlay(type, './d/' + d, ext) + } + + }) + .fail(function(e) { + alertBox(e.responseText, 'error'); + console.log(e.responseText); + }); +}; + +function streamFile(type, ext, path) { + alertBox('Getting file...', 'msg'); + $.post('./files/stream', {'drive_id': navSelect, 'path': path}) + .done(function(d) { + overlay(type, './d/' + d, ext) + }) + .fail(function(e) { + alertBox(e.responseText, 'error'); + console.log(e.responseText); }); }; @@ -124,7 +158,135 @@ function sortSection(type, direc, arr) { break; } return sorted; -} +}; + +function dispDir() { + updateLocation(); + try { + get('#directory').removeChild(get('#directoryCont')); + } catch(err) {} + + var cont = element('div', { + id: 'directoryCont', + class: 'transition', + style: 'opacity:0' + }); + + if(data[0].length === 0 && data[1].length === 0) { + cont.appendChild(element('p', { + text: 'Nothing here!', + style: 'font-weight: 100' + })); + } + + for(var i = 0; i < data.length; i++) { + for(var j = 0; j < data[i].length; j++) { + var itemInfo = data[i][j]; + + var ext = (itemInfo.folder) ? 'fol' : itemInfo.filetype + + var item = element('div', { + class: 'item transition', + ext: ext, + filename: itemInfo.name + }); + + item.appendChild(element('p', { + class: 'name', + text: itemInfo.name + })); + + if(version === 'desktop') { + item.appendChild(element('p', { + class: 'modified', + text: (itemInfo.folder) ? '----' : dateStr(itemInfo.date) + })); + + item.appendChild(element('p', { + class: 'size', + text: itemInfo.size || '----' + })); + } else if(version === 'mobile') { + item.appendChild(element('p', { + class: 'otherInfo', + text: (itemInfo.folder) ? '----' : + dateStr(itemInfo.date, 'date') + ' | ' + itemInfo.size + })); + } + + if(!itemInfo.folder) { + var a = element('div', { + onclick: function() { + console.log('generating download link'); + // DO EXPIRY LINKS HERE + // update link to get('copy') and copy + } + }); + + a.appendChild(element('i', { + class: 'fa fa-files-o transition' + })); + + item.appendChild(a); + } + + var ico = element('div', { + class: 'fileIcon', + }); + + ico.appendChild(element('i', { + class: faIcons[fileType(ext)] + })); + + item.appendChild(ico); + + item.onclick = function() { + if(!clickable) return; + // DO WITH SHIFT AND CONTROL LATER. + + if(this.className.search( 'selectedItem') === -1) { + get('.item').forEach(function(ele) { + ele.style.backgroundColor = ''; + ele.className = ele.className.replace(' selectedItem', + ''); + }); + this.className += ' selectedItem'; + this.style.backgroundColor = 'rgba(255,255,255,0.2)'; + return; + } + + // Below executes only after user has clicked twice. + var name = this.getAttribute('filename'); + var ext = this.getAttribute('ext'); + + clickable = false; + if(ext == 'fol') { + clearTbl(); + setTimeout(function() { + currDir += '/' + name; + listDir(currDir, 0); + }, 300); + } else if(ext.includes('image')) { + downloadFile('image', ext, currDir + '/' + name); + } else if(ext.includes('audio')) { + streamFile('audio', ext, currDir + '/' + name); + } else if(ext.includes('video')) { + streamFile('video', ext, currDir + '/' + name); + } else { + downloadFile('download', ext, currDir + '/' + name); + } + clickable = true; + + } + cont.appendChild(item); + } + } + + get('#directory').appendChild(cont); + setTimeout(function() { + get('#directoryCont').style.opacity = '1'; + }, 100); +}; function navLayout() { function createNavHeader(text) { @@ -172,10 +334,99 @@ function updateNav(op) { // Updates the sidebar navigation. }; function clearTbl() { - selectDiv = undefined; - get('#directoryCont').style.opacity = '0'; + selectDiv = undefined; + get('#directoryCont').style.opacity = '0'; }; +function overlay(type, src, mime) { + function resize(item, vH, vW) { + wH = window.innerHeight, wW = window.innerWidth; + if((vH/vW) > (wH/wW)) { + item.style.height = (wH * 0.9).toString() + "px"; + } else { + item.style.width = (wW * 0.9).toString() + "px"; + } + } + + var div = element('div', { + id: 'overlay', + class: 'transition', + style: `width: 100%; + height: 100%; + position: absolute; + top: 0; + left: 0; + background-color: rgba(0,0,0,0.7); + opacity: 0; + display: grid;`, + onclick: function() { + this.style.opacity = '0'; + that = this; + setTimeout(function() { + that.parentNode.removeChild(that); + }, 300); + } + }); + + var inner; + + if(type === 'image') { + var img = element('img', { + style: 'margin: auto;', + src: src, + onclick: function(event) { + event.stopPropagation(); + } + }); + + img.onload = function() { + resize(this, this.height, this.width); + }; + + inner = img; + + } else if (type === 'audio') { + var audio = element('audio', { + class: 'noSelect', + style: 'margin: auto; outline: none', + controls: true, + autoplay: true, + src: src, + type: mime, + onclick: function(event) { + event.stopPropagation(); + } + }); + + inner = audio; + + } else if (type === 'video') { + var vid = element('video', { + style: 'margin: auto; background-color: black;', + controls: true, + autoplay: true, + src: src, + type: mime, + onclick: function(event) { + event.stopPropagation(); + } + }); + + vid.onloadedmetadata = function() { + resize(this, this.videoHeight, this.videoWidth); + }; + + inner = vid; + } + + div.appendChild(inner); + get('body').appendChild(div); + + setTimeout(function() { + div.style.opacity = '1'; + }, 10); +} + function animFade(type, div) { if(type === 'open') { div.style.display = 'block'; @@ -200,4 +451,24 @@ function dateStr(date, type) { } else if(Type === 'time') { return str.substring(str.indexOf(',') + 1, str.length); } -}; \ No newline at end of file +}; + +function fileType(ext) { + if(ext === 'fol') return 'fol'; + if(ext.includes('image')) { + return 'image'; + } else if(ext.includes('video')) { + return 'video'; + } else if(ext.includes('pdf')) { + return 'pdf'; + } else if(ext.includes('audio')) { + return 'audio'; + } else if(ext.includes('zip') || + ext.includes('x-rar') || + ext.includes('x-7z-compressed') || + ext.includes('gzip')) { + return 'zip'; + } else { + return 'other' + } +} \ No newline at end of file diff --git a/templates/index.html b/templates/index.html index be5c488..50e864a 100644 --- a/templates/index.html +++ b/templates/index.html @@ -19,9 +19,9 @@

BinBin

Username:

- +

Password:

- +
diff --git a/templates/pre_main.html b/templates/pre_main.html index e5d43e5..ac6cd3b 100644 --- a/templates/pre_main.html +++ b/templates/pre_main.html @@ -9,7 +9,7 @@ - +