Compare commits
43 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fbc59fdaaa | ||
|
|
d57b5573c9 | ||
|
|
ba66b98200 | ||
|
|
e51bec4909 | ||
|
|
dbfb8db6d4 | ||
|
|
14a646e680 | ||
|
|
6e5c28c9c4 | ||
|
|
97d1b1ebe5 | ||
|
|
ec1905d37f | ||
|
|
d7c908a033 | ||
| 10bc3e132e | |||
|
|
9461c59ce1 | ||
|
|
4c50e001ef | ||
|
|
7843f2953d | ||
|
|
8212f2c679 | ||
|
|
8fd83c3040 | ||
|
|
5e05d0fbb8 | ||
|
|
80a92fc0c0 | ||
|
|
af4f9cf56b | ||
|
|
8f01863d39 | ||
|
|
7d5d2d5983 | ||
|
|
68fb3c4b5a | ||
|
|
b9363d5ec9 | ||
|
|
a01c9ca3b7 | ||
|
|
99f6dc1504 | ||
|
|
4bee0d69d3 | ||
|
|
df6a50ad7b | ||
|
|
4f884d9cac | ||
|
|
ae90ebd06c | ||
|
|
8476159433 | ||
|
|
26af6681ce | ||
|
|
58ba2141f4 | ||
|
|
a31e4dcd9f | ||
|
|
50d2afd6d8 | ||
|
|
1d6e8636ca | ||
|
|
d3cf696ae4 | ||
|
|
81a25b9139 | ||
|
|
54b59b6344 | ||
|
|
a31167bd4b | ||
|
|
ff0815e300 | ||
|
|
82489faae9 | ||
|
|
dd124a718b | ||
|
|
61d667cad5 |
22 changed files with 1345 additions and 106 deletions
179
.gitignore
vendored
Normal file
179
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,179 @@
|
|||
# Created by https://www.gitignore.io/api/git,emacs,python,coffeescript
|
||||
# Edit at https://www.gitignore.io/?templates=git,emacs,python,coffeescript
|
||||
|
||||
### CoffeeScript ###
|
||||
*.js
|
||||
|
||||
### Emacs ###
|
||||
# -*- mode: gitignore; -*-
|
||||
*~
|
||||
\#*\#
|
||||
/.emacs.desktop
|
||||
/.emacs.desktop.lock
|
||||
*.elc
|
||||
auto-save-list
|
||||
tramp
|
||||
.\#*
|
||||
|
||||
# Org-mode
|
||||
.org-id-locations
|
||||
*_archive
|
||||
|
||||
# flymake-mode
|
||||
*_flymake.*
|
||||
|
||||
# eshell files
|
||||
/eshell/history
|
||||
/eshell/lastdir
|
||||
|
||||
# elpa packages
|
||||
/elpa/
|
||||
|
||||
# reftex files
|
||||
*.rel
|
||||
|
||||
# AUCTeX auto folder
|
||||
/auto/
|
||||
|
||||
# cask packages
|
||||
.cask/
|
||||
dist/
|
||||
|
||||
# Flycheck
|
||||
flycheck_*.el
|
||||
|
||||
# server auth directory
|
||||
/server/
|
||||
|
||||
# projectiles files
|
||||
.projectile
|
||||
|
||||
# directory configuration
|
||||
.dir-locals.el
|
||||
|
||||
# network security
|
||||
/network-security.data
|
||||
|
||||
|
||||
### Git ###
|
||||
# Created by git for backups. To disable backups in Git:
|
||||
# $ git config --global mergetool.keepBackup false
|
||||
*.orig
|
||||
|
||||
# Created by git when using merge tools for conflicts
|
||||
*.BACKUP.*
|
||||
*.BASE.*
|
||||
*.LOCAL.*
|
||||
*.REMOTE.*
|
||||
*_BACKUP_*.txt
|
||||
*_BASE_*.txt
|
||||
*_LOCAL_*.txt
|
||||
*_REMOTE_*.txt
|
||||
|
||||
### Python ###
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
build/
|
||||
develop-eggs/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
pip-wheel-metadata/
|
||||
share/python-wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
MANIFEST
|
||||
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.nox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*.cover
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Scrapy stuff:
|
||||
.scrapy
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
target/
|
||||
|
||||
# pyenv
|
||||
.python-version
|
||||
|
||||
# pipenv
|
||||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||
# install all needed dependencies.
|
||||
#Pipfile.lock
|
||||
|
||||
# celery beat schedule file
|
||||
celerybeat-schedule
|
||||
|
||||
# SageMath parsed files
|
||||
*.sage.py
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
.spyproject
|
||||
|
||||
# Rope project settings
|
||||
.ropeproject
|
||||
|
||||
# Mr Developer
|
||||
.mr.developer.cfg
|
||||
.project
|
||||
.pydevproject
|
||||
|
||||
# mkdocs documentation
|
||||
/site
|
||||
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
.dmypy.json
|
||||
dmypy.json
|
||||
|
||||
# Pyre type checker
|
||||
.pyre/
|
||||
|
||||
#project settings
|
||||
sahli-venv/*
|
||||
*.wp*
|
||||
33
README.md
33
README.md
|
|
@ -6,7 +6,7 @@
|
|||
l__________/__________|___|______l__________j_____j
|
||||
|
||||
Ansi/Ansi Viewer in Ecmascript
|
||||
Coded by Sir Garbagetruck / Accession 2013
|
||||
Coded by Sir Garbagetruck / Accession 2013+
|
||||
Uses fonts by DMG, http:trueschool.se
|
||||
Uses SixteenColors textmode js library for rendering
|
||||
(well, my optimized version...)
|
||||
|
|
@ -48,6 +48,8 @@ idea...
|
|||
* Android tablets ARE considered modern; Ipad/Iphone too.
|
||||
* I haven't tested on MorphOS yet.
|
||||
|
||||
For Chrome/Chromium:
|
||||
|
||||
To use with _local_ files you need to run your browser
|
||||
in "developer" mode, that means:
|
||||
|
||||
|
|
@ -63,6 +65,30 @@ This works just fine if you use remote urls for the files.
|
|||
EVERY PERSON ALIVE, DEAD, OR IMAGINARY,
|
||||
INCLUDING THE NONEXISTENT. ***
|
||||
|
||||
Mr Doob (who I want to call Trace (: ) has a good page
|
||||
explaining how to do this and alternatives here:
|
||||
|
||||
https://github.com/mrdoob/three.js/wiki/How-to-run-things-locally
|
||||
|
||||
Firefox (and Icecat, possibly other Firefox codebased browsers)
|
||||
seem to work today (Sept 2016) _without_ making any changes, so
|
||||
you can use it 'out of the box.' M0qui was able to, and I tested,
|
||||
and so the big 72-point "not supported on Windows+Firefox" warning
|
||||
goes away.
|
||||
|
||||
Again, DON'T FREAKING TURN OFF JAVASCRIPT SECURITY AND FORGET TO
|
||||
TURN IT BACK ON. DON'T. NOT JUST ON WINDOWS. BUT ESPECIALLY ON
|
||||
WINDOWS.
|
||||
|
||||
I may be able to turn this into a chrome app at some point, which
|
||||
will eliminate that issue. Possibly also a Firefox solution, but:
|
||||
As of today: I do not support this on Windows + Firefox. That is
|
||||
100% at your own risk, because of the possibility you will forget
|
||||
to set the setting back.
|
||||
|
||||
It's just plain safer to install this on your webserver at the
|
||||
party place in a directory and use _that._
|
||||
|
||||
This product is licensed under the WTFPL. See:
|
||||
http://www.wtfpl.net
|
||||
for details, or just get the license:
|
||||
|
|
@ -98,3 +124,8 @@ Azzarro/Madwizards.
|
|||
- More examples came from 16colors archive. When the final
|
||||
Sahli ver. B comes out, I'll select some test files and
|
||||
put those credits in here too.
|
||||
|
||||
- Thanks to M0qui for submitting a patch for 'backwards'
|
||||
(in case you accidentally hit space. Which we c64 sceners
|
||||
never do, because that would be the NEXT demopart, and
|
||||
you'd have to reload (: )
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// Generated by CoffeeScript 1.7.1
|
||||
// Generated by CoffeeScript 1.11.0
|
||||
(function() {
|
||||
var Sahli, ansiorascii, arraytocolor, booltoint, colorindex, colortoarray, colortoname, dec2hex, dumpjson, emptyfiledef, getfilelist, hex2dec, inttobool, loadsahli, newsahli, resolvefiletype, sahlicolor, statustobool;
|
||||
|
||||
|
|
@ -163,19 +163,19 @@
|
|||
};
|
||||
|
||||
Sahli.prototype.buildlist = function(data) {
|
||||
var i, item, x, _i, _j, _len, _len1, _ref, _ref1;
|
||||
var i, item, j, k, len, len1, ref, ref1, x;
|
||||
$('#list').show(100);
|
||||
$('#list ol li').remove();
|
||||
_ref = this.data.filedata;
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
i = _ref[_i];
|
||||
ref = this.data.filedata;
|
||||
for (j = 0, len = ref.length; j < len; j++) {
|
||||
i = ref[j];
|
||||
console.log(i.author);
|
||||
}
|
||||
x = 0;
|
||||
$('#dirlocation').val(this.data.location);
|
||||
_ref1 = this.data.filedata;
|
||||
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
|
||||
item = _ref1[_j];
|
||||
ref1 = this.data.filedata;
|
||||
for (k = 0, len1 = ref1.length; k < len1; k++) {
|
||||
item = ref1[k];
|
||||
$('#sortlist').append(this.additem(item, x++));
|
||||
}
|
||||
return $('#sortlist').sortable({
|
||||
|
|
@ -186,13 +186,13 @@
|
|||
},
|
||||
stop: (function(_this) {
|
||||
return function(event, ui) {
|
||||
var e, name, s, _k, _len2, _ref2;
|
||||
var e, l, len2, name, ref2, s;
|
||||
s = ui.item.data().startpos;
|
||||
e = ui.item.index();
|
||||
_this.data.filedata = _this.rearrangearray(s, e, _this.data.filedata);
|
||||
_ref2 = _this.data.filedata;
|
||||
for (_k = 0, _len2 = _ref2.length; _k < _len2; _k++) {
|
||||
name = _ref2[_k];
|
||||
ref2 = _this.data.filedata;
|
||||
for (l = 0, len2 = ref2.length; l < len2; l++) {
|
||||
name = ref2[l];
|
||||
console.log(name.author, name.name, name.file);
|
||||
}
|
||||
console.log('---');
|
||||
|
|
@ -367,13 +367,13 @@
|
|||
arraytocolor = function(array) {
|
||||
var c, x;
|
||||
c = ((function() {
|
||||
var _i, _len, _results;
|
||||
_results = [];
|
||||
for (_i = 0, _len = array.length; _i < _len; _i++) {
|
||||
x = array[_i];
|
||||
_results.push(dec2hex(x));
|
||||
var j, len, results;
|
||||
results = [];
|
||||
for (j = 0, len = array.length; j < len; j++) {
|
||||
x = array[j];
|
||||
results.push(dec2hex(x));
|
||||
}
|
||||
return _results;
|
||||
return results;
|
||||
})()).slice(0, 3).join('');
|
||||
return "#" + c;
|
||||
};
|
||||
|
|
@ -383,13 +383,13 @@
|
|||
color = color.slice(1);
|
||||
c1 = [color.slice(0, 2), color.slice(2, 4), color.slice(4, 6)];
|
||||
x = (function() {
|
||||
var _i, _len, _results;
|
||||
_results = [];
|
||||
for (_i = 0, _len = c1.length; _i < _len; _i++) {
|
||||
i = c1[_i];
|
||||
_results.push(hex2dec(i));
|
||||
var j, len, results;
|
||||
results = [];
|
||||
for (j = 0, len = c1.length; j < len; j++) {
|
||||
i = c1[j];
|
||||
results.push(hex2dec(i));
|
||||
}
|
||||
return _results;
|
||||
return results;
|
||||
})();
|
||||
x.push(255);
|
||||
return x;
|
||||
160
editor.py
Normal file
160
editor.py
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
#!/usr/bin/env python
|
||||
# coding:utf-8
|
||||
"""
|
||||
Author: Sir Garbagetruck --<truck@notonfire.somewhere>
|
||||
Purpose: make editing the list.sahli file easier
|
||||
Created: 2020/04/09
|
||||
"""
|
||||
|
||||
import json
|
||||
import argparse
|
||||
import os
|
||||
from sauce import SAUCE
|
||||
from PIL import Image
|
||||
from sahliEditorPython import sahlifile as SF
|
||||
|
||||
|
||||
def getfilesindir(directory):
|
||||
"""return the files in a directory as an array"""
|
||||
for root, dirs, files, rootfd in os.fwalk(directory):
|
||||
return files
|
||||
|
||||
|
||||
def getfilenames(filedata):
|
||||
"""return the file names from a sahli filedata array"""
|
||||
f = []
|
||||
for i in filedata:
|
||||
f.append(i['file'])
|
||||
return f
|
||||
|
||||
|
||||
def getdata(filedata, name):
|
||||
"""get the filedata entry where file = name"""
|
||||
for i in filedata:
|
||||
if i['file'] == name:
|
||||
return i
|
||||
return []
|
||||
|
||||
|
||||
def getpicdata(filename):
|
||||
"""extract picture data from filename"""
|
||||
imagedata = Image.open(filename)
|
||||
picdata = {
|
||||
'width': imagedata.width,
|
||||
'height': imagedata.height
|
||||
}
|
||||
return picdata
|
||||
|
||||
|
||||
def getansidata(filename):
|
||||
"""extract SAUCE data from filename"""
|
||||
saucedata = SAUCE(filename)
|
||||
ansidata = {
|
||||
'author': saucedata.author,
|
||||
'group': saucedata.group,
|
||||
'title': saucedata.title,
|
||||
'filesize': saucedata.filesize,
|
||||
'comments': saucedata.comments,
|
||||
'width': None,
|
||||
'height': None
|
||||
}
|
||||
tinfonames = [saucedata.tinfo1_name,
|
||||
saucedata.tinfo2_name,
|
||||
saucedata.tinfo3_name,
|
||||
saucedata.tinfo4_name]
|
||||
tinfo = [saucedata.tinfo1,
|
||||
saucedata.tinfo2,
|
||||
saucedata.tinfo3,
|
||||
saucedata.tinfo4]
|
||||
for i in range(0, 3):
|
||||
if tinfonames[i] == 'width':
|
||||
ansidata['width'] = tinfo[i]
|
||||
if tinfonames[i] == 'height':
|
||||
ansidata['height'] = tinfo[i]
|
||||
# print(tinfonames[i])
|
||||
return ansidata
|
||||
|
||||
|
||||
def getamigadata(filename):
|
||||
"""try to get some form of info from file (:"""
|
||||
with open(filename, encoding='latin1') as f:
|
||||
ascii = f.readlines()
|
||||
width = 0
|
||||
for i in ascii:
|
||||
if len(i) > width:
|
||||
width = len(i)
|
||||
return {'height': len(ascii),
|
||||
'width': width}
|
||||
|
||||
|
||||
def main(args):
|
||||
"""maintain a list.sahli file"""
|
||||
if args.new:
|
||||
mysahli = SF.sahlifile(None)
|
||||
else:
|
||||
mysahli = SF.sahlifile(args.filename)
|
||||
mysahli.sahli['location'] = args.directory
|
||||
files = getfilesindir(args.directory)
|
||||
filedata = mysahli.sahli['filedata']
|
||||
filedatanames = getfilenames(filedata)
|
||||
newdata = []
|
||||
for i in files:
|
||||
dirfile = '{}/{}'.format(args.directory, i)
|
||||
if i in filedatanames:
|
||||
print('found! {}'.format(i))
|
||||
# todo: _if_ I ever make this a non-preparser, then... futz with
|
||||
a = getansidata(dirfile)
|
||||
newdata.append(getdata(filedata, i))
|
||||
else:
|
||||
print('not found! {}'.format(i))
|
||||
suf = i.split('.')[-1]
|
||||
if suf in ['png', 'jpg', 'jpeg', 'gif',
|
||||
'PNG', 'JPG', 'JPEG', 'GIF']:
|
||||
stuff = getpicdata(dirfile)
|
||||
entry = mysahli.blank_picture()
|
||||
entry['width'] = stuff['width']
|
||||
entry['height'] = stuff['height']
|
||||
entry['file'] = i
|
||||
entry['name'] = i
|
||||
newdata.append(entry)
|
||||
elif suf in ['ans', 'ANS', 'BIN', 'bin', 'XB', 'xb']:
|
||||
stuff = getansidata(dirfile)
|
||||
entry = mysahli.blank_ansi()
|
||||
entry['file'] = i
|
||||
entry['name'] = stuff['title']
|
||||
entry['author'] = '{}/{}'.format(
|
||||
stuff['author'], stuff['group'])
|
||||
entry['text'] = stuff['comments']
|
||||
if stuff['height'] is not None:
|
||||
entry['height'] = stuff['height']
|
||||
if stuff['width'] is not None:
|
||||
entry['width'] = stuff['width']
|
||||
newdata.append(entry)
|
||||
elif suf in ['TXT', 'ASC', 'txt', 'asc',
|
||||
'NFO', 'nfo', 'diz', 'DIZ']:
|
||||
stuff = getamigadata(dirfile)
|
||||
entry = mysahli.blank_amiga_ascii()
|
||||
entry['name'] = i
|
||||
# entry['title'] = i
|
||||
# entry['height'] = stuff['height']
|
||||
entry['file'] = i
|
||||
newdata.append(entry)
|
||||
else:
|
||||
print("dunno what type of file this is... {}".format(dirfile))
|
||||
mysahli.sahli['filedata'] = newdata
|
||||
out = json.dumps(mysahli.sahli, sort_keys=False, indent=4)
|
||||
if args.outfile == '>stdout':
|
||||
print(out)
|
||||
else:
|
||||
with open(args.outfile, 'w') as f:
|
||||
json.dump(mysahli.sahli, f, sort_keys=False, indent=4)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
ap = argparse.ArgumentParser()
|
||||
ap.add_argument('-f', '--filename', default='list.sahli')
|
||||
ap.add_argument('-n', '--new', action='store_true')
|
||||
ap.add_argument('-o', '--outfile', type=str, default='>stdout')
|
||||
ap.add_argument('-d', '--directory', type=str, required=True,
|
||||
help='directory where compo files are')
|
||||
main(ap.parse_args())
|
||||
|
|
@ -41,6 +41,8 @@
|
|||
<li><span class="key">W</span> Begin scrolling upward</li>
|
||||
<li><span class="key">A</span> Stop scrolling</li>
|
||||
|
||||
<li><span class="key">P</span> Previous Picture</li>
|
||||
|
||||
<li><span class="key">T</span> Jump to Top of picture (resets zoom)</li>
|
||||
<li><span class="key">B</span> Jump to Bottom</li>
|
||||
<li><span class="key">1</span><span class="key">2</span><span class="key">3</span><span class="key">4</span><span class="key">5</span> Alter scrollspeed (fast -> slow)</li>
|
||||
|
|
|
|||
102
list.sahli
102
list.sahli
|
|
@ -14,100 +14,104 @@
|
|||
|
||||
"filedata": [
|
||||
|
||||
{
|
||||
"file": "AD - Green Beam.scaled.png",
|
||||
"name": "Green Beam",
|
||||
"amiga": false,
|
||||
"filetype": "image",
|
||||
"width": "1600",
|
||||
"author": "AD",
|
||||
"font": "Propaz",
|
||||
"color": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
255
|
||||
],
|
||||
"bg": [
|
||||
255,
|
||||
255,
|
||||
255,
|
||||
255
|
||||
],
|
||||
"line1": "",
|
||||
"line2": "",
|
||||
"text": ""
|
||||
},
|
||||
|
||||
{
|
||||
"file": "om-boss.png",
|
||||
"name": "Green Beam",
|
||||
"amiga": false,
|
||||
"filetype": "image",
|
||||
"width": "640",
|
||||
"author": "AD",
|
||||
"font": "Propaz",
|
||||
"color": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
255
|
||||
],
|
||||
"bg": [
|
||||
255,
|
||||
255,
|
||||
255,
|
||||
255
|
||||
],
|
||||
"line1": "",
|
||||
"line2": "",
|
||||
"text": ""
|
||||
},
|
||||
|
||||
{
|
||||
|
||||
"file": "spaceflight.asc",
|
||||
|
||||
"name": "Spaceflight",
|
||||
|
||||
"amiga": true,
|
||||
|
||||
"filetype": "plain",
|
||||
|
||||
"width": "80",
|
||||
|
||||
"author": "Urs",
|
||||
|
||||
"font": "pot-noodle",
|
||||
|
||||
"color": [
|
||||
|
||||
255,
|
||||
|
||||
128,
|
||||
|
||||
0,
|
||||
|
||||
255
|
||||
|
||||
],
|
||||
|
||||
"bg": [
|
||||
|
||||
0,
|
||||
|
||||
0,
|
||||
|
||||
0,
|
||||
|
||||
255
|
||||
|
||||
],
|
||||
|
||||
"line1": "Orange on Dark Grey",
|
||||
|
||||
"line2": "Test for plain files",
|
||||
|
||||
"text": ""
|
||||
|
||||
},
|
||||
|
||||
{
|
||||
|
||||
"file": "az0!-revi510n.txt",
|
||||
|
||||
"name": "Revision",
|
||||
|
||||
"amiga": true,
|
||||
|
||||
"filetype": "plain",
|
||||
|
||||
"width": "80",
|
||||
|
||||
"author": "Azzarro/Madwizards",
|
||||
|
||||
"font": "Propaz",
|
||||
|
||||
"color": [
|
||||
|
||||
"font": "mosoul",
|
||||
"color": [
|
||||
0,
|
||||
|
||||
240,
|
||||
|
||||
0,
|
||||
|
||||
255
|
||||
|
||||
],
|
||||
|
||||
"bg": [
|
||||
|
||||
255,
|
||||
|
||||
0,
|
||||
|
||||
0,
|
||||
|
||||
255
|
||||
|
||||
],
|
||||
|
||||
"line1": "Azzaro Returns",
|
||||
|
||||
"line2": "Revision ansi/ascii compo 2013",
|
||||
|
||||
"text": "Color test as well as Microknight test."
|
||||
|
||||
"text": "Color test as well as mOsOul test."
|
||||
},
|
||||
{
|
||||
"file": "dS!-JUFV.txt",
|
||||
|
|
|
|||
103
sahli.coffee
103
sahli.coffee
|
|
@ -14,6 +14,7 @@ l__________/__________|___|______l__________j_____j
|
|||
|
||||
class @Sahli
|
||||
constructor: () ->
|
||||
$('body').css('cursor', 'none');
|
||||
# I don't think we actually are going to have one, as we don't
|
||||
# need instance variables (things used outside the function)
|
||||
|
||||
|
|
@ -39,6 +40,8 @@ class @Sahli
|
|||
@loadhugeansi picdata, inserthere
|
||||
when 'tundra'
|
||||
@loadhugeansi picdata, inserthere
|
||||
when 'image'
|
||||
@loadpicture picdata, inserthere
|
||||
else
|
||||
@loadplain picdata, inserthere
|
||||
|
||||
|
|
@ -49,6 +52,7 @@ class @Sahli
|
|||
buf = $('<span>')
|
||||
buf.css {'margin':'0 auto'}
|
||||
ptxt = $('<pre>')
|
||||
ptxt.addClass 'plaintext'
|
||||
color = @calccolor(picdata.color)
|
||||
bgcolor = @calccolor(picdata.bg)
|
||||
pdiv.addClass 'scrolly'
|
||||
|
|
@ -58,9 +62,9 @@ class @Sahli
|
|||
'background-color': bgcolor
|
||||
'margin': 'auto'
|
||||
'display': 'inline-block'
|
||||
ptxt.width picdata.width * 8
|
||||
@origwidth = ptxt.width
|
||||
pdiv.width ptxt.width
|
||||
#ptxt.width picdata.width * 8
|
||||
#@origwidth = ptxt.width
|
||||
#pdiv.width ptxt.width
|
||||
pdiv.prepend buf.clone()
|
||||
pdiv.append ptxt
|
||||
pdiv.append buf
|
||||
|
|
@ -78,6 +82,72 @@ class @Sahli
|
|||
req.open 'GET', fname, true
|
||||
req.send null
|
||||
|
||||
@increaseFont = (node, increaseBy=5) ->
|
||||
current_size = parseInt($(node).css("font-size"));
|
||||
$(node).css("font-size", current_size + increaseBy);
|
||||
|
||||
@loadpicture = (picdata, inserthere) ->
|
||||
fname = @location + '/' + picdata.file
|
||||
pdiv = $('<div>')
|
||||
pdiv.addClass 'scrolly'
|
||||
pdiv.addClass 'image'
|
||||
pdiv.width window.innerWidth
|
||||
pdiv.css 'display', 'inline-block'
|
||||
pimg = $('<img src="' + fname + '" />')
|
||||
pimg.addClass 'fullwidth'
|
||||
pdiv.append pimg
|
||||
inserthere.after pdiv
|
||||
$('h6').hide()
|
||||
$('body').scrollTop 0
|
||||
@origwidth = picdata.width
|
||||
@origheight = picdata.height
|
||||
@bestfit()
|
||||
|
||||
@fullwidthplain = =>
|
||||
if ($('pre').css("font-size") == "16px")
|
||||
$('pre').css("font-size", "2.5vw");
|
||||
else
|
||||
$('pre').css("font-size", "16px");
|
||||
|
||||
@togglefullwidthmode = =>
|
||||
if ($('pre').hasClass('plaintext'))
|
||||
@fullwidthplain()
|
||||
else
|
||||
if $('div.scrolly').hasClass('image')
|
||||
@bestfit()
|
||||
else
|
||||
@zoom()
|
||||
|
||||
@zoomin = =>
|
||||
if ($('pre').hasClass('plaintext'))
|
||||
@increaseFont($('pre'), 2)
|
||||
else
|
||||
@zoom(100);
|
||||
|
||||
@zoomout = =>
|
||||
if ($('pre').hasClass('plaintext'))
|
||||
@increaseFont($('pre'), -2)
|
||||
else
|
||||
@zoom(-100);
|
||||
|
||||
@bestfit = =>
|
||||
if $('div.scrolly').hasClass('image')
|
||||
if $('div.scrolly').hasClass('bestfitMode')
|
||||
$('div.scrolly').removeClass 'bestfitMode'
|
||||
$('div.scrolly').addClass 'fullwidthMode'
|
||||
$('div.scrolly').width window.innerWidth
|
||||
$('div.scrolly').height("")
|
||||
$('img.bestfit').addClass 'fullwidth'
|
||||
$('img.bestfit').removeClass 'bestfit'
|
||||
else
|
||||
$('h6').hide()
|
||||
$('div.scrolly').addClass 'bestfitMode'
|
||||
$('div.scrolly').removeClass 'fullwidthMode'
|
||||
$('div.scrolly').width window.innerWidth
|
||||
$('div.scrolly').height window.innerHeight
|
||||
$('img.fullwidth').addClass 'bestfit'
|
||||
$('img.fullwidth').removeClass 'fullwidth'
|
||||
|
||||
@loadhugeansi = (picdata, inserthere) ->
|
||||
fname = @location + '/' + picdata.file
|
||||
pdiv = $('<div>')
|
||||
|
|
@ -97,7 +167,7 @@ class @Sahli
|
|||
@origwidth = canvwidth
|
||||
@origheight = calcheight
|
||||
pdiv.width canvwidth
|
||||
), 30, 'bits': '8'
|
||||
), 30, {'bits': '8', "font": picdata.font}
|
||||
|
||||
@loadavatar = (picdata, inserthere) ->
|
||||
console.log 'avatar', picdata, inserthere
|
||||
|
|
@ -137,6 +207,7 @@ class @Sahli
|
|||
filedata = @filedata
|
||||
filedata[i].pic = $('<h6>' + filedata[i].file + '</h6>')
|
||||
viewbox.append filedata[i].pic
|
||||
$('h6').show()
|
||||
@loadpic filedata[i], filedata[i].pic
|
||||
@currentpic += 1
|
||||
if @currentpic > filedata.length - 1
|
||||
|
|
@ -146,6 +217,13 @@ class @Sahli
|
|||
$('body').stop()
|
||||
@loadinfopanel i
|
||||
|
||||
@prevpic = =>
|
||||
i = @currentpic-2
|
||||
if i < 0
|
||||
i = i + @filedata.length
|
||||
@currentpic = i
|
||||
@nextpic()
|
||||
|
||||
@togglefullscreen = ->
|
||||
docElm = document.documentElement
|
||||
if @fullscreen
|
||||
|
|
@ -230,7 +308,7 @@ class @Sahli
|
|||
zoomee.width newwidth
|
||||
$('canvas').width newwidth
|
||||
else
|
||||
if zoomee.width() != @origwidth
|
||||
if parseInt( zoomee.width(), 10 ) != parseInt( @origwidth, 10)
|
||||
zoomee.width @origwidth
|
||||
$('canvas').width '100%'
|
||||
else
|
||||
|
|
@ -315,24 +393,26 @@ class @Sahli
|
|||
switch ev.which
|
||||
when @keycode ' '
|
||||
@nextpic()
|
||||
when @keycode 'p'
|
||||
@prevpic()
|
||||
when @keycode 'f'
|
||||
@togglefullscreen()
|
||||
when @keycode 's'
|
||||
@setscroll()
|
||||
when @keycode 't'
|
||||
$('body').scrollTop 0
|
||||
@zoom 0
|
||||
@togglefullwidthmode()
|
||||
when @keycode 'b'
|
||||
$('body').scrollTop $('body').height()
|
||||
when @keycode 'a'
|
||||
$('body').stop()
|
||||
@scroll_direction = - @scroll_direction
|
||||
when @keycode 'z'
|
||||
@zoom()
|
||||
@togglefullwidthmode()
|
||||
when @keycode 'e'
|
||||
@zoom 100
|
||||
@zoomin()
|
||||
when @keycode 'r'
|
||||
@zoom -100
|
||||
@zoomout()
|
||||
when @keycode 'w'
|
||||
@changescrolldirection -1
|
||||
when @keycode 'x'
|
||||
|
|
@ -342,6 +422,7 @@ class @Sahli
|
|||
when @keycode 'i'
|
||||
$('div.infobox').toggle()
|
||||
when @keycode 'v'
|
||||
$('h6').show()
|
||||
$('h6').height( (window.innerHeight - $('.scrolly').height()) / 2 )
|
||||
when @keycode '1'
|
||||
@changespeed 1
|
||||
|
|
@ -356,6 +437,10 @@ class @Sahli
|
|||
@scroll_speed = 4
|
||||
when @keycode '5'
|
||||
@changespeed 5
|
||||
when @keycode '8'
|
||||
@increaseFont($('pre'), -2)
|
||||
when @keycode '9'
|
||||
@increaseFont($('pre'), 2)
|
||||
when 40 # down
|
||||
@moveline 1
|
||||
when 38 # up
|
||||
|
|
|
|||
20
sahli.css
20
sahli.css
|
|
@ -10,6 +10,10 @@ body {
|
|||
border: none;
|
||||
}
|
||||
|
||||
pre {
|
||||
line-height: 100%;
|
||||
}
|
||||
|
||||
#top {
|
||||
border: 1px solid green;
|
||||
color: green;
|
||||
|
|
@ -40,7 +44,7 @@ h6 {
|
|||
.help {
|
||||
position: fixed;
|
||||
top: 1em;
|
||||
left: 33%;
|
||||
left: 25%;
|
||||
text-align: left;
|
||||
background-color: lightgrey;
|
||||
border: outset darkgray;
|
||||
|
|
@ -49,7 +53,19 @@ h6 {
|
|||
border-radius: 8px;
|
||||
font-family: topaz1200,mOsOul, Consolas, monospace;
|
||||
opacity: .85;
|
||||
width: 33%;
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.fullwidth {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.bestfit {
|
||||
padding: 0;
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
}
|
||||
|
||||
.keylist {
|
||||
|
|
|
|||
148
sahli.js
148
sahli.js
|
|
@ -1,4 +1,4 @@
|
|||
// Generated by CoffeeScript 1.9.0
|
||||
// Generated by CoffeeScript 1.9.3
|
||||
|
||||
/*
|
||||
.___________________________________, ___
|
||||
|
|
@ -16,7 +16,9 @@ l__________/__________|___|______l__________j_____j
|
|||
|
||||
(function() {
|
||||
this.Sahli = (function() {
|
||||
function Sahli() {}
|
||||
function Sahli() {
|
||||
$('body').css('cursor', 'none');
|
||||
}
|
||||
|
||||
Sahli.loadpic = function(picdata, inserthere) {
|
||||
switch (picdata.filetype) {
|
||||
|
|
@ -40,6 +42,8 @@ l__________/__________|___|______l__________j_____j
|
|||
return this.loadhugeansi(picdata, inserthere);
|
||||
case 'tundra':
|
||||
return this.loadhugeansi(picdata, inserthere);
|
||||
case 'image':
|
||||
return this.loadpicture(picdata, inserthere);
|
||||
default:
|
||||
return this.loadplain(picdata, inserthere);
|
||||
}
|
||||
|
|
@ -55,6 +59,7 @@ l__________/__________|___|______l__________j_____j
|
|||
'margin': '0 auto'
|
||||
});
|
||||
ptxt = $('<pre>');
|
||||
ptxt.addClass('plaintext');
|
||||
color = this.calccolor(picdata.color);
|
||||
bgcolor = this.calccolor(picdata.bg);
|
||||
pdiv.addClass('scrolly');
|
||||
|
|
@ -65,9 +70,6 @@ l__________/__________|___|______l__________j_____j
|
|||
'margin': 'auto',
|
||||
'display': 'inline-block'
|
||||
});
|
||||
ptxt.width(picdata.width * 8);
|
||||
this.origwidth = ptxt.width;
|
||||
pdiv.width(ptxt.width);
|
||||
pdiv.prepend(buf.clone());
|
||||
pdiv.append(ptxt);
|
||||
pdiv.append(buf);
|
||||
|
|
@ -87,6 +89,91 @@ l__________/__________|___|______l__________j_____j
|
|||
return req.send(null);
|
||||
};
|
||||
|
||||
Sahli.increaseFont = function(node, increaseBy) {
|
||||
var current_size;
|
||||
if (increaseBy == null) {
|
||||
increaseBy = 5;
|
||||
}
|
||||
current_size = parseInt($(node).css("font-size"));
|
||||
return $(node).css("font-size", current_size + increaseBy);
|
||||
};
|
||||
|
||||
Sahli.loadpicture = function(picdata, inserthere) {
|
||||
var fname, pdiv, pimg;
|
||||
fname = this.location + '/' + picdata.file;
|
||||
pdiv = $('<div>');
|
||||
pdiv.addClass('scrolly');
|
||||
pdiv.addClass('image');
|
||||
pdiv.width(window.innerWidth);
|
||||
pdiv.css('display', 'inline-block');
|
||||
pimg = $('<img src="' + fname + '" />');
|
||||
pimg.addClass('fullwidth');
|
||||
pdiv.append(pimg);
|
||||
inserthere.after(pdiv);
|
||||
$('h6').hide();
|
||||
$('body').scrollTop(0);
|
||||
this.origwidth = picdata.width;
|
||||
this.origheight = picdata.height;
|
||||
return this.bestfit();
|
||||
};
|
||||
|
||||
Sahli.fullwidthplain = function() {
|
||||
if ($('pre').css("font-size") === "16px") {
|
||||
return $('pre').css("font-size", "2.5vw");
|
||||
} else {
|
||||
return $('pre').css("font-size", "16px");
|
||||
}
|
||||
};
|
||||
|
||||
Sahli.togglefullwidthmode = function() {
|
||||
if ($('pre').hasClass('plaintext')) {
|
||||
return Sahli.fullwidthplain();
|
||||
} else {
|
||||
if ($('div.scrolly').hasClass('image')) {
|
||||
return Sahli.bestfit();
|
||||
} else {
|
||||
return Sahli.zoom();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Sahli.zoomin = function() {
|
||||
if ($('pre').hasClass('plaintext')) {
|
||||
return Sahli.increaseFont($('pre'), 2);
|
||||
} else {
|
||||
return Sahli.zoom(100);
|
||||
}
|
||||
};
|
||||
|
||||
Sahli.zoomout = function() {
|
||||
if ($('pre').hasClass('plaintext')) {
|
||||
return Sahli.increaseFont($('pre'), -2);
|
||||
} else {
|
||||
return Sahli.zoom(-100);
|
||||
}
|
||||
};
|
||||
|
||||
Sahli.bestfit = function() {
|
||||
if ($('div.scrolly').hasClass('image')) {
|
||||
if ($('div.scrolly').hasClass('bestfitMode')) {
|
||||
$('div.scrolly').removeClass('bestfitMode');
|
||||
$('div.scrolly').addClass('fullwidthMode');
|
||||
$('div.scrolly').width(window.innerWidth);
|
||||
$('div.scrolly').height("");
|
||||
$('img.bestfit').addClass('fullwidth');
|
||||
return $('img.bestfit').removeClass('bestfit');
|
||||
} else {
|
||||
$('h6').hide();
|
||||
$('div.scrolly').addClass('bestfitMode');
|
||||
$('div.scrolly').removeClass('fullwidthMode');
|
||||
$('div.scrolly').width(window.innerWidth);
|
||||
$('div.scrolly').height(window.innerHeight);
|
||||
$('img.fullwidth').addClass('bestfit');
|
||||
return $('img.fullwidth').removeClass('fullwidth');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Sahli.loadhugeansi = function(picdata, inserthere) {
|
||||
var calcheight, canvwidth, fname, pdiv;
|
||||
fname = this.location + '/' + picdata.file;
|
||||
|
|
@ -111,7 +198,8 @@ l__________/__________|___|______l__________j_____j
|
|||
return pdiv.width(canvwidth);
|
||||
};
|
||||
})(this)), 30, {
|
||||
'bits': '8'
|
||||
'bits': '8',
|
||||
"font": picdata.font
|
||||
});
|
||||
};
|
||||
|
||||
|
|
@ -161,6 +249,7 @@ l__________/__________|___|______l__________j_____j
|
|||
filedata = Sahli.filedata;
|
||||
filedata[i].pic = $('<h6>' + filedata[i].file + '</h6>');
|
||||
viewbox.append(filedata[i].pic);
|
||||
$('h6').show();
|
||||
Sahli.loadpic(filedata[i], filedata[i].pic);
|
||||
Sahli.currentpic += 1;
|
||||
if (Sahli.currentpic > filedata.length - 1) {
|
||||
|
|
@ -172,6 +261,16 @@ l__________/__________|___|______l__________j_____j
|
|||
return Sahli.loadinfopanel(i);
|
||||
};
|
||||
|
||||
Sahli.prevpic = function() {
|
||||
var i;
|
||||
i = Sahli.currentpic - 2;
|
||||
if (i < 0) {
|
||||
i = i + Sahli.filedata.length;
|
||||
}
|
||||
Sahli.currentpic = i;
|
||||
return Sahli.nextpic();
|
||||
};
|
||||
|
||||
Sahli.togglefullscreen = function() {
|
||||
var docElm;
|
||||
docElm = document.documentElement;
|
||||
|
|
@ -270,7 +369,7 @@ l__________/__________|___|______l__________j_____j
|
|||
zoomee.width(newwidth);
|
||||
return $('canvas').width(newwidth);
|
||||
} else {
|
||||
if (zoomee.width() !== this.origwidth) {
|
||||
if (parseInt(zoomee.width(), 10) !== parseInt(this.origwidth, 10)) {
|
||||
zoomee.width(this.origwidth);
|
||||
return $('canvas').width('100%');
|
||||
} else {
|
||||
|
|
@ -281,7 +380,7 @@ l__________/__________|___|______l__________j_____j
|
|||
};
|
||||
|
||||
Sahli.panelmode = function() {
|
||||
var canvs, ct, drawcol, level, newheight, newwidth, numcols, numpanels, outer, panelratio, panelslotheight, panelsperslot, pic, picdpercol, screenratio, wh, ww, x, _i, _j, _len, _len1, _results;
|
||||
var canvs, ct, drawcol, j, k, len, len1, level, newheight, newwidth, numcols, numpanels, outer, panelratio, panelslotheight, panelsperslot, pic, picdpercol, results, screenratio, wh, ww, x;
|
||||
$('#panel').toggle();
|
||||
canvs = $('canvas');
|
||||
$('.scrolly').width(this.origwidth);
|
||||
|
|
@ -309,9 +408,9 @@ l__________/__________|___|______l__________j_____j
|
|||
drawcol = 1;
|
||||
ct = 0;
|
||||
outer.append(this.createpanel(1, newwidth - 6));
|
||||
_results = [];
|
||||
for (_i = 0, _len = canvs.length; _i < _len; _i++) {
|
||||
pic = canvs[_i];
|
||||
results = [];
|
||||
for (j = 0, len = canvs.length; j < len; j++) {
|
||||
pic = canvs[j];
|
||||
$("#column" + drawcol).append(pic);
|
||||
level += 1;
|
||||
ct += 1;
|
||||
|
|
@ -319,19 +418,19 @@ l__________/__________|___|______l__________j_____j
|
|||
level = 0;
|
||||
drawcol = drawcol + 1;
|
||||
if (ct < numpanels) {
|
||||
_results.push(outer.append(this.createpanel(drawcol, newwidth - 6)));
|
||||
results.push(outer.append(this.createpanel(drawcol, newwidth - 6)));
|
||||
} else {
|
||||
_results.push(void 0);
|
||||
results.push(void 0);
|
||||
}
|
||||
} else {
|
||||
_results.push(void 0);
|
||||
results.push(void 0);
|
||||
}
|
||||
}
|
||||
return _results;
|
||||
return results;
|
||||
} else {
|
||||
$('#outbox').show();
|
||||
for (_j = 0, _len1 = canvs.length; _j < _len1; _j++) {
|
||||
pic = canvs[_j];
|
||||
for (k = 0, len1 = canvs.length; k < len1; k++) {
|
||||
pic = canvs[k];
|
||||
$('.scrolly').append(pic);
|
||||
}
|
||||
canvs.width(this.origwidth);
|
||||
|
|
@ -374,24 +473,26 @@ l__________/__________|___|______l__________j_____j
|
|||
switch (ev.which) {
|
||||
case _this.keycode(' '):
|
||||
return _this.nextpic();
|
||||
case _this.keycode('p'):
|
||||
return _this.prevpic();
|
||||
case _this.keycode('f'):
|
||||
return _this.togglefullscreen();
|
||||
case _this.keycode('s'):
|
||||
return _this.setscroll();
|
||||
case _this.keycode('t'):
|
||||
$('body').scrollTop(0);
|
||||
return _this.zoom(0);
|
||||
return _this.togglefullwidthmode();
|
||||
case _this.keycode('b'):
|
||||
return $('body').scrollTop($('body').height());
|
||||
case _this.keycode('a'):
|
||||
$('body').stop();
|
||||
return _this.scroll_direction = -_this.scroll_direction;
|
||||
case _this.keycode('z'):
|
||||
return _this.zoom();
|
||||
return _this.togglefullwidthmode();
|
||||
case _this.keycode('e'):
|
||||
return _this.zoom(100);
|
||||
return _this.zoomin();
|
||||
case _this.keycode('r'):
|
||||
return _this.zoom(-100);
|
||||
return _this.zoomout();
|
||||
case _this.keycode('w'):
|
||||
return _this.changescrolldirection(-1);
|
||||
case _this.keycode('x'):
|
||||
|
|
@ -401,6 +502,7 @@ l__________/__________|___|______l__________j_____j
|
|||
case _this.keycode('i'):
|
||||
return $('div.infobox').toggle();
|
||||
case _this.keycode('v'):
|
||||
$('h6').show();
|
||||
return $('h6').height((window.innerHeight - $('.scrolly').height()) / 2);
|
||||
case _this.keycode('1'):
|
||||
return _this.changespeed(1);
|
||||
|
|
@ -415,6 +517,10 @@ l__________/__________|___|______l__________j_____j
|
|||
return _this.scroll_speed = 4;
|
||||
case _this.keycode('5'):
|
||||
return _this.changespeed(5);
|
||||
case _this.keycode('8'):
|
||||
return _this.increaseFont($('pre'), -2);
|
||||
case _this.keycode('9'):
|
||||
return _this.increaseFont($('pre'), 2);
|
||||
case 40:
|
||||
return _this.moveline(1);
|
||||
case 38:
|
||||
|
|
|
|||
0
sahliEditorPython/__init__.py
Normal file
0
sahliEditorPython/__init__.py
Normal file
130
sahliEditorPython/sahlifile.py
Normal file
130
sahliEditorPython/sahlifile.py
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
#!/usr/bin/env python
|
||||
# coding:utf-8
|
||||
"""
|
||||
Author: Sir Garbagetruck --<truck@whatever>
|
||||
Purpose: base class for Sahli file
|
||||
Created: 2020/04/09
|
||||
"""
|
||||
|
||||
import json
|
||||
########################################################################
|
||||
|
||||
|
||||
class sahlifile:
|
||||
"""the Sahli file structure and classes to futz with"""
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
def __init__(self, filename):
|
||||
"""Constructor"""
|
||||
self.valid_filetypes = [
|
||||
"plain",
|
||||
"ansi",
|
||||
"xbin",
|
||||
"ice",
|
||||
"adf",
|
||||
"avatar",
|
||||
"bin",
|
||||
"idf",
|
||||
"pcboard",
|
||||
"tundra"
|
||||
]
|
||||
self.valid_fonts = [
|
||||
'Propaz', 'ansifont', 'mOsOul', 'Microknight', 'p0t-nOodle'
|
||||
]
|
||||
if filename is not None:
|
||||
with open(filename) as f:
|
||||
self.sahli = json.load(f)
|
||||
else:
|
||||
location = self.blank_location()
|
||||
slides = self.blank_slides()
|
||||
filedata = []
|
||||
self.sahli = {
|
||||
'location': location,
|
||||
'slides': slides,
|
||||
'filedata': filedata
|
||||
}
|
||||
|
||||
def blank_slides(self):
|
||||
"""blank slide structure"""
|
||||
slides = {
|
||||
'background': '',
|
||||
'template': '',
|
||||
'css': ''
|
||||
}
|
||||
return slides
|
||||
|
||||
def blank_location(self):
|
||||
"""blank location structure"""
|
||||
return ''
|
||||
|
||||
def blank_picture(self):
|
||||
"""Blank picture structure"""
|
||||
return {
|
||||
'file': '',
|
||||
'name': '',
|
||||
'amiga': False,
|
||||
'filetype': 'image',
|
||||
'width': '1600',
|
||||
'author': '',
|
||||
'font': 'Propaz',
|
||||
'color': [0, 0, 0, 255],
|
||||
'bg': [255, 255, 255, 255],
|
||||
'line1': '',
|
||||
'line2': '',
|
||||
'text': ''
|
||||
}
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
def blank_amiga_ascii(self):
|
||||
"""blank amiga ascii"""
|
||||
return {
|
||||
'file': '',
|
||||
'name': '',
|
||||
'amiga': True,
|
||||
'filetype': 'plain',
|
||||
'width': '80',
|
||||
'author': '',
|
||||
'font': 'Propaz',
|
||||
'color': [250, 250, 250, 255],
|
||||
'bg': [0, 0, 0, 255],
|
||||
'line1': '',
|
||||
'line2': '',
|
||||
'text': ''
|
||||
}
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
def blank_ansi(self):
|
||||
"""blank PC Ansi"""
|
||||
return {
|
||||
'file': '',
|
||||
'name': '',
|
||||
'amiga': False,
|
||||
'filetype': 'ansi',
|
||||
'width': '80',
|
||||
'author': '',
|
||||
'font': 'Propaz',
|
||||
'color': [255, 255, 255, 255],
|
||||
'bg': [0, 0, 0, 255],
|
||||
'line1': '',
|
||||
'line2': '',
|
||||
'text': ''
|
||||
}
|
||||
|
||||
def blank_filedata(self):
|
||||
"""Blank filedata structure"""
|
||||
|
||||
filedata = {
|
||||
'file': '',
|
||||
'name': '',
|
||||
'amiga': False,
|
||||
'filetype': 'image',
|
||||
'width': '',
|
||||
'author': '',
|
||||
'font': 'Propaz',
|
||||
'color': [0, 0, 0, 255],
|
||||
'bg': [255, 255, 255, 255],
|
||||
'line1': '',
|
||||
'line2': '',
|
||||
'text': ''
|
||||
}
|
||||
return filedata
|
||||
510
sauce.py
Normal file
510
sauce.py
Normal file
|
|
@ -0,0 +1,510 @@
|
|||
#! /usr/bin/env python
|
||||
#
|
||||
# _______
|
||||
# ____________ _______ _\__ /_________ ___ _____
|
||||
# | _ _ \ _ | ____\ _ / | |/ _ \
|
||||
# | / / / / | | | /___/ _ | | / /
|
||||
# |___/___/ /___/____|________|___ | |_| |___|_____/
|
||||
# \__/ |___|
|
||||
#
|
||||
# (c) 2006-2012 Wijnand Modderman-Lenstra - https://maze.io/
|
||||
#
|
||||
|
||||
'''
|
||||
Parser for SAUCE or Standard Architecture for Universal Comment Extensions.
|
||||
'''
|
||||
|
||||
__author__ = 'Wijnand Modderman-Lenstra <maze@pyth0n.org>'
|
||||
__copyright__ = '(C) 2006-2012 Wijnand Modderman-Lenstra'
|
||||
__license__ = 'LGPL'
|
||||
__version__ = '1.2'
|
||||
__url__ = 'https://github.com/tehmaze/sauce'
|
||||
|
||||
import datetime
|
||||
import os
|
||||
import struct
|
||||
try:
|
||||
from io import StringIO
|
||||
except ImportError:
|
||||
from io import StringIO
|
||||
|
||||
|
||||
class SAUCE(object):
|
||||
'''
|
||||
Parser for SAUCE or Standard Architecture for Universal Comment Extensions,
|
||||
as defined in http://www.acid.org/info/sauce/s_spec.htm.
|
||||
|
||||
:param filename: file name or file handle
|
||||
:property author: Name or 'handle' of the creator of the file
|
||||
:property datatype: Type of data
|
||||
:property date: Date the file was created
|
||||
:property filesize: Original filesize NOT including any information of
|
||||
SAUCE
|
||||
:property group: Name of the group/company the creator is employed by
|
||||
:property title: Title of the file
|
||||
|
||||
Example::
|
||||
|
||||
>>> art = open('31337.ANS', 'rb')
|
||||
>>> nfo = sauce.SAUCE(art)
|
||||
>>> nfo.author
|
||||
'maze'
|
||||
...
|
||||
>>> nfo.group
|
||||
''
|
||||
>>> nfo.group = 'mononoke'
|
||||
>>> raw = str(nfo)
|
||||
|
||||
Saving the new file::
|
||||
|
||||
>>> sav = open('31337.NEW', 'wb')
|
||||
>>> nfo.write(sav)
|
||||
>>> # OR you can do:
|
||||
>>> sav = nfo.write('31337.NEW')
|
||||
|
||||
'''
|
||||
|
||||
# template
|
||||
template = (
|
||||
# name default size type
|
||||
('SAUCE', 'SAUCE', 5, '5s'),
|
||||
('SAUCEVersion', '00', 2, '2s'),
|
||||
('Title', '\x00' * 35, 35, '35s'),
|
||||
('Author', '\x00' * 20, 20, '20s'),
|
||||
('Group', '\x00' * 20, 20, '20s'),
|
||||
('Date', '\x00' * 8, 8, '8s'),
|
||||
('FileSize', [0], 4, 'I'),
|
||||
('DataType', [0], 1, 'B'),
|
||||
('FileType', [0], 1, 'B'),
|
||||
('TInfo1', [0], 2, 'H'),
|
||||
('TInfo2', [0], 2, 'H'),
|
||||
('TInfo3', [0], 2, 'H'),
|
||||
('TInfo4', [0], 2, 'H'),
|
||||
('Comments', [0], 1, 'B'),
|
||||
('Flags', [0], 1, 'B'),
|
||||
('Filler', ['\x00'] * 22, 22, '22c'),
|
||||
)
|
||||
templates = [t[0] for t in template]
|
||||
datatypes = ['None', 'Character', 'Graphics', 'Vector', 'Sound',
|
||||
'BinaryText', 'XBin', 'Archive', 'Executable']
|
||||
filetypes = {
|
||||
'None': {
|
||||
'filetype': ['Undefined'],
|
||||
},
|
||||
'Character': {
|
||||
'filetype': ['ASCII', 'ANSi', 'ANSiMation', 'RIP', 'PCBoard',
|
||||
'Avatar', 'HTML', 'Source'],
|
||||
'flags': {0: 'None', 1: 'iCE Color'},
|
||||
'tinfo': (
|
||||
('width', 'height', None, None),
|
||||
('width', 'height', None, None),
|
||||
('width', 'height', None, None),
|
||||
('width', 'height', 'colors', None),
|
||||
('width', 'height', None, None),
|
||||
('width', 'height', None, None),
|
||||
(None, None, None, None),
|
||||
),
|
||||
},
|
||||
'Graphics': {
|
||||
'filetype': ['GIF', 'PCX', 'LBM/IFF', 'TGA', 'FLI', 'FLC',
|
||||
'BMP', 'GL', 'DL', 'WPG', 'PNG', 'JPG', 'MPG',
|
||||
'AVI'],
|
||||
'tinfo': (('width', 'height', 'bpp')) * 14,
|
||||
},
|
||||
'Vector': {
|
||||
'filetype': ['DX', 'DWG', 'WPG', '3DS'],
|
||||
},
|
||||
'Sound': {
|
||||
'filetype': ['MOD', '669', 'STM', 'S3M', 'MTM', 'FAR', 'ULT',
|
||||
'AMF', 'DMF', 'OKT', 'ROL', 'CMF', 'MIDI', 'SADT',
|
||||
'VOC', 'WAV', 'SMP8', 'SMP8S', 'SMP16', 'SMP16S',
|
||||
'PATCH8', 'PATCH16', 'XM', 'HSC', 'IT'],
|
||||
'tinfo': ((None,)) * 16 + (('Sampling Rate',)) * 4,
|
||||
},
|
||||
'BinaryText': {
|
||||
'flags': {0: 'None', 1: 'iCE Color'},
|
||||
},
|
||||
'XBin': {
|
||||
'tinfo': (('width', 'height'),),
|
||||
},
|
||||
'Archive': {
|
||||
'filetype': ['ZIP', 'ARJ', 'LZH', 'ARC', 'TAR', 'ZOO', 'RAR',
|
||||
'UC2', 'PAK', 'SQZ'],
|
||||
},
|
||||
}
|
||||
|
||||
def __init__(self, filename='', data=''):
|
||||
assert (filename or data), 'Need either filename or record'
|
||||
|
||||
if filename:
|
||||
# if type(filename) == file:
|
||||
# self.filehand = filename
|
||||
# else:
|
||||
self.filehand = open(filename, 'rb')
|
||||
self._size = os.path.getsize(self.filehand.name)
|
||||
else:
|
||||
self._size = len(data)
|
||||
self.filehand = StringIO(data)
|
||||
|
||||
self.record, self.data = self._read()
|
||||
|
||||
def __str__(self):
|
||||
return ''.join(list(self._read_file()))
|
||||
|
||||
def _read_file(self):
|
||||
# Buffered reader (generator), reads the original file without SAUCE
|
||||
# record.
|
||||
self.filehand.seek(0)
|
||||
# Check if we have SAUCE data
|
||||
if self.record:
|
||||
reads, rest = divmod(self._size - 128, 1024)
|
||||
else:
|
||||
reads, rest = divmod(self._size, 1024)
|
||||
for x in range(0, reads):
|
||||
yield self.filehand.read(1024)
|
||||
if rest:
|
||||
yield self.filehand.read(rest)
|
||||
|
||||
def _read(self):
|
||||
if self._size >= 128:
|
||||
self.filehand.seek(self._size - 128)
|
||||
record = self.filehand.read(128)
|
||||
if record.startswith(b'SAUCE'):
|
||||
self.filehand.seek(0)
|
||||
return record, self.filehand.read(self._size - 128)
|
||||
|
||||
self.filehand.seek(0)
|
||||
return None, self.filehand.read()
|
||||
|
||||
def _gets(self, key):
|
||||
if self.record is None:
|
||||
return None
|
||||
|
||||
name, default, offset, size, stype = self._template(key)
|
||||
data = self.record[offset:offset + size]
|
||||
data = struct.unpack(stype, data)
|
||||
if stype[-1] in 'cs':
|
||||
# return ''.join(data)
|
||||
return data[0].decode()
|
||||
elif stype[-1] in 'BI' and len(stype) == 1:
|
||||
return data[0]
|
||||
else:
|
||||
return data
|
||||
|
||||
def _puts(self, key, data):
|
||||
name, default, offset, size, stype = self._template(key)
|
||||
#print offset, size, data, repr(struct.pack(stype, data))
|
||||
if self.record is None:
|
||||
self.record = self.sauce()
|
||||
self.record = ''.join([
|
||||
self.record[:offset],
|
||||
struct.pack(stype, data),
|
||||
self.record[offset + size:]
|
||||
])
|
||||
return self.record
|
||||
|
||||
def _template(self, key):
|
||||
index = self.templates.index(key)
|
||||
name, default, size, stype = self.template[index]
|
||||
offset = sum([self.template[x][2] for x in range(0, index)])
|
||||
return name, default, offset, size, stype
|
||||
|
||||
def sauce(self):
|
||||
'''
|
||||
Get the raw SAUCE record.
|
||||
'''
|
||||
if self.record:
|
||||
return self.record
|
||||
else:
|
||||
data = 'SAUCE'
|
||||
for name, default, size, stype in self.template[1:]:
|
||||
#print stype, default
|
||||
if stype[-1] in 's':
|
||||
data += struct.pack(stype, default)
|
||||
else:
|
||||
data += struct.pack(stype, *default)
|
||||
return data
|
||||
|
||||
def write(self, filename):
|
||||
'''
|
||||
Save the file including SAUCE data to the given file(handle).
|
||||
'''
|
||||
filename = type(filename) == file and filename or open(
|
||||
filename, 'wb')
|
||||
for part in self._read_file():
|
||||
filename.write(part)
|
||||
filename.write(self.sauce())
|
||||
return filename
|
||||
|
||||
# SAUCE meta data
|
||||
|
||||
def get_author(self):
|
||||
astr = self._gets('Author')
|
||||
if astr is not None:
|
||||
return astr.strip()
|
||||
else:
|
||||
return ''
|
||||
|
||||
def set_author(self, author):
|
||||
self._puts('Author', author)
|
||||
return self
|
||||
|
||||
def get_comments(self):
|
||||
return self._gets('Comments')
|
||||
|
||||
def set_comments(self, comments):
|
||||
self._puts('Comments', comments)
|
||||
return self
|
||||
|
||||
def get_datatype(self):
|
||||
return self._gets('DataType')
|
||||
|
||||
def get_datatype_str(self):
|
||||
datatype = self.datatype
|
||||
if datatype is None:
|
||||
return None
|
||||
if datatype < len(self.datatypes):
|
||||
return self.datatypes[datatype]
|
||||
else:
|
||||
return None
|
||||
|
||||
def set_datatype(self, datatype):
|
||||
if type(datatype) == str:
|
||||
datatype = datatype.lower().title() # fOoBAR -> Foobar
|
||||
datatype = self.datatypes.index(datatype)
|
||||
self._puts('DataType', datatype)
|
||||
return self
|
||||
|
||||
def get_date(self):
|
||||
return self._gets('Date')
|
||||
|
||||
def get_date_str(self, format='%Y%m%d'):
|
||||
return datetime.datetime.strptime(self.date, format)
|
||||
|
||||
def set_date(self, date=None, format='%Y%m%d'):
|
||||
if date is None:
|
||||
date = datetime.datetime.now().strftime(format)
|
||||
elif type(date) in [datetime.date, datetime.datetime]:
|
||||
date = date.strftime(format)
|
||||
elif type(date) in [int, int, float]:
|
||||
date = datetime.datetime.fromtimestamp(date).strftime(format)
|
||||
self._puts('Date', date)
|
||||
return self
|
||||
|
||||
def get_filesize(self):
|
||||
return self._gets('FileSize')
|
||||
|
||||
def set_filesize(self, size):
|
||||
self._puts('FileSize', size)
|
||||
|
||||
def get_filler(self):
|
||||
return self._gets('Filler')
|
||||
|
||||
def get_filler_str(self):
|
||||
filler = self._gets('Filler')
|
||||
if filler is None:
|
||||
return ''
|
||||
else:
|
||||
return filler.rstrip('\x00')
|
||||
|
||||
def get_filetype(self):
|
||||
return self._gets('FileType')
|
||||
|
||||
def get_filetype_str(self):
|
||||
datatype = self.datatype_str
|
||||
filetype = self.filetype
|
||||
|
||||
if datatype is None or filetype is None:
|
||||
return None
|
||||
|
||||
if datatype in self.filetypes and \
|
||||
'filetype' in self.filetypes[datatype] and \
|
||||
filetype < len(self.filetypes[datatype]['filetype']):
|
||||
return self.filetypes[datatype]['filetype'][filetype]
|
||||
else:
|
||||
return None
|
||||
|
||||
def set_filetype(self, filetype):
|
||||
datatype = self.datatype_str
|
||||
if type(filetype) == str:
|
||||
filetype = filetype.lower().title() # fOoBAR -> Foobar
|
||||
filetype = [name.lower().title()
|
||||
for name in self.filetypes[datatype]['filetype']].index(filetype)
|
||||
self._puts('FileType', filetype)
|
||||
return self
|
||||
|
||||
def get_flags(self):
|
||||
return self._gets('Flags')
|
||||
|
||||
def set_flags(self, flags):
|
||||
self._puts('Flags', flags)
|
||||
return self
|
||||
|
||||
def get_flags_str(self):
|
||||
datatype = self.datatype_str
|
||||
filetype = self.filetype
|
||||
|
||||
if datatype is None or filetype is None:
|
||||
return None
|
||||
|
||||
if datatype in self.filetypes and \
|
||||
'flags' in self.filetypes[datatype] and \
|
||||
filetype < len(self.filetypes[datatype]['filetype']):
|
||||
return self.filetypes[datatype]['filetype'][filetype]
|
||||
else:
|
||||
return None
|
||||
|
||||
def get_group(self):
|
||||
gstr = self._gets('Group')
|
||||
if gstr is not None:
|
||||
return gstr.strip()
|
||||
else:
|
||||
return ''
|
||||
# return self._gets('Group').strip()
|
||||
|
||||
def set_group(self, group):
|
||||
self._puts('Group', group)
|
||||
return self
|
||||
|
||||
def _get_tinfo_name(self, i):
|
||||
datatype = self.datatype_str
|
||||
filetype = self.filetype
|
||||
|
||||
if datatype is None or filetype is None:
|
||||
return None
|
||||
|
||||
try:
|
||||
return self.filetypes[datatype]['tinfo'][filetype][i - 1]
|
||||
except (KeyError, IndexError):
|
||||
return ''
|
||||
|
||||
def get_tinfo1(self):
|
||||
tinfo = self._gets('TInfo1')
|
||||
if tinfo is not None:
|
||||
return tinfo[0]
|
||||
else:
|
||||
return ''
|
||||
|
||||
def get_tinfo1_name(self):
|
||||
return self._get_tinfo_name(1)
|
||||
|
||||
def set_tinfo1(self, tinfo):
|
||||
self._puts('TInfo1', tinfo)
|
||||
return self
|
||||
|
||||
def get_tinfo2(self):
|
||||
tinfo = self._gets('TInfo2')
|
||||
if tinfo is not None:
|
||||
return tinfo[0]
|
||||
else:
|
||||
return ''
|
||||
|
||||
def get_tinfo2_name(self):
|
||||
return self._get_tinfo_name(2)
|
||||
|
||||
def set_tinfo2(self, tinfo):
|
||||
self._puts('TInfo2', tinfo)
|
||||
return self
|
||||
|
||||
def get_tinfo3(self):
|
||||
tinfo = self._gets('TInfo3')
|
||||
if tinfo is not None:
|
||||
return tinfo[0]
|
||||
return ''
|
||||
|
||||
def get_tinfo3_name(self):
|
||||
return self._get_tinfo_name(3)
|
||||
|
||||
def set_tinfo3(self, tinfo):
|
||||
self._puts('TInfo3', tinfo)
|
||||
return self
|
||||
|
||||
def get_tinfo4(self):
|
||||
tinfo = self._gets('TInfo4')
|
||||
if tinfo is not None:
|
||||
return tinfo[0]
|
||||
return ''
|
||||
|
||||
def get_tinfo4_name(self):
|
||||
return self._get_tinfo_name(4)
|
||||
|
||||
def set_tinfo4(self, tinfo):
|
||||
self._puts('TInfo4', tinfo)
|
||||
return self
|
||||
|
||||
def get_title(self):
|
||||
tstr = self._gets('Title')
|
||||
if tstr is not None:
|
||||
return tstr.strip()
|
||||
else:
|
||||
return ''
|
||||
# return self._gets('Title').strip()
|
||||
|
||||
def set_title(self, title):
|
||||
self._puts('Title', title)
|
||||
return self
|
||||
|
||||
def get_version(self):
|
||||
return self._gets('SAUCEVersion')
|
||||
|
||||
def set_version(self, version):
|
||||
self._puts('SAUCEVersion', version)
|
||||
return self
|
||||
|
||||
# properties
|
||||
author = property(get_author, set_author)
|
||||
comments = property(get_comments, set_comments)
|
||||
datatype = property(get_datatype, set_datatype)
|
||||
datatype_str = property(get_datatype_str)
|
||||
date = property(get_date, set_date)
|
||||
filesize = property(get_filesize, set_filesize)
|
||||
filetype = property(get_filetype, set_filetype)
|
||||
filetype_str = property(get_filetype_str)
|
||||
filler = property(get_filler)
|
||||
filler_str = property(get_filler_str)
|
||||
flags = property(get_flags, set_flags)
|
||||
flags_str = property(get_flags_str)
|
||||
group = property(get_group, set_group)
|
||||
tinfo1 = property(get_tinfo1, set_tinfo1)
|
||||
tinfo1_name = property(get_tinfo1_name)
|
||||
tinfo2 = property(get_tinfo2, set_tinfo2)
|
||||
tinfo2_name = property(get_tinfo2_name)
|
||||
tinfo3 = property(get_tinfo3, set_tinfo3)
|
||||
tinfo3_name = property(get_tinfo3_name)
|
||||
tinfo4 = property(get_tinfo4, set_tinfo4)
|
||||
tinfo4_name = property(get_tinfo4_name)
|
||||
title = property(get_title, set_title)
|
||||
version = property(get_version)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
if len(sys.argv) != 2:
|
||||
print('%s <file>' % (sys.argv[0],), file=sys.stderr)
|
||||
sys.exit(1)
|
||||
else:
|
||||
test = SAUCE(sys.argv[1])
|
||||
|
||||
def show(sauce):
|
||||
print('Version.:', sauce.version)
|
||||
print('Title...:', sauce.title)
|
||||
print('Author..:', sauce.author)
|
||||
print('Group...:', sauce.group)
|
||||
print('Date....:', sauce.date)
|
||||
print('FileSize:', sauce.filesize)
|
||||
print('DataType:', sauce.datatype, sauce.datatype_str)
|
||||
print('FileType:', sauce.filetype, sauce.filetype_str)
|
||||
print('TInfo1..:', sauce.tinfo1)
|
||||
print('TInfo2..:', sauce.tinfo2)
|
||||
print('TInfo3..:', sauce.tinfo3)
|
||||
print('TInfo4..:', sauce.tinfo4)
|
||||
print('Flags...:', sauce.flags, sauce.flags_str)
|
||||
print('Record..:', len(sauce.record), repr(sauce.record))
|
||||
print('Filler..:', sauce.filler_str)
|
||||
|
||||
if test.record:
|
||||
show(test)
|
||||
else:
|
||||
print('No SAUCE record found')
|
||||
test = SAUCE(data=test.sauce())
|
||||
show(test)
|
||||
15
setup.py
Normal file
15
setup.py
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
#!/usr/bin/env python
|
||||
# coding:utf-8
|
||||
"""
|
||||
Author: Sir Garbagetruck --<truck@whatever>
|
||||
Purpose: setup script for Sahli editor tools
|
||||
Created: 2020/04/09
|
||||
"""
|
||||
|
||||
from setuptools import setup, find_packages
|
||||
|
||||
setup(
|
||||
name="SahliEditor",
|
||||
version="0.1",
|
||||
packages=find_packages()
|
||||
)
|
||||
BIN
testshow/AD - Green Beam.scaled.png
Normal file
BIN
testshow/AD - Green Beam.scaled.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
BIN
testshow/om-boss.png
Normal file
BIN
testshow/om-boss.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.1 KiB |
1
todo.txt
1
todo.txt
|
|
@ -7,3 +7,4 @@
|
|||
(C) SAHLI ansi & ascii for load page
|
||||
(C) redo load page (not popup, info)
|
||||
(B) Preload
|
||||
(C) Chrome app
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue