Giter Site home page Giter Site logo

apricot-s / majsoulrpa Goto Github PK

View Code? Open in Web Editor NEW
16.0 4.0 5.0 2.2 MB

A Robotic Process Automation (RPA) framework for Mahjong Soul (雀魂)

License: Other

Python 100.00%
mahjong mahjong-soul mahjongsoul majsoul python rpa automation automation-framework robotic-process-automation

majsoulrpa's Introduction

MajsoulRPA

A Robotic Process Automation (RPA) framework for Mahjong Soul (雀魂)

This is fork of Cryolite's majsoul-rpa with following changes.

  1. Requires Python 3.11 or later
  2. Removed dependencies on Docker and Redis
  3. Supports moving browser position after launch
  4. Mouse can be used freely even while RPA is running
  5. Supports browser viewport sizes other than 1920 x 1080
  6. Supports 3-player mahjong

Announcements

  • [2024/04/16] mode and length of HomePresentation.create_room can now be specified with non-literal variables. Please check the source code for details.
  • [2024/04/16] user_data_dir of RPA.__init__ can now be specified with pathlib.Path.
  • [2024/04/24] Added an optional argument user_data_dir to launch_remote_browser and --user_data_dir option to majsoulrpa_remote_browser.

About The Program

  • This program is intended to enable the participation of bots in friendly matches and tournaments where bot participation is explicitly allowed.
  • This program does not support the functionality to enter bots into matches that are open to unspecified individuals, including, but not limited to, ranked matches and special rooms within tournament matches. Furthermore, there is no intention to introduce such functionality in the future.
  • Users of this program accept full responsibility for its use. The authors shall bear no liability whatsoever for any damages resulting from utilization this program, including, but not limited to, account suspension or legal repercussions.

Implementation concept diagram

desktop

remote

how to setup

poetry install
poetry shell

License

Copyright (c) Apricot S. All rights reserved.

Licensed under the MIT license.

majsoulrpa's People

Contributors

0num4 avatar apricot-s avatar cryolite avatar smly avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

majsoulrpa's Issues

リモートブラウザがないときRPA.wait()が停止する

概要

リモートモードでRPAの接続先のリモートブラウザがないとき固まる
・タイムアウトを過ぎても処理が終了しない
・Ctrl+cが効かない
Loginの__init__内で止まっている

再現手順

majsoulrpa_remote_browserが起動していない状態で
リモートモードのRPAを起動し、RPA.wait()を実行する

To Be

リモートモードでRPAの接続先のリモートブラウザがないときも
・タイムアウトを過ぎるとTimeoutErrorを投げる
・Ctrl+cを入力するとKeyboardinterruptを投げる

開発方針・注意事項のREADMEへの追記

概要

開発方針と注意事項をREADMEに明記する

開発方針

許可のとれた身内での大会戦・友人戦に麻雀AIを参加させる等を想定している
段位戦参加機能は開発しない(プルリクが来てもrejectする)

注意事項

利用して運営からBANされるリスクなどの責任はとれないことを明記する

TODO

  • 他のRPAライブラリでの記載事項の調査
  • 記載内容原文の作成
  • 記載内容の英訳
  • README.mdへの追記

`majsoulrpa_remote_browser` コマンドを実行すると `ModuleNotFoundError` 例外が送出される

概要

majsoulrpa_remote_browser コマンドを実行すると ModuleNotFoundError 例外が送出される

再現手順

python3 -m pip . でインストール後, majsoulrpa_remote_browser コマンドを実行する.

As Is

以下の例外が送出されてコマンドの実行が終了する.

Traceback (most recent call last):
  File "C:\Users\Cryolite\Documents\work\majsoulrpa\.venv\Scripts\\majsoulrpa_remote_browser", line 3, in <module>
    from src.majsoulrpa.remote_browser._remote_browser import main
ModuleNotFoundError: No module named 'src'

To Be

リモートブラウザが正常に起動する.

