Skip to content
Snippets Groups Projects
Commit 9bd08695 authored by echicken's avatar echicken
Browse files

New version of ANSIView.

- Uses SyncTERM output speed emulation if available
- Server-side output throttling if client is non-SyncTERM, somewhat better than before
- Enable / disable screen pause
- Scrollbars
- No more static "background" UI graphic
- Uses new filebrowser.js
- Supports multiple local libraries
- Supports file descriptions for local libraries (requested by nolageek)
- Two additional "browser modules" included for access to online art archives (sixteencolors.net, thescene.electronicchicken.com)
- Read readme.txt if you want to use this.  It won't do anything until you follow the instructions
parent 00beef81
No related branches found
No related tags found
No related merge requests found
// 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();
(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
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
/* 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
(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
(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
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment