Skip to content

Commit

Permalink
Develop (#75)
Browse files Browse the repository at this point in the history
* release v2.0.0

   * refacotr: rename cli_config => options

   * feat: 撤回上条消息 #67

   * chore: ws支持多个

   * 项目名变更

   * optimze: 优雅退出

   * 账号多开

   * doc: 文档添加
  • Loading branch information
gakkiyomi committed Dec 3, 2023
1 parent 66cd5b3 commit 89871c6
Show file tree
Hide file tree
Showing 22 changed files with 511 additions and 251 deletions.
21 changes: 13 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
![摸鱼派cn.png](https://b3logfile.com/file/2023/05/摸鱼派-cn-owZQT8f.png)

# pwl-chat-python
# fishpi-pyclient

> 摸鱼派聊天室 python 命令行客户端
Expand All @@ -13,13 +13,13 @@
执行

```bash
pip install pwl-chat-python
pip install fishpi-pyclient
```

## 运行

```bash
pwl-chat-python -u username -p password -c <两步验证码>
fishpi-pyclient -u username -p password -c <两步验证码>
```

## 调试
Expand All @@ -32,18 +32,18 @@ python core.py

## 功能

- 🥷 账号多开
- 一键切换
- 更多功能请期待
- 💬 聊天模式
- 💬 聊天吹水
- 🤖️ 自动复读
- 🤖️ 自动领取昨日奖励
- 🌛 发送清风明月
- 聊天室消息撤回
- 🧠 自言自语
- 自定义语句池
- 定时发送
- 🧧 自动化抢红包(脚本哥)
- 自定义抢红包延时
- 心跳红包防止踩坑
- 心跳红包风险预测
- ~~猜拳红包百分百胜率~~
- 命令模式
- 命令/聊天模式切换
- (聊天模式也可以执行命令)
Expand All @@ -68,9 +68,14 @@ python core.py
- 猜拳红包
- 设置抢红包等待时间
- 抢猜拳红包最大限制
- 🧧 自动化抢红包(脚本哥)
- 自定义抢红包延时
- 心跳红包防止踩坑
- 心跳红包风险预测

## 效果

![fenshen.png](https://file.fishpi.cn/2023/12/账号分身-0a25be81.png)
![image.png](https://file.fishpi.cn/2023/06/image-d4da9bf7.png)
![redpacket](https://file.fishpi.cn/2023/06/image-d0ad7756.png)
![image.png](https://pwl.stackoverflow.wiki/2022/01/image-f74aae7e.png)
Expand Down
4 changes: 3 additions & 1 deletion config.ini
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
username=xxx
; 摸鱼派用户密码
password=xxx

;账号多开
sockpuppet_usernames=xxx,yyy
sockpuppet_passwords=xxx_password,yyy_password
[redPacket]
; 是否开启抢红包模式
openRedPacket=true
Expand Down
3 changes: 2 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
requests==2.22.0
websocket_client==1.2.3
schedule==1.1.0
click==8.1.3
click==8.1.3
objprint==0.2.3
24 changes: 12 additions & 12 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,31 +1,31 @@
from setuptools import setup
import io
import os
import sys
from shutil import rmtree

from setuptools import Command, setup

from src.utils.version import __version__

#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Note: To use the 'upload' functionality of this file, you must:
# $ pipenv install twine --dev

import io
import os
import sys
from shutil import rmtree
from src.utils.version import __version__

from setuptools import setup, Command

# Package meta-data.
NAME = 'pwl-chat-python'
NAME = 'fishpi-pyclient'
DESCRIPTION = '摸鱼派聊天室python客户端'
URL = 'https://github.com/gakkiyomi/pwl-chat-python'
URL = 'https://github.com/gakkiyomi/fishpi-pyclient'
EMAIL = '[email protected]'
AUTHOR = 'gakkiyomi'
REQUIRES_PYTHON = '>=3.9'
VERSION = __version__

# What packages are required for this module to be executed?
REQUIRED = [
'requests', 'websocket-client', 'click', 'schedule'
'requests', 'websocket-client', 'click', 'schedule', 'objprint'
]

# What packages are optional?
Expand Down Expand Up @@ -122,7 +122,7 @@ def run(self):
},
entry_points={
'console_scripts': [
'pwl-chat-python = src.main:cli',
'fishpi-pyclient = src.main:cli',
],
}

Expand Down
15 changes: 0 additions & 15 deletions src/api/__api__.py

This file was deleted.

80 changes: 39 additions & 41 deletions src/api/__init__.py
Original file line number Diff line number Diff line change
@@ -1,58 +1,56 @@
# -*- coding: utf-8 -*-

import hashlib
import json
import sys
from typing import Any

import requests

from src.utils.utils import HOST, UA
from src.api.base import Base
from src.utils import HOST, UA

from .__api__ import Base
from .chatroom import ChatRoom
from .user import User
from .article import ArticleAPI
from .chatroom import ChatRoomAPI
from .user import UserAPI


class FishPi(Base):
def __init__(self):
self.ws_calls = []
self.ws = None
self.current_user = ''
self.user = User()
self.chatroom = ChatRoom()
Base.__init__(self)
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.is_online = False

def online(self, func) -> 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
func()
self.is_online = True

def add_listener(self, listener):
self.ws_calls.append(listener)
def offline(self) -> None:
keys = list(self.ws.keys())
for key in keys:
self.ws[key].stop()
self.is_online = False

def set_current_user(self, username):
self.current_user = username

class FishPi(Base):
def __init__(self):
self.sockpuppets: dict[str, UserInfo] = {}
self.user = UserAPI()
self.chatroom = ChatRoomAPI()
self.article = ArticleAPI()
super().__init__(self)

def set_token(self, key):
Base.set_token(self, key)
super().set_token(key)
self.user.set_token(key)
self.chatroom.set_token(key)

def login(self, username: str, password: str, mfa_code='') -> bool:
params = {
'nameOrEmail': username,
'userPassword': hashlib.md5(str(password).encode('utf-8')).hexdigest(),
'mfaCode': mfa_code
}
res = requests.post(f"{HOST}/api/getKey",
json=params, headers={'User-Agent': UA})
rsp = json.loads(res.text)
if rsp['code'] == 0:
self.set_token(rsp['Key'])
self.set_current_user(username)
print(f'登陆成功! 更多功能与趣味游戏请访问网页端: {HOST}')
return True
elif rsp['code'] == -1 and rsp['msg'] == '两步验证失败,请填写正确的一次性密码':
print("请输入两步验证码:")
return False
else:
print(f"登陆失败: {rsp['msg']}")
sys.exit()
self.article.set_token(key)

def get_breezemoons(self, page: int = 1, size: int = 10) -> dict | None:
res = requests.get(
Expand Down
103 changes: 103 additions & 0 deletions src/api/article.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
# -*- coding: utf-8 -*-

import json
from enum import Enum
from typing import Any

import requests

from src.api import Base
from src.utils import HOST, UA


class ArticleType(Enum):
RECENT = 'recent'
HOT = RECENT+'/hot'
GOOD = RECENT+'/good'
REPLY = RECENT+'/reply'


class Article(object):
def __init__(self, *args: Any, **kwargs: Any) -> None:
for dict in args:
for key in dict:
setattr(self, key, dict[key])
for key in kwargs:
setattr(self, key, kwargs[key])

def vote(self, api) -> None:
api.vote_for_article(self.oId)

def thanks(self, api) -> None:
api.thanks_for_article(self.oId)

def comment(self, api, comment: str) -> None:
api.comment_article(self.oId, comment)


class ArticleAPI(Base):
def vote_for_article(self, article_id: str) -> None:
if self.api_key == '':
return None
resp = requests.post(
f'{HOST}/vote/up/article', headers={'User-Agent': UA}, json={
'apiKey': self.api_key,
'dataId': article_id
})
if resp.status_code == 200:
data = json.loads(resp.text)
if 'code' in data and data['code'] == 0:
if data['type'] == -1:
print('点赞成功')
else:
print('取消点赞')
else:
print('点赞失败: ' + data['msg'])
else:
print('点赞失败')

def thanks_for_article(self, article_id: str) -> None:
res = requests.post(f'{HOST}/article/thank?articleId={article_id}', headers={'User-Agent': UA}, json={
'apiKey': self.api_key
})
response = json.loads(res.text)
if 'code' in response and response['code'] == 0:
print('感谢文章成功')
else:
print('感谢文章失败: ' + response['msg'])

def list_articles(self, type: ArticleType = ArticleType.RECENT, page: int = 1, size: int = 20) -> dict:
res = requests.get(
f'{HOST}/api/articles/{type}?p={page}&size={size}', headers={'User-Agent': UA}, json={
'apiKey': self.api_key
})
response = json.loads(res.text)
if 'code' in response and response['code'] == 0:
return response
else:
print('获取帖子列表失败: ' + response['msg'])

def get_article(self, article_id: str) -> Article:
res = requests.get(
f'{HOST}/api/article/{article_id}', headers={'User-Agent': UA}, json={
'apiKey': self.api_key
})
response = json.loads(res.text)
if 'code' in response and response['code'] == 0:
return Article(response['data'])
else:
print('获取帖子详情失败: ' + response['msg'])

def comment_article(self, article_id: str, comment: str) -> Article:
res = requests.post(f'{HOST}/comment/{article_id}', headers={'User-Agent': UA}, json={
'apiKey': self.api_key,
'articleId': article_id,
'commentAnonymous': False,
'commentVisible': False,
'commentContent': comment
})
response = json.loads(res.text)
if 'code' in response and response['code'] == 0:
print('评论成功')
else:
print('评论失败: ' + response['msg'])
45 changes: 45 additions & 0 deletions src/api/base.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# -*- coding: utf-8 -*-

import hashlib
import json
import sys

import requests

from src.utils import HELP, HOST, UA


class Base(object):
def __init__(self, key=''):
self.current_user = ''
self.set_token(key)

def set_token(self, api_key=''):
self.api_key = api_key

def set_current_user(self, username):
self.current_user = username

def login(self, username: str, password: str, mfa_code=''):
params = {
'nameOrEmail': username,
'userPassword': hashlib.md5(str(password).encode('utf-8')).hexdigest(),
'mfaCode': mfa_code
}
res = requests.post(f"{HOST}/api/getKey",
json=params, headers={'User-Agent': UA})
rsp = json.loads(res.text)
if rsp['code'] == 0:
self.set_token(rsp['Key'])
self.set_current_user(username)
print(f'登陆成功! 更多功能与趣味游戏请访问网页端: {HOST}')
print(HELP)
elif rsp['code'] == -1 and rsp['msg'] == '两步验证失败,请填写正确的一次性密码':
self.set_token('')
print("请输入两步验证码:")
while len(self.api_key) == 0:
code = input("")
self.login(username, password, code)
else:
print(f"登陆失败: {rsp['msg']}")
sys.exit(0)
Loading

0 comments on commit 89871c6

Please sign in to comment.