ruffのnoqaを設定する

概要

コードにnoqaが散らばっているので設定頻度が多いものに関しては
pyproject.tomlに一括で設定する

・C901 → リファクタリング箇所の参考にするため一旦保留とする
・PLRの一部
init.pyのF401 → 代わりに__all__を設定する

EN版・CN版対応

概要

EN版、CN版に対応する

各国語版の違い

  • URL
  • 認証メールのアドレス
  • 画面の文字
  • (CN版のみ)ログインに認証コードではなくパスワードが必要
  • 表示言語の選択部が存在する

As Is

JP版のみ対応している

To Be

JP版、CN版(中文(简体)、中文(繫體))、EN版(English、中文(繁體)、한국어)に対応する

大会戦参加機能の実装

概要

大会戦に参加することができるようにする

進捗

  • テンプレート画像用のスクショを集める
  • ホーム画面から大会ロビーに移動する処理の実装
  • 大会ロビーから大会IDで検索する機能の実装
  • 大会名で検索する機能が必要か検討する → 実装しない方針に決定(#96 (comment) 参照)
  • 大会部屋で準備完了を押す機能の実装
  • 大会から対局に入ったときのWSメッセージをMatchPresentationで読み捨てる処理の実装
  • 大会の期間内か確認する処理が可能か調査
  • 対局から大会部屋に戻る処理の実装
  • 大会部屋からホーム画面に戻る処理の実装

Presentationが_implではなくRPAに依存するようにする

概要

各Presentationは現在_impl
BrowserBase, MessageQueueClientBase, PresentationCreatorBase
をメンバーに持っているが、できればRPAをメンバーに持つようにする
ただし、RPAのプライベートメンバーへのアクセスを避けつつ外部には非公開にする必要がある(要設計)

なぜ必要か

  • 現在の実装だと利用者はRPA.waitからしかPresentationBaseを受け取れず、自分で生成できない
  • RPA.close()にてBrowserBase, MessageQueueClientBaseを終了してもPresentationからの参照が残っているため
    _implのクラスの__del__が呼ばれない

To Be

Presentationクラスの__init___implのクラスではなくRPAクラスを与える
RPAはPresentationに各メンバーを公開する手段を持つ(フレームワーク利用者には非公開にする)

`remote_browser`にも`user_data_dir`を指定できるようにする

概要

ローカルブラウザではuser_data_dirの指定によってプロファイルを保存でき、
2回目以降の起動ではメールアドレス経由の認証を省略できる。

リモートブラウザでも同じ動作ができるようにする

To Be

launch_remote_browser関数、majsoulrpa_remote_browserコマンドにuser_data_dirを指定可能にする

メールアドレスの入力エラーを処理する

概要

メールアドレスの形式が間違っていても
正しいときと同様のボタンの表示待ち・タイムアウトが発生する。
また、メールアドレスの再入力ができないため、
メールアドレスの形式は正しいがtypoがあった場合に再入力できない。
(参考: メールアドレス欄の最大入力可能文字数は半角全角合わせて50文字までである。)

再現手順

  1. AuthPresentation.enter_email_address()にメールアドレスとして不正な文字列を渡す。
  2. 「コードを受け取る」がクリックされると「使用不可」の文字が出る(アドレスが長い場合「使」の下に重なる)。

To Be

  1. メールアドレスが最大入力文字数より多い(51文字以上)の場合は入力せずにValueErrorを投げる。
  2. メールアドレスの形式が間違っている(「使用不可」が出る)場合はValueErrorを投げる。
  3. メールアドレスの形式が正しいかに関わらず再入力できるようにする。

`HomePresentation.join_room` で指定した部屋への join が失敗した原因を識別したい

HomePresentation.join_room の戻り値の型は bool ですが,これだと False が返ってきたときに

  • 指定した ID の部屋が存在しない
  • 指定した ID の部屋が満員である
  • 指定した ID の部屋の対戦がすでに始まっている

のどれが原因で部屋への join が失敗したかが分からないです.上記3つはゲーム画面上のエラーメッセージとしては区別されているため, API を調べれば区別できる可能性が高いと思います(要調査).これが区別できるように join_room を拡張してほしいです.

RPA と Presentation*** の循環参照を解消する

概要

RPA と Presentation が循環参照になっている
設計の観点からも RPA.wait() は本来 presentation モジュール側のクラスのメソッドかトップレベルの関数になると思われる

As Is
Presentation*** の import を RPA.wait() メソッド内まで遅延させて循環インポートを回避している

To Be
RPA.wait() に相当するトップレベルの関数もしくは別クラスのメソッドを作成する
RPA.wait() を削除する (しばらくは非推奨の警告を出しつつ残す)

認証コードの入力エラーを処理する

概要

認証コードの入力が間違っていても
入力が正しいときと同様のボタンの表示待ち・タイムアウトが発生する。

再現手順

  1. メールアドレスを入力して認証コードが入力できるようにする。
  2. AuthPresentation.enter_auth_code()に誤った認証コードを渡す
  3. 「認証失敗。後ほど再度お試しください」と「確認」ボタンが表示される
    (4. 「確認」をクリックするとログイン画面になる)
    (5. 「ログイン」ボタンをクリックするとメールアドレスは入力済みである)

To Be

認証コードの形式(半角数字6桁)が誤っていた場合は画面に入力せずにValueErrorを投げる
認証コードが誤っていた場合「確認」をクリック後「ログイン」をクリックして認証画面に戻ってからValueErrorを投げる

protocへの依存を削除する

概要

protocはZMQClientが未知のAPIを受け取ったとき、エラーメッセージにデコードしたAPIを表示するためだけに必要である
未知のAPIに対応するには新しいliqi.jsonからliqi_pb2.pyを作成して差し替えるしかないため、
ユーザーにとってはエラーメッセージを表示する必要性は薄い
稀な事象でのスクショと同様に、バイナリ(bytes)の生データをそのままバイナリファイルに保存するだけでいいと思われる
その場合、ユーザーがインストールするソフトウェアを減らすことができる

As Is

ZMQClientが未知のAPIを受け取ったとき、
protocを使用してWebSocketメッセージをデコードし、その結果をエラーメッセージとして表示する

そのためにユーザーはprotocのインストールが必要となる

To Be

ZMQClientが未知のAPIを受け取ったとき、
WebSocketメッセージのバイナリをそのままファイルに保存する

ユーザーはprotocをインストールする必要がない

イベントアイテム入手の際、「確認」が出ない状態で1回クリックが必要となる

概要

イベント期間中は対局後イベントアイテムを獲得することがある。
獲得後次の画面に進むためには画面をクリックする必要があるが、現在対応していないので対処する。

イベントアイテムを獲得したとき

  • 画面にはアイテムのアイコンのみ表示され、「確認」ボタンが表示されない。
  • 画面をクリックしない限り次の画面に進まない。クリック位置は画面のどこでもよい。
  • 一回画面をクリックをすれば「確認」ボタンが表示される。

(2024/01/31アップデート後のイベントで確認)
match_event_item

As Is

イベント期間中の対局後にイベントアイテムを獲得したとき、
アイテムを獲得した後の画面から次の画面(友人戦部屋など)に遷移しない。

To Be

イベント期間中の対局後にイベントアイテムを獲得した場合も正常に次の画面に遷移する。

リモートブラウザを起動しようとすると `net::ERR_PROXY_CONNECTION_FAILED` 例外が送出される場合がある

概要

リモートブラウザを起動しようとすると net::ERR_PROXY_CONNECTION_FAILED 例外が送出される場合がある.

再現手順

リモートブラウザの起動を試みる.ただし,タイミングに関するバグと推測されるため,必ずしも再現されるとは限らない.

原因

リモートブラウザの起動に関する実装において, sniffer プロセスの起動直後にブラウザを起動している.

sniffer_process = Popen(sniffer_args) # noqa: S603
try:
initial_position = f"--window-position={initial_left},{initial_top}"
proxy_server = f"--proxy-server=http://localhost:{proxy_port}"
ignore_certifi_errors = "--ignore-certificate-errors"
options = [initial_position, proxy_server, ignore_certifi_errors]
viewport_size = {"width": viewport_width, "height": viewport_height}
mute_audio_off = None if headless else ["--mute-audio"]
with (
sync_playwright() as playwright,
playwright.chromium.launch(
args=options,
ignore_default_args=mute_audio_off,
headless=headless,
) as browser,

この結果, sniffer プロセスがプロキシポートの listen を開始する前にブラウザがプロキシポートに接続しようとする可能性がある.この場合,プロキシポートがまだ開いていないため,ブラウザがプロキシに接続できず net::ERR_PROXY_CONNECTION_FAILED 例外を送出するものと推測される.

As Is

以下の例外が送出される.

Traceback (most recent call last):
  File "/root/majsoulrpa/.venv/bin/majsoulrpa_remote_browser", line 8, in <module>
    sys.exit(main())
             ^^^^^^
  File "/root/majsoulrpa/.venv/lib/python3.12/site-packages/majsoulrpa/remote_browser/_remote_browser.py", line 252, in main
    launch_remote_browser(
  File "/root/majsoulrpa/.venv/lib/python3.12/site-packages/majsoulrpa/remote_browser/_remote_browser.py", line 226, in launch_remote_browser
    _launch_remote_browser_core(
  File "/root/majsoulrpa/.venv/lib/python3.12/site-packages/majsoulrpa/remote_browser/_remote_browser.py", line 75, in _launch_remote_browser_core
    page.goto(URL_MAJSOUL)
  File "/root/majsoulrpa/.venv/lib/python3.12/site-packages/playwright/sync_api/_generated.py", line 9312, in goto
    self._sync(
  File "/root/majsoulrpa/.venv/lib/python3.12/site-packages/playwright/_impl/_sync_base.py", line 115, in _sync
    return task.result()
           ^^^^^^^^^^^^^
  File "/root/majsoulrpa/.venv/lib/python3.12/site-packages/playwright/_impl/_page.py", line 475, in goto
    return await self._main_frame.goto(**locals_to_params(locals()))
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/root/majsoulrpa/.venv/lib/python3.12/site-packages/playwright/_impl/_frame.py", line 139, in goto
    await self._channel.send("goto", locals_to_params(locals()))
  File "/root/majsoulrpa/.venv/lib/python3.12/site-packages/playwright/_impl/_connection.py", line 62, in send
    return await self._connection.wrap_api_call(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/root/majsoulrpa/.venv/lib/python3.12/site-packages/playwright/_impl/_connection.py", line 492, in wrap_api_call
    return await cb()
           ^^^^^^^^^^
  File "/root/majsoulrpa/.venv/lib/python3.12/site-packages/playwright/_impl/_connection.py", line 100, in inner_send
    result = next(iter(done)).result()
             ^^^^^^^^^^^^^^^^^^^^^^^^^
playwright._impl._errors.Error: net::ERR_PROXY_CONNECTION_FAILED at https://game.mahjongsoul.com/

To Be

リモートブラウザが正常に起動する.

毎朝6時をまたぐ試合がエラーとなる

毎朝6時にはクエスト更新やショップの更新などの通知メッセージがあります。そのため試合が6時をまたがって行われた場合、以下のメッセージを受け取ります。

  • ('inbound', '.lq.NotifyActivityTaskUpdate', {'progresses': ...})
  • ('outbound', '.lq.Lobby.fetchShopInterval', ...)

MatchPresentation では対応できていないためエラーとなります。
_on_end_of_match() などのメッセージを dequeue する処理において、上述したメッセージを dequeue してもエラーが発生しないよう修正する必要があります。

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.