论摸鱼的那些事

首先我今天是来给大家解闷的, 推荐一个有趣的网页聊天室 - 摸鱼派 - 白与画科技,这个网页有一个聊天功能,可以愉快的跟大家摸鱼,但是目标太大

容易被boss发现,所以小编今天给大家整理了一下大家都可以用的操作来减少被发现的办法。

第一个方法

        就是官网自提供的摸鱼插件,仅限于vscodeFishPiOffical/fishpi.vsix: 摸鱼派聊天室 VSCode 扩展

第二个方法

        就是我自己写的python程序

因为是小编自己写的一个隐蔽的窗口,因为隐私的原因所以展示这么多(也就是[用户]:<p>语言</p>),因为这是在python控制台展示的所以相当隐秘,但是缺点很明显就是你在控制台输入 的时候别人发信息就会导致你换行,输错字的时候他就会删除不了

下面是代码展示:

import os
import json
import hashlib
import requests
import websocket
import time
import threading


class FishPiChatroom:
    def __init__(self, username, password, mfa_code="", cache_file="api_key.txt"):
        self.username = username
        self.password_raw = password
        self.password = hashlib.md5(password.encode()).hexdigest()
        self.mfa_code = mfa_code
        self.api_key = None
        self.ws = None
        self.base_url = "https://fishpi.cn"
        self.headers = {
            "User-Agent": "Mozilla/5.0"
        }
        self.cache_file = cache_file
        self.node_info = None
        self.reconnect_count = 0
        self.max_reconnect_attempts = 5
        self.reconnect_delay = 3

    def load_cached_api_key(self):
        if os.path.exists(self.cache_file):
            with open(self.cache_file, "r") as f:
                self.api_key = f.read().strip()
                if self.api_key:
                    print(" 使用缓存 API Key")
                    return True
        return False

    def save_api_key(self):
        with open(self.cache_file, "w") as f:
            f.write(self.api_key)

    def get_api_key(self):
        if self.load_cached_api_key():
            return True

        url = f"{self.base_url}/api/getKey"
        data = {
            "nameOrEmail": self.username,
            "userPassword": self.password
        }
        if self.mfa_code:
            data["mfaCode"] = self.mfa_code

        response = requests.post(url, json=data, headers=self.headers)
        result = response.json()

        msg = result.get("msg", "")
        if result.get("code") == 0:
            self.api_key = result.get("Key")
            self.save_api_key()
            print(f" API Key获取成功并已缓存")
            return True
        elif "频率过快" in msg:
            print(" 登录频率过快,请 5 分钟后再试")
        else:
            print(f" API Key获取失败: {msg}")
        return False

    def get_node_url(self):
        if not self.api_key and not self.get_api_key():
            return None

        url = f"{self.base_url}/chat-room/node/get?apiKey={self.api_key}"
        try:
            response = requests.get(url, headers=self.headers)
            if response.status_code != 200:
                print(f" 获取节点失败: {response.status_code}")
                print(f" 响应内容: {response.text}")
                return None

            result = response.json()
            if result.get("code") == 0:
                self.node_info = result
                print(" 节点获取成功")
                return result.get("data")
            else:
                print(f" 节点错误: {result.get('msg')}")
                return None
        except Exception as e:
            print(f" 节点请求异常: {e}")
            return None

    def on_message(self, ws, message):
        try:
            data = json.loads(message)
            print(f"[{data.get('userName', '系统')}]: {data.get('content', '')}")
        except:
            print(" 消息格式错误")

    def on_error(self, ws, error):
        print(f" 连接错误: {error}")
        self.reconnect()

    def on_close(self, ws, close_status_code, close_msg):
        print(f" 连接关闭: {close_status_code} - {close_msg}")
        self.reconnect()

    def reconnect(self):
        if self.reconnect_count >= self.max_reconnect_attempts:
            print(" 达到最大重连次数")
            return
        self.reconnect_count += 1
        print(f" 正在重连({self.reconnect_count})...")
        time.sleep(self.reconnect_delay)
        self.connect()

    def connect(self):
        node_url = self.get_node_url()
        if not node_url:
            print(" 无法连接到聊天室")
            return False
        print(f" 正在连接节点: {node_url}")
        self.ws = websocket.WebSocketApp(
            node_url,
            on_open=lambda ws: print(" WebSocket连接已建立"),
            on_message=self.on_message,
            on_error=self.on_error,
            on_close=self.on_close,
            header=self.headers
        )
        threading.Thread(target=self.ws.run_forever, daemon=True).start()
        return True

    def send_message(self, content):
        if not self.api_key:
            if not self.get_api_key():
                return False
        url = f"{self.base_url}/chat-room/send"
        data = {
            "apiKey": self.api_key,
            "content": content
        }
        try:
            response = requests.post(url, json=data, headers=self.headers)
            result = response.json()
            if result.get("code") == 0:
                return True
            else:
                print(f" 发送失败: {result.get('msg')}")
        except Exception as e:
            print(f" 发送出错: {e}")
        return False

    def send_redpacket(self, count=5, value=32, msg="恭喜发财"):
        payload = {
            "msg": msg,
            "money": value,
            "count": count,
            "type": "random"
        }
        content = f"[redpacket]{json.dumps(payload)}[/redpacket]"
        return self.send_message(content)

    def close(self):
        if self.ws:
            self.ws.close()

