.NET斗鱼直播弹幕客户端(下)
.NET斗鱼直播弹幕客户端(下)
在上篇文章中,我们提到了如何使用.NET
连接斗鱼TV直播弹幕的基本操作。然而想要做得好,做得容易扩展,就需要做进一步的代码整理。
本文将涉及以下内容:
- 介绍如何使用
Reactive Extensions
(Rx
),演示这一系列操作用起来,就像写Hello World
一样简单; - 用我自制的“准游戏引擎”
FlysEngine
,只需少量代码,即可实现桌面弹幕的效果; - 最后提供一波“伸手党”福利,文中所有可运行、完整代码,将按原样奉上。
Rx.NET
Rx
,是Reactive Extensions
的缩写,据说Rx
发明于.NET 2.0
时代的微软。那时候还没有async/await
。后来,也许由于RX
对编程语言要求不高(如不要求内置协程
-coroutine
),RX
反倒在.NET
之外的其它编程语言中大行其道。如rx.js
、RxJava
等等。
C#
从.NET 2.0
就提供了yield
关键字,然后3.0
提供了LINQ
,5.0
提供了async/await
,因此很多时候RX
的意义不大。但在某些情况下(如这种情况),就有意义了,原因请见下图:
- | 单数据 | 多数据 |
---|---|---|
同步 | T |
IEnumerable<T> |
异步 | Task<T> |
Observable<T> /IAsyncEnumerable<T> |
C#
的协程
支持同步多数据,异步单数据,但不支持异步多数据(C# 8.0
现在已经支持IAsyncEnumerable<T>
),本文将使用Rx
来包装上一篇文章的斗鱼TV直播弹幕客户端。
来先看一波老代码:
注意剪头所指的位置,那是基础代码“出口”,或者业务逻辑“入口”,基础代码不能简单地return
打断,因为它要不停地输出数据,这时就需要像协程
等编程语言功能,或者Rx
的支持。
Rx
-Hello World
首先引入NuGet
包System.Reactive
,一个简单的“异步多值返回”的Rx
示例代码如下:
Observable.Create<int>(async (o, cancellationToken) =>
{
for (var i = 0; i < 5; ++i)
{
await Task.Delay(1000);
o.OnNext(i);
}
o.OnCompleted();
})
麻雀虽小,五脏俱全,如代码所示,几乎只需在正常代码外包一层Rx
,即可享受Rx
的好处。
使用Rx
使用起来就更简单了,上篇展示的长达252
行代码的demo
,现在只需一行代码,即可无侵入式地调用:
DouyuBarrage.ChatMessageFromUrl("https://www.douyu.com/scboy")
调用结果如下(和昨天效果完全一样):
Rx
的其它好处
除了调用简单之外,Rx
的扩展也非常非常简单,比如完成以下操作,以前可能非常麻烦,需要改多处代码,而使用Rx
,只需像LINQ
一样加几个指令即可:
同时抓多个直播间的弹幕
#load ".\barrage.linq"
DouyuBarrage.ChatMessageFromUrl("https://www.douyu.com/scboy")
.Select(x => new { Room = "scboy", Message = x.Message })
.Merge(DouyuBarrage.ChatMessageFromUrl("https://www.douyu.com/topic/lscs?rid=633019")
.Select(x => new { Room = "lalala", Message = x.Message}))
效果如下:
只需一个Merge
指令即可合并两个直播间的弹幕(Observable<T>
)
扩展简单
比如只想提取特殊的弹幕,或者数据之前想做一些转换,可以使用Where
,Select
等数据过滤和转换操作符,符合LINQ
的习惯,非常好用。比如我正常弹幕的提取,其实是从JObjectFromUrl
转换而来,JObjectFromUrl
,又是从RawFromUrl
转换而来,这提高了扩展性,又无需修改老代码,正是所谓“对扩展开放,对修改封闭”的开放-封闭原则:
public IObservable<JToken> JObjectFromUrl(string url)
=> RawFromUrl(url).Select(MsgTool.DecodeStringToJObject);
public IObservable<Barrage> ChatMessageFromUrl(string url) =>
JObjectFromUrl(url)
.Where(x => x["type"].Value<string>() == "chatmsg")
.Select(Barrage.FromJToken);
又比如可能我只想提取彩色弹幕,我只需ChatMessageFromUrl().Where(x => x.Color != 0xffffff)
即可,非常方便。
桌面弹幕
这可能是另一个主题——实时渲染,用到了我自己写的“准游戏引擎”FlysEngine
,因此需要安装NuGet
包:FlysEngine.Desktop
。
桌面弹幕
不同于网页弹幕
,只能在网页中显示,而桌面弹幕
可以直接显示在屏幕最上方。有些公司年会可能用到了桌面弹幕
,这无疑增加了主持人与观众们的互动,提高了群众参与的积极性。
注意:本文中所说
FlysEngine
的实质是Direct2D
和Windows API
-UpdateLayeredWindowIndirect
函数。如果不想使用FlysEngine
,完全可以使用其它方式代替。最简单的方式是使用WPF
,然后设置AllowsTransparency=true
,但这样性能会差一些。本文介绍的方法,CPU
使用率将保持在0%
左右!
桌面弹幕的要点
- 渲染文字
DirectWrite
; - 文字移动 将文字从屏幕右边移动到左边;
- 检测是否离开屏幕 如果屏幕上不显示弹幕,即可将弹幕删除;
- 初始位置确定 如果一行显示不下,则将弹幕放在下一行。
渲染文字
渲染文字一般是通过DirectWrite
,它性能很好,功能也强大。FlysEngine
将DirectWrite
封装了,因此直接用便是。
注意:
DirectWrite
不仅渲染文字,还提供了.Metrics
属性,可以计算文字渲染之后的大小,这会让事情变得容易很多。
文字移动
文字移动首先需要一个位置,随着时间变化,将该位置的X
坐标不段减少即可。这可以通过FlysEngine
中的UpdateLogic
事件实现,它会定期调用,传入一个float dt
,代码离上一次调用UpdateLogic
的时间间隔。因此可以利用这个dt
变量,计算是弹幕的新位置:
public void MoveLeft(float dt, float speed)
{
Position.X -= dt * speed;
}
检测是否离开屏幕
由于我们已知弹幕是矩形,(很显然屏幕也是矩形)因此这个检测比较简单,直接判断文字的右边缘
是否大于0
即可。
也由于需要经常/频繁地删除在屏幕上的弹幕对象,因此最好储存弹幕的数据结构别使用O(n)
的集合,如最好别使用List<T>
,它是线性表。我这里使用的是链表
,.NET
的链表实现是LinkedList<T>
(很多人以为是List<T>
)。
多说一句,链接的遍历算法如下(while
循环):
var node = barrages.First;
while (node != null)
{
var next = node.Next;
// do work here
node = next;
}
之所以不使用foreach
来遍历,因为这样遍历可以实现高性能的“边遍历、边删除”的实现。
初始位置确定
这一点思想需要多想想,需要从第一行开始,从后往前看,看最后那一边弹幕是否大于屏幕右边。只要想清楚了,代码很容易:
float GetNewY()
{
float y = 0;
while (barrages.Reverse().Where(x => x.Position.Y == y).Select(x => x.Rect.Right).FirstOrDefault() > form.Width)
{
y += FontSize;
}
return y;
}
有了这些,就可以愉快地感受屏幕弹幕啦!
彩色emoji
表情
Direct2D
支持——但默认不显示弹幕emoji
表情:
需要多加一个枚举让其支持:
target.DrawText("
.NET斗鱼直播弹幕客户端(下)的更多相关文章
- .NET斗鱼直播弹幕客户端(2021)
.NET斗鱼直播弹幕客户端(2021) 离之前更新的两篇<.NET斗鱼直播弹幕客户端>已经有一段时间,近期有许多客户向我反馈刚好有这方面的需求,但之前的代码不能用了--但网上许多流传的No ...
- .NET斗鱼直播弹幕客户端(上)
现在直播平台由于弹幕的存在,主播与观众可以更轻松地进行互动,非常受年轻群众的欢迎.斗鱼TV就是一款非常流行的直播平台,弹幕更是非常火爆.看到有不少主播接入弹幕语音播报器.弹幕点歌等模块,这都需要首先连 ...
- ubuntu下使用OBS开斗鱼直播
系统环境:ubuntu 15.10,OBS Studio 0.13.1 OBS是可以在linux,windows,mac下直播的开源软件,官方地址:https://obsproject.com/ 斗鱼 ...
- android文件管理器源码、斗鱼直播源码、企业级erp源码等
Android精选源码 文件清理管理器 自定义水平带数字的进度条以及自定义圆形带数字的进度条 利用sectionedRecyclerViewAdapter实现分组列表的recyclerView源码 流 ...
- Android Studio 直播弹幕
我只是搬运:https://blog.csdn.net/HighForehead/article/details/55520199 写的很好很详细,挺有参考价值的 demo直通车:https://do ...
- Python爬虫实例(二)使用selenium抓取斗鱼直播平台数据
程序说明:抓取斗鱼直播平台的直播房间号及其观众人数,最后统计出某一时刻的总直播人数和总观众人数. 过程分析: 一.进入斗鱼首页http://www.douyu.com/directory/all 进入 ...
- Scrapy项目 - 实现斗鱼直播网站信息爬取的爬虫设计
要求编写的程序可爬取斗鱼直播网站上的直播信息,如:房间数,直播类别和人气等.熟悉掌握基本的网页和url分析,同时能灵活使用Xmind工具对Python爬虫程序(网络爬虫)流程图进行分析. 一.项目 ...
- iOS仿QQ侧滑菜单、登录按钮动画、仿斗鱼直播APP、城市选择器、自动布局等源码
iOS精选源码 QQ侧滑菜单,右滑菜单,QQ展开菜单,QQ好友分组 登录按钮 3分钟快捷创建高性能轮播图 ScrollView嵌套ScrolloView(UITableView .UICollecti ...
- 使用Selenium模拟浏览器抓取斗鱼直播间信息
获取斗鱼直播间每个房间的名称.观看人数.tag.主播名字 代码: import time from multiprocessing import Pool from selenium import w ...
随机推荐
- hdu 5495 LCS(并查集)
Problem Description You are given two sequence {a1,a2,...,an} and {b1,b2,...,bn}. Both sequences are ...
- Atcoder E - RGB Sequence(dp)
题目链接:http://arc074.contest.atcoder.jp/tasks/arc074_c 题意:一共有3种颜色,红色,绿色,蓝色.给出m个要求l,r,x表示在区间[l,r]内要有x种不 ...
- Investigating Div-Sum Property UVA - 11361
An integer is divisible by 3 if the sum of its digits is also divisible by 3. For example, 3702 is d ...
- codeforces 789 C. Functions again(dp求区间和最大)
题目链接:http://codeforces.com/contest/789/problem/C 题意:就是给出一个公式 然后给出一串数求一个区间使得f(l,r)最大. 这题需要一个小小的处理 可以设 ...
- js中的this介绍
今天跟大家一起简单的来了解一下js中一个有趣的东西,this. 在js中我们用面向对象的思想去编写的时候,各个模块之间的变量就不那么容易获取的到了,当然也可以通过闭包的方式拿到其他函数的变量,如果说每 ...
- MyCat数据库的基础配置及使用
一.为什么需要分布式数据据库 随着计算机和信息技术的迅猛发展,行业应用系统的规模迅速扩大,行业应用所产生的数据量呈爆炸式增长,动辄达到数百TB甚至数百PB的规模,已远远超出传统计算技术和信息系统的处理 ...
- MariaDB数据库自学一
在CentOS下安装Mariadb 数据库,命令: yum -y mariadb mariadb.server 等待几分钟后就可以自动完成安装了,然后启动对应的服务: systemctl start ...
- maven:Fatal error compiling: 无效的目标发行版: 1.8.0_45 -> [Help 1]
使用mvn clean install命令的时候出现如下的错误: Failed to execute goal org.apache.maven.plugins:maven-compiler-plug ...
- [币严区块链]数字货币交易所之以太坊(ETH)钱包对接(四) 使用web3j对接以太坊钱包
本文给大家介绍了 Web3j Java 版本的框架的基本使用,大家可根据本文的内容进行扩展性的练习,对其他 API 的使用进行尝试. 使用web3j对接以太坊钱包 一.开发准备事项 启动 Geth 此 ...
- Winform中实现更改DevExpress的RadioGroup的选项时更改其他控件(TextEdit、ColorPickEdit)的值
场景 Winform中实现读取xml配置文件并动态配置ZedGraph的RadioGroup的选项: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article ...