dr1p4ns1/dr1p4ns1.py

1230 lines
62 KiB
Python

#################################################################################################### ################### SOF
#################################################################################################### #######################
from glob import glob
from time import sleep
from collections import namedtuple
import sys,tty,os,termios,shutil
#################################################################################################### #######################
#################################################################################################### #######################
####
#################################################################################################### #######################
"""MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM #######################
MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMh+MMMMMMMMMMMMMMhsMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM #######################
MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMm/ oMMMMMMMMMMMMMMm +NMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM #######################
MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMy` yMMMMMMMMMMMMMMM- -mMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM #######################
MMMMMMMMMMMMMMMMMMMMMMMMs+dMMMMMMMMMM+ sMMMMMMMMMMMMMMM- `dMMMMMMMMMMms/NMMMMMMMMMMMMMMMMMMMMMMM #######################
MMMMMMMMMMMMMMMMMMMMMMMMM+ .omMMMMMM: -MMMMMMMMMMMMMMo `yMMMMMMMy: `dMMMMMMMMMMMMMMMMMMMMMMMM #######################
MMMMMMMMMMMMMMMMMMMMMMMMMM- /dMMM+ sMMMMMMMMMMMMh `hMMMNo` sMMMMMMMMMMMMMMMMMMMMMMMMM #######################
MMMMMMMMMMMMMMMMMMMMMMMMMMd :dm `mMMMMMMMMMMN. .NNo` .MMMMMMMMMMMMMMMMMMMMMMMMMM #######################
MMMMMMMMMMMMMMMMMMMMMMMMMMM: - :MMMMMMMMMMs :` sMMMMMMMMMMMMMMMMMMMMMMMMMM #######################
MMMMMMMMMMMMMMMMMMMMMMMMMMMs ymNMMMMMNm. NMMMMMMMMMMMMMMMMMMMMMMMMMM #######################
MMMMMMMMMMMMMMMMMMMMMMMMMMMy `-/-` .MMMMMMMMMMMMMMMMMMMMMMMMMMM #######################
MMMMMMMMMMMMMMMMMMMMMMMMMMMo .NMMMMMMMMMMMMMMMMMMMMMMMMMM #######################
MMMMMMMMMMMMMMMMMMMMMMMNh+. :sdMMMMMMMMMMMMMMMMMMMMMMM #######################
MMMMMMMMMMMMMMMMMhso+:. `-/+syMMMMMMMMMMMMMMMMM #######################
MMMMMMMMMMMMMMMMM- dMMMMMMMMMMMMMMMM #######################
MMMMMMMMMMMMMMMMM` `.:+/. `/s+:. sMMMMMMMMMMMMMMMM #######################
MMMMMMMMMMMMMMMNo -oms. .//-` `:/:` `+md+` .hMMMMMMMMMMMMMMM #######################
MMMMMMMMMMMMMNs` .odNdo. .ohmd+` :dMMMMMMMMMMMMM #######################
MMMMMMMMMMMNo` .. .- :hMMMMMMMMMMM #######################
MMMMMMMMMd+` -sNMMMMMMMM #######################
###MMMNs- `.. `/-. `+dMMMMMM #######################
###Ny: ./sdNMMMh: `sNMMMNds/. .odMMM #######################
MM+ :ymMMMMMMMMMMh. +NMMMMMMMMMMmo- /NM #######################
MMMh: .sNMMMMMMMMMMMMMMN- `hMMMMMMMMMMMMMMMm+` :hMMM #######################
MMMMMd:` ``-:+shmMMMMMMMMMMMMMMMMMMN. hMMMMMMMMMMMMMMMMMMMmhs+/-..``````./dMMMMM #######################
MMMMMMMMMNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMo .MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM #######################
MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMy .MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM #######################
MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMN. /MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM #######################
MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMN+` `+NMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM #######################
MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMNs. -hMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM #######################
MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMdyymMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM""" #######################
#################################################################################################### #######################
#####
#################################################################################################### #######################
#################################################################################################### #######################
FIFO_PATH = f"{os.path.expanduser('~')}/.weechat/weechat_fifo" #####
FIFO_ENABLED = True #####
COPY_PATH = f"{os.path.expanduser('~')}/Pictures" #####
DELETE_PATH = "/tmp" #####
#################################################################################################### #######################
#################################################################################################### #######################
#####
### "00", "01", "02", "03", "04", "05", "06", "07", ###########################################
### "08", "09", "10", "11", "12", "13", "14", "15", ###########################################
#####
0xFFFFFF, 0x000000, 0x00007F, 0x009300, 0xFF0000, 0x7F0000, 0x9C009C, 0xFC7F00, ###########################################
0xFFFF00, 0x00FC00, 0x009393, 0x00FFFF, 0x0000FC, 0xFF00FF, 0x7F7F7F, 0xD2D2D2, ###########################################
#####
#############################################################################################################################
#############################################################################################################################
### #####
### "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", #####
### "28", "29", "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", #####
### "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "50", "51", #####
### "52", "53", "54", "55", "56", "57", "58", "59", "60", "61", "62", "63", #####
### "64", "65", "66", "67", "68", "69", "70", "71", "72", "73", "74", "75", #####
### "76", "77", "78", "79", "80", "81", "82", "83", "84", "85", "86", "87", #####
### "88", "89", "90", "91", "92", "93", "94", "95", "96", "97", "98" ''' #####
0x470000, 0x472100, 0x474700, 0x324700, 0x004700, 0x00472C, 0x004747, 0x002747, 0x000047, 0x2E0047, 0x470047, 0x47002A, #####
0x740000, 0x743a00, 0x747400, 0x517400, 0x007400, 0x007449, 0x007474, 0x004074, 0x000074, 0x4b0074, 0x740074, 0x740045, #####
0xb50000, 0xb56300, 0xb5b500, 0x7db500, 0x00b500, 0x00b571, 0x00b5b5, 0x0063b5, 0x0000b5, 0x7500b5, 0xb500b5, 0xb5006b, #####
0xff0000, 0xff8c00, 0xffff00, 0xb2ff00, 0x00ff00, 0x00ffa0, 0x00ffff, 0x008cff, 0x0000ff, 0xa500ff, 0xff00ff, 0xff0098, #####
0xff5959, 0xffb459, 0xffff71, 0xcfff60, 0x6fff6f, 0x65ffc9, 0x6dffff, 0x59b4ff, 0x5959ff, 0xc459ff, 0xff66ff, 0xff59bc, #####
0xff9c9c, 0xffd39c, 0xffff9c, 0xe2ff9c, 0x9cff9c, 0x9cffdb, 0x9cffff, 0x9cd3ff, 0x9c9cff, 0xdc9cff, 0xff9cff, 0xff94d3, #####
0x000000, 0x131313, 0x282828, 0x363636, 0x4d4d4d, 0x656565, 0x818181, 0x9f9f9f, 0xbcbcbc, 0xe2e2e2, 0xffffff #####
#####
#############################################################################################################################
#############################################################################################################################
def getfiles(argv=""):
PATH=""
if len(argv) > 1:
if argv[1] == ".":
PATH=""
else:
PATH=f'{argv[1]}/'
if len(argv) == 1:
PATH=""
files=glob(PATH+"*")
FILES=[]
for _ in files:
if _.lower()[-4:]==".ans":
FILES.append(_)
if len(FILES)==0:
print('ERROR: NO ANSI FILES IN THE PATH SPECIFIED',end='')
sys.exit(1)
return FILES
########################################################################################################## CLASS DR1P4NS1 - 2
class dr1p4ns1:
############################################################################################################ LOOKUP TABLE
commands = {
'A': 'up',
'B': 'down',
'C': 'forward',
'D': 'back',
'H': 'position',
'f': 'position',
'J': 'erase',
'K': 'erase_line',
's': 'save_cursor',
'u': 'restore_cursor',
'm': 'color',
'R': 'report_cursor_position'}
############################################################################################################ LOOKUP TABLE
asc_table="""\
╟ⁿΘΓΣαστΩδΦ∩ε∞─┼╔µ╞⌠÷≥√∙ ╓▄óúÑ₧ƒ\
ßφ≤·±╤¬║┐⌐¼╜╝í½╗░▒▓│┤╡╢╖╕╣║╗╝╜╛┐\
└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀\
α▀ΓπΣσ╡τΦΘΩδ∞φε∩≡▒≥≤⌠⌡≈≈░∙╖√ⁿ▓■á"""
##################################################################################################### ASCII TABLE CLEANUP
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
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',
88: '28', 130: '29', 142: '30', 64: '31',
28: '32', 35: '33', 30: '34', 25: '35',
18: '36', 91: '37', 90: '38', 125: '39',
124: '40', 166: '41', 184: '42', 106: '43',
34: '44', 49: '45', 37: '46', 33: '47',
19: '48', 129: '49', 127: '50', 161: '51',
196: '52', 208: '53', 226: '54', 154: '55',
46: '56', 86: '57', 51: '58', 75: '59',
21: '60', 171: '61', 201: '62', 198: '63',
203: '64', 215: '65', 227: '66', 191: '67',
83: '68', 122: '69', 87: '70', 111: '71',
63: '72', 177: '73', 207: '74', 205: '75',
217: '76', 223: '77', 229: '78', 193: '79',
157: '80', 158: '81', 159: '82', 153: '83',
147: '84', 183: '85', 219: '86', 212: '87',
16: '88', 233: '89', 235: '90', 237: '91',
239: '92', 241: '93', 244: '94', 247: '95',
250: '96', 254: '97', 231: '98', }
########################################################################################################## CLASS INIT - 3
def __init__(self,ansifile="",width=80,height=25,debug=False,pump=False):
self.DEBUG=debug
self.width=width
self.height=height
self.filename=ansifile
self.openansi(ansifile)
self.code='\x1b[0m'
self.cmps=[]
self.op=[]
self.optype=[]
self.sauce_found=False
print('\x1bc')
self.pump=pump
self.boot()
######################################################################################################### FILE OPERATIONS
def fifo(self,s):
s=[s]
f=open(FIFO_PATH,"w")
[f.write("*{}\n".format(x)) for x in s]
f.close()
######################################################################################################### FILE OPERATIONS
def openansi(self,s):
f=open(s,'rb')
self.ansifile=f.read().decode('cp437')
f.close()
############################################################################################################### DEBUGGING
def openascii(self):
f=open('ansiscii/work.asc','r')
self.reference=f.read()
f.close()
#################################################################################################################### TOOL
def printascii(self):
for i,_ in enumerate(self.asc_table):
_int=str(i+128).zfill(3)
_hex=hex(i+128)[2:].upper().zfill(2)
_ord=str(ord(_)).zfill(4)
print(f'{_} - {_int} - {_hex} - {_ord}')
############################################################################################################### DEBUGGING
def printrange(self,n,nn):
for index,_ in enumerate(self.ansifile):
h=hex(_)[2:].upper()
i=str(_).zfill(3)
s=''
if _>47 and _<127:
s=chr(_)
else:
s='.'
l=str(index).zfill(len(str(len(self.ansifile))))
if index >=n and index <=nn:
print(f"{l} {i} {h} {s}")
if index==nn:
break
############################################################################################################### DEBUGGING
def printhex(self):
theasc=[]
thehex=[]
buffer=''
for _ in self.ansifile:
buffer+=hex(ord(_)).upper()[2:].zfill(2)
for _ in self.chunk(buffer,32):
subchunks=''
for i,__ in enumerate(self.chunk(_,2)):
if i>0 and i%4==0: subchunks+=" "
subchunks+=f'{__} '
thehex.append(subchunks.strip())
for __ in thehex:
buffer=''
for _ in __.split():
i=int(_,16)
if i>47 and i<127:
buffer+=chr(i)
else:
buffer+='.'
theasc.append(buffer)
for _ in range(len(thehex)):
old=buffer
buffer={thehex[_]}
if not buffer == old:
print(f"{hex(16 * _)[2:].zfill(8)} {thehex[_]} {theasc[_]}")
############################################################################################################### DEBUGGING
def hexdump(self):
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':
code=self.ansifile[i:]
self.codes.append([code,i,len(self.ansifile)])
else:
if 64 <= ord(_) <= 126:
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])
############################################################################################################### 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()
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=[]
codes=[]
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)
self.processed = processed
irc_processed=[]
terminal_processed=[]
color_table=[1,5,3,7,2,6,10,15,14,4,9,8,12,13,11,0];
default_fg_color=7
default_bg_color=0
codes=[]
for _ in processed:
line=_
for r in (('\x16',chr(9644)),('\x15','\u00A7')):
line=line.replace(*r)
_line=line
bold_offset=0
bold_before=[]
bold_init=False
codes_root_popped=False
fg_color=color_table[default_fg_color]
bg_color=color_table[default_bg_color]
color_set='0'
for _ in [line[x[0]:x[1]+1] for x in zip([x for x in self.findall(line,'\x1b')],[line.find('m',x) for x in self.findall(line,'\x1b')])]:
codes.append(_)
code_values=_.split('[')[1].split(';')
code_replace=_
newcode=''
for __ in code_values:
__=__.replace('m','')
if 0 <= int(__) <= 9:
color_set=int(__)
if color_set==1:
bold_offset=8
bold_before=[]
else:
bold_offset=0
elif 40 <= int(__) <= 49:
if bold_init and bold_offset==0:
bg_color=color_table[default_bg_color]
else:
bg_color=__
if not bold_offset==0 and not bold_init:
bold_before.append(int(bg_color))
elif 30 <= int(__) <= 39:
if bold_init and bold_offset==0:
fg_color=color_table[default_fg_color]
else:
fg_color=__
if not bold_offset==0 and not bold_init:
bold_before.append(int(fg_color))
if bold_init and bold_offset==0:
bold_init=False
newcode='\x03'
bold_before.sort()
for _ in bold_before:
if 30 <= int(_) <= 39:
newcode += str(color_table[default_fg_color])
if 40 <= int(_) <= 49:
newcode += "," + str(color_table[default_bg_color])
elif not bold_offset == 0 and not bold_init:
newcode='\x03'
bold_before.sort()
for _ in bold_before:
if 30 <= int(_) <= 39:
newcode+=str(color_table[int(fg_color)-30+bold_offset])
if 40 <= int(_) <= 49:
newcode+=","+str(color_table[int(bg_color)-40])
bold_init=True
elif not bold_offset == 0 and bold_init:
for _ in bold_before:
if len(bold_before)==1:
if 30 <= int(_) <= 39:
bold_before.append(int(bg_color))
else:
bold_before.append(int(fg_color))
newcode='\x03'
bold_before.sort()
for _ in bold_before:
if 30 <= int(_) <= 39:
newcode+=str(color_table[int(fg_color)-30+bold_offset])
if 40 <= int(_) <= 49:
newcode+=","+str(color_table[int(bg_color)-40])
else:
pass #non-bold-operations
if len(codes) == 1 and not codes_root_popped:
if color_set == 0:
_line=_line.replace(codes[-1],"",1)
codes_root_popped=True
else:
_line=_line.replace(code_replace,newcode,1)
irc_processed.append(_line)
terminal_processed.append(line)
#################################################################################################################### TOOL
def getsauce(self):
f=open(self.filename,'rb')
l=f.read()
f.close()
self.sauce=l[-128:]
self.sauce_found=True
self.width=self.sauce[96]
self.height=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
#################################################################################################################### TOOL
def findall(self,s,w):
return [i for i in range(len(s)) if s.startswith(w, i)]
############################################################################################################### DEBUGGING
def cmpans(self,s1,s2,n1=0,n2=0):
_s1=''; _s2=''; _sn1=''; _sn2=''
_s1=self.stripcodes(s1)
_s2=self.stripcodes(s2)
if not n1 == n2:
_sn1=_s1[n1:n2]
_sn2=_s2[n1:n2]
_sn3=''
for i in range(self.width):
try:
if ord(_sn1[i]) == ord(_sn2[i]):
_sn3+='\x1b[32m0\x1b[0m'
else:
_sn3+='\x1b[31m1\x1b[0m'
except Exception as e:
print(e)
self.cmps.append(f'{_sn1}\n{_sn2}\n{_sn3}')
n1+=self.width
n2+=self.width
#################################################################################################################### TOOL
def chunk(self,s,n):
return [s[i:i+n] for i in range(0,len(s),n)]
#################################################################################################################### TOOL
def stripcodes(self,s):
buffer=s
code_start=0
code_end=0
code_state=False
for i,_ in enumerate(s):
if code_state==False:
if _ == '\x1b':
code_state=True
code_start=i
else:
if 64 <= ord(_) <= 126:
if _ in self.commands:
code_state=False
code_end=i+1
code=s[code_start:code_end]
buffer=buffer.replace(code,'')
return buffer
#################################################################################################################### TOOL
def rgb(self,t='',r=0,g=0,b=0):
"""colorize text with rgb values"""
return f"\033[38;2;{r};{g};{b}m{t}\033[38;2;255;255;255m"
#################################################################################################################### TOOL
def vga(self,t='',i=0):
"""colorize text using vga color set"""
vga = [ '#000000','#aa0000','#00aa00','#aa5500',
'#0000aa','#aa00aa','#00aaaa','#aaaaaa',
'#555555','#ff5555','#55ff55','#ffff55',
'#5555ff','#ff55ff','#55ffff','#ffffff', ]
try:
r=int(vga[i][1:][0:2],16)
g=int(vga[i][1:][2:4],16)
b=int(vga[i][1:][4:6],16)
except:
r,g,b=0,0,0
return f"\033[38;2;{r};{g};{b}m{t}\033[38;2;255;255;255m"
#################################################################################################################### TOOL
def invert_dict(self,d):
return {v: k for k, v in d.items()}
#################################################################################################################### BOOT
def boot(self):
if self.DEBUG:
print("\n\x1b[1;31m[ HEXDUMP ]\x1b[0m\n")
self.printhex()
self.codedump()
self.processdump()
####################################################################################### HUMAN INTERFACE * * * * * * * * * * *
class UI:
def __init__(self,files=""):
self.REMOVED=False
self.QUEUE=[]
self.files=files
self.uis_menu()
################################################################################### HUMAN INTERFACE * * * * * * * * * * *
def getkey(self):
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:
k = ord(b)
key_mapping = {
112: 'p',
27: 'esc',
67: 'right',
68: 'left',
113: 'q',
120: 'x',
99: 'c',
82: 'R'
}
return key_mapping.get(k, chr(k))
finally:
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_settings)
################################################################################### HUMAN INTERFACE * * * * * * * * * * *
def uis_menu(self):
index=0
try:
print(f'loading: {self.files[index]}')
d=dr1p4ns1(ansifile=self.files[index],width=80,debug=False)
decoder=ANSIDecoder(self.files[index],d.width)
decoder.as_terminal()
except:
pass
#######################################
try:
while True:
B='\x1b[1;94m'; C='\x1b[1;95m'; S='\x1b[1;36m'; M='\x1b[1;92m'; E='\x1b[0m'; R='\x1b[31m'
msg=f"{B}[ {C}DR1P {B}] {B}- {B}[ {M}x{B}: {M}exit{B}, {M}c{B}: {M}copy{B}, {M}R{B}: {M}remove{B}, {M}q{B}: {M}pumpqueue{B}, {M}p{B}: {M}pump{B}, "
msg+=f"{M}left{B}/{M}right{B}: {M}browse {B}] {B}- "
msg+=f"{B}[ {S}pumpqueue{B}: {C}{len(self.QUEUE)} {B}- {S}index{B}: {C}{index+1}{B}/{C}{len(self.files)} {B}- {S}filename{B}: {C}{d.filename} {B}]{E}"
if self.REMOVED==True: msg+=f'{R} - FILE REMOVED'
print(msg)
k = self.getkey()
if k == 'left':
index-=1
if index < 0: index=len(self.files)-1
try:
self.REMOVED=False
if len(self.files) == 0:
print(f'{B}NO FILES LEFT IN QUEUE - {R} EXITING')
sleep(1)
break
print(f'{C}loading{B}: {S}{self.files[index]}')
d=dr1p4ns1(ansifile=self.files[index],width=80,debug=False)
decoder=ANSIDecoder(self.files[index],d.width)
print('\x1bc')
decoder.as_terminal()
except:
pass
elif k == 'right':
index+=1
if index >= len(self.files): index=0
try:
self.REMOVED=False
if len(self.files) == 0:
print(f'{B}NO FILES LEFT IN QUEUE - {R} EXITING')
sleep(1)
break
print(f'{C}loading{B}: {S}{self.files[index]}')
d=dr1p4ns1(ansifile=self.files[index],width=80,debug=False)
decoder=ANSIDecoder(self.files[index],d.width)
print('\x1bc')
decoder.as_terminal()
except:
pass
elif k == 'esc' or k == 'x':
quit()
elif k == 'c':
try:
if not self.files[index].find('/') == -1:
FILEPATH=f'{COPY_PATH}/{str(self.files[index]).split("/")[1]}'
shutil.copyfile(self.files[index],FILEPATH)
print(f'{C}{self.files[index]} copied to {FILEPATH}')
else:
FILEPATH=f'{COPY_PATH}/{self.files[index]}'
shutil.copyfile(self.files[index],FILEPATH)
print(f'{C}{self.files[index]} {M}copied to {C}{FILEPATH}')
except:
print(f'{C}{self.files[index]} {M}was not copied')
sleep(1)
print('\x1bc')
decoder.as_terminal()
elif k == 'q':
self.QUEUE.append(self.files[index])
print(f'{C}{self.files[index]} {B}added to pumpqueue')
sleep(1)
print('\x1bc')
decoder.as_terminal()
elif k == 'p':
PMSG=""
try:
if FIFO_ENABLED:
if len(self.QUEUE) > 0:
self.QUEUE.reverse()
buffer=self.QUEUE[-1]
self.QUEUE.pop()
self.QUEUE.reverse()
decoder=ANSIDecoder(buffer,d.width)
PMSG=f'{M}pump: pumped from pumpqueue {C}{self.files[index]} {M}to fifo - {C}{FIFO_PATH}'
else:
decoder=ANSIDecoder(self.files[index],d.width)
PMSG=f'{M}pump: nothing in pumpqueue, pumping from screen {C}{self.files[index]} {M}to fifo - {C}{FIFO_PATH}'
decoder.as_irc()
else:
PMSG=f'{M}pumping disabled - fifo not detected in path: {C}{FIFO_PATH}'
except Exception as e:
PMSG=f'{M}pumping failed - {e}'
print('\x1bc')
decoder.as_terminal()
print(PMSG)
elif k == 'R':
try:
if not self.files[index].find('/') == -1:
FILEPATH=f'{DELETE_PATH}/{str(self.files[index]).split("/")[1]}'
shutil.copyfile(self.files[index],FILEPATH)
else:
FILEPATH=f'{DELETE_PATH}/{self.files[index]}'
shutil.copyfile(self.files[index],FILEPATH)
os.remove(self.files[index])
self.REMOVED=True
buffer=self.files[index]
self.files.remove(self.files[index])
print(f'{R}{buffer} removed: placed in {DELETE_PATH} directory')
except:
print(f'{C}{self.files[index]} {M}was not removed')
sleep(3)
print('\x1bc')
decoder.as_terminal()
else:
index+=1
if index >= len(self.files): index=0
try:
self.REMOVED=False
if len(self.files) == 0:
print(f'{B}NO FILES LEFT IN QUEUE - {R} EXITING')
sleep(1)
break
d=dr1p4ns1(ansifile=self.files[index],width=80,debug=False)
decoder=ANSIDecoder(self.files[index],d.width)
print('\x1bc')
decoder.as_terminal()
except:
pass
#######################################
except (KeyboardInterrupt, SystemExit):
os.system('stty sane')
#############################################################################################################################
class ANSIDecodeError(ValueError):
pass
#############################################################################################################################
class ANSIDecoder:
#############################################################################################################################
PALETTES = {
'vga': {
False: ['000', 'a00', '0a0', 'a50', '00a', 'a0a', '0aa', 'aaa'],
True: ['555', 'f55', '5f5', 'ff5', '55f', 'f5f', '5ff', 'fff'],
},
'workbench': {
False: ['aaa', '000', 'fff', '68b', '00f', 'f0f', '0ff', 'fff'],
True: ['aaa', '000', 'fff', '68b', '00f', 'f0f', '0ff', 'fff'],
}
}
#########################################################################################################################
PALETTE_NAMES = PALETTES.keys()
REMAPPED_CHARS = {
'\x00': ' ',
'\x01': '\u263a',
'\x02': '\u263b',
'\x03': '\u2665',
'\x04': '\u2666',
'\x05': '\u2663',
'\x06': '\u2660',
'\x10': '\u25ba',
'\x11': '\u25c4',
'\x16': '\u25ac',
'\x1d': '\u2194',
'\x1e': '\u25b2',
'\x1f': '\u25bc',
}
#########################################################################################################################
DEFAULT_FG = 7
DEFAULT_BG = 0
#########################################################################################################################
Attribute = namedtuple('Attribute', ['fg', 'bg', 'bright', 'underline'])
#########################################################################################################################
DEFAULT_ATTR = Attribute(fg=DEFAULT_FG, bg=DEFAULT_BG, bright=False, underline=False)
def __init__(self,files="",width=80):
#stream=None, palette='vga', width=80, strict=False
self.current_line = []
self.buffer = [self.current_line]
self.palette = self.PALETTES['vga']
self.x = 0
self.y = 0
self.saved_x = 0
self.saved_y = 0
self.current_attr = self.DEFAULT_ATTR
self.width = width
self.strict = False
self.filename=files
stream=open(self.filename,'rt',encoding='cp437')
if stream:
self.play(stream)
#########################################################################################################################
def write_char(self, char):
# Handle an ordinary character
try:
self.current_line[self.x] = (self.current_attr, char)
except IndexError:
# X position is out of range; append to current line
while len(self.current_line) < self.x:
self.current_line.append((self.DEFAULT_ATTR, ' '))
self.current_line.append((self.current_attr, char))
self.x += 1
if self.x >= self.width:
self.write_newline()
#########################################################################################################################
def set_cursor(self, x=None, y=None):
if x is not None:
self.x = max(x, 0)
if y is not None:
self.y = max(y, 0)
try:
self.current_line = self.buffer[self.y]
except IndexError:
while len(self.buffer) <= self.y:
self.current_line = []
self.buffer.append(self.current_line)
#########################################################################################################################
def write_newline(self):
# Handle a line break
self.set_cursor(x=0, y=(self.y + 1))
#########################################################################################################################
def set_attr(self, fg=None, bg=None, bright=None, underline=None):
if fg is None:
fg = self.current_attr.fg
if bg is None:
bg = self.current_attr.bg
if bright is None:
bright = self.current_attr.bright
if underline is None:
underline = self.current_attr.underline
self.current_attr = self.Attribute(fg=fg, bg=bg, bright=bright, underline=underline)
#########################################################################################################################
def write_escape(self, code, params):
if code == 'm':
for param in params:
if param == 0:
self.current_attr = self.DEFAULT_ATTR
elif param == 1:
self.set_attr(bright=True)
elif param == 2 or param == 22:
self.set_attr(bright=False)
elif param == 4:
self.set_attr(underline=True)
elif param == 24:
self.set_attr(underline=False)
elif 30 <= param <= 37:
self.set_attr(fg=(param - 30))
elif 40 <= param <= 47:
self.set_attr(bg=(param - 40))
else:
if self.strict:
raise ANSIDecodeError("Unsupported parameter to 'm' escape sequence: %r" % param)
elif code == 'J':
if params == [] or params == [0]:
# erase from cursor to end of screen
del self.current_line[self.x:]
del self.buffer[(self.y + 1):]
elif params == [1]:
# erase up to cursor
for i in range(0, self.y):
del self.buffer[i][:]
try:
for i in range(0, self.x + 1):
self.current_line[i] = (self.DEFAULT_ATTR, ' ')
except IndexError:
del self.current_line[:]
elif params == [2]:
# erase entire screen
for i in range(0, self.y):
del self.buffer[i][:]
del self.buffer[(self.y + 1):]
else:
if self.strict:
raise ANSIDecodeError("Unrecognised parameters to 'J' escape sequence: %r" % params)
elif code == 'K':
if params == [] or params == [0]:
# erase from cursor to end of line
del self.current_line[self.x:]
elif params == [1]:
# erase up to cursor
try:
for i in range(0, self.x + 1):
self.current_line[i] = (self.DEFAULT_ATTR, ' ')
except IndexError:
del self.current_line[:]
elif params == [2]:
# erase entire line
del self.current_line[:]
else:
if self.strict:
raise ANSIDecodeError("Unrecognised parameters to 'K' escape sequence: %r" % params)
elif code == 'A':
# move cursor up N lines
if not params:
self.set_cursor(y=(self.y - 1))
elif len(params) == 1:
self.set_cursor(y=(self.y - params[0]))
elif self.strict:
raise ANSIDecodeError("Expected 0 or 1 param to 'A' escape sequence, got %d" % len(params))
elif code == 'B':
# move cursor down N lines
if not params:
self.set_cursor(y=(self.y + 1))
elif len(params) == 1:
self.set_cursor(y=(self.y + params[0]))
elif self.strict:
raise ANSIDecodeError("Expected 0 or 1 param to 'B' escape sequence, got %d" % len(params))
elif code == 'C':
# move cursor right N cols
if not params:
self.set_cursor(x=(self.x + 1))
elif len(params) == 1:
self.set_cursor(x=(self.x + params[0]))
elif self.strict:
raise ANSIDecodeError("Expected 0 or 1 param to 'C' escape sequence, got %d" % len(params))
elif code == 'D':
# move cursor left N cols
if not params:
self.set_cursor(x=(self.x - 1))
elif len(params) == 1:
self.set_cursor(x=(self.x - params[0]))
elif self.strict:
raise ANSIDecodeError("Expected 0 or 1 param to 'D' escape sequence, got %d" % len(params))
elif code == 'E':
# move cursor to beginning of next line, N lines down
if not params:
self.set_cursor(x=0, y=(self.y + 1))
elif len(params) == 1:
self.set_cursor(x=0, y=(self.y + params[0]))
elif self.strict:
raise ANSIDecodeError("Expected 0 or 1 param to 'E' escape sequence, got %d" % len(params))
elif code == 'F':
# move cursor to beginning of previous line, N lines up
if not params:
self.set_cursor(x=0, y=(self.y - 1))
elif len(params) == 1:
self.set_cursor(x=0, y=(self.y - params[0]))
elif self.strict:
raise ANSIDecodeError("Expected 0 or 1 param to 'F' escape sequence, got %d" % len(params))
elif code == 'G':
# move cursor to column N
if len(params) == 1:
self.set_cursor(x=params[0])
elif self.strict:
raise ANSIDecodeError("Expected 1 param to 'G' escape sequence, got %d" % len(params))
elif code == 'H' or code == 'f':
# move cursor to (line, col)
if not params:
self.set_cursor(x=0, y=0)
elif len(params) == 2:
self.set_cursor(x=params[1] - 1, y=params[0] - 1)
elif self.strict:
raise ANSIDecodeError("Expected 0 or 2 param to '%s' escape sequence, got %d" % (code, len(params)))
elif code == 'h':
if params == [7]:
# enable line wrapping
pass
elif self.strict:
raise ANSIDecodeError("Unrecognised params to 'h' - got %r" % params)
elif code == 's':
# save cursor position
if params and self.strict:
raise ANSIDecodeError("Unrecognised params to 's' - got %r" % params)
self.saved_x = self.x
self.saved_y = self.y
elif code == 'u':
# restore cursor position
if params and self.strict:
raise ANSIDecodeError("Unrecognised params to 'u' - got %r" % params)
self.set_cursor(x=self.saved_x, y=self.saved_y)
else:
if self.strict:
raise ANSIDecodeError("Unrecognised escape code: %r" % code)
#########################################################################################################################
def play(self, f):
while True:
# Read file a character at a time
char = f.read(1)
if not char:
# End of file
break
elif char >= ' ':
self.write_char(char)
elif char == '\x0a': # LF
self.write_newline()
elif char == '\x0d': # CR
continue
elif char in self.REMAPPED_CHARS:
self.write_char(self.REMAPPED_CHARS[char])
elif char == '\x1a':
# EOF when using SAUCE records
break
elif char == '\x1b':
# Handle an escape sequence
char = f.read(1)
# Next character is expected to be '['
if char != '[':
if self.strict:
raise ANSIDecodeError("Unrecognised character after ESC: %r" % char)
continue
params = []
param = None
private = False
while True:
char = f.read(1)
if '0' <= char <= '9':
if param is None:
param = int(char)
else:
param = param * 10 + int(char)
elif char == ';':
if param is None:
if self.strict:
raise ANSIDecodeError("Encountered ';' character without parameter")
else:
params.append(param)
param = None
elif char == ' ':
pass
elif char == '?':
private = True
else:
if param is not None:
params.append(param)
if not private:
self.write_escape(char, params)
break
elif self.strict:
raise ANSIDecodeError("Unrecognised character: %r" % char)
#########################################################################################################################
def fifo(self,s):
s=[s]
f=open(FIFO_PATH,"w")
[f.write("*{}\n".format(x)) for x in s]
f.close()
################################################################################################### RE-ENCODING ENCODINGS
def as_irc_lines(self):
default_fg=7
default_bg=0
color_table=[1,5,3,7,2,6,10,15,14,4,9,8,12,13,11,0]
color_fg=color_table[default_fg]
color_bg=color_table[default_bg]
offset_bold=0
reset_bold=False
last_attr = None
processing=''
self.fifo(f"filename: {self.filename}")
for i,line in enumerate(self.buffer):
for n,(attr, char) in enumerate(line):
####################################################################################### FOR LINE
if attr[2]:
offset_bold=8
else:
offset_bold=0
color_fg=color_table[attr[0]+offset_bold]
color_bg=color_table[attr[1]]
if attr != last_attr:
if last_attr==None:
processing+=f'\x03{color_table[attr[0]]},{color_table[attr[1]]}'
color_fg=color_table[attr[0]]
color_bg=color_table[attr[1]]
else:
if n==0 and not attr[0]==default_fg:
if attr[2]:
processing+=f'\x03{color_table[attr[0]+offset_bold]},{color_table[attr[1]]}'
color_fg=color_table[attr[0]+offset_bold]
color_bg=color_table[attr[1]]
else:
processing+=f'\x03{color_table[attr[0]]},{color_table[attr[1]]}'
color_fg=color_table[attr[0]]
color_bg=color_table[attr[1]]
elif n==0 and attr[2]:
processing+=f'\x03{color_table[attr[0]+offset_bold]},{color_table[attr[1]]}'
color_fg=attr[0]+offset_bold
color_bg=attr[1]
if not attr[2]==last_attr[2] and not n==0:
if attr[0] == last_attr[0] and not attr[1] == last_attr[1]:
processing+=f'\x03{color_table[attr[0]+offset_bold]},{color_table[attr[1]]}'
color_fg=attr[0]+offset_bold
color_bg=attr[1]
elif attr[0] == last_attr[0] and attr[1] == last_attr[1]:
processing+=f'\x03{color_table[attr[0]+offset_bold]}'
color_fg=attr[0]+offset_bold
elif not attr[0] == last_attr[0] and attr[1] == last_attr[1]:
processing+=f'\x03{color_table[attr[0]+offset_bold]}'
color_fg=attr[0]+offset_bold
elif not attr[0] == last_attr[0] and not attr[1] == last_attr[1]:
processing+=f'\x03{color_table[attr[0]+offset_bold]},{color_table[attr[1]]}'
color_fg=attr[0]+offset_bold
color_bg=attr[1]
elif not attr[0]==last_attr[0] and not attr[1]==last_attr[1] and not n==0:
processing+=f'\x03{color_table[attr[0]+offset_bold]},{color_table[attr[1]]}'
color_fg=attr[0]+offset_bold
color_bg=attr[1]
elif not attr[0]==last_attr[0] and not n==0:
if attr[2]:
processing+=f'\x03{color_table[attr[0]+offset_bold]}'
color_fg=attr[0]+offset_bold
else:
if not '\x30' <= char <= '\x39':
processing+=f'\x03{color_table[attr[0]]},{color_table[attr[1]]}'
else:
processing+=f'\x03{color_table[attr[0]]},{str(color_table[attr[1]]).zfill(2)}'
color_fg=attr[0]
elif not attr[1]==last_attr[1] and not n==0:
if attr[2]:
processing+=f'\x03{color_table[attr[0]+offset_bold]},{color_table[attr[1]]}'
color_fg=attr[0]+offset_bold
color_bg=attr[1]
else:
processing+=f'\x03{color_table[attr[0]]},{color_table[attr[1]]}'
color_fg=attr[0]
color_bg=attr[1]
else:
if n==0 and not attr[0]==default_fg:
if attr[2]:
processing+=f'\x03{color_table[attr[0]+offset_bold]},{color_table[attr[1]]}'
color_fg=color_table[attr[0]+offset_bold]
color_bg=color_table[attr[1]]
else:
processing+=f'\x03{color_table[attr[0]]},{color_table[attr[1]]}'
color_fg=color_table[attr[0]]
color_bg=color_table[attr[1]]
if len(processing) == 0:
processing+=f"\x0315,1"
processing+=char
last_attr=attr
if len(self.buffer[i]) == 0:
self.output_lines.append(f"\x031,1{''*self.width}")
else:
distance=int(self.width)-len(line)
processing+=f"\x031,1{''*distance}"
self.output_lines.append(processing)
processing=''
#########################################################################################################################
def as_irc(self):
self.output_lines=[]
self.as_irc_lines()
for _ in self.output_lines:
self.fifo(_)
################################################################################################### RE-ENCODING ENCODINGS
def as_terminal_lines(self):
default_fg=7
default_bg=0
last_attr = None
processing=''
for i,line in enumerate(self.buffer):
for n,(attr, char) in enumerate(line):
if attr != last_attr:
if last_attr == None:
processing+=f'\x1b[{attr[0]+30};{attr[1]+40}m'
else:
if n==0 and not attr[0]==default_fg:
if attr[2]:
processing+=f'\x1b[1;{attr[0]+30};{attr[1]+40}m'
else:
processing+=f'\x1b[0;{attr[0]+30};{attr[1]+40}m'
elif n==0 and attr[2]:
processing+=f'\x1b[1;{attr[0]+30};{attr[1]+40}m'
elif n==0 and not attr[2]:
processing+=f'\x1b[0;{attr[0]+30};{attr[1]+40}m'
if not attr[2]==last_attr[2] and not n==0:
if attr[0] == last_attr[0] and not attr[1] == last_attr[1]:
if attr[2]:
processing+=f'\x1b[1;{attr[0]+30};{attr[1]+40}m'
else:
processing+=f'\x1b[0;{attr[0]+30};{attr[1]+40}m'
elif attr[0] == last_attr[0] and attr[1] == last_attr[1]:
if attr[2]:
processing+=f'\x1b[1;{attr[0]+30}m'
else:
processing+=f'\x1b[0;{attr[0]+30}m'
elif not attr[0] == last_attr[0] and attr[1] == last_attr[1]:
if attr[2]:
processing+=f'\x1b[1;{attr[0]+30}m'
else:
processing+=f'\x1b[0;{attr[0]+30}m'
elif not attr[0] == last_attr[0] and not attr[1] == last_attr[1]:
if attr[2]:
processing+=f'\x1b[1;{attr[0]+30};{attr[1]+40}m'
else:
processing+=f'\x1b[0;{attr[0]+30};{attr[1]+40}m'
elif not attr[0]==last_attr[0] and not attr[1]==last_attr[1] and not n==0:
if attr[2]:
processing+=f'\x1b[1;{attr[0]+30};{attr[1]+40}m'
else:
processing+=f'\x1b[0;{attr[0]+30};{attr[1]+40}m'
elif not attr[0]==last_attr[0] and not n==0:
if attr[2]:
processing+=f'\x1b[1;{attr[0]+30}m'
else:
processing+=f'\x1b[{attr[0]+30};{attr[1]+40}m'
elif not attr[1]==last_attr[1] and not n==0:
if attr[2]:
processing+=f'\x1b[1;{attr[0]+30};{attr[1]+40}m'
else:
processing+=f'\x1b[0;{attr[0]+30};{attr[1]+40}m'
else:
if n==0 and not attr[0]==default_fg:
if attr[2]:
processing+=f'\x1b[1;{attr[0]+30};{attr[1]+40}m'
else:
processing+=f'\x1b[0;{attr[0]+30};{attr[1]+40}m'
processing+=char
last_attr=attr
self.output_lines.append(processing + '\x1b[40;37m')
processing=''
#########################################################################################################################
def as_terminal(self):
self.output_lines=[]
self.as_terminal_lines()
for _ in self.output_lines:
print(_)
################################################################################################################### ENTRY - 1
if __name__=="__main__":
FIFO_ENABLED = os.path.exists(FIFO_PATH)
files = getfiles(sys.argv)
ui = UI(files)