v1.2
This commit is contained in:
parent
64457efc5c
commit
7509104ca3
12
README.md
12
README.md
|
@ -33,13 +33,14 @@ MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMNs. -hMMMMMMMMMMMMMMMMMMMMMMMMM
|
|||
MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMdyymMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
|
||||
```
|
||||
```
|
||||
cp437 ansi parsing - this will be integrated into bots like krylon/maple/g1mp when finished.
|
||||
dr1p4ns1 v1.2 - cp437 ansi parsing - this logic will be rolled into bots like krylon/maple/g1mp
|
||||
```
|
||||
## prerequisites
|
||||
- `apt install python3`
|
||||
## usage - main file
|
||||
```
|
||||
running 'python3 dr1p4ns1.py' will batch process all the {ans,asc} files in the ansiscii directory
|
||||
running 'python3 dr1p4ns1.py /path/to/ansi/files' will load all the .ans files in that directory
|
||||
```
|
||||
## test data and debugging
|
||||
- running `python3 test.py` will present table data and create an ansi file for testing
|
||||
|
@ -47,18 +48,11 @@ running 'python3 dr1p4ns1.py' will batch process all the {ans,asc} files in the
|
|||
```d=dr1p4ns1(ansifile=_FILE_,width=80,debug=False)```
|
||||
## files overview
|
||||
```
|
||||
/access.log - after usage the files laded or with error are logged into this file
|
||||
/dr1p4ns1.py - main file, reads 'work.ans' and attempts to parse and display
|
||||
/ansiscii/ - storing the ansi and ascii graphics in this subdirectory while testing
|
||||
/test.py - used to generate test ansi file and presents table data
|
||||
/test.ans - thie file is created after running test.py to contain controlled test data
|
||||
/ansiscii/ - storing the ansi and ascii graphics in this subdirectory while testing
|
||||
/ansiscii/work.ans - this ansi file is loaded by 'dr1p4ns1.py', this is the logic testing
|
||||
/ansiscii/work.asc - escape codes/colors stripped in text for test referencing
|
||||
```
|
||||
## main files of interest
|
||||
- dr1p4ns1.py
|
||||
- work.ans
|
||||
- work.asc
|
||||
- test.py
|
||||
- test.ans
|
||||
```
|
||||
|
|
368
dr1p4ns1.py
368
dr1p4ns1.py
|
@ -2,7 +2,7 @@
|
|||
#################################################################################################### #######################
|
||||
from glob import glob
|
||||
from time import sleep
|
||||
import os
|
||||
import sys,tty,os,termios
|
||||
"""MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM #######################
|
||||
MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMh+MMMMMMMMMMMMMMhsMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM #######################
|
||||
MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMm/ oMMMMMMMMMMMMMMm +NMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM #######################
|
||||
|
@ -81,7 +81,7 @@ class dr1p4ns1:
|
|||
'm': 'color',
|
||||
'R': 'report_cursor_position'}
|
||||
############################################################################################################ LOOKUP TABLE
|
||||
asc_table="""
|
||||
asc_table="""\
|
||||
╟ⁿΘΓΣαστΩδΦ∩ε∞─┼╔µ╞⌠÷≥√∙ ╓▄óúÑ₧ƒ\
|
||||
ßφ≤·±╤¬║┐⌐¼╜╝í½╗░▒▓│┤╡╢╖╕╣║╗╝╜╛┐\
|
||||
└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀\
|
||||
|
@ -90,10 +90,24 @@ class dr1p4ns1:
|
|||
for r in (('\n',''),(' ','')):
|
||||
asc_table=asc_table.replace(*r)
|
||||
############################################################################################################ LOOKUP TABLE
|
||||
asc_table_full="""\
|
||||
\x00☺☻♥♦♣♠•◘○◙♂♀♪♫☼►◄↕‼¶§▬↨↑↓→←∟↔▲▼\
|
||||
\_!"#$%&\'()*+,-./0123456789:;<=>\
|
||||
?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^\
|
||||
_`abcdefghijklmnopqrstuvwxyz{|}~\
|
||||
⌂ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜ¢£¥₧\
|
||||
ƒáíóúñѪº¿⌐¬½¼¡«»░▒▓│┤╡╢╖╕╣║╗╝╜╛\
|
||||
┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐\
|
||||
▀ɑϐᴦᴨ∑ơµᴛɸϴΩẟ∞∅∈∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■\
|
||||
ÿ"""
|
||||
##################################################################################################### ASCII TABLE CLEANUP
|
||||
for r in ((' ',''),('\_',' ')):
|
||||
asc_table_full=asc_table_full.replace(*r)
|
||||
############################################################################################################ LOOKUP TABLE
|
||||
asc2uni=dict(zip([i for i in range(128,256)],[ord(c) for c in asc_table]))
|
||||
############################################################################################################ LOOKUP TABLE
|
||||
asc2chr=dict(zip([i for i in range(128,256)],[c for c in asc_table]))
|
||||
############################################################################################################ LOOKUP TABLE
|
||||
############################################################################################################ LOOKUP TABLE
|
||||
rgb2irc = { 52: '16', 94: '17', 100: '18', 58: '19',
|
||||
22: '20', 29: '21', 23: '22', 24: '23',
|
||||
17: '24', 54: '25', 53: '26', 89: '27',
|
||||
|
@ -122,10 +136,12 @@ class dr1p4ns1:
|
|||
self.height=height
|
||||
self.filename=ansifile
|
||||
self.openansi(ansifile)
|
||||
self.openascii()
|
||||
#self.openascii()
|
||||
self.code='\x1b[0m'
|
||||
self.cmps=[]
|
||||
print("\x1bc\x1b[1;31m[ DR1P ]\x1b[0m\n")
|
||||
self.op=[]
|
||||
self.optype=[]
|
||||
self.sauce_found=False
|
||||
self.boot()
|
||||
######################################################################################################### FILE OPERATIONS
|
||||
def fifo(self,s):
|
||||
|
@ -194,9 +210,6 @@ class dr1p4ns1:
|
|||
print(f"{hex(16 * _)[2:].zfill(8)} {thehex[_]} {theasc[_]}")
|
||||
############################################################################################################### DEBUGGING
|
||||
def hexdump(self):
|
||||
if self.DEBUG:
|
||||
print("\n\x1b[1;31m[ HEXDUMP ]\x1b[0m\n")
|
||||
self.printhex()
|
||||
self.codes=[]
|
||||
code_start=0
|
||||
code_end=0
|
||||
|
@ -216,25 +229,173 @@ class dr1p4ns1:
|
|||
code_end=i+1
|
||||
code=self.ansifile[code_start:code_end]
|
||||
self.codes.append([code,code_start,code_end])
|
||||
############################################################################################################### DEBUGGING
|
||||
def codedump(self):
|
||||
xpos_old=0
|
||||
xpos_new=0
|
||||
self.codes=[]
|
||||
code_start=0
|
||||
code_end=0
|
||||
code_state=False
|
||||
for i,_ in enumerate(self.ansifile):
|
||||
if code_state==False:
|
||||
if _ == '\x1b':
|
||||
code_state=True
|
||||
code_start=i
|
||||
elif _ == '\x1a':
|
||||
self.op.append(self.ansifile[code_end:i])
|
||||
code=self.ansifile[i:]
|
||||
self.codes.append([code,i,len(self.ansifile)])
|
||||
if code[1:6].upper()=="SAUCE":
|
||||
self.getsauce(code[1:])
|
||||
else:
|
||||
if 64 <= ord(_) <= 126:
|
||||
try:
|
||||
if _ in self.commands:
|
||||
code_state=False
|
||||
code_end=i+1
|
||||
code=self.ansifile[code_start:code_end]
|
||||
self.codes.append([code,code_start,code_end])
|
||||
xpos_new=code_start
|
||||
distance=xpos_new-xpos_old
|
||||
if not distance == 0:
|
||||
nonop=self.ansifile[xpos_old:xpos_old+distance]
|
||||
self.op.append(nonop)
|
||||
self.optype.append(1)
|
||||
self.op.append(code)
|
||||
xpos_old=code_end
|
||||
if self.commands[_] == 'color':
|
||||
self.optype.append(2)
|
||||
elif self.commands[_] == 'forward':
|
||||
self.optype.append(3)
|
||||
else:
|
||||
self.optype.append(0)
|
||||
except Exception as e:
|
||||
print(f'error: {e}')
|
||||
if not self.sauce_found:
|
||||
code=self.ansifile[i:]
|
||||
#################################################################################################################### TOOL
|
||||
def processdump(self):
|
||||
offset=0
|
||||
offsets=[]
|
||||
processed=[]
|
||||
uniqued=[]
|
||||
uniques=[]
|
||||
processing=''
|
||||
for i,_optype in enumerate(self.optype):
|
||||
if _optype==2:
|
||||
processing+=self.op[i]
|
||||
offset+=len(self.op[i])
|
||||
elif _optype==3:
|
||||
count=int(self.op[i].split('[')[1].split('C')[0])
|
||||
processing+=' '*count
|
||||
elif _optype==1:
|
||||
processing+=self.op[i]
|
||||
_bseq='\r\n'
|
||||
_xpos=processing.find(_bseq)
|
||||
distance=0
|
||||
while not processing.find(_bseq) == -1:
|
||||
_xpos=processing.find(_bseq)
|
||||
if not _xpos == -1:
|
||||
uniques.append(_bseq)
|
||||
uniques.append(_xpos)
|
||||
if len(self.stripcodes(processing[:_xpos])) >= 80: distance=80
|
||||
gaps=self.width-len(self.stripcodes(processing)[distance:].split('\r\n')[0])
|
||||
processing=processing.replace(_bseq,chr(32)*gaps,1)
|
||||
if len(processing)-offset > self.width:
|
||||
trailing_size=0
|
||||
while len(processing)-offset > self.width:
|
||||
deconcatenate=processing[0:self.width+offset]
|
||||
if deconcatenate.endswith('m'):
|
||||
if not deconcatenate.rfind('\x1b')==-1:
|
||||
trailing_size=len(deconcatenate[deconcatenate.rfind('\x1b'):])
|
||||
deconcatenate=deconcatenate[:deconcatenate.rfind('\x1b')]
|
||||
processed.append(deconcatenate)
|
||||
if len(uniques) < 2:
|
||||
uniqued.append('')
|
||||
else:
|
||||
uniqued.append(uniques)
|
||||
uniqued.append(uniques)
|
||||
uniques=[]
|
||||
offsets.append(offset)
|
||||
processing=processing.replace(deconcatenate,'',1)
|
||||
offset=0+trailing_size
|
||||
if len(processing) > 0:
|
||||
gaps=int(80-len(self.stripcodes(processing)))
|
||||
processing+=chr(32)*gaps
|
||||
processed.append(processing)
|
||||
|
||||
processed_colors=[]; last_colors=''; color_fg=''; color_bg=''; color_set='';
|
||||
for y,__ in enumerate(processed):
|
||||
code_start=0; code_end=0; code_state=False; codes=[];
|
||||
for x,_ in enumerate(__):
|
||||
if not code_state:
|
||||
if _ =='\x1b':
|
||||
code_start = x
|
||||
code_state = True
|
||||
else:
|
||||
if _ in self.commands:
|
||||
if self.commands[_] == 'color':
|
||||
code_end = x+1
|
||||
code_state = False
|
||||
codes.append(__[code_start:code_end])
|
||||
for code in codes:
|
||||
for _ in code.replace('m','').split('[')[1].split(';'):
|
||||
if 0 <= int(_) <= 9:
|
||||
color_set=_
|
||||
if 30 <= int(_) <= 39:
|
||||
color_fg=_
|
||||
if 40 <= int(_) <= 49:
|
||||
color_bg=_
|
||||
colors=f"{color_set}"
|
||||
processed_colors.append(colors)
|
||||
|
||||
# last_processed_color_set=0
|
||||
# for i,_ in enumerate(processed):
|
||||
# line=''
|
||||
# if last_processed_color_set:
|
||||
# line+='\x1b[1m'
|
||||
# if int(processed_colors[i]):
|
||||
# line+=f'{_}\x1b[0m'
|
||||
# else:
|
||||
# line+=f'{_}'
|
||||
# last_processed_color_set=int(processed_colors[i])
|
||||
# for r in (('\x16',chr(9644)),('\x15','\u00A7')):
|
||||
# line=line.replace(*r)
|
||||
# print(line+f" - {str(i).zfill(3)}")
|
||||
|
||||
for _ in processed:
|
||||
line=_
|
||||
for r in (('\x16',chr(9644)),('\x15','\u00A7')):
|
||||
line=line.replace(*r)
|
||||
print(line)
|
||||
|
||||
#################################################################################################################### TOOL
|
||||
def getsauce(self,sauce):
|
||||
self.sauce=sauce
|
||||
self.sauce_found=True
|
||||
self.width=ord(self.sauce[96])
|
||||
self.height=ord(self.sauce[98])
|
||||
offset=len("SAUCE")
|
||||
self.sauce_version=str(int(self.sauce[offset:offset+2].strip()))
|
||||
offset+=2
|
||||
self.sauce_title=self.sauce[offset:offset+35].strip()
|
||||
offset+=35
|
||||
self.sauce_title=self.sauce[offset:offset+20].strip()
|
||||
offset+=20
|
||||
self.sauce_group=self.sauce[offset:offset+20].strip()
|
||||
offset+=20
|
||||
self.sauce_date=self.sauce[offset:offset+8].strip()
|
||||
offset+=8
|
||||
# SAUCE_PASS='\x1b[1;31m[ SAUCE INFO FOUND ] - X: {} Y: {}\x1b[0m\n'
|
||||
# SAUCE_FAIL='\x1b[1;31m[ NO SAUCE INFO FOUND ]\x1b[0m\n'
|
||||
# if self.sauce_found==True:
|
||||
# print(SAUCE_PASS.format(self.width,self.height))
|
||||
# else:
|
||||
# print(SAUCE_FAIL.format(self))
|
||||
#################################################################################################################### TOOL
|
||||
def findall(self,s,w):
|
||||
return [i for i in range(len(s)) if s.startswith(w, i)]
|
||||
#################################################################################################################### TOOL
|
||||
def getsauce(self):
|
||||
SPASS='\x1b[1;31m[ SAUCE INFO FOUND ] - X: {} Y: {} - FILE: {}\x1b[0m\n'
|
||||
SFAIL='\x1b[1;31m[ NO SAUCE INFO FOUND ] - FILE: {}\x1b[0m\n'
|
||||
try:
|
||||
if self.ansifile[-129:][0] == '\x1a' \
|
||||
and self.ansifile[-128:][:5] == 'SAUCE':
|
||||
self.ansifile_xwidth=ord(self.ansifile[-128:][96])
|
||||
self.ansifile_yheight=ord(self.ansifile[-128:][98])
|
||||
self.width=self.ansifile_xwidth
|
||||
self.height=self.ansifile_yheight
|
||||
print(SPASS.format(self.width,self.height,self.filename))
|
||||
else:
|
||||
print(SFAIL.format(self.filename))
|
||||
except:
|
||||
print(SFAIL.format(self.filename))
|
||||
############################################################################################################### DEBUGGING
|
||||
def cmpans(self,s1,s2,n1=0,n2=0):
|
||||
_s1=''; _s2=''; _sn1=''; _sn2=''
|
||||
|
@ -300,104 +461,71 @@ class dr1p4ns1:
|
|||
return {v: k for k, v in d.items()}
|
||||
########################################################################################################## CLASS MAIN - 4
|
||||
def boot(self):
|
||||
self.getsauce()
|
||||
self.hexdump()
|
||||
op=[]
|
||||
fb=self.ansifile
|
||||
xnew=0
|
||||
xold=0
|
||||
for _ in self.codes:
|
||||
xnew=_[1]
|
||||
distance=xnew-xold
|
||||
if not distance == 0:
|
||||
gap=fb[xold:xold+distance]
|
||||
op.append(gap)
|
||||
op.append(_[0])
|
||||
xold=_[2]
|
||||
optype=[]
|
||||
for i,_op in enumerate(op):
|
||||
if _op.startswith('\x1b'):
|
||||
if _op.endswith('m'):
|
||||
optype.append(2)
|
||||
elif _op.endswith('C'):
|
||||
optype.append(3)
|
||||
else:
|
||||
optype.append(0)
|
||||
elif _op.startswith('\x1a'):
|
||||
optype.append(4)
|
||||
if self.DEBUG:
|
||||
print("\n\x1b[1;31m[ HEXDUMP ]\x1b[0m\n")
|
||||
self.printhex()
|
||||
self.codedump()
|
||||
self.processdump()
|
||||
#############################################################################################################################
|
||||
def getkey():
|
||||
old_settings = termios.tcgetattr(sys.stdin)
|
||||
tty.setcbreak(sys.stdin.fileno())
|
||||
try:
|
||||
while True:
|
||||
b = os.read(sys.stdin.fileno(), 3).decode()
|
||||
if len(b) == 3:
|
||||
k = ord(b[2])
|
||||
else:
|
||||
optype.append(1)
|
||||
offset=0
|
||||
offsets=[]
|
||||
processed=[]
|
||||
uniqued=[]
|
||||
uniques=[]
|
||||
processing=''
|
||||
for i,_optype in enumerate(optype):
|
||||
if _optype==2:
|
||||
processing+=op[i]
|
||||
offset+=len(op[i])
|
||||
elif _optype==3:
|
||||
count=int(op[i].split('[')[1].split('C')[0])
|
||||
processing+=' '*count
|
||||
elif _optype==1:
|
||||
processing+=op[i]
|
||||
_bseq='\r\n'
|
||||
_xpos=processing.find(_bseq)
|
||||
if not _xpos == -1:
|
||||
uniques.append(_bseq)
|
||||
uniques.append(_xpos)
|
||||
processing=processing.replace(_bseq,'',1)
|
||||
gaps=self.width-len(self.stripcodes(processing))
|
||||
processing+=' '*int(gaps)
|
||||
if len(processing)-offset > self.width:
|
||||
while len(processing)-offset > self.width:
|
||||
deconcatenate=processing[0:self.width+offset]
|
||||
processed.append(deconcatenate)
|
||||
if len(uniques) < 2:
|
||||
uniqued.append('')
|
||||
else:
|
||||
uniqued.append(uniques)
|
||||
uniqued.append(uniques)
|
||||
uniques=[]
|
||||
offsets.append(offset)
|
||||
processing=processing.replace(deconcatenate,'',1)
|
||||
offset=0
|
||||
# if self.DEBUG:
|
||||
# print("\n\x1b[1;31m[ COMPARE LINE AGAINST REFERENCE ]\x1b[0m\n")
|
||||
# _r=self.reference.strip().splitlines()
|
||||
# for i,_ in enumerate(processed):
|
||||
# s1=_r[i]
|
||||
# s2=_
|
||||
# self.cmpans(s1=s1,s2=s2,n1=0,n2=self.width)
|
||||
# if i >= 128:
|
||||
# break
|
||||
# for i,_ in enumerate(self.cmps):
|
||||
# print(_+f' - {str(i).zfill(4)}')
|
||||
# if self.DEBUG:
|
||||
# print("\n \x1b[1;31m[ PROCESSED ANSI ]\x1b[0m\n")
|
||||
for i,_ in enumerate(processed):
|
||||
print(_)
|
||||
k = ord(b)
|
||||
key_mapping = {
|
||||
27: 'esc',
|
||||
67: 'right',
|
||||
68: 'left',
|
||||
113: 'q',
|
||||
120: 'x'
|
||||
}
|
||||
return key_mapping.get(k, chr(k))
|
||||
finally:
|
||||
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_settings)
|
||||
################################################################################################################### ENTRY - 1
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) > 1:
|
||||
PATH=''
|
||||
if sys.argv[1]=='.':
|
||||
PATH=os.getcwd()
|
||||
files=glob(PATH+"/*.ans")
|
||||
files+=glob(PATH+"/*.ANS")
|
||||
else:
|
||||
files=glob(sys.argv[1]+"/*.ans")
|
||||
files+=glob(sys.argv[1]+"/*.ANS")
|
||||
else:
|
||||
files=glob('ansiscii/*.ans')
|
||||
files+=glob('ansiscii/*.ANS')
|
||||
|
||||
if len(files)==0:
|
||||
print('ERROR: NO ANSI FILES IN THE PATH SPECIFIED',end='')
|
||||
sys.exit(1)
|
||||
|
||||
index=0
|
||||
d=dr1p4ns1(ansifile=files[index],width=80,debug=False)
|
||||
try:
|
||||
os.remove('access.log')
|
||||
except:
|
||||
pass
|
||||
files=glob('ansiscii/*.ans')
|
||||
files+=glob('ansiscii/*.ANS')
|
||||
for _FILE_ in files:
|
||||
print(f'\n[ LOADING FILE ] - {_FILE_}\n')
|
||||
try:
|
||||
d=dr1p4ns1(ansifile=_FILE_,width=80,debug=False)
|
||||
f=open('access.log','a')
|
||||
f.write(f'LOADED: {_FILE_}\n')
|
||||
f.close()
|
||||
except Exception as e:
|
||||
print(f'[ ERROR WITH FILE: {_FILE_} ] - {e}')
|
||||
f=open('access.log','a')
|
||||
f.write(f'FAILED: {_FILE_} - {e}\n')
|
||||
f.close()
|
||||
del(d)
|
||||
sleep(5)
|
||||
while True:
|
||||
B='\x1b[1;94m'; C='\x1b[1;94m'; S='\x1b[1;36m'; M='\x1b[1;92m'; E='\x1b[0m'
|
||||
msg=f"{B}[ {C}DR1P {B}] {S}- {B}[ {C}q{S}: {M}quit{S}, {C}left{S}: {M}previous{S}, {C}right{S}: {M}next {B}] {S}- {C}filename{S}: {M}"
|
||||
msg+=f"{d.filename}{E}"
|
||||
print(msg)
|
||||
k = getkey()
|
||||
if k == 'left':
|
||||
index-=1
|
||||
if index < 0: index=len(files)-1
|
||||
d=dr1p4ns1(ansifile=files[index],width=80,debug=False)
|
||||
if k == 'right':
|
||||
index+=1
|
||||
if index >= len(files): index=0
|
||||
d=dr1p4ns1(ansifile=files[index],width=80,debug=False)
|
||||
if k == 'esc' or k == 'q' or k == 'x':
|
||||
quit()
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
os.system('stty sane')
|
||||
|
||||
######################################################################################################################### EOF
|
Loading…
Reference in New Issue