From 815b1d3d3826f415173a675a50f179f865a8be7d Mon Sep 17 00:00:00 2001 From: gakkiyomi Date: Tue, 24 Dec 2024 20:34:22 +0800 Subject: [PATCH] Bumped to version v2.1.9 --- setup.py | 3 +- src/api/__init__.py | 92 ------- src/api/article.py | 5 +- src/api/base.py | 3 +- src/api/bolo.py | 2 +- src/api/chat.py | 5 +- src/api/chatroom.py | 5 +- src/api/config.py | 151 ------------ src/api/user.py | 5 +- src/config/__init__.py | 43 ++++ src/config/auth.py | 26 ++ src/config/bolo.py | 17 ++ src/config/chat.py | 43 ++++ src/config/redpacket.py | 25 ++ src/core/__init__.py | 380 +---------------------------- src/core/blacklist.py | 4 +- src/core/chat.py | 4 +- src/core/chatroom.py | 6 +- src/core/command.py | 51 ++-- src/core/fishpi.py | 92 +++++++ src/core/initor/__init__.py | 26 ++ src/core/initor/bolo_initor.py | 12 + src/core/initor/chatroom_initor.py | 17 ++ src/core/initor/cli_initor.py | 34 +++ src/core/initor/defualt_initor.py | 16 ++ src/core/initor/env_initor.py | 24 ++ src/core/initor/file_initor.py | 187 ++++++++++++++ src/core/initor/init_chan.py | 48 ++++ src/core/initor/login_initor.py | 62 +++++ src/core/notification.py | 2 +- src/core/redpacket.py | 4 +- src/core/user.py | 7 +- src/{api => core}/ws.py | 2 +- src/main.py | 6 +- src/utils/version.py | 2 +- 35 files changed, 729 insertions(+), 682 deletions(-) delete mode 100644 src/api/config.py create mode 100644 src/config/__init__.py create mode 100644 src/config/auth.py create mode 100644 src/config/bolo.py create mode 100644 src/config/chat.py create mode 100644 src/config/redpacket.py create mode 100644 src/core/fishpi.py create mode 100644 src/core/initor/__init__.py create mode 100644 src/core/initor/bolo_initor.py create mode 100644 src/core/initor/chatroom_initor.py create mode 100644 src/core/initor/cli_initor.py create mode 100644 src/core/initor/defualt_initor.py create mode 100644 src/core/initor/env_initor.py create mode 100644 src/core/initor/file_initor.py create mode 100644 src/core/initor/init_chan.py create mode 100644 src/core/initor/login_initor.py rename src/{api => core}/ws.py (98%) diff --git a/setup.py b/setup.py index f5dd4a5..cd40f23 100644 --- a/setup.py +++ b/setup.py @@ -98,7 +98,8 @@ def run(self): author_email=EMAIL, python_requires=REQUIRES_PYTHON, url=URL, - packages=['src', 'src/api', 'src/core', 'src/utils'], + packages=['src', 'src/api', 'src/core', + 'src/utils', 'src/config', 'src/core/initor'], # If your package is a single module, use this instead of 'packages': # py_modules=['mypackage'], diff --git a/src/api/__init__.py b/src/api/__init__.py index f6c6a75..40a96af 100644 --- a/src/api/__init__.py +++ b/src/api/__init__.py @@ -1,93 +1 @@ # -*- coding: utf-8 -*- -import json -from typing import Any - -import requests - -from src.api.base import Base -from src.utils import UA - -from .article import ArticleAPI -from .chat import ChatAPI -from .chatroom import ChatRoomAPI -from .config import GLOBAL_CONFIG -from .user import UserAPI - - -class UserInfo(object): - - def __init__(self, username: str, password: str, api_key: str) -> None: - self.username = username - self.password = password - self.api_key = api_key - self.ws: dict[str, Any] = {} - self.in_chatroom = False - - def online(self, *funcs) -> None: - if (len(self.api_key) != 0): - API.set_token(self.api_key) - API.set_current_user(self.username) - else: - API.login(self.username, self.password) - self.api_key = API.api_key - for func in funcs: - func() - self.in_chatroom = True - GLOBAL_CONFIG.auth_config.username = self.username - GLOBAL_CONFIG.auth_config.password = self.password - GLOBAL_CONFIG.auth_config.key = self.api_key - API.user_key_write_to_config_file() - - def out_chatroom(self) -> None: - if 'fishpi.cn/chat-room-channel' in self.ws: - self.ws['fishpi.cn/chat-room-channel'].stop() - self.in_chatroom = False - - def offline(self) -> None: - keys = list(self.ws.keys()) - for key in keys: - self.ws[key].stop() - self.in_chatroom = False - - def out_chat(self) -> None: - if 'fishpi.cn/chat-channel' in self.ws: - self.ws['fishpi.cn/chat-channel'].stop() - - def chat(self, func) -> None: - self.out_chat() - self.out_chatroom() - func() - - -class FishPi(Base): - def __init__(self): - self.sockpuppets: dict[str, UserInfo] = {} - self.user = UserAPI() - self.chatroom = ChatRoomAPI() - self.article = ArticleAPI() - self.chat = ChatAPI() - super().__init__(self) - - def set_token(self, key): - super().set_token(key) - self.user.set_token(key) - self.chatroom.set_token(key) - self.article.set_token(key) - self.chat.set_token(key) - - def get_current_user(self): - return self.sockpuppets[self.current_user] - - def get_breezemoons(self, page: int = 1, size: int = 10) -> dict | None: - res = requests.get( - f'{GLOBAL_CONFIG.host}/api/breezemoons?p={page}&size={size}', headers={'User-Agent': UA}) - print(res.text) - response = json.loads(res.text) - if 'code' in response and response['code'] == 0: - return response['breezemoons'] - else: - print(response['msg']) - return None - - -API = FishPi() diff --git a/src/api/article.py b/src/api/article.py index 6942e7f..bd6fb53 100644 --- a/src/api/article.py +++ b/src/api/article.py @@ -8,11 +8,10 @@ import requests from bs4 import BeautifulSoup -from src.api import Base +from src.api.base import Base +from src.config import GLOBAL_CONFIG from src.utils import UA -from .config import GLOBAL_CONFIG - class ArticleType(Enum): RECENT = 'recent' diff --git a/src/api/base.py b/src/api/base.py index 0b20a21..8d1b539 100644 --- a/src/api/base.py +++ b/src/api/base.py @@ -7,10 +7,9 @@ import requests +from src.config import GLOBAL_CONFIG from src.utils import HELP, UA -from .config import GLOBAL_CONFIG - class Base(object): def __init__(self, key=''): diff --git a/src/api/bolo.py b/src/api/bolo.py index fd8e34e..2b79a5c 100644 --- a/src/api/bolo.py +++ b/src/api/bolo.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- import requests -from src.api.config import GLOBAL_CONFIG +from src.config import GLOBAL_CONFIG from src.utils import UA diff --git a/src/api/chat.py b/src/api/chat.py index 6891f8b..4f7fe50 100644 --- a/src/api/chat.py +++ b/src/api/chat.py @@ -3,11 +3,10 @@ import requests +from src.api.base import Base +from src.config import GLOBAL_CONFIG from src.utils import UA -from .base import Base -from .config import GLOBAL_CONFIG - class ChatAPI(Base): diff --git a/src/api/chatroom.py b/src/api/chatroom.py index 4a697e0..0b656b4 100644 --- a/src/api/chatroom.py +++ b/src/api/chatroom.py @@ -4,13 +4,12 @@ import requests -from src.api import Base +from src.api.base import Base from src.api.redpacket import RedPacket, RedPacketType +from src.config import GLOBAL_CONFIG from src.utils import UA from src.utils.version import __version__ -from .config import GLOBAL_CONFIG - class ChatRoomAPI(Base): diff --git a/src/api/config.py b/src/api/config.py deleted file mode 100644 index f24de60..0000000 --- a/src/api/config.py +++ /dev/null @@ -1,151 +0,0 @@ -# -*- coding: utf-8 -*- -import configparser - -from src.utils import HOST - - -class RedPacketConfig(object): - def __init__(self, red_packet_switch=True, heartbeat=True, smart_mode=True, threshold=0.5, adventure_mode=True, - timeout=7, rate=3, rps_limit=100): - self.red_packet_switch = red_packet_switch - self.heartbeat = heartbeat - self.smart_mode = smart_mode - self.threshold = threshold - self.adventure_mode = adventure_mode - self.timeout = timeout - self.rate = rate - self.rps_limit = rps_limit - - def to_config(self) -> dict: - return { - 'openRedPacket': str(self.red_packet_switch), - 'rate': str(self.rate), - 'rpsLimit': str(self.rps_limit), - 'heartbeat': str(self.heartbeat), - 'heartbeatSmartMode': str(self.smart_mode), - 'heartbeatThreshold': str(self.threshold), - 'heartbeatTimeout': str(self.timeout), - 'heartbeatAdventure': str(self.adventure_mode), - } - - -class BoloConfig(object): - - def __init__(self, host: str, username: str, password: str): - self.host = host - self.username = username - self.password = password - self.cookie = '' - - def to_config(self) -> dict: - return { - 'host': self.host, - 'username': self.username, - 'password': self.password, - 'cookie': self.cookie, - } - - -class AuthConfig(object): - def __init__(self, username='', password='', mfa_code='', key=''): - self.username = username - self.password = password - self.mfa_code = mfa_code - self.key = key - self.accounts: list[tuple[str, ...]] = [] - - def add_account(self, username='', password=''): - self.accounts.append((username, password)) - - def to_config(self) -> dict: - usernames = '' - passwords = '' - if len(self.accounts) != 0: - usernames = ",".join(username for username, _ in self.accounts) - usernames = ",".join(password for password, _ in self.accounts) - return { - 'username': self.username, - 'password': self.password, - 'key': self.key, - 'sockpuppet_usernames': usernames, - 'sockpuppet_passwords': passwords - } - - -class ChatConfig(object): - def __init__(self, blacklist: list[str] = [], kw_notification: list[str] = [], kw_blacklist: list[str] = ['你点的歌来了'], repeat_mode_switch=False, frequency=5, soliloquize_switch=False, - soliloquize_frequency=20, sentences: list[str] = [], answer_mode: bool = False, fish_ball: str = '凌 捞鱼丸', - chat_user_color: str | None = None, chat_content_color: str | None = None, output_mode: str = 'console', output_path: str = None): - self.repeat_mode_switch = repeat_mode_switch - self.frequency = frequency - self.soliloquize_switch = soliloquize_switch - self.soliloquize_frequency = soliloquize_frequency - self.sentences = ['你们好!', '牵着我的手,闭着眼睛走你也不会迷路。', - '吃饭了没有?', '💗 爱你哟!'] + sentences - self.blacklist = blacklist - self.kw_blacklist = kw_blacklist - self.kw_notification = kw_notification - self.answer_mode = answer_mode - self.fish_ball = fish_ball - self.chat_user_color = chat_user_color - self.chat_content_color = chat_content_color - self.output_mode = output_mode - self.output_path = output_path - - def to_config(self) -> dict: - res = { - 'fishBall': str(self.fish_ball), - 'repeatMode': str(self.repeat_mode_switch), - 'answerMode': str(self.answer_mode), - 'repeatFrequency': str(self.frequency), - 'soliloquizeMode': str(self.soliloquize_switch), - 'soliloquizeFrequency': str(self.soliloquize_frequency), - 'sentences': '[' + ",".join('\"'+item+'\"' for item in self.sentences) + ']', - 'blacklist': '[' + ",".join('\"'+item+'\"' for item in self.blacklist) + ']', - 'kwBlacklist': '[' + ",".join('\"'+item+'\"' for item in self.kw_blacklist) + ']', - 'kwNotification': '[' + ",".join('\"'+item+'\"' for item in self.kw_notification) + ']', - 'chatUserColor': self.chat_user_color, - 'chatContentColor': self.chat_content_color, - 'outputMode': self.output_mode, - 'outputPath': self.output_path - } - - if self.chat_user_color is None: - res['chatUserColor'] = '' - if self.chat_user_color is None: - res['chatContentColor'] = '' - return res - - -class Config(object): - def __init__(self, auth: AuthConfig = None, redpacket: RedPacketConfig = None, chat: ChatConfig = None, bolo: BoloConfig = None, cfg_path: str = None, host: str = 'https://fishpi.cn'): - self.auth_config = auth - self.redpacket_config = redpacket - self.chat_config = chat - self.bolo_config = bolo - self.cfg_path = cfg_path - self.host = host - - def to_ini_template(self) -> configparser.ConfigParser: - config = configparser.ConfigParser() - config['auth'] = self.auth_config.to_config() - config['redPacket'] = self.redpacket_config.to_config() - config['chat'] = self.chat_config.to_config() - config['bolo'] = self.bolo_config.to_config() - return config - - -class CliOptions(object): - def __init__(self, username: str = '', password: str = '', code: str = '', file_path: str = None, host: str = None): - self.username = username - self.password = password - self.code = code - self.file_path = file_path - self.host = host - - -def init_defualt_config() -> Config: - return Config(AuthConfig(), RedPacketConfig(), ChatConfig(), BoloConfig('', '', ''), None, HOST) - - -GLOBAL_CONFIG = Config() diff --git a/src/api/user.py b/src/api/user.py index 7f8e632..9ca2380 100644 --- a/src/api/user.py +++ b/src/api/user.py @@ -4,11 +4,10 @@ import requests -from src.api import Base +from src.api.base import Base +from src.config import GLOBAL_CONFIG from src.utils import UA -from .config import GLOBAL_CONFIG - class UserAPI(Base): diff --git a/src/config/__init__.py b/src/config/__init__.py new file mode 100644 index 0000000..77a8bca --- /dev/null +++ b/src/config/__init__.py @@ -0,0 +1,43 @@ +# -*- coding: utf-8 -*- +import configparser + +from src.utils import HOST + +from .auth import AuthConfig +from .bolo import BoloConfig +from .chat import ChatConfig +from .redpacket import RedPacketConfig + + +class Config(object): + def __init__(self, auth: AuthConfig = None, redpacket: RedPacketConfig = None, chat: ChatConfig = None, bolo: BoloConfig = None, cfg_path: str = None, host: str = 'https://fishpi.cn'): + self.auth_config = auth + self.redpacket_config = redpacket + self.chat_config = chat + self.bolo_config = bolo + self.cfg_path = cfg_path + self.host = host + + def to_ini_template(self) -> configparser.ConfigParser: + config = configparser.ConfigParser() + config['auth'] = self.auth_config.to_config() + config['redPacket'] = self.redpacket_config.to_config() + config['chat'] = self.chat_config.to_config() + config['bolo'] = self.bolo_config.to_config() + return config + + +class CliOptions(object): + def __init__(self, username: str = '', password: str = '', code: str = '', file_path: str = None, host: str = None): + self.username = username + self.password = password + self.code = code + self.file_path = file_path + self.host = host + + +def init_defualt_config() -> Config: + return Config(AuthConfig(), RedPacketConfig(), ChatConfig(), BoloConfig('', '', ''), None, HOST) + + +GLOBAL_CONFIG = Config() diff --git a/src/config/auth.py b/src/config/auth.py new file mode 100644 index 0000000..65c11f3 --- /dev/null +++ b/src/config/auth.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- + +class AuthConfig(object): + def __init__(self, username='', password='', mfa_code='', key=''): + self.username = username + self.password = password + self.mfa_code = mfa_code + self.key = key + self.accounts: list[tuple[str, ...]] = [] + + def add_account(self, username='', password=''): + self.accounts.append((username, password)) + + def to_config(self) -> dict: + usernames = '' + passwords = '' + if len(self.accounts) != 0: + usernames = ",".join(username for username, _ in self.accounts) + usernames = ",".join(password for password, _ in self.accounts) + return { + 'username': self.username, + 'password': self.password, + 'key': self.key, + 'sockpuppet_usernames': usernames, + 'sockpuppet_passwords': passwords + } diff --git a/src/config/bolo.py b/src/config/bolo.py new file mode 100644 index 0000000..eb33234 --- /dev/null +++ b/src/config/bolo.py @@ -0,0 +1,17 @@ +# -*- coding: utf-8 -*- + +class BoloConfig(object): + + def __init__(self, host: str, username: str, password: str): + self.host = host + self.username = username + self.password = password + self.cookie = '' + + def to_config(self) -> dict: + return { + 'host': self.host, + 'username': self.username, + 'password': self.password, + 'cookie': self.cookie, + } diff --git a/src/config/chat.py b/src/config/chat.py new file mode 100644 index 0000000..81a9009 --- /dev/null +++ b/src/config/chat.py @@ -0,0 +1,43 @@ +class ChatConfig(object): + def __init__(self, blacklist: list[str] = [], kw_notification: list[str] = [], kw_blacklist: list[str] = ['你点的歌来了'], repeat_mode_switch=False, frequency=5, soliloquize_switch=False, + soliloquize_frequency=20, sentences: list[str] = [], answer_mode: bool = False, fish_ball: str = '凌 捞鱼丸', + chat_user_color: str | None = None, chat_content_color: str | None = None, output_mode: str = 'console', output_path: str = None): + self.repeat_mode_switch = repeat_mode_switch + self.frequency = frequency + self.soliloquize_switch = soliloquize_switch + self.soliloquize_frequency = soliloquize_frequency + self.sentences = ['你们好!', '牵着我的手,闭着眼睛走你也不会迷路。', + '吃饭了没有?', '💗 爱你哟!'] + sentences + self.blacklist = blacklist + self.kw_blacklist = kw_blacklist + self.kw_notification = kw_notification + self.answer_mode = answer_mode + self.fish_ball = fish_ball + self.chat_user_color = chat_user_color + self.chat_content_color = chat_content_color + self.output_mode = output_mode + self.output_path = output_path + + def to_config(self) -> dict: + res = { + 'fishBall': str(self.fish_ball), + 'repeatMode': str(self.repeat_mode_switch), + 'answerMode': str(self.answer_mode), + 'repeatFrequency': str(self.frequency), + 'soliloquizeMode': str(self.soliloquize_switch), + 'soliloquizeFrequency': str(self.soliloquize_frequency), + 'sentences': '[' + ",".join('\"'+item+'\"' for item in self.sentences) + ']', + 'blacklist': '[' + ",".join('\"'+item+'\"' for item in self.blacklist) + ']', + 'kwBlacklist': '[' + ",".join('\"'+item+'\"' for item in self.kw_blacklist) + ']', + 'kwNotification': '[' + ",".join('\"'+item+'\"' for item in self.kw_notification) + ']', + 'chatUserColor': self.chat_user_color, + 'chatContentColor': self.chat_content_color, + 'outputMode': self.output_mode, + 'outputPath': self.output_path + } + + if self.chat_user_color is None: + res['chatUserColor'] = '' + if self.chat_user_color is None: + res['chatContentColor'] = '' + return res diff --git a/src/config/redpacket.py b/src/config/redpacket.py new file mode 100644 index 0000000..774b1c0 --- /dev/null +++ b/src/config/redpacket.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- + +class RedPacketConfig(object): + def __init__(self, red_packet_switch=True, heartbeat=True, smart_mode=True, threshold=0.5, adventure_mode=True, + timeout=7, rate=3, rps_limit=100): + self.red_packet_switch = red_packet_switch + self.heartbeat = heartbeat + self.smart_mode = smart_mode + self.threshold = threshold + self.adventure_mode = adventure_mode + self.timeout = timeout + self.rate = rate + self.rps_limit = rps_limit + + def to_config(self) -> dict: + return { + 'openRedPacket': str(self.red_packet_switch), + 'rate': str(self.rate), + 'rpsLimit': str(self.rps_limit), + 'heartbeat': str(self.heartbeat), + 'heartbeatSmartMode': str(self.smart_mode), + 'heartbeatThreshold': str(self.threshold), + 'heartbeatTimeout': str(self.timeout), + 'heartbeatAdventure': str(self.adventure_mode), + } diff --git a/src/core/__init__.py b/src/core/__init__.py index 3c62aab..40a96af 100644 --- a/src/core/__init__.py +++ b/src/core/__init__.py @@ -1,379 +1 @@ -import json -import os -import re -from abc import ABC, abstractmethod -from configparser import ConfigParser, NoOptionError -from typing import Any - -import schedule -from colorama import just_fix_windows_console - -from src.api import FishPi, UserInfo, bolo -from src.api.config import ( - GLOBAL_CONFIG, - ChatConfig, - CliOptions, - RedPacketConfig, - init_defualt_config, -) -from src.utils import HOST, HOST_RE, cli_login - -from .chatroom import ChatRoom, init_soliloquize -from .command import init_cli -from .user import User - - -class Initor(ABC): - def __init__(self, next=None): - self.next = next - - def __iter__(self): - node = self - while node is not None: - yield node - node = node.next - - @abstractmethod - def exec(self, api: FishPi, options: CliOptions) -> None: - pass - - def init(self, api: FishPi, options: CliOptions) -> None: - self.exec(api, options) - self.next.init(api, options) - - -class DefualtConfigInitor(Initor): - def exec(self, api: FishPi, options: CliOptions) -> None: - print("生成默认配置") - defualt = init_defualt_config() - GLOBAL_CONFIG.auth_config = defualt.auth_config - GLOBAL_CONFIG.redpacket_config = defualt.redpacket_config - GLOBAL_CONFIG.chat_config = defualt.chat_config - GLOBAL_CONFIG.bolo_config = defualt.bolo_config - GLOBAL_CONFIG.cfg_path = defualt.cfg_path - GLOBAL_CONFIG.host = defualt.host - - -class EnvConfigInitor(Initor): - def exec(self, api: FishPi, options: CliOptions) -> None: - GLOBAL_CONFIG.auth_config.username = os.environ.get( - "FISH_PI_USERNAME", '') - GLOBAL_CONFIG.auth_config.password = os.environ.get( - "FISH_PI_PASSWORD", '') - GLOBAL_CONFIG.auth_config.key = os.environ.get('FISH_PI_KEY', '') - GLOBAL_CONFIG.bolo_config.username = os.environ.get( - "BOLO_USERNAME", '') - GLOBAL_CONFIG.bolo_config.password = os.environ.get( - "BOLO_PASSWORD", '') - GLOBAL_CONFIG.bolo_config.cookie = os.environ.get( - "BOLO_COOKIE", '') - GLOBAL_CONFIG.bolo_config.host = os.environ.get( - "BOLO_HOST", '') - - -class FileConfigInitor(Initor): - def exec(self, api: FishPi, options: CliOptions) -> None: - file_path = options.file_path - if file_path is None: - file_path = f'{os.getcwd()}/config.ini' - config = ConfigParser() - try: - print("配置读取中...") - if not os.path.exists(file_path): - print(f'{file_path}配置文件不存在') - else: - config.read(file_path, encoding='utf-8') - init_auth_config(config) - init_bolo_config(config) - GLOBAL_CONFIG.redpacket_config = int_redpacket_config(config) - GLOBAL_CONFIG.chat_config = init_chat_config(config) - GLOBAL_CONFIG.cfg_path = file_path - GLOBAL_CONFIG.host = init_host_config(config) - except Exception: - print(f'{file_path}配置文件不合法') - - -class CilConfigInitor(Initor): - def exec(self, api: FishPi, options: CliOptions) -> None: - init_userinfo_with_options(options) - just_fix_windows_console() - - -def _login_with_key(api: FishPi) -> None: - username = api.user.get_username_by_key( - GLOBAL_CONFIG.auth_config.key) - if username is not None: - GLOBAL_CONFIG.auth_config.username = username - api.set_token(GLOBAL_CONFIG.auth_config.key) - api.set_current_user(GLOBAL_CONFIG.auth_config.username) - else: - print("非法API-KEY, 使用账户密码登陆") - while len(GLOBAL_CONFIG.auth_config.username) == 0: - print('请输入用户名:') - GLOBAL_CONFIG.auth_config.username = input("") - while len(GLOBAL_CONFIG.auth_config.password) == 0: - print('请输入密码:') - GLOBAL_CONFIG.auth_config.password = input("") - api.login(GLOBAL_CONFIG.auth_config.username, - GLOBAL_CONFIG.auth_config.password, - GLOBAL_CONFIG.auth_config.mfa_code) - GLOBAL_CONFIG.auth_config.key = api.api_key - if cli_login(GLOBAL_CONFIG.auth_config.username): - api.user_key_write_to_config_file() - - -def _login_without_key(api: FishPi) -> None: - while len(GLOBAL_CONFIG.auth_config.username) == 0: - print('请输入用户名:') - GLOBAL_CONFIG.auth_config.username = input("") - while len(GLOBAL_CONFIG.auth_config.password) == 0: - print('请输入密码:') - GLOBAL_CONFIG.auth_config.password = input("") - api.login(GLOBAL_CONFIG.auth_config.username, - GLOBAL_CONFIG.auth_config.password, - GLOBAL_CONFIG.auth_config.mfa_code) - GLOBAL_CONFIG.auth_config.key = api.api_key - if cli_login(GLOBAL_CONFIG.auth_config.username): - api.user_key_write_to_config_file() - - -class LoginInitor(Initor): - def exec(self, api: FishPi, options: CliOptions) -> None: - os.environ['NO_PROXY'] = GLOBAL_CONFIG.host - if GLOBAL_CONFIG.auth_config.key == '': - _login_without_key(api) - else: - # 直接使用api-key - _login_with_key(api) - if len(GLOBAL_CONFIG.auth_config.accounts) != 0: - api.sockpuppets = {account[0]: UserInfo( - account[0], account[1], '') for account in GLOBAL_CONFIG.auth_config.accounts} - api.sockpuppets[api.current_user] = UserInfo( - api.current_user, GLOBAL_CONFIG.auth_config.password, api.api_key) - User().online(api.sockpuppets[api.current_user]) - - -class BoloLoginInitor(Initor): - def exec(self, api: FishPi, options: CliOptions) -> None: - if GLOBAL_CONFIG.bolo_config.cookie == '' and (GLOBAL_CONFIG.bolo_config.username != '' and GLOBAL_CONFIG.bolo_config.password != ''): - # try login bolo - bolo.bolo_login() - - -class ChaRoomInitor(Initor): - def exec(self, api: FishPi, options: CliOptions) -> None: - init_soliloquize(api) - if GLOBAL_CONFIG.chat_config.soliloquize_switch: - schedule.run_pending() - api.get_current_user().in_chatroom = True - chatroom = ChatRoom() - chatroom.start() - - -class CliInitor(Initor): - def exec(self, api: FishPi, options: CliOptions) -> None: - init_cli(api) - - -class InitChain(object): - def __init__(self, api: FishPi = None, options: CliOptions = None) -> None: - self.head: Initor = None - self.api = api - self.options = options - - def __call__(self, *args: Any, **kwds: Any) -> None: - self.api = kwds['api'] - self.options = kwds['options'] - self.init() - - def append(self, *args) -> None: - curr_node = self.head - initors = (i for i in args) - if curr_node is None: - self.head = next(initors) - curr_node = self.head - for initor in initors: - curr_node.next = initor - curr_node = curr_node.next - - def init(self): - self.append(DefualtConfigInitor(), - EnvConfigInitor(), - FileConfigInitor(), - CilConfigInitor(), - LoginInitor(), - BoloLoginInitor(), - ChaRoomInitor(), - CliInitor()) - self.head.init(self.api, self.options) - - -def int_redpacket_config(config: ConfigParser) -> RedPacketConfig: - ret = RedPacketConfig() - if config.getint('redPacket', 'rate') > 0: - ret.rate = config.getint('redPacket', 'rate') - if config.getint('redPacket', 'rpsLimit') > 0: - ret.rps_limit = config.getint('redPacket', 'rpsLimit') - ret.red_packet_switch = config.getboolean( - 'redPacket', 'openRedPacket') - ret.heartbeat = config.getboolean( - 'redPacket', 'heartbeat') - ret.smart_mode = config.getboolean( - 'redPacket', 'heartbeatSmartMode') - ret.adventure_mode = config.getboolean( - 'redPacket', 'heartbeatAdventure') - if config.getfloat('redPacket', 'heartbeatThreshold') < 0: - ret.threshold = 0.4 - else: - ret.threshold = config.getfloat('redPacket', 'heartbeatThreshold') - if ret.threshold > 1: - ret.threshold = 1 - ret.timeout = config.getint( - 'redPacket', 'heartbeatTimeout') - return ret - - -def init_auth_config(config: ConfigParser) -> None: - try: - if len(config.get('auth', 'username')) != 0: - GLOBAL_CONFIG.auth_config.username = '' - GLOBAL_CONFIG.auth_config.password = '' - GLOBAL_CONFIG.auth_config.key = '' - GLOBAL_CONFIG.auth_config.username = config.get('auth', 'username') - except NoOptionError: - pass - try: - if len(config.get('auth', 'password')) != 0: - GLOBAL_CONFIG.auth_config.password = config.get('auth', 'password') - except NoOptionError: - pass - try: - if len(config.get('auth', 'key')) != 0: - GLOBAL_CONFIG.auth_config.key = config.get('auth', 'key') - except NoOptionError: - pass - init_sockpuppets(config) - - -def init_sockpuppets(config: ConfigParser) -> None: - try: - sockpuppet_usernames = [] - sockpuppet_passwords = [] - usernames = config.get( - 'auth', 'sockpuppet_usernames') - if len(usernames) != 0: - sockpuppet_usernames = usernames.replace(',', ',').split(',') - passwords = config.get( - 'auth', 'sockpuppet_passwords') - if len(passwords) != 0: - sockpuppet_passwords = passwords.replace(',', ',').split(',') - if len(sockpuppet_usernames) == 0 or len(sockpuppet_usernames) != len(sockpuppet_passwords): - return - sockpuppets = zip(sockpuppet_usernames, sockpuppet_passwords) - for sockpuppet in sockpuppets: - GLOBAL_CONFIG.auth_config.add_account( - sockpuppet[0].strip(), sockpuppet[1].strip()) - except NoOptionError: - pass - - -def init_userinfo_with_options(options: CliOptions) -> None: - if options.username is not None: - GLOBAL_CONFIG.auth_config.username = options.username - GLOBAL_CONFIG.auth_config.password = '' - GLOBAL_CONFIG.auth_config.key = '' - if options.password is not None: - GLOBAL_CONFIG.auth_config.password = options.password - GLOBAL_CONFIG.auth_config.mfa_code = options.code - if options.host is not None: - if HOST_RE.match(options.host): - GLOBAL_CONFIG.host = options.host - else: - GLOBAL_CONFIG.host = 'https://' + options.host - - -def init_chat_config(config: ConfigParser) -> ChatConfig: - ret = ChatConfig() - ret.repeat_mode_switch = config.getboolean('chat', 'repeatMode') - ret.answer_mode = config.getboolean('chat', "answerMode") - ret.frequency = config.getint('chat', 'repeatFrequency') - ret.soliloquize_switch = config.getboolean('chat', 'soliloquizeMode') - ret.soliloquize_frequency = config.getint('chat', 'soliloquizeFrequency') - ret.sentences = json.loads(config.get('chat', 'sentences')) - ret.blacklist = json.loads(config.get('chat', 'blacklist')) - if ret.blacklist.__contains__(''): - ret.blacklist.remove('') - ret.kw_blacklist = json.loads(config.get('chat', 'kwBlacklist')) - if ret.kw_blacklist.__contains__(''): - ret.kw_blacklist.remove('') - ret.kw_notification = json.loads(config.get('chat', 'kwNotification')) - if ret.kw_notification.__contains__(''): - ret.kw_notification.remove('') - ret.fish_ball = config.get('chat', "fishBall") - init_chat_color(ret, config) - ret.output_mode = config.get('chat', 'outputMode') - ret.output_path = config.get('chat', 'outputPath') - return ret - - -def init_chat_color(ret: ChatConfig, config: ConfigParser) -> None: - try: - user_color = config.get('chat', "chatUserColor") - if user_color != '': - ret.chat_user_color = user_color - except NoOptionError: - pass - try: - content_color = config.get('chat', "chatContentColor") - if content_color != '': - ret.chat_content_color = content_color - except NoOptionError: - pass - - -def init_host_config(config: ConfigParser) -> str: - try: - host = config.get('auth', 'host') - if host is None: - return HOST - if HOST_RE.match(host): - return host - else: - return 'https://' + host - except NoOptionError: - return HOST - - -def init_bolo_config(config: ConfigParser) -> None: - try: - if len(config.get('bolo', 'username')) != 0: - GLOBAL_CONFIG.bolo_config.username = '' - GLOBAL_CONFIG.bolo_config.password = '' - GLOBAL_CONFIG.bolo_config.cookie = '' - GLOBAL_CONFIG.bolo_config.username = config.get('bolo', 'username') - except NoOptionError: - pass - try: - if len(config.get('bolo', 'password')) != 0: - GLOBAL_CONFIG.bolo_config.password = config.get('bolo', 'password') - except NoOptionError: - pass - try: - if len(config.get('bolo', 'cookie')) != 0: - GLOBAL_CONFIG.bolo_config.cookie = config.get('bolo', 'cookie') - except NoOptionError: - pass - try: - if len(config.get('bolo', 'host')) != 0: - host = config.get('bolo', 'host') - if host is None: - return - if HOST_RE.match(host): - GLOBAL_CONFIG.bolo_config.host = host - else: - GLOBAL_CONFIG.bolo_config.host = 'http://' + host - except NoOptionError: - pass - - -FishPiInitor = InitChain() +# -*- coding: utf-8 -*- diff --git a/src/core/blacklist.py b/src/core/blacklist.py index e364ab3..70415f6 100644 --- a/src/core/blacklist.py +++ b/src/core/blacklist.py @@ -2,8 +2,8 @@ import re -from src.api import FishPi -from src.api.config import GLOBAL_CONFIG +from src.config import GLOBAL_CONFIG +from src.core.fishpi import FishPi def release_someone(api: FishPi, username: str) -> None: diff --git a/src/core/chat.py b/src/core/chat.py index e7791f2..6efbb45 100644 --- a/src/core/chat.py +++ b/src/core/chat.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- -from src.api import API -from src.api.ws import WS +from src.core.fishpi import API +from src.core.ws import WS class Chat(WS): diff --git a/src/core/chatroom.py b/src/core/chatroom.py index 95f3636..1b9ebef 100644 --- a/src/core/chatroom.py +++ b/src/core/chatroom.py @@ -11,10 +11,10 @@ from prettytable import PrettyTable from termcolor import colored -from src.api import API, FishPi -from src.api.config import GLOBAL_CONFIG from src.api.enum import NTYPE -from src.api.ws import WS +from src.config import GLOBAL_CONFIG +from src.core.fishpi import API, FishPi +from src.core.ws import WS from .notification import Event, sender, sys_notification from .redpacket import render_redpacket, rush_redpacket diff --git a/src/core/command.py b/src/core/command.py index 650cc76..6fe7cfb 100644 --- a/src/core/command.py +++ b/src/core/command.py @@ -7,10 +7,11 @@ from objprint import op -from src.api import FishPi, UserInfo, bolo +from src.api import bolo from src.api.article import Article -from src.api.config import GLOBAL_CONFIG, Config, init_defualt_config from src.api.redpacket import RedPacket, RedPacketType, RPSRedPacket, SpecifyRedPacket +from src.config import GLOBAL_CONFIG, Config, init_defualt_config +from src.core.fishpi import FishPi, UserInfo from src.utils import ( COMMAND_GUIDE, OUTPUT_RE, @@ -33,6 +34,29 @@ from .user import User, render_online_users, render_user_info +class CLIInvoker: + commands = {} + + def __init__(self, api): + self.api = api + + def add_command(self, command_name, command): + CLIInvoker.commands[command_name] = command + + def run(self): + while True: + msg = input("") + params = msg.split(' ') + if len(params) < 2 and not msg.startswith('#'): + DefaultCommand().exec(self.api, tuple(params)) + else: + args = tuple(params[1:]) + command = CLIInvoker.commands.get(params[0], DefaultCommand()) + if isinstance(command, DefaultCommand): + args = tuple(params) + command.exec(self.api, args) + + class Command(ABC): @abstractmethod def exec(self, api: FishPi, args: Tuple[str, ...]): @@ -500,29 +524,6 @@ def exec(self, api: FishPi, args: Tuple[str, ...]): api.opPath_write_to_config_file(path) -class CLIInvoker: - commands = {} - - def __init__(self, api): - self.api = api - - def add_command(self, command_name, command): - CLIInvoker.commands[command_name] = command - - def run(self): - while True: - msg = input("") - params = msg.split(' ') - if len(params) < 2 and not msg.startswith('#'): - DefaultCommand().exec(self.api, tuple(params)) - else: - args = tuple(params[1:]) - command = CLIInvoker.commands.get(params[0], DefaultCommand()) - if isinstance(command, DefaultCommand): - args = tuple(params) - command.exec(self.api, args) - - def init_cli(api: FishPi): cli_handler = CLIInvoker(api) help_c = HelpCommand() diff --git a/src/core/fishpi.py b/src/core/fishpi.py new file mode 100644 index 0000000..753aefa --- /dev/null +++ b/src/core/fishpi.py @@ -0,0 +1,92 @@ +# -*- coding: utf-8 -*- +import json +from typing import Any + +import requests + +from src.api.article import ArticleAPI +from src.api.base import Base +from src.api.chat import ChatAPI +from src.api.chatroom import ChatRoomAPI +from src.api.user import UserAPI +from src.config import GLOBAL_CONFIG +from src.utils import UA + + +class UserInfo(object): + + def __init__(self, username: str, password: str, api_key: str) -> None: + self.username = username + self.password = password + self.api_key = api_key + self.ws: dict[str, Any] = {} + self.in_chatroom = False + + def online(self, *funcs) -> None: + if (len(self.api_key) != 0): + API.set_token(self.api_key) + API.set_current_user(self.username) + else: + API.login(self.username, self.password) + self.api_key = API.api_key + for func in funcs: + func() + self.in_chatroom = True + GLOBAL_CONFIG.auth_config.username = self.username + GLOBAL_CONFIG.auth_config.password = self.password + GLOBAL_CONFIG.auth_config.key = self.api_key + API.user_key_write_to_config_file() + + def out_chatroom(self) -> None: + if 'fishpi.cn/chat-room-channel' in self.ws: + self.ws['fishpi.cn/chat-room-channel'].stop() + self.in_chatroom = False + + def offline(self) -> None: + keys = list(self.ws.keys()) + for key in keys: + self.ws[key].stop() + self.in_chatroom = False + + def out_chat(self) -> None: + if 'fishpi.cn/chat-channel' in self.ws: + self.ws['fishpi.cn/chat-channel'].stop() + + def chat(self, func) -> None: + self.out_chat() + self.out_chatroom() + func() + + +class FishPi(Base): + def __init__(self): + self.sockpuppets: dict[str, UserInfo] = {} + self.user = UserAPI() + self.chatroom = ChatRoomAPI() + self.article = ArticleAPI() + self.chat = ChatAPI() + super().__init__(self) + + def set_token(self, key): + super().set_token(key) + self.user.set_token(key) + self.chatroom.set_token(key) + self.article.set_token(key) + self.chat.set_token(key) + + def get_current_user(self): + return self.sockpuppets[self.current_user] + + def get_breezemoons(self, page: int = 1, size: int = 10) -> dict | None: + res = requests.get( + f'{GLOBAL_CONFIG.host}/api/breezemoons?p={page}&size={size}', headers={'User-Agent': UA}) + print(res.text) + response = json.loads(res.text) + if 'code' in response and response['code'] == 0: + return response['breezemoons'] + else: + print(response['msg']) + return None + + +API = FishPi() diff --git a/src/core/initor/__init__.py b/src/core/initor/__init__.py new file mode 100644 index 0000000..c489cbc --- /dev/null +++ b/src/core/initor/__init__.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- + +from abc import ABC, abstractmethod +from typing import Any + +from src.config import CliOptions +from src.core.fishpi import FishPi + + +class Initor(ABC): + def __init__(self, next=None): + self.next = next + + def __iter__(self): + node = self + while node is not None: + yield node + node = node.next + + @abstractmethod + def exec(self, api: FishPi, options: CliOptions) -> None: + pass + + def init(self, api: FishPi, options: CliOptions) -> None: + self.exec(api, options) + self.next.init(api, options) diff --git a/src/core/initor/bolo_initor.py b/src/core/initor/bolo_initor.py new file mode 100644 index 0000000..d4557c9 --- /dev/null +++ b/src/core/initor/bolo_initor.py @@ -0,0 +1,12 @@ +# -*- coding: utf-8 -*- +from src.api import bolo +from src.config import GLOBAL_CONFIG, CliOptions +from src.core.fishpi import FishPi +from src.core.initor import Initor + + +class BoloLoginInitor(Initor): + def exec(self, api: FishPi, options: CliOptions) -> None: + if GLOBAL_CONFIG.bolo_config.cookie == '' and (GLOBAL_CONFIG.bolo_config.username != '' and GLOBAL_CONFIG.bolo_config.password != ''): + # try login bolo + bolo.bolo_login() diff --git a/src/core/initor/chatroom_initor.py b/src/core/initor/chatroom_initor.py new file mode 100644 index 0000000..da1835a --- /dev/null +++ b/src/core/initor/chatroom_initor.py @@ -0,0 +1,17 @@ +# -*- coding: utf-8 -*- +import schedule + +from src.config import GLOBAL_CONFIG, CliOptions +from src.core.chatroom import ChatRoom, init_soliloquize +from src.core.fishpi import FishPi +from src.core.initor import Initor + + +class ChaRoomInitor(Initor): + def exec(self, api: FishPi, options: CliOptions) -> None: + init_soliloquize(api) + if GLOBAL_CONFIG.chat_config.soliloquize_switch: + schedule.run_pending() + api.get_current_user().in_chatroom = True + chatroom = ChatRoom() + chatroom.start() diff --git a/src/core/initor/cli_initor.py b/src/core/initor/cli_initor.py new file mode 100644 index 0000000..96cc18d --- /dev/null +++ b/src/core/initor/cli_initor.py @@ -0,0 +1,34 @@ +# -*- coding: utf-8 -*- +from colorama import just_fix_windows_console + +from src.config import GLOBAL_CONFIG, CliOptions +from src.core.command import init_cli +from src.core.fishpi import FishPi +from src.core.initor import Initor +from src.utils import HOST_RE + + +class CilConfigInitor(Initor): + def exec(self, api: FishPi, options: CliOptions) -> None: + init_userinfo_with_options(options) + just_fix_windows_console() + + +class CliInitor(Initor): + def exec(self, api: FishPi, options: CliOptions) -> None: + init_cli(api) + + +def init_userinfo_with_options(options: CliOptions) -> None: + if options.username is not None: + GLOBAL_CONFIG.auth_config.username = options.username + GLOBAL_CONFIG.auth_config.password = '' + GLOBAL_CONFIG.auth_config.key = '' + if options.password is not None: + GLOBAL_CONFIG.auth_config.password = options.password + GLOBAL_CONFIG.auth_config.mfa_code = options.code + if options.host is not None: + if HOST_RE.match(options.host): + GLOBAL_CONFIG.host = options.host + else: + GLOBAL_CONFIG.host = 'https://' + options.host diff --git a/src/core/initor/defualt_initor.py b/src/core/initor/defualt_initor.py new file mode 100644 index 0000000..e1c6741 --- /dev/null +++ b/src/core/initor/defualt_initor.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- +from src.config import GLOBAL_CONFIG, CliOptions, init_defualt_config +from src.core.fishpi import FishPi +from src.core.initor import Initor + + +class DefualtConfigInitor(Initor): + def exec(self, api: FishPi, options: CliOptions) -> None: + print("生成默认配置") + defualt = init_defualt_config() + GLOBAL_CONFIG.auth_config = defualt.auth_config + GLOBAL_CONFIG.redpacket_config = defualt.redpacket_config + GLOBAL_CONFIG.chat_config = defualt.chat_config + GLOBAL_CONFIG.bolo_config = defualt.bolo_config + GLOBAL_CONFIG.cfg_path = defualt.cfg_path + GLOBAL_CONFIG.host = defualt.host diff --git a/src/core/initor/env_initor.py b/src/core/initor/env_initor.py new file mode 100644 index 0000000..8448fa7 --- /dev/null +++ b/src/core/initor/env_initor.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- + +import os + +from src.config import GLOBAL_CONFIG, CliOptions +from src.core.fishpi import FishPi +from src.core.initor import Initor + + +class EnvConfigInitor(Initor): + def exec(self, api: FishPi, options: CliOptions) -> None: + GLOBAL_CONFIG.auth_config.username = os.environ.get( + "FISH_PI_USERNAME", '') + GLOBAL_CONFIG.auth_config.password = os.environ.get( + "FISH_PI_PASSWORD", '') + GLOBAL_CONFIG.auth_config.key = os.environ.get('FISH_PI_KEY', '') + GLOBAL_CONFIG.bolo_config.username = os.environ.get( + "BOLO_USERNAME", '') + GLOBAL_CONFIG.bolo_config.password = os.environ.get( + "BOLO_PASSWORD", '') + GLOBAL_CONFIG.bolo_config.cookie = os.environ.get( + "BOLO_COOKIE", '') + GLOBAL_CONFIG.bolo_config.host = os.environ.get( + "BOLO_HOST", '') diff --git a/src/core/initor/file_initor.py b/src/core/initor/file_initor.py new file mode 100644 index 0000000..c3a1c0b --- /dev/null +++ b/src/core/initor/file_initor.py @@ -0,0 +1,187 @@ +# -*- coding: utf-8 -*- + +import json +import os +from configparser import ConfigParser, NoOptionError + +from src.config import GLOBAL_CONFIG, CliOptions +from src.config.chat import ChatConfig +from src.config.redpacket import RedPacketConfig +from src.core.fishpi import FishPi +from src.core.initor import Initor +from src.utils import HOST, HOST_RE + + +class FileConfigInitor(Initor): + def exec(self, api: FishPi, options: CliOptions) -> None: + file_path = options.file_path + if file_path is None: + file_path = f'{os.getcwd()}/config.ini' + config = ConfigParser() + try: + print("配置读取中...") + if not os.path.exists(file_path): + print(f'{file_path}配置文件不存在') + else: + config.read(file_path, encoding='utf-8') + init_auth_config(config) + init_bolo_config(config) + GLOBAL_CONFIG.redpacket_config = int_redpacket_config(config) + GLOBAL_CONFIG.chat_config = init_chat_config(config) + GLOBAL_CONFIG.cfg_path = file_path + GLOBAL_CONFIG.host = init_host_config(config) + except Exception: + print(f'{file_path}配置文件不合法') + + +def init_auth_config(config: ConfigParser) -> None: + try: + if len(config.get('auth', 'username')) != 0: + GLOBAL_CONFIG.auth_config.username = '' + GLOBAL_CONFIG.auth_config.password = '' + GLOBAL_CONFIG.auth_config.key = '' + GLOBAL_CONFIG.auth_config.username = config.get('auth', 'username') + except NoOptionError: + pass + try: + if len(config.get('auth', 'password')) != 0: + GLOBAL_CONFIG.auth_config.password = config.get('auth', 'password') + except NoOptionError: + pass + try: + if len(config.get('auth', 'key')) != 0: + GLOBAL_CONFIG.auth_config.key = config.get('auth', 'key') + except NoOptionError: + pass + init_sockpuppets(config) + + +def init_sockpuppets(config: ConfigParser) -> None: + try: + sockpuppet_usernames = [] + sockpuppet_passwords = [] + usernames = config.get( + 'auth', 'sockpuppet_usernames') + if len(usernames) != 0: + sockpuppet_usernames = usernames.replace(',', ',').split(',') + passwords = config.get( + 'auth', 'sockpuppet_passwords') + if len(passwords) != 0: + sockpuppet_passwords = passwords.replace(',', ',').split(',') + if len(sockpuppet_usernames) == 0 or len(sockpuppet_usernames) != len(sockpuppet_passwords): + return + sockpuppets = zip(sockpuppet_usernames, sockpuppet_passwords) + for sockpuppet in sockpuppets: + GLOBAL_CONFIG.auth_config.add_account( + sockpuppet[0].strip(), sockpuppet[1].strip()) + except NoOptionError: + pass + + +def init_chat_config(config: ConfigParser) -> ChatConfig: + ret = ChatConfig() + ret.repeat_mode_switch = config.getboolean('chat', 'repeatMode') + ret.answer_mode = config.getboolean('chat', "answerMode") + ret.frequency = config.getint('chat', 'repeatFrequency') + ret.soliloquize_switch = config.getboolean('chat', 'soliloquizeMode') + ret.soliloquize_frequency = config.getint('chat', 'soliloquizeFrequency') + ret.sentences = json.loads(config.get('chat', 'sentences')) + ret.blacklist = json.loads(config.get('chat', 'blacklist')) + if ret.blacklist.__contains__(''): + ret.blacklist.remove('') + ret.kw_blacklist = json.loads(config.get('chat', 'kwBlacklist')) + if ret.kw_blacklist.__contains__(''): + ret.kw_blacklist.remove('') + ret.kw_notification = json.loads(config.get('chat', 'kwNotification')) + if ret.kw_notification.__contains__(''): + ret.kw_notification.remove('') + ret.fish_ball = config.get('chat', "fishBall") + init_chat_color(ret, config) + ret.output_mode = config.get('chat', 'outputMode') + ret.output_path = config.get('chat', 'outputPath') + return ret + + +def init_chat_color(ret: ChatConfig, config: ConfigParser) -> None: + try: + user_color = config.get('chat', "chatUserColor") + if user_color != '': + ret.chat_user_color = user_color + except NoOptionError: + pass + try: + content_color = config.get('chat', "chatContentColor") + if content_color != '': + ret.chat_content_color = content_color + except NoOptionError: + pass + + +def init_host_config(config: ConfigParser) -> str: + try: + host = config.get('auth', 'host') + if host is None: + return HOST + if HOST_RE.match(host): + return host + else: + return 'https://' + host + except NoOptionError: + return HOST + + +def init_bolo_config(config: ConfigParser) -> None: + try: + if len(config.get('bolo', 'username')) != 0: + GLOBAL_CONFIG.bolo_config.username = '' + GLOBAL_CONFIG.bolo_config.password = '' + GLOBAL_CONFIG.bolo_config.cookie = '' + GLOBAL_CONFIG.bolo_config.username = config.get('bolo', 'username') + except NoOptionError: + pass + try: + if len(config.get('bolo', 'password')) != 0: + GLOBAL_CONFIG.bolo_config.password = config.get('bolo', 'password') + except NoOptionError: + pass + try: + if len(config.get('bolo', 'cookie')) != 0: + GLOBAL_CONFIG.bolo_config.cookie = config.get('bolo', 'cookie') + except NoOptionError: + pass + try: + if len(config.get('bolo', 'host')) != 0: + host = config.get('bolo', 'host') + if host is None: + return + if HOST_RE.match(host): + GLOBAL_CONFIG.bolo_config.host = host + else: + GLOBAL_CONFIG.bolo_config.host = 'http://' + host + except NoOptionError: + pass + + +def int_redpacket_config(config: ConfigParser) -> RedPacketConfig: + ret = RedPacketConfig() + if config.getint('redPacket', 'rate') > 0: + ret.rate = config.getint('redPacket', 'rate') + if config.getint('redPacket', 'rpsLimit') > 0: + ret.rps_limit = config.getint('redPacket', 'rpsLimit') + ret.red_packet_switch = config.getboolean( + 'redPacket', 'openRedPacket') + ret.heartbeat = config.getboolean( + 'redPacket', 'heartbeat') + ret.smart_mode = config.getboolean( + 'redPacket', 'heartbeatSmartMode') + ret.adventure_mode = config.getboolean( + 'redPacket', 'heartbeatAdventure') + if config.getfloat('redPacket', 'heartbeatThreshold') < 0: + ret.threshold = 0.4 + else: + ret.threshold = config.getfloat('redPacket', 'heartbeatThreshold') + if ret.threshold > 1: + ret.threshold = 1 + ret.timeout = config.getint( + 'redPacket', 'heartbeatTimeout') + return ret diff --git a/src/core/initor/init_chan.py b/src/core/initor/init_chan.py new file mode 100644 index 0000000..34aae11 --- /dev/null +++ b/src/core/initor/init_chan.py @@ -0,0 +1,48 @@ +from typing import Any + +from src.config import CliOptions +from src.core.fishpi import FishPi +from src.core.initor import Initor +from src.core.initor.bolo_initor import BoloLoginInitor +from src.core.initor.chatroom_initor import ChaRoomInitor +from src.core.initor.cli_initor import CilConfigInitor, CliInitor +from src.core.initor.defualt_initor import DefualtConfigInitor +from src.core.initor.env_initor import EnvConfigInitor +from src.core.initor.file_initor import FileConfigInitor +from src.core.initor.login_initor import LoginInitor + + +class InitChain(object): + def __init__(self, api: FishPi = None, options: CliOptions = None) -> None: + self.head: Initor = None + self.api = api + self.options = options + + def __call__(self, *args: Any, **kwds: Any) -> None: + self.api = kwds['api'] + self.options = kwds['options'] + self.init() + + def append(self, *args) -> None: + curr_node = self.head + initors = (i for i in args) + if curr_node is None: + self.head = next(initors) + curr_node = self.head + for initor in initors: + curr_node.next = initor + curr_node = curr_node.next + + def init(self): + self.append(DefualtConfigInitor(), + EnvConfigInitor(), + FileConfigInitor(), + CilConfigInitor(), + LoginInitor(), + BoloLoginInitor(), + ChaRoomInitor(), + CliInitor()) + self.head.init(self.api, self.options) + + +FishPiInitor = InitChain() diff --git a/src/core/initor/login_initor.py b/src/core/initor/login_initor.py new file mode 100644 index 0000000..30f43bc --- /dev/null +++ b/src/core/initor/login_initor.py @@ -0,0 +1,62 @@ +# -*- coding: utf-8 -*- +import os + +from src.config import GLOBAL_CONFIG, CliOptions +from src.core.fishpi import FishPi, UserInfo +from src.core.initor import Initor +from src.core.user import User +from src.utils import cli_login + + +class LoginInitor(Initor): + def exec(self, api: FishPi, options: CliOptions) -> None: + os.environ['NO_PROXY'] = GLOBAL_CONFIG.host + if GLOBAL_CONFIG.auth_config.key == '': + _login_without_key(api) + else: + # 直接使用api-key + _login_with_key(api) + if len(GLOBAL_CONFIG.auth_config.accounts) != 0: + api.sockpuppets = {account[0]: UserInfo( + account[0], account[1], '') for account in GLOBAL_CONFIG.auth_config.accounts} + api.sockpuppets[api.current_user] = UserInfo( + api.current_user, GLOBAL_CONFIG.auth_config.password, api.api_key) + User().online(api.sockpuppets[api.current_user]) + + +def _login_with_key(api: FishPi) -> None: + username = api.user.get_username_by_key( + GLOBAL_CONFIG.auth_config.key) + if username is not None: + GLOBAL_CONFIG.auth_config.username = username + api.set_token(GLOBAL_CONFIG.auth_config.key) + api.set_current_user(GLOBAL_CONFIG.auth_config.username) + else: + print("非法API-KEY, 使用账户密码登陆") + while len(GLOBAL_CONFIG.auth_config.username) == 0: + print('请输入用户名:') + GLOBAL_CONFIG.auth_config.username = input("") + while len(GLOBAL_CONFIG.auth_config.password) == 0: + print('请输入密码:') + GLOBAL_CONFIG.auth_config.password = input("") + api.login(GLOBAL_CONFIG.auth_config.username, + GLOBAL_CONFIG.auth_config.password, + GLOBAL_CONFIG.auth_config.mfa_code) + GLOBAL_CONFIG.auth_config.key = api.api_key + if cli_login(GLOBAL_CONFIG.auth_config.username): + api.user_key_write_to_config_file() + + +def _login_without_key(api: FishPi) -> None: + while len(GLOBAL_CONFIG.auth_config.username) == 0: + print('请输入用户名:') + GLOBAL_CONFIG.auth_config.username = input("") + while len(GLOBAL_CONFIG.auth_config.password) == 0: + print('请输入密码:') + GLOBAL_CONFIG.auth_config.password = input("") + api.login(GLOBAL_CONFIG.auth_config.username, + GLOBAL_CONFIG.auth_config.password, + GLOBAL_CONFIG.auth_config.mfa_code) + GLOBAL_CONFIG.auth_config.key = api.api_key + if cli_login(GLOBAL_CONFIG.auth_config.username): + api.user_key_write_to_config_file() diff --git a/src/core/notification.py b/src/core/notification.py index 9821ccd..ac49010 100644 --- a/src/core/notification.py +++ b/src/core/notification.py @@ -4,8 +4,8 @@ from plyer import notification -from src.api.config import GLOBAL_CONFIG from src.api.enum import NTYPE +from src.config import GLOBAL_CONFIG from src.utils.file import project_root diff --git a/src/core/redpacket.py b/src/core/redpacket.py index 23154e1..bf66a25 100644 --- a/src/core/redpacket.py +++ b/src/core/redpacket.py @@ -3,9 +3,9 @@ import json import time -from src.api import FishPi -from src.api.config import GLOBAL_CONFIG from src.api.enum import CODE +from src.config import GLOBAL_CONFIG +from src.core.fishpi import FishPi from src.utils import RPS_LOSED, RPS_SUCCESS, RPS_ZERO diff --git a/src/core/user.py b/src/core/user.py index e263b93..c1b1fd6 100644 --- a/src/core/user.py +++ b/src/core/user.py @@ -1,10 +1,9 @@ # -*- coding: utf-8 -*- -from src.api import FishPi, UserInfo from src.api.enum import NTYPE -from src.api.ws import WS - -from .notification import Event, sender, sys_notification +from src.core.fishpi import FishPi, UserInfo +from src.core.notification import Event, sender, sys_notification +from src.core.ws import WS class User(WS): diff --git a/src/api/ws.py b/src/core/ws.py similarity index 98% rename from src/api/ws.py rename to src/core/ws.py index 8d60c68..1a9ed47 100644 --- a/src/api/ws.py +++ b/src/core/ws.py @@ -7,7 +7,7 @@ import websocket -from src.api import API +from src.core.fishpi import API class WS(ABC): diff --git a/src/main.py b/src/main.py index 974697e..f91bc4e 100644 --- a/src/main.py +++ b/src/main.py @@ -5,9 +5,9 @@ import click import schedule -from src.api import API -from src.api.config import CliOptions -from src.core import FishPiInitor +from src.config import CliOptions +from src.core.fishpi import API +from src.core.initor.init_chan import FishPiInitor from src.utils.version import __version__ diff --git a/src/utils/version.py b/src/utils/version.py index 9dc7909..6238ff4 100644 --- a/src/utils/version.py +++ b/src/utils/version.py @@ -1,4 +1,4 @@ # -*- coding: utf-8 -*- -__version__ = "2.1.8" +__version__ = "2.1.9"