#  加上主程序
def main():
    #  替换为你自己的用户名和密码
    username = "请输入你的账号"
    password = "请输入你的密码"

    client = FishPiChatroom(username, password)

    if not client.connect():
        print(" 无法连接到聊天室")
        return

    try:
        while True:
            msg = input("你:")
            if msg.strip().lower() == "exit":
                break
            client.send_message(msg)
    except KeyboardInterrupt:
        print("\n 已终止")
    finally:
        client.close()

#  启动入口
if __name__ == "__main__":
    main()

在请输入你的密码和请输入你的账号就是对应着网站你注册的账号和密码,切记先注册在使用哦,

Python 3.13.5

certifi            2025.7.14
charset-normalizer 3.4.2
idna               3.10
markdown-it-py     3.0.0
mdurl              0.1.2
pip                25.1.1
prompt_toolkit     3.0.51
Pygments           2.19.2
rel                0.4.9.20
requests           2.32.4
rich               14.1.0
urllib3            2.5.0
wcwidth            0.2.13
websocket-client   1.8.0

这是小编项目用到的插件

第三个方法

直接上图!!!

直接做成页面性质的,图片可能是站主有设置,我没有办法上传图片,我可以看到我发的图片但是,别人看不到,表情是可以用的

废话不多说直接上代码(环境同上):

import tkinter as tk
from tkinter.scrolledtext import ScrolledText
from tkinter import filedialog as fd
import hashlib
import requests
import websocket
import json
import time
import os
import threading
import re
from html import unescape
from datetime import datetime

# emoji 数据(可扩展)
EMOJI_LIST = [
    ("😀", "笑脸"), ("😂", "笑泪"), ("😍", "爱心眼"), ("🥺", "可怜"), ("🤔", "思考"),
    ("👍", "点赞"), ("😎", "酷"), ("😭", "大哭"), ("🎉", "庆祝"), ("🔥", "火焰"),
    ("🙌", "举手"), ("😡", "生气"), ("😴", "困"), ("😱", "惊讶"), ("😇", "天使"),
    ("🤯", "爆炸头"), ("🤮", "想吐"), ("🥳", "派对"), ("🤓", "书呆子"), ("😤", "生闷气"),
    ("💀", "笑死"), ("🤡", "小丑"), ("😈", "恶魔"), ("🤑", "发财"), ("🤗", "拥抱"),
    ("💩", "便便")
]

