Ready for backend hook
Client-side script 'start.py' is now ready for a backend hook. The only thing remaining to do on the client-side is to add the actual initializer of labylib. Added support for "us.mineplex.com" in 'servers.json'
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
.cache.png
|
BIN
backend/background.png
Normal file
After Width: | Height: | Size: 713 B |
0
backend/render.php
Normal file
0
backend/servers.json
Normal file
BIN
backend/tags/us.mineplex.com/rank_admin.png
Normal file
After Width: | Height: | Size: 6.8 KiB |
BIN
backend/tags/us.mineplex.com/rank_eternal.png
Normal file
After Width: | Height: | Size: 7.5 KiB |
BIN
backend/tags/us.mineplex.com/rank_hero.png
Normal file
After Width: | Height: | Size: 6.8 KiB |
BIN
backend/tags/us.mineplex.com/rank_immortal.png
Normal file
After Width: | Height: | Size: 9.1 KiB |
BIN
backend/tags/us.mineplex.com/rank_leader.png
Normal file
After Width: | Height: | Size: 7.1 KiB |
BIN
backend/tags/us.mineplex.com/rank_legend.png
Normal file
After Width: | Height: | Size: 7.2 KiB |
BIN
backend/tags/us.mineplex.com/rank_mod.png
Normal file
After Width: | Height: | Size: 7 KiB |
BIN
backend/tags/us.mineplex.com/rank_owner.png
Normal file
After Width: | Height: | Size: 7.1 KiB |
BIN
backend/tags/us.mineplex.com/rank_srmod.png
Normal file
After Width: | Height: | Size: 7.5 KiB |
BIN
backend/tags/us.mineplex.com/rank_titan.png
Normal file
After Width: | Height: | Size: 6.5 KiB |
BIN
backend/tags/us.mineplex.com/rank_trainee.png
Normal file
After Width: | Height: | Size: 8.5 KiB |
BIN
backend/tags/us.mineplex.com/rank_ultra.png
Normal file
After Width: | Height: | Size: 6.9 KiB |
Before Width: | Height: | Size: 239 B |
38
servers.json
|
@ -1,5 +1,39 @@
|
||||||
{
|
{
|
||||||
"us.mineplex.net": [
|
"us.mineplex.com": {
|
||||||
"/(?<=\\[CHAT\\])(.*)(?=ULTRA|HERO|LEGEND|TITAN|ETERNAL|IMMORTAL|TRAINEE|MOD)/g"
|
"pattern": "([abcef0-9])\\w+ ",
|
||||||
|
"lookup": {
|
||||||
|
"start": 1,
|
||||||
|
"ignore": [
|
||||||
|
"MPS",
|
||||||
|
"Host",
|
||||||
|
"Co-Host",
|
||||||
|
"el?"
|
||||||
|
],
|
||||||
|
"tag": [
|
||||||
|
"ULTRA",
|
||||||
|
"HERO",
|
||||||
|
"LEGEND",
|
||||||
|
"TITAN",
|
||||||
|
"ETERNAL",
|
||||||
|
"IMMORTAL",
|
||||||
|
"YT",
|
||||||
|
"STREAM",
|
||||||
|
"YOUTUBE",
|
||||||
|
"TRAINEE",
|
||||||
|
"MOD",
|
||||||
|
"SR.MOD",
|
||||||
|
"ADMIN",
|
||||||
|
"LEADER",
|
||||||
|
"OWNER"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"vanilla": {
|
||||||
|
"pattern": "\\<(?s)(.*)\\>",
|
||||||
|
"lookup": {
|
||||||
|
"start": 0,
|
||||||
|
"ignore": [],
|
||||||
|
"tag": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
119
start.py
|
@ -2,13 +2,12 @@ from labylib import Cape
|
||||||
from threading import Thread, Event
|
from threading import Thread, Event
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from PIL import Image
|
import re
|
||||||
from PIL import ImageFont
|
import json
|
||||||
from PIL import ImageDraw
|
|
||||||
|
|
||||||
import platform
|
import platform
|
||||||
import getpass
|
import getpass
|
||||||
import subprocess
|
import subprocess
|
||||||
|
import requests
|
||||||
|
|
||||||
# Chattycape daemon
|
# Chattycape daemon
|
||||||
class Chattycape(Thread):
|
class Chattycape(Thread):
|
||||||
|
@ -16,26 +15,91 @@ class Chattycape(Thread):
|
||||||
pollRate = 1 # Logfile pollrate
|
pollRate = 1 # Logfile pollrate
|
||||||
updateRate = 1 # Update rate of Labylib cosmetic
|
updateRate = 1 # Update rate of Labylib cosmetic
|
||||||
|
|
||||||
def __init__(self,event,phpsessid,logfile):
|
def __init__(self,event,phpsessid,endpoint,logfile,me = "None"):
|
||||||
Thread.__init__(self)
|
Thread.__init__(self)
|
||||||
self.stopped = event
|
self.stopped = event
|
||||||
|
self.params = (phpsessid,endpoint,logfile,me) # Create tuple from params
|
||||||
|
|
||||||
self.phpsessid = phpsessid
|
self.server = None # Connected to server (hostname)
|
||||||
self.logfile = logfile
|
self.config = None # Chat config for current server
|
||||||
|
|
||||||
self.line = ""
|
|
||||||
|
|
||||||
|
self.line = "[21:42:25] [main/INFO]: [CHAT] 725 IMMORTAL VicW test"
|
||||||
self.i = 0
|
self.i = 0
|
||||||
|
|
||||||
# Poll last line from logfile
|
# Read last line from logfile
|
||||||
def linefeed(self):
|
def linefeed(self):
|
||||||
self.line = subprocess.check_output(['tail','-1',self.logfile])
|
# tail last line from logfile
|
||||||
|
line = subprocess.check_output(['tail','-1',self.params[2]]).decode("utf-8","ignore")[:-2]
|
||||||
|
|
||||||
|
match = re.search(self.config["pattern"],line)
|
||||||
|
|
||||||
|
if match:
|
||||||
|
self.line = line
|
||||||
|
return
|
||||||
|
|
||||||
|
# Extract Minecraft username and tag from current line
|
||||||
|
def getUser(self):
|
||||||
|
line = self.line[31:].split() # Split current line. Offset (31) for log-prefixes
|
||||||
|
|
||||||
|
username = tag = "None"
|
||||||
|
|
||||||
|
start = self.config["lookup"]["start"] # List offset for iterator
|
||||||
|
ignoreList = self.config["lookup"]["ignore"] # Jumps to next index if match
|
||||||
|
tagList = self.config["lookup"]["tag"] # 'tag' set if match
|
||||||
|
|
||||||
|
for substr in line[start:]: # Start at offset
|
||||||
|
if substr in ignoreList:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if substr in tagList:
|
||||||
|
tag = substr
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Not ignored, and not a tag, so assume we've reached the username
|
||||||
|
username = substr
|
||||||
|
break
|
||||||
|
|
||||||
|
return (username,tag)
|
||||||
|
|
||||||
# Update labylib cosmetic
|
# Update labylib cosmetic
|
||||||
def update(self):
|
def update(self):
|
||||||
print(self.line)
|
args = self.getUser() # Get minecraft username and tag
|
||||||
|
|
||||||
|
urlparams = f"?server={self.server}&ign={args[0]}&rank={args[1]}"
|
||||||
|
|
||||||
|
# Save cape texture from endpoint to disk
|
||||||
|
with open(".cache.png","wb") as handle:
|
||||||
|
fetch = requests.get(self.params[1] + urlparams,stream=True)
|
||||||
|
|
||||||
|
if not fetch.ok:
|
||||||
|
print(fetch)
|
||||||
|
|
||||||
|
for block in fetch.iter_content(1024):
|
||||||
|
if not block:
|
||||||
|
break
|
||||||
|
|
||||||
|
handle.write(block)
|
||||||
|
|
||||||
|
# TODO: Labylib here
|
||||||
|
|
||||||
|
# ----------------------------
|
||||||
|
|
||||||
|
# Import RegEx patterns for current server
|
||||||
|
def loadConfig(self):
|
||||||
|
self.server = "us.mineplex.com"
|
||||||
|
|
||||||
|
with open("./servers.json") as config:
|
||||||
|
data = json.load(config)
|
||||||
|
|
||||||
|
self.config = data[self.server]
|
||||||
|
self.config["pattern"] = r"\[CHAT\]+ " + self.config["pattern"]
|
||||||
|
|
||||||
|
# Start the thread
|
||||||
def run(self):
|
def run(self):
|
||||||
|
print("\nRunning..")
|
||||||
|
self.loadConfig()
|
||||||
|
|
||||||
|
# Start the chat 'listener'
|
||||||
while not self.stopped.wait(Chattycape.pollRate):
|
while not self.stopped.wait(Chattycape.pollRate):
|
||||||
self.linefeed() # Poll logfile
|
self.linefeed() # Poll logfile
|
||||||
|
|
||||||
|
@ -53,10 +117,28 @@ class Main:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
print("-- Labylib Chattycape --")
|
print("-- Labylib Chattycape --")
|
||||||
self.logfile = self.locate()
|
self.logfile = self.locate()
|
||||||
self.phpsessid = input("\nhttps://github.com/VictorWesterlund/labylib#find-your-phpsessid-cookie\nPaste your PHPSESSID here:\n")
|
|
||||||
|
self.endpoint = self.prompt("Cape render endpoint","http://192.168.86.21/victor-westerlund/labylib-chattycape/back-end/render.php")
|
||||||
|
self.me = self.prompt("My Minecraft in-game name (Case Sensitive)","Don't exclude me")
|
||||||
|
self.phpsessid = self.prompt("PHPSESSID cookie")
|
||||||
|
|
||||||
self.start()
|
self.start()
|
||||||
|
|
||||||
|
# Prompt user to enter information
|
||||||
|
def prompt(self,message,default = "None"):
|
||||||
|
# Add '[default]' flag if present
|
||||||
|
if(default != "None"):
|
||||||
|
message += f" [{default}]"
|
||||||
|
message += ":"
|
||||||
|
|
||||||
|
value = default
|
||||||
|
userinput = input(message + "\n")
|
||||||
|
|
||||||
|
if(userinput):
|
||||||
|
value = userinput
|
||||||
|
|
||||||
|
return value
|
||||||
|
|
||||||
# Attempt to locate '.minecraft' automatically, otherwise prompt user
|
# Attempt to locate '.minecraft' automatically, otherwise prompt user
|
||||||
def locate(self):
|
def locate(self):
|
||||||
sys = platform.system() # Get operating system
|
sys = platform.system() # Get operating system
|
||||||
|
@ -86,7 +168,7 @@ class Main:
|
||||||
|
|
||||||
# Failed to locate Minecraft-installation automatically
|
# Failed to locate Minecraft-installation automatically
|
||||||
|
|
||||||
path = input("Please paste the path to your '.minecraft'-folder:\n")
|
path = self.prompt("Path to your '.minecraft'-folder","/mnt/c/Users/victo/AppData/Roaming/.minecraft")
|
||||||
|
|
||||||
if(Path(path).exists()):
|
if(Path(path).exists()):
|
||||||
return path + mclog
|
return path + mclog
|
||||||
|
@ -98,12 +180,11 @@ class Main:
|
||||||
stop = Event()
|
stop = Event()
|
||||||
|
|
||||||
# Start the daemon
|
# Start the daemon
|
||||||
chattycape = Chattycape(stop,self.phpsessid,self.logfile)
|
chattycape = Chattycape(stop,self.phpsessid,self.endpoint,self.logfile,self.me)
|
||||||
chattycape.start()
|
chattycape.start()
|
||||||
|
|
||||||
interrupt = input("\nRunning! Press enter to stop\n")
|
input("Press enter to stop the daemon")
|
||||||
stop.set() # Stop the daemon
|
stop.set() # Stop the daemon
|
||||||
print("Bye!")
|
print("Stopped!")
|
||||||
|
|
||||||
main = Main()
|
Main()
|
||||||
print(main.file)
|
|