JAVA抖音 WSS弹幕

更新websocket读取数据。

数据格式变化不大,没有太复杂的加密。

外层多包了一层proto协议,数据增加了gzip压缩。

废话不多说,下面详细介绍。

一、浏览器包依旧采用微软playwright引擎包,访问网址,监控websocket数据收发。proto相关包也必不可少。关键引用如下。

      <dependency>
            <groupId>com.microsoft.playwright</groupId>
            <artifactId>playwright</artifactId>
            <version>1.17.1</version>
        </dependency>
        <dependency>
            <groupId>com.google.protobuf</groupId>
            <artifactId>protobuf-java</artifactId>
            <version>3.5.1</version>
        </dependency>
    <!--    <dependency>
            <groupId>com.google.protobuf</groupId>
            <artifactId>protobuf-java</artifactId>
            <version>3.5.1</version>
        </dependency>-->
        <!-- https://mvnrepository.com/artifact/com.google.protobuf/protobuf-java-util -->
        <dependency>
            <groupId>com.google.protobuf</groupId>
            <artifactId>protobuf-java-util</artifactId>
            <version>3.5.1</version>
        </dependency>

二、proto数据协议,除了原有的message外,更新了对response也进行了封装。proto文件格式大致如下

syntax = "proto3";
option java_outer_classname = "WSS";//生成的外部类名,同时也是文件名
option java_package = "com.yplan.dm.proto";//生成的外部类名,同时也是文件名

message WssResponse{
  int64 wss_push_room_id = 1;
  int64 wss_push_did = 2;
  int64 wss_push_log_id = 3;
  int64 wss_fetch_ms = 4;
  int64 wss_push_ms = 5;
  string wss_msg_type = 6;
  string pb = 7;
  bytes data = 8;
  int64 server_time = 9;
  string compress_type = 10;
}

消息的proto

syntax = "proto3";
option java_outer_classname = "DanmuvoWSS";//生成的外部类名,同时也是文件名
option java_package = "com.yplan.dm.proto";//生成的外部类名,同时也是文件名

message Response{
  repeated Message messages = 1;
  string cursor = 2;
  int64 fetchInterval = 3;
  int64 now = 4;
  string internalExt = 5;
  int32 fetchType = 6;
  map<string, string> routeParams = 7;
  int64 heartbeatDuration = 8;
  bool needAck = 9;
  string pushServer = 10;
}

message Message{
  string method = 1;
  bytes payload = 2;
  int64 msgId = 3;
  int32 msgType = 4;
  int64 offset = 5;
}
……
……
……
比较长省略了,和改为websocket之前一样