def strip_html_tags(html):
    # 处理 <blockquote> 引用块
    quote_parts = []

    def process_quote_block(match):
        block = match.group(1)

        # 处理图片
        block = re.sub(r'<img[^>]*src="([^"]+)"[^>]*>', lambda m: f"[图片: {m.group(1)}]", block)

        # 提取纯文本
        block = re.sub(r'<.*?>', '', block)
        block = unescape(block.strip())

        # 加前缀
        if block:
            quote_parts.append(f"【引用】{block}")
        return ""  # 移除原始引用块

    # 找出所有 blockquote 内容,并处理
    html = re.sub(r'<blockquote>(.*?)</blockquote>', process_quote_block, html, flags=re.DOTALL)

    # 处理正文中的图片
    html = re.sub(r'<img[^>]*src="([^"]+)"[^>]*>', r'[图片: \1]', html)

    # 清理剩余 HTML 标签
    html = re.sub(r'<.*?>', '', html)
    html = unescape(html.strip())

    # 合并引用和正文
    return "\n".join(quote_parts + [html]) if html else "\n".join(quote_parts)


def upload_with_fallback(file_path, retries=2, delay=2):
    def upload_to_imgurl(path):
        try:
            with open(path, "rb") as img:
                res = requests.post("https://imgurl.org/api/v2/upload", files={"file": img}, timeout=10)
                data = res.json()
                if data.get("code") == 200:
                    return data["data"]["url"]
        except: return None

    def upload_to_catbox(path):
        try:
            with open(path, "rb") as img:
                res = requests.post("https://catbox.moe/user/api.php", data={"reqtype": "fileupload"},
                                    files={"fileToUpload": img}, timeout=10)
                if res.status_code == 200 and res.text.startswith("https://"):
                    return res.text.strip()
        except: return None

    def upload_to_telegra(path):
        try:
            with open(path, 'rb') as f:
                res = requests.post("https://telegra.ph/upload", files=[("file", f)], timeout=10)
                if res.status_code == 200 and isinstance(res.json(), list):
                    return "https://telegra.ph" + res.json()[0]["src"]
        except: return None

    for _ in range(retries):
        for method in [upload_to_imgurl, upload_to_catbox, upload_to_telegra]:
            url = method(file_path)
            if url:
                return url
        time.sleep(delay)
    return None

class FishPiChatroom:
    def __init__(self, username, password):
        self.username = username
        self.password = hashlib.md5(password.encode()).hexdigest()
        self.api_key = None
        self.base_url = "https://fishpi.cn"
        self.ws = None
        self.headers = {"User-Agent": "Mozilla/5.0"}

    def get_api_key(self):
        url = f"{self.base_url}/api/getKey"
        data = {"nameOrEmail": self.username, "userPassword": self.password}
        try:
            res = requests.post(url, json=data, headers=self.headers)
            if res.status_code == 200 and res.json().get("code") == 0:
                self.api_key = res.json().get("Key")
                self.user_id = res.json().get("userId")  # 保存自己的 senderId
                return True
        except:
            pass
        return False

    def get_node_url(self):
        url = f"{self.base_url}/chat-room/node/get?apiKey={self.api_key}"
        try:
            res = requests.get(url, headers=self.headers)
            if res.status_code == 200 and res.json().get("code") == 0:
                return res.json()["data"]
        except: pass
        return None

    def send_message(self, content):
        url = f"{self.base_url}/chat-room/send"
        data = {"apiKey": self.api_key, "content": content}
        try:
            res = requests.post(url, json=data, headers=self.headers)
            return res.status_code == 200 and res.json().get("code") == 0
        except: return False

    def connect(self, on_message_callback):
        if not self.get_api_key(): return False
        node_url = self.get_node_url()
        if not node_url: return False

        def on_message(ws, message):
            try:
                data = json.loads(message)

                # 判断是否为自己发的消息(用 senderId 而不是 userName)
                sender_id = data.get("senderId")
                if sender_id and hasattr(self, "user_id") and sender_id == self.user_id:
                    return

                user = data.get("userName", "").strip()
                if not user or user.lower() in ("系统", "system", "sys", "null", "none"):
                    user = "系统"

                raw_content = data.get("content", "")

                # 尝试将 content 解析为 dict
                content_data = None
                if isinstance(raw_content, str):
                    try:
                        content_data = json.loads(raw_content)
                    except:
                        pass

                # ===== 处理嵌套红包 =====
                if isinstance(content_data, dict) and content_data.get("msgType") == "redPacket":
                    red_type = content_data.get("type", "")
                    money = content_data.get("money", 0)
                    count = content_data.get("count", 0)
                    msg = content_data.get("msg", "")

                    type_map = {
                        "common": "普通红包",
                        "rockPaperScissors": "猜拳红包",
                        "thunder": "雷红包",
                    }
                    red_type_name = type_map.get(red_type, red_type or "红包")
                    msg_line = f"发送了一个{red_type_name}({count} 个,共 {money} 元)"
                    if msg:
                        msg_line += f":{msg}"
                    on_message_callback(f"[{user}]: {msg_line}")
                    return

                # ===== 普通文本消息 =====
                content = strip_html_tags(raw_content)
                on_message_callback(f"[{user}]: {content}")

            except Exception as e:
                print(f"[调试] 消息处理失败: {e}")

        def on_open(ws): on_message_callback("[系统]: WebSocket连接已建立")

        self.ws = websocket.WebSocketApp(
            node_url, on_message=on_message, on_open=on_open
        )
        threading.Thread(target=self.ws.run_forever, daemon=True).start()
        return True

