Skip to content

Commit 5d17aec

Browse files
committed
feat: 支持移除重复弹幕
1 parent 15ffc39 commit 5d17aec

6 files changed

+46
-12
lines changed

BilibiliLive/Component/Settings.swift

+3
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,9 @@ enum Settings {
110110

111111
@UserDefault("Settings.danmuFilter", defaultValue: false)
112112
static var enableDanmuFilter: Bool
113+
114+
@UserDefault("Settings.danmuRemoveDup", defaultValue: false)
115+
static var enableDanmuRemoveDup: Bool
113116
}
114117

115118
struct MediaQuality {

BilibiliLive/Component/Video/NewVideoPlayerViewModel.swift

+2-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ class VideoPlayerViewModel {
2828
var nextProvider: VideoNextProvider?
2929

3030
private var playInfo: PlayInfo
31-
private let danmuProvider = VideoDanmuProvider()
31+
private let danmuProvider = VideoDanmuProvider(enableDanmuFilter: Settings.enableDanmuFilter,
32+
enableDanmuRemoveDup: Settings.enableDanmuRemoveDup)
3233
private var videoDetail: VideoDetail?
3334
private var cancellable = Set<AnyCancellable>()
3435
private var playPlugin: CommonPlayerPlugin?

BilibiliLive/Component/Video/VideoDanmuProvider.swift

+14-2
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,9 @@ struct Danmu: Codable {
3737
}
3838

3939
class VideoDanmuProvider: DanmuProviderProtocol {
40-
var cid: Int!
40+
private var cid: Int!
41+
private let enableDanmuFilter: Bool
42+
private let enableDanmuRemoveDup: Bool
4143
private var allDanmus = [Danmu]()
4244
private var playingDanmus = [Danmu]()
4345

@@ -59,6 +61,11 @@ class VideoDanmuProvider: DanmuProviderProtocol {
5961
private let segmentDuration = 60 * 6
6062
private func getSegmentIdx(time: TimeInterval) -> Int { Int(time) / segmentDuration + 1 }
6163

64+
init(enableDanmuFilter: Bool, enableDanmuRemoveDup: Bool) {
65+
self.enableDanmuFilter = enableDanmuFilter
66+
self.enableDanmuRemoveDup = enableDanmuRemoveDup
67+
}
68+
6269
func initVideo(cid id: Int, startPos: Int) async {
6370
cid = id
6471
upDanmus.removeAll()
@@ -108,7 +115,12 @@ class VideoDanmuProvider: DanmuProviderProtocol {
108115
var dms = reply.elems
109116
.filter { $0.mode <= 5 }
110117

111-
if Settings.enableDanmuFilter {
118+
if enableDanmuRemoveDup {
119+
var set = Set<String>()
120+
dms = dms.filter { set.insert($0.content).inserted }
121+
}
122+
123+
if enableDanmuFilter {
112124
dms = dms.filter {
113125
VideoDanmuFilter.shared.accept($0.content)
114126
}

BilibiliLive/Module/Live/LiveDanMuProvider.swift

+25-8
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,19 @@ import SwiftyJSON
1313

1414
class LiveDanMuProvider: DanmuProviderProtocol {
1515
let observerPlayerTime = false
16+
let enableDanmuRemoveDup: Bool
1617
var onSendTextModel = PassthroughSubject<DanmakuTextCellModel, Never>()
1718

1819
private var websocket: WebSocketRequest?
1920
private var heartBeatTimer: Timer?
2021
private let roomID: Int
2122
private var token = ""
23+
private var danmuSet = Set<String>()
24+
private var danmuSetClearTimer: Timer?
2225

23-
init(roomID: Int) {
26+
init(roomID: Int, removeDup: Bool) {
2427
self.roomID = roomID
28+
enableDanmuRemoveDup = removeDup
2529
}
2630

2731
deinit {
@@ -31,6 +35,7 @@ class LiveDanMuProvider: DanmuProviderProtocol {
3135
func playerTimeChange(time: TimeInterval) {}
3236

3337
func start() async throws {
38+
stop()
3439
let info = try await WebRequest.requestDanmuServerInfo(roomID: roomID)
3540
guard let server = info.host_list.first else {
3641
Logger.info("Get room server info Fail")
@@ -45,11 +50,20 @@ class LiveDanMuProvider: DanmuProviderProtocol {
4550
websocket = AF.webSocketRequest(to: "wss://\(server.host):\(server.wss_port)/sub", headers: afheaders).streamMessageEvents { [weak self] event in
4651
self?.handleWebsocketEvent(event: event)
4752
}
53+
54+
if enableDanmuRemoveDup {
55+
danmuSetClearTimer = Timer.scheduledTimer(withTimeInterval: 60, repeats: true) {
56+
[weak self] _ in
57+
self?.danmuSet.removeAll(keepingCapacity: true)
58+
}
59+
}
4860
}
4961

5062
func stop() {
5163
websocket?.close(sending: .normalClosure)
5264
heartBeatTimer?.invalidate()
65+
danmuSet.removeAll()
66+
danmuSetClearTimer?.invalidate()
5367
}
5468

5569
private func setupHeartBeat() {
@@ -122,35 +136,38 @@ extension LiveDanMuProvider {
122136
case "DANMU_MSG":
123137
if let str = json["info"][1].string {
124138
let model = DanmakuTextCellModel(str: str)
125-
onSendTextModel.send(model)
139+
sentDanmuModel(model)
126140
}
127141
case "DM_INTERACTION":
128142
guard let data = json["data"]["data"].string else { return }
129143
let comboArr = JSON(parseJSON: data)["combo"]
130144
for combo in comboArr.arrayValue {
131145
if let str = combo["content"].string {
132146
let model = DanmakuTextCellModel(str: str)
133-
onSendTextModel.send(model)
147+
sentDanmuModel(model)
134148
}
135149
}
136150
case "SUPER_CHAT_MESSAGE":
137151
if let str = json["data"]["message"].string {
138152
let model = DanmakuTextCellModel(str: str)
139153
model.type = .top
140154
model.displayTime = 60
155+
sentDanmuModel(model)
141156
}
142157
default:
143158
break
144159
}
145160
}
146161
}
147162

148-
private func getDanMu(data: [JSON]) -> [String] {
149-
return data.filter {
150-
$0["cmd"].stringValue == "DANMU_MSG"
151-
}.compactMap { json in
152-
json["info"][1].string
163+
private func sentDanmuModel(_ model: DanmakuTextCellModel) {
164+
if enableDanmuRemoveDup {
165+
if danmuSet.contains(model.text) {
166+
return
167+
}
168+
danmuSet.insert(model.text)
153169
}
170+
onSendTextModel.send(model)
154171
}
155172
}
156173

BilibiliLive/Module/Live/LivePlayerViewModel.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ class LivePlayerViewModel {
167167
}
168168

169169
@MainActor private func initDanmu() async -> [CommonPlayerPlugin] {
170-
danMuProvider = LiveDanMuProvider(roomID: roomID)
170+
danMuProvider = LiveDanMuProvider(roomID: roomID, removeDup: Settings.enableDanmuRemoveDup)
171171
let danmuPlugin = DanmuViewPlugin(provider: danMuProvider!)
172172

173173
try? await danMuProvider?.start()

BilibiliLive/Module/Personal/SettingsViewController.swift

+1
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ class SettingsViewController: UIViewController {
186186
}
187187
}
188188
}
189+
Toggle(title: "移除重复弹幕", setting: Settings.enableDanmuRemoveDup, onChange: Settings.enableDanmuRemoveDup.toggle())
189190
Actions(title: "弹幕大小", message: "默认为36", current: Settings.danmuSize.title, options: DanmuSize.allCases, optionString: DanmuSize.allCases.map({ $0.title })) {
190191
Settings.danmuSize = $0
191192
}

0 commit comments

Comments
 (0)