关键代码如下; 【playwright 访问直播间】->【监听websocket返回值】->【数据解析】

 private void trackDouyin() {
        try (Playwright playwright = Playwright.create()) {
            Browser browser = playwright.webkit().launch();
            Page page = browser.newPage();
//                page.emulateMedia(null);
         
            Map<String, String> map = new HashMap<>();
            Consumer<Request> listener = request -> {
//                    if (request.url().startsWith("https://live.douyin.com/webcast/im/fetch/?")) {
            };
            //监听websocket
            page.onWebSocket(new Consumer<WebSocket>() {
                @Override
                public void accept(WebSocket webSocket) {
                    webSocket.onFrameReceived(new Consumer<WebSocketFrame>() {
                        @Override
                        public void accept(WebSocketFrame webSocketFrame) {
                            final byte[] data = webSocketFrame.binary();
                            System.out.println("::::::::::::::::::::::::::::::::::::::::::::::::::::::::");
                            try {
                                //最外层解析 try catch 不指定ws路径也可以,解析失败不会崩溃
                                //proto解析外层
                                WSS.WssResponse wss = WSS.WssResponse.parseFrom(data);
                                System.out.println(wss);
                                //GZIP解压data数据
                                final byte[] uncompress = Utils.uncompress(wss.getData());
                                //解析data
                                DanmuvoWSS.Response response = DanmuvoWSS.Response.parseFrom(uncompress);
                                final List<DanmuvoWSS.Message> messagesList = response.getMessagesList();
                                System.out.println(messagesList);
                                //根据message区分message类型解析 与之前接口相同
                                decodeMessage(messagesList, manager);
                            } catch (InvalidProtocolBufferException e) {
                                e.printStackTrace();
                            }

                            System.out.println("11111111111111111111111111111111111111111111111111111111111111111111111111111111");
                            System.out.println("::::::::::::::::::::::::::::::::::::::::::::::::::::::::");

                        }
                    });
                }
            });

            page.onRequestFinished(listener);
            //访问页面
            page.navigate(url);
//                browser.startTracing();

            while (true) {
                try {
                    //循环访问激活页面
                    page.content();
                    if (stop) {
                        if (manager != null) {
                            browser.close();
                            closeManager();

                        }
                        break;
                    }
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

        }
    }

GZIP解压采用JAVA原生即可

public static byte[] uncompress(ByteString bytes1) {
        final byte[] bytes = bytes1.toByteArray();
        if (bytes == null || bytes.length == 0) {
            return null;
        }
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        ByteArrayInputStream in = new ByteArrayInputStream(bytes);
        try {
            GZIPInputStream ungzip = new GZIPInputStream(in);
            byte[] buffer = new byte[5096];
            int n;
            while ((n = ungzip.read(buffer)) >= 0) {
                out.write(buffer, 0, n);
            }
        } catch (IOException e) {
            System.out.println("gzip uncompress error."+ e);
        }

        return out.toByteArray();
}

简单搭建页面-实现效果;

GZH搜“桃哥543技术交流”,获取发"弹幕"源码

 

### 实现 UniApp 中的 WSS 弹幕功能 为了实现在 UniApp 中通过 WebSocket 安全连接 (WSS) 获取并展示类似于平台上的实时评论或弹幕效果,可以按照如下方法构建应用逻辑[^1]。 #### 创建 WebSocket 连接实例 首先,在 Vue 组件生命周期钩子 `mounted` 或者页面加载函数内初始化 WebSockets: ```javascript export default { data() { return { socketTask: null, messageList: [] }; }, mounted() { this.initWebSocket(); }, methods: { initWebSocket() { const url = 'wss://example.com/socket'; // 替换成目标服务器地址 uni.connectSocket({ url: url.replace('ws', 'wss'), success(res) { console.log('WebSocket 成功打开'); } }); this.socketTask = uni.onSocketMessage((res) => { let msg = JSON.parse(res.data); this.messageList.push(msg); // 将收到的消息推入消息列表中 }); uni.onSocketOpen(() => { console.log('WebSocket 已打开'); }); uni.onSocketError(function (errormsg) { console.error(errormsg.errMsg); }); } } } ``` #### 动态渲染弹幕组件 接着定义一个简单的模板来显示这些动态获取到的信息作为滚动字幕。这里假设每条信息都有唯一的 ID 和文本内容属性。 ```html <template> <view class="container"> <!-- 弹幕容器 --> <scroll-view scroll-x="true" :style="{height: `${messageList.length * 40}px`}"> <block v-for="(item, index) in messageList" :key="index"> <text>{{ item.text }}</text><br /> </block> </scroll-view> <!-- 页面其他部分... --> </view> </template> <style scoped lang="scss"> .container { position: relative; } /* 设置字体样式 */ .scroll-view >>> text { font-size: 32rpx; color: white; background-color: rgba(0, 0, 0, .7); padding: 8rpx 16rpx; border-radius: 8rpx; margin-right: 20rpx; animation-name: slideInLeft; /* 使用 CSS 动画库中的动画名称 */ animation-duration: 5s; display: inline-block; } @import "path/to/your/css/animations.css"; // 导入自定义CSS文件路径下的动画规则 </style> ``` 此代码片段展示了如何设置 WebSocket 的监听器以及处理传入的数据流,并将其转换成可视化的形式呈现给用户。需要注意的是,实际开发过程中还需要考虑更多细节问题,比如错误重试机制、心跳检测防止断线等优化措施。
评论 30
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

桃哥543

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值