diff --git a/xtrn/ansiview/ansiview.js b/xtrn/ansiview/ansiview.js index 6fc0dae59455b6e1d82a371a8ebdb1e5ec80f181..a9eb67aff5118f2ea7cef569376a4ec23bdfc3bb 100644 --- a/xtrn/ansiview/ansiview.js +++ b/xtrn/ansiview/ansiview.js @@ -1,210 +1,396 @@ -// ansiview.js by echicken -at- bbs.electronicchicken.com - load("sbbsdefs.js"); -load("tree.js"); load("frame.js"); +load("tree.js"); +load("scrollbar.js"); +load("funclib.js"); +load("filebrowser.js"); -// Configuration variables: -var ansiRoot = js.exec_dir + "library/"; // The location of your ANSI library, eg. "/dev/magicalansigenerator/" -var disallowedFiles = ["PASSWD", "USER.DAT", "*.COM", "*.EXE", "*.GIF", "*.JPG", "*.MP3", "*.PNG", "*.RAR"]; // Files matching these patterns will not be shown in directory listings -var slow = .033; // Seconds between printed characters, slow speed -var medium = .0033; // Seconds between printed characters, medium speed -var fast = .00033; // Seconds between printed characters, fast speed -var ansiDelay = medium; // Default output speed as one of slow, medium, or fast -// End of configuration variables - -var lastPrint = system.timer; -var curDir = ansiRoot; -var parentDir = ansiRoot; -var choice; -var userInput; -var treeCmd; -var disp; - -function getInput(slideshow, ansiName) { - var retval = 1; - userInput = ascii(console.inkey(K_NOECHO).toUpperCase()); - if(userInput == 0) return retval; - if(userInput == 32) { - console.saveline(); - console.clearline(); - if(slideshow) { - console.putmsg(ascii(27) + "[1;37;40m[\1h\1c" + ansiName.substr(0, 18) + "\1w] Q\1cuit\1w, <\1cSpace\1w> \1cfor more\1w, S\1clow\1w, M\1cedium\1w, F\1cast\1w, P\1crevious\1w, N\1cext"); - } else { - console.putmsg(ascii(27) + "[1;37;40m[\1h\1c" + ansiName.substr(0, 34) + "\1w] Q\1cuit\1w, <\1cSpace\1w> \1cfor more\1w, S\1clow\1w, M\1cedium\1w, F\1cast"); +Frame.prototype.drawBorder = function(color) { + var theColor = color; + if(Array.isArray(color)); + var sectionLength = Math.round(this.width / color.length); + this.pushxy(); + for(var y = 1; y <= this.height; y++) { + for(var x = 1; x <= this.width; x++) { + if(x > 1 && x < this.width && y > 1 && y < this.height) + continue; + var msg; + this.gotoxy(x, y); + if(y == 1 && x == 1) + msg = ascii(218); + else if(y == 1 && x == this.width) + msg = ascii(191); + else if(y == this.height && x == 1) + msg = ascii(192); + else if(y == this.height && x == this.width) + msg = ascii(217); + else if(x == 1 || x == this.width) + msg = ascii(179); + else + msg = ascii(196); + if(Array.isArray(color)) { + if(x == 1) + theColor = color[0]; + else if(x % sectionLength == 0 && x < this.width) + theColor = color[x / sectionLength]; + else if(x == this.width) + theColor = color[color.length - 1]; + } + this.putmsg(msg, theColor); } - var userInput = ascii(console.getkey(K_NOECHO).toUpperCase()); - console.clearline(); - console.restoreline(); - } - switch(userInput) { - case 70: - ansiDelay = fast; - break; - case 77: - ansiDelay = medium; - break; - case 83: - ansiDelay = slow; - break; - case 81: - retval = 0; - break; - case 78: - if(slideshow) retval = 2; - break; - case 80: - if(slideshow) retval = 3; - break; } - return retval; + this.popxy(); } -function printAnsi(ansi, slideshow, ansiName) { - var retval = 1; - console.clear(LIGHTGRAY); - forLoop: - for(var a = 0; a < ansi.length; a++) { - console.putmsg(ansi[a]); - console.line_counter = 0; - while(system.timer - lastPrint < ansiDelay) { - retval = getInput(slideshow, ansiName); - if(retval != 1) - break forLoop; +var root = js.exec_dir, + settings, + frame, + browserFrame, + statusBarFrame, + areaFrame, + speedFrame, + pauseFrame; + +var state = { + 'status' : bbs.sys_status, + 'attr' : console.attributes, + 'syncTerm' : false, + 'fileList' : [], + 'pausing' : false, + 'speed' : 0, + 'browser' : null +}; + +var speedMap = [ + 0, // 0 (unlimited) + 300, // 1 + 600, // 2 + 1200, // 3 + 2400, // 4 + 4800, // 5 + 9600, // 6 + 19200, // 7 + 38400, // 8 + 57600, // 9 + 76800, // 10 + 115200 // 11 +]; + +var printFile = function(file) { + + console.clear(BG_BLACK|LIGHTGRAY); + frame.invalidate(); + + if(state.syncTerm) { + + console.putmsg("\x1B[0;" + state.speed + "*r"); + mswait(500); + console.printfile(file, (state.pausing ? P_NONE : P_NOPAUSE)); + console.pause(); + console.putmsg("\x1B[0;0*r"); + + } else if(state.speed == 0) { + + console.printfile(file, (state.pausing ? P_NONE : P_NOPAUSE)); + console.pause(); + + } else { + + var f = new File(file); + f.open("r"); + var contents = f.read().split(""); + f.close(); + + var buf = Math.ceil((speedMap[state.speed] / 8) / 1000); + + if(!state.pausing) { + bbs.sys_status&=(~SS_PAUSEON); + bbs.sys_status|=SS_PAUSEOFF; } - lastPrint = system.timer; - } - if(retval == 1) { - console.putmsg(ascii(27) + "[1;37;40m[\1c" + ansiName + " \1w - \1c Press any key to continue\1w]"); - console.getkey(K_NOECHO|K_NOCRLF); + + while(contents.length > 0) { + console.write(contents.splice(0, buf).join("")); + if(console.inkey(K_NONE, 1) != "") + break; + } + console.pause(); + + bbs.sys_status|=SS_PAUSEON; + bbs.sys_status&=(~SS_PAUSEOFF); + } - return retval; + + console.clear(BG_BLACK|LIGHTGRAY); + } -function fileChooser() { - console.clear(LIGHTGRAY); - var f = new File(js.exec_dir + "ansiview.ans"); - f.open("r"); - var g = f.read(); - f.close(); - console.putmsg(g); - console.gotoxy(3, 4); - console.putmsg(ascii(27) + "[1;37;40mpath: " + curDir.replace(ansiRoot, "/")); - var dirList = directory(curDir + "*"); - var frame = new Frame(2,6,76,15) - var tree = new Tree(frame); - tree.colors.lfg = WHITE; // The lightbar foreground colour, see sbbsdefs.js for valid values - tree.colors.lbg = BG_CYAN; // The lightbar background colour, see sbbsdefs.js for valid values - if(curDir != ansiRoot) - tree.addItem("[..]", parentDir); - for(var d = 0; d < dirList.length; d++) { - if(checkFile(dirList[d])) - continue; - disp = dirList[d].split("/"); - if(file_isdir(dirList[d])) { - disp = disp[disp.length - 2]; - disp = "[" + disp + "]"; - } else { - disp = disp[disp.length - 1]; - } - tree.addItem(disp, dirList[d]); - } - frame.open(); - tree.open(); - while(!js.terminated) { - frame.cycle(); - userInput = console.inkey(K_NOECHO, 5).toUpperCase(); - if(userInput == "") +// Basic check for SyncTERM; we don't really care which version it is +var isSyncTerm = function() { + + console.clear(BG_BLACK|LIGHTGRAY); + console.write("Checking for SyncTERM ..."); + + var ret = true, + cTerm = "\x1B[=67;84;101;114;109;".split(""), + ckpt = console.ctrlkey_passthru; + + console.ctrlkey_passthru = -1; + console.write("\x1B[0c"); + + while(cTerm.length > 0) { + if(console.inkey(K_NONE, 5000) == cTerm.shift()) continue; - if(userInput == "Q" || userInput == "S" || userInput == "H") - break; - userInput = tree.getcmd(userInput); - console.line_counter = 0; - if(userInput !== true && userInput !== false) - break; + ret = false; + break; } - return userInput; + do {} while(console.inkey(K_NONE) != "") // Flush the input toilet + + console.ctrlkey_passthru = ckpt; + return ret; + } -function loadAnsiFile(ansi) { - var f = new File(ansi); - if(f.exists) f.open("r"); - if(!f.is_open) return; - var ansiFileContents = f.read(); - f.close(); - return ansiFileContents; +var showSpeed = function() { + speedFrame.clear(); + speedFrame.putmsg( + (state.speed == 0) ? "Full" : speedMap[state.speed] + ); } -function checkFile(str) { - if(file_isdir(str)) { - var matchMe = str.split("/"); - matchMe = matchMe[matchMe.length - 2]; - } else { - matchMe = file_getname(str); - } - for(var f = 0; f < disallowedFiles.length; f++) - if(wildmatch(false, matchMe, disallowedFiles[f])) - return true; - return false; +var showPause = function() { + pauseFrame.clear(); + pauseFrame.putmsg((state.pausing) ? "On" : "Off"); } -function slideshow() { - var dirList = directory(curDir + "*.*"); - var retval; - ssForLoop: - for(var d = 0; d< dirList.length; d++) { - if(!file_isdir(dirList[d]) && !checkFile(dirList[d]) && !wildmatch(false, file_getname(dirList[d]), "*.ZIP")) retval = printAnsi(loadAnsiFile(dirList[d]), true, file_getname(dirList[d])); - switch(retval) { - case 0: - break ssForLoop; - case 3: - d = d - 2; - if(d < -1) d = -1; - break; - default: - break; - } +var GalleryChooser = function() { + + var frames = { + 'frame' : null, + 'tree' : null, + 'scrollBar' : null + }; + + var getList = function() { + var f = new File(root + "settings.ini"); + f.open("r"); + var galleries = f.iniGetAllObjects(); + f.close(); + return galleries; } + + this.open = function() { + + areaFrame.clear(); + areaFrame.putmsg("Gallery Menu"); + + frames.frame = new Frame( + browserFrame.x, + browserFrame.y, + browserFrame.width, + browserFrame.height, + browserFrame.attr, + browserFrame + ); + frames.tree = new Tree(frames.frame); + frames.tree.colors.fg = getColor(settings.fg); + frames.tree.colors.bg = getColor(settings.bg); + frames.tree.colors.lfg = getColor(settings.lfg); + frames.tree.colors.lbg = getColor(settings.lbg); + + var list = getList(); + list.forEach( + function(item) { + item.colors = settings; + frames.tree.addItem( + format("%-35s %s", item.name, item.description), + function() { + state.browser.close(); + state.browser = load(root + item.module, JSON.stringify(item)); + state.browser.open(); + areaFrame.clear(); + areaFrame.putmsg(item.name); + } + ); + } + ); + + frames.scrollBar = new ScrollBar(frames.tree); + + frames.frame.open(); + frames.tree.open(); + + } + + this.close = function() { + frames.tree.close(); + frames.scrollBar.close(); + frames.frame.close(); + } + + this.cycle = function() { + frames.scrollBar.cycle(); + } + + this.getcmd = function(cmd) { + frames.tree.getcmd(cmd); + } + +} + +var initDisplay = function() { + + console.clear(BG_BLACK|LIGHTGRAY); + + frame = new Frame( + 1, + 1, + console.screen_columns, + console.screen_rows, + BG_BLACK|LIGHTGRAY + ); + + browserFrame = new Frame( + frame.x + 1, + frame.y + 1, + frame.width - 2, + frame.height - 3, + frame.attr, + frame + ); + + statusBarFrame = new Frame( + frame.x + 1, + frame.x + frame.height - 2, + frame.width - 2, + 1, + settings.sbg|settings.sfg, + frame + ); + statusBarFrame.putmsg( + format( + "%-41s%-16s%-13s", + "Area:","S)peed:","P)ause:" + ) + ); + statusBarFrame.gotoxy(statusBarFrame.width - 4, 1); + statusBarFrame.putmsg("Q)uit"); + + areaFrame = new Frame( + statusBarFrame.x + 6, + statusBarFrame.y, + 35, + 1, + statusBarFrame.attr, + statusBarFrame + ); + + speedFrame = new Frame( + statusBarFrame.x + 49, + statusBarFrame.y, + 6, + 1, + statusBarFrame.attr, + statusBarFrame + ); + showSpeed(); + + pauseFrame = new Frame( + statusBarFrame.x + 65, + statusBarFrame.y, + 3, + 1, + statusBarFrame.attr, + statusBarFrame + ); + showPause(); + + frame.drawBorder(settings.border); + frame.gotoxy(frame.width - 24, 1); + frame.putmsg(ascii(180) + "\1h\1kansiview by echicken\1h\1w" + ascii(195)); + + frame.open(); + } -function helpScreen() { - console.clear(LIGHTGRAY); - var f = new File(js.exec_dir + "help.ans"); +var initSettings = function() { + var f = new File(js.exec_dir + "settings.ini"); f.open("r"); - var g = f.read(); + settings = f.iniGetObject(); f.close(); - console.putmsg(g); - while(console.getkey(K_NOECHO).toUpperCase() != "Q") { } + settings.fg = getColor(settings.fg); + settings.bg = getColor(settings.bg); + settings.lfg = getColor(settings.lfg); + settings.lbg = getColor(settings.lbg); + settings.sfg = getColor(settings.sfg); + settings.sbg = getColor(settings.sbg); + settings.border = settings.border.split(","); + settings.border.forEach( + function(e, i, a) { + a[i] = getColor(e); + } + ); } -while(!js.terminated) { - var choice = fileChooser(); - console.line_counter = 0; - if(file_isdir(choice)) { - if(choice.length > curDir.length) { - parentDir = curDir; - } else if(parentDir != ansiRoot && parentDir.length > ansiRoot.length) { - parentDir = curDir.split("/"); - parentDir = parentDir.slice(0, parentDir.length - 3).join("/") + "/"; - } else { - parentDir = ansiRoot; - } - curDir = choice; - } else if(choice == "Q") { - exit(); - } else if(choice == "S") { - slideshow(); - } else if(choice == "H") { - helpScreen(); - } else if(file_getext(choice).toUpperCase() == ".ZIP") { - destDir = curDir + file_getname(choice).toUpperCase().replace(".ZIP", "") + "/"; - parentDir = curDir; - curDir = destDir; - if(file_isdir(destDir)) - continue; - bbs.exec(system.exec_dir + "unzip -s -o -qq -d" + destDir + " " + choice); - } else { - var ansi = loadAnsiFile(choice); - printAnsi(ansi, false, file_getname(choice)); +var init = function() { + + bbs.sys_status|=(SS_MOFF|SS_PAUSEON); + bbs.sys_status&=(~SS_PAUSEOFF); + + state.syncTerm = isSyncTerm(); + + initSettings(); + initDisplay(); + + state.browser = new GalleryChooser(); + state.browser.open(); + +} + +var cleanUp = function() { + frame.close(); + bbs.sys_status = state.status; + console.attributes = state.attr; + console.clear(); + exit(0); +} + +var handleInput = function(userInput) { + switch(userInput) { + case "P": + state.pausing = (state.pausing) ? false : true; + showPause(); + break; + case "S": + state.speed = (state.speed + 1) % 12; + showSpeed(); + break; + case "Q": + state.browser.close(); + frame.invalidate(); + if(state.browser instanceof GalleryChooser) { + cleanUp(); + } else { + state.browser = new GalleryChooser(); + state.browser.open(); + } + break; + default: + state.browser.getcmd(userInput); + break; } } + +var main = function() { + + while(!js.terminated) { + handleInput(console.inkey(K_NONE, 5).toUpperCase()); + state.browser.cycle(); + if(frame.cycle()) + console.gotoxy(console.screen_columns, console.screen_rows); + } + +} + +init(); +main(); +cleanUp(); diff --git a/xtrn/ansiview/local.js b/xtrn/ansiview/local.js new file mode 100644 index 0000000000000000000000000000000000000000..aac743585b060f5b99c1e3107f95bc7f283eca0b --- /dev/null +++ b/xtrn/ansiview/local.js @@ -0,0 +1,60 @@ +(function() { + + var onLoad = function(files) { + + if(files.length < 1) + return; + + var path = files[0].replace(file_getname(files[0]), ""); + + if(!file_exists(path + "ansiview.ini")) + return; + var f = new File(path + "ansiview.ini"); + f.open("r"); + this.descriptions = f.iniGetObject("descriptions"); + f.close(); + + } + + var onFile = function(file) { + + var fn = file_getname(file); + + if(typeof this.descriptions == "undefined") + this.descriptions = {}; + + var ret = format( + "%-25s%s", + file_isdir(file) ? ("[" + fn + "]") : fn, + typeof this.descriptions[fn.toLowerCase()] == "undefined" ? "" : (" " + this.descriptions[fn.toLowerCase()]) + ); + return ret; + + } + + var args = JSON.parse(argv[0]); + + var hide = [".", "ansiview.ini", "ANSIVIEW.INI"]; + + var fileBrowser = new FileBrowser( + { 'path' : args.path, + 'top' : args.path, + 'frame' : browserFrame, + 'colors' : { + 'lfg' : args.colors.lfg, + 'lbg' : args.colors.lbg, + 'fg' : args.colors.fg, + 'bg' : args.colors.bg, + 'sfg' : args.colors.sfg, + 'sbg' : args.colors.sbg + }, + 'hide' : (typeof args.hide == "undefined") ? hide : hide.concat(args.hide.split(",")) + } + ); + fileBrowser.on("load", onLoad); + fileBrowser.on("file", onFile); + fileBrowser.on("fileSelect", printFile); + + return fileBrowser; + +})(); \ No newline at end of file diff --git a/xtrn/ansiview/settings.ini b/xtrn/ansiview/settings.ini new file mode 100644 index 0000000000000000000000000000000000000000..81e41423dfaff4ab9150c65e6abfbdacb14bfc49 --- /dev/null +++ b/xtrn/ansiview/settings.ini @@ -0,0 +1,27 @@ +border = LIGHTBLUE,CYAN,LIGHTCYAN,WHITE +fg = WHITE +bg = BG_BLACK +lfg = WHITE +lbg = BG_CYAN +sfg = WHITE +sbg = BG_BLUE + +[ANSI Gallery] +description = A local archive of ANSI and ASCII artwork +module = local.js +path = /path/to/my/ansi/art/collection +hide = *.exe,*.com + +; Uncomment this section to enable access to sixteencolors.net +;[sixteencolors.net] +;description = An online ANSI and ASCII artwork archive +;module = sixteencolors.js +;cache = true +;cachettl = 86400 + +; Uncomment this section to enable access to thescene.electronicchicken.com +;[thescene.electronicchicken.com] +;description = An online ANSI and ASCII artwork archive +;module = thescene.js +;cache = true +;cachettl = 86400 diff --git a/xtrn/ansiview/sixteencolors-api.js b/xtrn/ansiview/sixteencolors-api.js new file mode 100644 index 0000000000000000000000000000000000000000..6ca94945e9de9954897d6421924a985995029af5 --- /dev/null +++ b/xtrn/ansiview/sixteencolors-api.js @@ -0,0 +1,179 @@ +/* SixteenColors object + A simple interface between Synchronet 3.15+ and the sixteencolors.net API. + echicken -at- bbs.electronicchicken.com + + With the exception of .getFile(), which returns a file as a string, all + other methods return arrays of objects. + + Useful methods: + + - .years() + - Returns a list of years, and how many packs each year has. + - .year(year) + - Returns a list of all packs in a year + - Each object in the array has a 'name' property, among others + - .pack(pack) + - Finds a pack by name (see above - not 'filename') + - Returns an object with various properties, most useful being + 'files', which is an array + - Each object in the 'files' array has a 'file_location' property + - .getFile(file_location) + - Retrieves a file by file_location (see above) + - Returns the file as a string + + Not-as-useful methods: + + - .packs(page, rows) + - Returns 'page' of entries from the full list of packs in the archive + with 'rows' number of elements in the array. + - I haven't tried this, but I assume its return value will be similar + to .year(), possibly alphabetized + - .file(pack, name) + - Returns info about a given file in a given pack + - I didn't see much detail that you don't already get from .pack() + - .randomFiles(page, rows) + - Get a list of random files, I guess + - .randomPacks(page, rows) + - Get a list of random packs, I guess + + Currently useless methods: + + The API currently returns empty arrays for the following: + + - .groups() + - .group(group) + - .artists() + - .artist() + - .month(year, month) + + Errors: + + On error, all methods log an error message and then return null. This is + lame, but it's all I need for now. + +*/ + +load("http.js"); + +var SixteenColors = function() { + + var apiUrl = "http://api.sixteencolors.net/v0"; + var downloadUrl = "http://sixteencolors.net/"; + + var getJSON = function(path) { + try { + return JSON.parse( + new HTTPRequest().Get(apiUrl + (typeof path == "undefined" ? "" : path)) + ); + } catch(err) { + log("SixteenColors._getJSON: " + err); + return null; + } + } + + this.years = function() { + return getJSON("/year"); + } + + this.year = function(year) { + if(typeof year == "undefined") { + throw "SixteenColors.year: Invalid or no year provided."; + } else { + var y = this.years(); + if(y === null) + return y; + var count = 0; + for(var yy = 0; yy < y.length; yy++) { + if(y[yy].year != "year") + continue; + count = y[yy].packs; + break; + } + return getJSON("/year/" + year + "?page=1&rows=" + count); + } + } + + this.packs = function(page, rows) { + var path = "/pack"; + if(typeof page == "number" && typeof rows == "number") + path += "?page=" + page + "&rows=" + rows; + return getJSON(path); + } + + this.pack = function(name) { + if(typeof name != "string") + throw "SixteenColors.pack: Invalid or no pack name provided."; + else + return getJSON("/pack/" + name); + } + + this.file = function(pack, name) { + if(typeof pack != "string") + throw "SixteenColors.file: Invalid or no pack name provided."; + else if(typeof name != "string") + throw "SixteenColors.file: Invalid or no file name provided."; + else + return getJSON("/pack/" + pack + "/" + name); + } + + this.randomFiles = function(page, rows) { + if(typeof page == "undefined" || typeof rows == "undefined") + throw "SixteenColors.randomFiles: Invalid 'page' or 'rows' argument (must be numbers)"; + else + return getJSON("/file/random?page=" + page + "&rows=" + rows); + } + + this.randomPacks = function(page, rows) { + if(typeof page == "undefined" || typeof rows == "undefined") + throw "SixteenColors.randomPacks: Invalid or missing 'page' or 'rows' arguments"; + else + return getJSON("/pack/random?page=" + page + "&rows=" + rows); + } + + this.getFile = function(file_location) { + try { + return (new HTTPRequest().Get(downloadUrl + file_location)); + } catch(err) { + log("SixteenColors.getFile: " + err); + return null; + } + } + + /* The API seems to always return empty arrays for these last five calls. + I don't think that anything's broken - just that 16c doesn't have + group / artist / month metadata entered in for most (or any) packs yet. + (When you list packs in a year, for example, each pack's 'month' value + always seems to be null.) */ + + this.groups = function() { + return getJSON("/group"); + } + + this.group = function(name) { + if(typeof name != "string") + throw "SixteenColors.group: Invalid or no group name provided."; + else + return getJSON("/group/" + name); + } + + this.artists = function() { + return getJSON("/artist"); + } + + this.artist = function(artist) { + if(typeof artist != "string") + throw "SixteenColors.artist: Invalid or no artist name provided."; + else + return getJSON("/artist/" + artist); + } + + this.month = function(year, month) { + if(typeof year != "string" || year.length != 4) + throw "SixteenColors.month: Invalid or no year provided."; + else if(typeof month != "string" || month.length != 2) + throw "SixteenColors.month: Invalid or no month provided."; + else + return getJSON("/year/" + year + "/" + month); + } + +} \ No newline at end of file diff --git a/xtrn/ansiview/sixteencolors.js b/xtrn/ansiview/sixteencolors.js new file mode 100644 index 0000000000000000000000000000000000000000..1113b5152731042b68a7228238d15df22764227c --- /dev/null +++ b/xtrn/ansiview/sixteencolors.js @@ -0,0 +1,378 @@ +(function() { + + load(root + "sixteencolors-api.js"); + + var Browser = function(options) { + + var self = this; + + var badExtensions = [ + "exe", + "com", + "zip", + "gif", + "jpg", + "png" + ]; + + var properties = { + 'path' : "", + 'parentFrame' : null, + 'frame' : null, + 'pathFrame' : null, + 'tree' : null, + 'treeFrame' : null, + 'scrollbar' : null, + 'colors' : { + 'fg' : WHITE, + 'bg' : BG_BLACK, + 'lfg' : WHITE, + 'lbg' : BG_CYAN, + 'sfg' : WHITE, + 'sbg' : BG_BLUE + }, + 'index' : 0, + 'cache' : false, + 'cachettl' : 0, + 'cachePath' : root + ".cache/sixteencolors/", + 'selectHook' : function(item) {} + } + + var api = new SixteenColors(); + + var errorItem = function() { + properties.tree.addItem( + "An error was encountered. Press 'Q' to quit this module.", + function() {} + ); + } + + var initSettings = function() { + + if(typeof options.frame == "undefined") + throw "SixteenColors Browser: No 'frame' argument provided."; + else + properties.parentFrame = options.frame; + + if(typeof options.colors != "object") + throw "SixteenColors Browser: Invalid or no 'colors' argument provided."; + else + properties.colors = options.colors; + + if( typeof options.selectHook != "undefined" + && + typeof options.selectHook != "function" + ) { + throw "SixteenColors Browser: 'selectHook' argument is not a function."; + } else { + properties.selectHook = options.selectHook; + } + + if(typeof options.path == "string") + properties.path = options.path; + + if(typeof options.cache == "boolean") + properties.cache = options.cache; + + if(typeof options.cachettl == "number") + properties.cachettl = options.cachettl; + + } + + var initCache = function() { + if(!properties.cache) + return; + if(!file_isdir(properties.cachePath)) + mkpath(properties.cachePath); + } + + var listYears = function() { + + if(properties.cache) { + var cacheDir = properties.cachePath + "years/"; + if(!file_isdir(cacheDir)) + mkpath(cacheDir); + if( !file_exists(cacheDir + "list.json") + || + time() - file_date(cacheDir + "list.json") > properties.cachettl + ) { + var list = api.years(); + if(list === null) { + errorItem(); + return; + } + var f = new File(cacheDir + "list.json"); + f.open("w"); + f.write(JSON.stringify(list)); + f.close(); + } else { + var f = new File(cacheDir + "list.json"); + f.open("r"); + var list = JSON.parse(f.read()); + f.close(); + } + } else { + var list = api.years(); + if(list === null) { + errorItem(); + return; + } + } + + list.forEach( + function(year) { + properties.tree.addItem( + format("[%s]...%s packs", year.year, year.packs), + function() { + properties.path = "/years/" + year.year; + self.refresh(); + } + ); + } + ); + + } + + var listYear = function(year) { + + if(properties.cache) { + var cacheDir = properties.cachePath + "years/" + year + "/"; + if(!file_isdir(cacheDir)) + mkpath(cacheDir); + if( !file_exists(cacheDir + "list.json") + || + time() - file_date(cacheDir + "list.json") > properties.cachettl + ) { + var list = api.year(year); + if(list === null) { + errorItem(); + return; + } + var f = new File(cacheDir + "list.json"); + f.open("w"); + f.write(JSON.stringify(list)); + f.close(); + } else { + var f = new File(cacheDir + "list.json"); + f.open("r"); + var list = JSON.parse(f.read()); + f.close(); + } + } else { + var list = api.year(year); + if(list === null) { + errorItem(); + return; + } + } + + properties.tree.addItem( + "[..]", + function() { + properties.path = "/years"; + self.refresh(); + } + ); + + list.forEach( + function(item) { + properties.tree.addItem( + format("[%s]", item.name), + function() { + properties.path = "/pack/" + item.name; + self.refresh(); + } + ); + } + ); + + } + + var listPack = function(pack) { + + if(properties.cache) { + var cacheDir = properties.cachePath + "packs/" + pack + "/"; + if(!file_isdir(cacheDir)) + mkpath(cacheDir); + if( !file_exists(cacheDir + "pack.json") + || + time() - file_date(cacheDir + "pack.json") > properties.cachettl + ) { + var pack = api.pack(pack); + if(pack === null) { + errorItem(); + return; + } + var f = new File(cacheDir + "pack.json"); + f.open("w"); + f.write(JSON.stringify(pack)); + f.close(); + } else { + var f = new File(cacheDir + "pack.json"); + f.open("r"); + var pack = JSON.parse(f.read()); + f.close(); + } + } else { + var pack = api.pack(pack); + if(pack === null) { + errorItem(); + return; + } + } + + properties.tree.addItem( + "[..]", + function() { + properties.path = "/years/" + pack.year; + self.refresh(); + } + ); + + pack.files.forEach( + function(item) { + for(var b = 0; b < badExtensions.length; b++) { + var re = new RegExp(badExtensions[b] + "$", "i"); + if(item.filename.match(re) !== null) + return; + } + properties.tree.addItem( + format("%s", item.filename), + function() { + properties.index = properties.tree.index; + if(properties.cache) { + if(!file_exists(cacheDir + item.filename)) { + var ansi = api.getFile(item.file_location); + if(ansi === null) + return; + var f = new File(cacheDir + item.filename); + f.open("w"); + f.write(ansi); + f.close(); + } + properties.selectHook(cacheDir + item.filename); + } else { + if(!file_exists(system.temp_dir + item.filename)) { + var ansi = api.getFile(item.file_location); + if(ansi === null) + return; + var f = new File(system.temp_dir + item.filename); + f.open("w"); + f.write(ansi); + f.close(); + } + properties.selectHook(system.temp_dir + item.filename); + } + self.refresh(); + properties.tree.index = properties.index; + properties.tree.refresh(); + } + ); + } + ); + + } + + var initList = function() { + if(properties.path == "/years") + listYears(); + else if(properties.path.match(/^\/years\/\d\d\d\d$/) !== null) + listYear(properties.path.split("/")[2]); + else if(properties.path.match(/^\/pack\/.*$/) !== null) + listPack(properties.path.split("/")[2]); + } + + var initDisplay = function() { + + properties.frame = new Frame( + properties.parentFrame.x, + properties.parentFrame.y, + properties.parentFrame.width, + properties.parentFrame.height, + BG_BLACK|LIGHTGRAY, + properties.parentFrame + ); + + properties.pathFrame = new Frame( + properties.frame.x, + properties.frame.y, + properties.frame.width, + 1, + properties.colors.sbg|properties.colors.sfg, + properties.frame + ); + properties.pathFrame.putmsg( + "Browsing: " + decodeURIComponent(properties.path) + ); + + properties.treeFrame = new Frame( + properties.frame.x, + properties.frame.y + 1, + properties.frame.width, + properties.frame.height - 1, + properties.frame.attr, + properties.frame + ); + + properties.tree = new Tree(properties.treeFrame); + for(var color in properties.colors) + properties.tree.colors[color] = properties.colors[color]; + initList(); + properties.scrollBar = new ScrollBar(properties.tree); + properties.frame.open(); + properties.tree.open(); + + } + + var init = function() { + initSettings(); + initCache(); + initDisplay(); + } + + this.open = function() { + init(); + properties.frame.draw(); + } + + this.cycle = function() { + properties.scrollBar.cycle(); + } + + this.getcmd = function(cmd) { + properties.tree.getcmd(cmd); + } + + this.refresh = function() { + this.close(); + options.path = properties.path; + this.open(); + } + + this.close = function() { + properties.tree.close(); + properties.scrollBar.close(); + properties.frame.close(); + } + + } + + var args = JSON.parse(argv[0]); + return new Browser( + { 'path' : "/years", + 'frame' : browserFrame, + 'selectHook' : printFile, + 'colors' : { + 'fg' : args.colors.fg, + 'bg' : args.colors.bg, + 'lfg' : args.colors.lfg, + 'lbg' : args.colors.lbg, + 'sfg' : args.colors.sfg, + 'sbg' : args.colors.sbg + }, + 'cache' : (typeof args.cache == "undefined") ? true : args.cache, + 'cachettl' : parseInt(args.cachettl) + } + ); + +})(); \ No newline at end of file diff --git a/xtrn/ansiview/thescene.js b/xtrn/ansiview/thescene.js new file mode 100644 index 0000000000000000000000000000000000000000..f08781c13596691dd5b25dfd5769e5c6dea2c502 --- /dev/null +++ b/xtrn/ansiview/thescene.js @@ -0,0 +1,282 @@ +(function() { + + load("http.js"); + + var TheScene = function() { + var apiUrl = "http://thescene.electronicchicken.com/api"; + this.list = function(path) { + try { + return JSON.parse( + new HTTPRequest().Get( + apiUrl + "/list/" + (typeof path == "undefined" ? "" : path) + ) + ); + } catch(err) { + return null; + log(err); + } + } + this.getANSI = function(path) { + if(typeof path != "string") + throw "TheScene.getANSI: Invalid 'path' argument: " + path; + try { + return (new HTTPRequest().Get(apiUrl + "/ansi/" + path)); + } catch(err) { + return null; + log(err); + } + } + } + + var Browser = function(options) { + + var self = this; + + var properties = { + 'path' : "", + 'parentFrame' : null, + 'frame' : null, + 'pathFrame' : null, + 'tree' : null, + 'treeFrame' : null, + 'scrollbar' : null, + 'colors' : { + 'fg' : WHITE, + 'bg' : BG_BLACK, + 'lfg' : WHITE, + 'lbg' : BG_CYAN, + 'sfg' : WHITE, + 'sbg' : BG_BLUE + }, + 'index' : 0, + 'cache' : false, + 'cachettl' : 0, + 'cachePath' : root + ".cache/thescene/", + 'selectHook' : function(item) {} + } + + var api = new TheScene(); + + var errorItem = function() { + properties.tree.addItem( + "An error was encountered. Press 'Q' to quit this module.", + function() {} + ); + } + + var initSettings = function() { + + if(typeof options.frame == "undefined") + throw "TheScene Browser: No 'frame' argument provided."; + else + properties.parentFrame = options.frame; + + if(typeof options.colors != "object") + throw "TheScene Browser: Invalid or no 'colors' argument provided."; + else + properties.colors = options.colors; + + if( typeof options.selectHook != "undefined" + && + typeof options.selectHook != "function" + ) { + throw "TheScene Browser: 'selectHook' argument is not a function."; + } else { + properties.selectHook = options.selectHook; + } + + if(typeof options.path == "string") + properties.path = options.path; + + if(typeof options.cache == "boolean") + properties.cache = options.cache; + + if(typeof options.cachettl == "number") + properties.cachettl = options.cachettl; + + } + + var initCache = function() { + if(!properties.cache) + return; + if(!file_isdir(properties.cachePath)) + mkpath(properties.cachePath); + } + + var initList = function() { + + if(properties.cache) { + var cacheDir = properties.cachePath + backslash(decodeURIComponent(properties.path)); + if(!file_isdir(cacheDir)) + mkpath(cacheDir); + if( !file_exists(cacheDir + "list.json") + || + time() - file_date(cacheDir + "list.json") > properties.cachettl + ) { + var list = api.list(properties.path); + if(list === null) { + errorItem(); + return; + } + var f = new File(cacheDir + "list.json"); + f.open("w"); + f.write(JSON.stringify(list)); + f.close(); + } else { + var f = new File(cacheDir + "list.json"); + f.open("r"); + var list = JSON.parse(f.read()); + f.close(); + } + } else { + var list = api.list(properties.path); + if(list === null) { + errorItem(); + return; + } + } + + for(var l in list) { + (function(item) { + if(item.type == "file") { + properties.tree.addItem( + item.filename, + function() { + properties.index = properties.tree.index; + if(properties.cache) { + var cacheItem = properties.cachePath + decodeURIComponent(item.path); + if(!file_exists(cacheItem)) { + var ansi = api.getANSI(item.path); + if(ansi === null) + return; + var f = new File(cacheItem); + f.open("w"); + f.write(ansi); + f.close(); + } + properties.selectHook(cacheItem); + } else { + var tempItem = system.temp_dir + md5_calc(item.path, true); + if(!file_exists(tempItem)) { + var ansi = api.getANSI(item.path); + if(ansi === null) + return; + var f = new File(tempItem); + f.open("w"); + f.write(ansi); + f.close(); + } + properties.selectHook(tempItem); + } + self.refresh(); + properties.tree.index = properties.index; + properties.tree.refresh(); + } + ); + } else { + properties.tree.addItem( + "[" + item.filename + "]", + function() { + properties.path = item.path; + self.refresh(); + } + ); + } + })(list[l]); + } + } + + var initDisplay = function() { + + properties.frame = new Frame( + properties.parentFrame.x, + properties.parentFrame.y, + properties.parentFrame.width, + properties.parentFrame.height, + BG_BLACK|LIGHTGRAY, + properties.parentFrame + ); + + properties.pathFrame = new Frame( + properties.frame.x, + properties.frame.y, + properties.frame.width, + 1, + properties.colors.sbg|properties.colors.sfg, + properties.frame + ); + properties.pathFrame.putmsg( + "Browsing: /" + decodeURIComponent(properties.path) + ); + + properties.treeFrame = new Frame( + properties.frame.x, + properties.frame.y + 1, + properties.frame.width, + properties.frame.height - 1, + properties.frame.attr, + properties.frame + ); + + properties.tree = new Tree(properties.treeFrame); + for(var color in properties.colors) + properties.tree.colors[color] = properties.colors[color]; + initList(); + properties.scrollBar = new ScrollBar(properties.tree); + properties.frame.open(); + properties.tree.open(); + + } + + var init = function() { + initSettings(); + initCache(); + initDisplay(); + } + + this.open = function() { + init(); + properties.frame.draw(); + } + + this.cycle = function() { + properties.scrollBar.cycle(); + } + + this.getcmd = function(cmd) { + properties.tree.getcmd(cmd); + } + + this.refresh = function() { + this.close(); + options.path = properties.path; + this.open(); + } + + this.close = function() { + properties.tree.close(); + properties.scrollBar.close(); + properties.frame.close(); + } + + } + + var args = JSON.parse(argv[0]); + return new Browser( + { 'path' : "", + 'frame' : browserFrame, + 'selectHook' : printFile, + 'colors' : { + 'fg' : args.colors.fg, + 'bg' : args.colors.bg, + 'lfg' : args.colors.lfg, + 'lbg' : args.colors.lbg, + 'sfg' : args.colors.sfg, + 'sbg' : args.colors.sbg + }, + 'cache' : (typeof args.cache == "undefined") ? true : args.cache, + 'cachettl' : parseInt(args.cachettl) + } + ); + +})(); \ No newline at end of file