class EmojiPanel(tk.Toplevel):
    def __init__(self, master, entry):
        super().__init__(master)
        self.entry = entry
        self.configure(bg="#2e2e2e")
        self.overrideredirect(True)
        self.attributes("-topmost", True)
        self.build_ui()

    def build_ui(self):
        for i, (emoji, label) in enumerate(EMOJI_LIST):
            btn = tk.Button(self, text=emoji, width=4, height=2, command=lambda e=emoji: self.insert_emoji(e),
                            bg="#2e2e2e", fg="white", relief="flat")
            btn.grid(row=i // 6, column=i % 6, padx=2, pady=2)

    def insert_emoji(self, emoji):
        self.entry.insert('insert', emoji)
        self.destroy()

class ChatApp:
    def __init__(self, root, client):
        self.client = client
        root.title("FishPi 聊天客户端")
        root.geometry("500x400+1400+700")
        root.configure(bg="#1e1e1e")
        root.resizable(False, False)

        self.text_area = ScrolledText(root, state='disabled', height=20, width=70,
                                      bg="#1e1e1e", fg="#d4d4d4", insertbackground="white", font=("Consolas", 10))
        self.text_area.pack(padx=10, pady=10)

        frame = tk.Frame(root, bg="#1e1e1e")
        frame.pack(padx=10, pady=(0, 10), fill='x')

        self.entry = tk.Entry(frame, width=40, bg="#2e2e2e", fg="#d4d4d4",
                              insertbackground="white", font=("Consolas", 10))
        self.entry.pack(side='left', expand=True, fill='x')
        self.entry.bind("<Return>", self.send_message)

        self.send_btn = tk.Button(frame, text="发送", bg="#4caf50", fg="white", relief="flat", command=self.send_message)
        self.send_btn.pack(side='left', padx=(5, 0))

        self.upload_btn = tk.Button(frame, text="上传图片", bg="#2196f3", fg="white", relief="flat", command=self.send_image)
        self.upload_btn.pack(side='left', padx=(5, 0))

        self.emoji_btn = tk.Button(frame, text="😀", bg="#444", fg="white", relief="flat", command=self.toggle_emoji_panel)
        self.emoji_btn.pack(side='left', padx=(5, 0))

        if not self.client.connect(self.display_message):
            self.display_message("[系统]: 无法连接到聊天室")

        self.emoji_panel = None

    def toggle_emoji_panel(self):
        if self.emoji_panel and self.emoji_panel.winfo_exists():
            self.emoji_panel.destroy()
        else:
            x = self.entry.winfo_rootx()
            y = self.entry.winfo_rooty() - 90
            self.emoji_panel = EmojiPanel(self.entry, self.entry)
            self.emoji_panel.geometry(f"+{x}+{y}")

    def display_message(self, msg):
        timestamp = datetime.now().strftime('%H:%M:%S')
        self.text_area.config(state='normal')
        self.text_area.insert('end', f"{timestamp} {msg}\n")
        self.text_area.yview('end')
        self.text_area.config(state='disabled')

    def send_message(self, event=None):
        content = self.entry.get().strip()
        if content:
            html = f"<p>{content}</p>"
            success = self.client.send_message(html)
            if not success:
                self.display_message("[系统]: 消息发送失败")
        self.entry.delete(0, 'end')

    def send_image(self):
        threading.Thread(target=self._upload_image_thread, daemon=True).start()

    def _upload_image_thread(self):
        try:
            file_path = fd.askopenfilename(filetypes=[("Image files", "*.png;*.jpg;*.jpeg;*.gif")])
            if not file_path:
                return

            if os.path.getsize(file_path) > 2 * 1024 * 1024:
                self.display_message("[系统]: 图片太大,请选择小于2MB的图片")
                return

            self.display_message("[系统]: 正在上传图片,请稍候...")

            img_url = upload_with_fallback(file_path)
            if img_url:
                html = f'<p><img src="{img_url}" /></p>'
                self.client.send_message(html)
                self.display_message(f"[{self.client.username}]: [图片: {img_url}]")
            else:
                self.display_message("[系统]: 所有图床上传失败,请稍后重试")
        except Exception as e:
            self.display_message(f"[系统]: 上传异常:{str(e)}")

if __name__ == '__main__':
    username = "请输入你的账号"
    password = "请输入你的密码"
    client = FishPiChatroom(username, password)

    root = tk.Tk()
    app = ChatApp(root, client)
    root.mainloop()

到此,完美结束,希望大家适当摸鱼,在遇到困境的时候看看聊天室的朋友们在干什么缓缓思维,换换心情,或许就能一敲十行,日进斗金呢,祝愿大家节节高升,薪资高高

### 使用 C# 开发娱乐或效率类应用的最佳实践 #### 设计原则 在开发任何应用程序之前,设计阶段至关重要。应遵循面向对象的设计原则(SOLID 原则),并考虑模块化和可扩展性[^1]。这有助于在未来轻松维护代码以及添加新功能。 #### 工具选择 对于高效开发,建议使用 Visual Studio 或者轻量级编辑器如 Visual Studio Code [^2]。这些工具有强大的 IntelliSense 功能和支持插件生态系统,能够显著提升开发者的工作效率。 #### 用户界面(UI) 如果目标是创建桌面应用程序,则可以利用 Windows Forms 或 WPF 技术来构建图形用户界面(GUI)。WPF 提供更现代的布局选项,并支持数据绑定等功能,适合复杂的应用场景;而 WinForms 更加简单易学,适用于快速原型制作。 #### 后端逻辑处理 针对后台业务逻辑部分, 可以采用 Entity Framework Core 来简化数据库交互操作 . 它提供了流畅的 LINQ 查询接口以及迁移机制, 方便管理实体模型及其变化. 另外,在实现具体功能时还需要注意异常捕获与日志记录等方面的内容: - **异常处理**: 对可能出现错误的地方进行全面覆盖, 避免程序崩溃. - **日志系统**: 实现详细的日志跟踪可以帮助定位问题所在位置及时解决BUGs. #### 测试驱动开发(TDD) 为了保证最终产品的质量, 推荐采取测试先行的方法论即TDD(Test Driven Development). 即先编写单元测试用例再完成相应的编码工作直至所有测试均能顺利通过为止. #### 版本控制 无论个人还是团队协作都离不开版本控制系统Git的支持. Git不仅便于保存不同时间节点上的修改历史还方便多人共同参与同一个项目的建设进程当中去.[^1] ```csharp // Example of simple logging mechanism using NLog library using NLog; public class LoggerService { private static readonly ILogger logger = LogManager.GetCurrentClassLogger(); public void LogInformation(string message){ logger.Info(message); } } ``` #### 结合第三方服务增强用户体验 适当引入外部API或者开源组件往往能让我们的产品更加丰富多彩比如地图显示、天气预报查询等等都可以借助现有的成熟解决方案来进行集成从而节省大量时间精力专注于核心竞争力打造上头[无引用].
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值