Skip to content

Commit

Permalink
Merge pull request #26 from shinkuan/dev
Browse files Browse the repository at this point in the history
v1.4.0
  • Loading branch information
shinkuan authored Feb 13, 2024
2 parents 3844053 + e4917bd commit a6d79f2
Show file tree
Hide file tree
Showing 19 changed files with 5,474 additions and 73,225 deletions.
10 changes: 4 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,12 @@ https://github.com/shinkuan/RandomStuff/assets/35415788/ce1b598d-b1d7-49fe-a175-

### Installation.

[YouTube Video for you to follow.](https://youtu.be/NdAULJgBJ-U)
[YouTube Video for you to follow.](https://youtu.be/V7NMNsZ3Ut8)

### You will need:
1. A `mortal.pth`. [(Get one from Discord server if you don't have one.)](https://discord.gg/Z2wjXUK8bN)
2. A `libriichi` that match your system. [(Get it here)](https://github.com/shinkuan/Akagi/releases/tag/v0.1.0-libriichi)
3. (Optional, Recommend) Use Windows Terminal to open client.py for a nice looking TUI.
4. (Optional) If you want to use Steam, Majsoul Plus, or anything other client, proxy the client using tools like proxifier.
2. (Optional, Recommend) Use Windows Terminal to open client.py for a nice looking TUI.
3. (Optional) If you want to use Steam, Majsoul Plus, or anything other client, proxy the client using tools like proxifier.

__Get mortal.pth at [Discord](https://discord.gg/Z2wjXUK8bN)__
1. Go to #verify and click the ✅ reaction.
Expand All @@ -65,8 +64,7 @@ Download `install_akagi.ps1` at [Release](https://github.com/shinkuan/Akagi/rele
7. Close it.
8. Go to your user home directory `~/.mitmproxy`
9. Install the certificate.
10. Put `libriichi` into `./Akagi/mjai/bot` and rename it as `libriichi`
11. Put `mortal.pth` into `./Akagi/mjai/bot`
10. Put `mortal.pth` into `./Akagi/mjai/bot`

### settings.json

Expand Down
12 changes: 5 additions & 7 deletions README_CH.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,12 @@ https://github.com/shinkuan/RandomStuff/assets/35415788/ce1b598d-b1d7-49fe-a175-

### 安裝

[點我到Youtube觀看安裝影片](https://youtu.be/NdAULJgBJ-U)
[點我到Youtube觀看安裝影片](https://youtu.be/V7NMNsZ3Ut8)

在開始前,你需要以下東西:
1. `mortal.pth` [(如果你沒有的話,到Discord去下載)](https://discord.gg/Z2wjXUK8bN)
2. `libriichi` [(到這邊根據你的平台下載對應版本)](https://github.com/shinkuan/Akagi/releases/tag/v0.1.0-libriichi)
3. (Optional) 推薦使用Windows Terminal,以獲得預期中的UI效果。
4. (Optional) 如果你要使用Steam或Majsoul Plus之類的,請使用類似Proxifier的軟體將連線導向至MITM
2. (Optional) 推薦使用Windows Terminal,以獲得預期中的UI效果。
3. (Optional) 如果你要使用Steam或Majsoul Plus之類的,請使用類似Proxifier的軟體將連線導向至MITM

__[Discord](https://discord.gg/Z2wjXUK8bN)下載我提供的mortal.pth__
1. 到 #verify 頻道點擊 ✅ 驗證身分.
Expand All @@ -60,10 +59,9 @@ __到[Discord](https://discord.gg/Z2wjXUK8bN)下載我提供的mortal.pth__
5. 執行: `install_akagi.ps1`
6. 如果這是您第一次使用mitmproxy,請打開它。
7. 關閉它。
8. cd 到用戶主目錄 `~/.mitmproxy`
8. 到使用者主目錄 `~/.mitmproxy`
9. 安裝證書。
10.`libriichi` 放入 `./Akagi/mjai/bot` 並將其重新命名為 `libriichi`
11.`mortal.pth` 放入 `./Akagi/mjai/bot`
10.`mortal.pth` 放入 `./Akagi/mjai/bot`

### settings.json

Expand Down
109 changes: 78 additions & 31 deletions client.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@
import time
os.environ["LOGURU_AUTOINIT"] = "False"

import pathlib
import webbrowser
from sys import executable
from subprocess import Popen, CREATE_NEW_CONSOLE

from typing import Any, Coroutine
from xmlrpc.client import ServerProxy
import json
Expand Down Expand Up @@ -40,9 +45,6 @@
class FlowScreen(Screen):

BINDINGS = [
# ("d", "toggle_dark", "Toggle dark mode"),
# ("a", "add_stopwatch", "Add"),
# ("r", "remove_stopwatch", "Remove"),
("ctrl+q", "quit", "Quit"),
]

Expand Down Expand Up @@ -225,13 +227,20 @@ def on_button_pressed(self, event: Button.Pressed) -> None:
self.app.push_screen(FlowScreen(self.flow_id))
self.app.update_flow.pause()

class HoverLink(Static):
def __init__(self, text, url, *args, **kwargs) -> None:
super().__init__(*args, **kwargs)
self.renderable = text
self.url = url
self.add_class("hover-link")
self.border_title = self.url
self.border_subtitle = "Click to open link"

def on_click(self, event):
webbrowser.open_new_tab(self.url)
pass

class SettingsScreen(Screen):

BINDINGS = [
("ctrl+q", "quit_setting", "Quit Settings"),
("ctrl+s", "quit_setting", "Quit Settings"),
]
class SettingsScreen(Static):

def __init__(self, *args, **kwargs) -> None:
super().__init__(*args, **kwargs)
Expand All @@ -241,6 +250,7 @@ def __init__(self, *args, **kwargs) -> None:
self.value_port_setting_xmlrpc_input = settings["Port"]["XMLRPC"]
self.value_unlocker_setting_enable_checkbox = settings["Unlocker"]
self.value_unlocker_setting_v10_checkbox = settings["v10"]
self.value_helper_setting_checkbox = settings["Helper"]
self.value_autoplay_setting_enable_checkbox = settings["Autoplay"]
# self.value_autoplay_setting_random_time_min_input = settings["Autoplay"]["Random Time"]["Min"]
# self.value_autoplay_setting_random_time_max_input = settings["Autoplay"]["Random Time"]["Max"]
Expand All @@ -264,6 +274,11 @@ def compose(self) -> ComposeResult:
self.unlocker_setting_container = Horizontal(self.unlocker_setting_label, self.unlocker_setting_enable_checkbox, self.unlocker_setting_v10_checkbox, id="unlocker_setting_container")
self.unlocker_setting_container.border_title = "Unlocker"

self.helper_setting_label = Label("Helper", id="helper_setting_label")
self.helper_setting_checkbox = Checkbox("Enable", id="helper_setting_checkbox", classes="short", value=self.value_helper_setting_checkbox)
self.helper_setting_container = Horizontal(self.helper_setting_label, self.helper_setting_checkbox, id="helper_setting_container")
self.helper_setting_container.border_title = "Helper"

self.autoplay_setting_enable_label = Label("Enable", id="autoplay_setting_enable_label")
self.autoplay_setting_enable_checkbox = Checkbox("Enable", id="autoplay_setting_enable_checkbox", classes="short", value=self.value_autoplay_setting_enable_checkbox)
self.autoplay_setting_enable_container = Horizontal(self.autoplay_setting_enable_label, self.autoplay_setting_enable_checkbox, id="autoplay_setting_enable_container")
Expand All @@ -284,13 +299,22 @@ def compose(self) -> ComposeResult:
self.playwright_setting_container = Vertical(self.playwright_setting_enable_container, self.playwright_setting_resolution_container, id="playwright_setting_container")
self.playwright_setting_container.border_title = "Playwright"

yield Header()
yield Markdown("# Settings")
yield self.port_setting_container
yield self.unlocker_setting_container
yield self.autoplay_setting_container
yield self.playwright_setting_container
yield Footer()
self.setting_save_button = Button("Save", variant="warning", id="setting_save_button")

self.remove_this_then_you_badluck_for_100years_and_get_hit_by_a_car_then_die = HoverLink("Akagi is Free and Open Sourced on GitHub.\n本程式Akagi在GitHub上完全開源且免費。如果你是付費取得的,你已經被賣家欺騙,請立即舉報、差評、退款。", "https://github.com/shinkuan/Akagi", id="remove_this_you_die")

self.setting_container = ScrollableContainer(
self.port_setting_container,
self.unlocker_setting_container,
self.helper_setting_container,
self.autoplay_setting_container,
self.playwright_setting_container,
self.setting_save_button,
self.remove_this_then_you_badluck_for_100years_and_get_hit_by_a_car_then_die,
id="setting_container"
)

yield self.setting_container

@on(Input.Changed, "#port_setting_mitm_input")
def port_setting_mitm_input_changed(self, event: Input.Changed) -> None:
Expand All @@ -304,6 +328,10 @@ def port_setting_xmlrpc_input_changed(self, event: Input.Changed) -> None:
def unlocker_setting_enable_checkbox_changed(self, event: Checkbox.Changed) -> None:
self.value_unlocker_setting_enable_checkbox = event.value

@on(Checkbox.Changed, "#helper_setting_checkbox")
def helper_setting_checkbox_changed(self, event: Checkbox.Changed) -> None:
self.value_helper_setting_checkbox = event.value

@on(Checkbox.Changed, "#unlocker_setting_v10_checkbox")
def unlocker_setting_v10_checkbox_changed(self, event: Checkbox.Changed) -> None:
self.value_unlocker_setting_v10_checkbox = event.value
Expand Down Expand Up @@ -336,13 +364,15 @@ def playwright_setting_width_input_changed(self, event: Input.Changed) -> None:
def playwright_setting_height_input_changed(self, event: Input.Changed) -> None:
self.value_playwright_setting_height_input = int(event.value)

def action_quit_setting(self) -> None:
@on(Button.Pressed, "#setting_save_button")
def setting_save_button_pressed(self) -> None:
with open("settings.json", "r") as f:
settings = json.load(f)
settings["Port"]["MITM"] = self.value_port_setting_mitm_input
settings["Port"]["XMLRPC"] = self.value_port_setting_xmlrpc_input
settings["Unlocker"] = self.value_unlocker_setting_enable_checkbox
settings["v10"] = self.value_unlocker_setting_v10_checkbox
settings["Helper"] = self.value_helper_setting_checkbox
settings["Autoplay"] = self.value_autoplay_setting_enable_checkbox
# settings["Autoplay"]["Random Time"]["Min"] = self.value_autoplay_setting_random_time_min_input
# settings["Autoplay"]["Random Time"]["Max"] = self.value_autoplay_setting_random_time_max_input
Expand All @@ -351,18 +381,13 @@ def action_quit_setting(self) -> None:
settings["Playwright"]["height"] = self.value_playwright_setting_height_input
with open("settings.json", "w") as f:
json.dump(settings, f, indent=4)
self.app.pop_screen()


class Akagi(App):
CSS_PATH = "client.tcss"

BINDINGS = [
# ("d", "toggle_dark", "Toggle dark mode"),
# ("a", "add_stopwatch", "Add"),
# ("r", "remove_stopwatch", "Remove"),
("ctrl+q", "quit", "Quit"),
("ctrl+s", "settings", "Settings")
]

def __init__(self, rpc_server, *args, **kwargs) -> None:
Expand All @@ -376,14 +401,15 @@ def __init__(self, rpc_server, *args, **kwargs) -> None:
self.mjai_msg_dict = dict() # flow.id -> List[mjai_msg]
self.akagi_log_dict= dict() # flow.id -> List[akagi_log]
self.loguru_log = [] # List[loguru_log]


self.mitm_started = False

def on_mount(self) -> None:
self.update_flow = self.set_interval(1, self.refresh_flow)
self.get_messages_flow = self.set_interval(0.05, self.get_messages)

def refresh_flow(self) -> None:
if not self.mitm_started:
return
flows = self.rpc_server.get_activated_flows()
for flow_id in self.active_flows:
if flow_id not in flows:
Expand Down Expand Up @@ -414,6 +440,8 @@ def refresh_flow(self) -> None:
self.bridge[flow_id] = MajsoulBridge()

def get_messages(self):
if not self.mitm_started:
return
for flow_id in self.active_flows:
messages = self.rpc_server.get_messages(flow_id)
if messages is not None:
Expand All @@ -438,27 +466,47 @@ def get_messages(self):
def compose(self) -> ComposeResult:
"""Called to add widgets to the app."""
yield Header()
yield Footer()
yield Button(label="Start MITM", variant="success", id="start_mitm_button")
yield SettingsScreen(id="settings_screen")
yield ScrollableContainer(id="FlowContainer")
yield Footer()

def on_event(self, event: Event) -> Coroutine[Any, Any, None]:
return super().on_event(event)


def on_button_pressed(self, event: Button.Pressed) -> None:
if event.button.id == "start_mitm_button":
self.query_one("#settings_screen").remove()
start_mitm()
event.button.variant = "default"
event.button.disabled = True
self.set_timer(5, self.mitm_connected)
pass

def mitm_connected(self):
self.mitm_started = True

def my_sink(self, message) -> None:
record = message.record
self.loguru_log.append(f"{record['time'].strftime('%H:%M:%S')} | {record['level'].name}\t | {record['message']}")

def action_quit(self) -> None:
self.update_flow.stop()
self.get_messages_flow.stop()
self.rpc_server.reset_message_idx()
self.exit()

def action_settings(self) -> None:
self.push_screen(SettingsScreen())
pass

def exit_handler():
global mitm_exec
try:
mitm_exec.kill()
except:
pass
pass

def start_mitm():
global mitm_exec
mitm_exec = Popen([executable, pathlib.Path(__file__).parent / "mitm.py"], creationflags=CREATE_NEW_CONSOLE)
pass

if __name__ == '__main__':
Expand All @@ -467,7 +515,6 @@ def exit_handler():
rpc_port = settings["Port"]["XMLRPC"]
rpc_host = "127.0.0.1"
s = ServerProxy(f"http://{rpc_host}:{rpc_port}", allow_none=True)
s.reset_message_idx()
logger.level("CLICK", no=10, icon="CLICK")
logger.add("akagi.log")
app = Akagi(rpc_server=s)
Expand Down
58 changes: 58 additions & 0 deletions client.tcss
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
#start_mitm_button {
width: 1fr;
align: center top;
margin: 1 1;
}

#log_container {
width: 1fr;
height: 2fr;
Expand Down Expand Up @@ -465,6 +471,29 @@ Button.action_nukidora.-active {
border-title-align: center;
}

#helper_setting_label {
padding: 1 0;
width: 11;
height: 3;
align: center middle;
margin: 0 1;
}

#helper_setting_checkbox {
width: 1fr;
align: center top;
margin: 0 1;
}

#helper_setting_container {
width: 1fr;
height: auto;
align: center top;
margin: 0;
border: round $accent;
border-title-align: center;
}

#port_setting_mitm_label {
padding: 1 0;
width: 11;
Expand Down Expand Up @@ -514,4 +543,33 @@ Button.action_nukidora.-active {
margin: 0;
border: round $accent;
border-title-align: center;
}

#remove_this_you_die {
width: 1fr;
height: auto;
align: center top;
margin: 1;
}

#setting_save_button {
width: 1fr;
height: auto;
align: center top;
margin: 1;
}

#setting_container {
width: 1fr;
height: auto;
align: center top;
}

.hover-link {
border: double $accent;
text-align: center;
}

.hover-link:hover {
border: double $secondary;
}
Loading

0 comments on commit a6d79f2

Please sign in to comment.