Skip to content

Commit

Permalink
feat: 支持移除重复弹幕
Browse files Browse the repository at this point in the history
  • Loading branch information
yichengchen committed Feb 7, 2025
1 parent 15ffc39 commit 5d17aec
Show file tree
Hide file tree
Showing 6 changed files with 46 additions and 12 deletions.
3 changes: 3 additions & 0 deletions BilibiliLive/Component/Settings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,9 @@ enum Settings {

@UserDefault("Settings.danmuFilter", defaultValue: false)
static var enableDanmuFilter: Bool

@UserDefault("Settings.danmuRemoveDup", defaultValue: false)
static var enableDanmuRemoveDup: Bool
}

struct MediaQuality {
Expand Down
3 changes: 2 additions & 1 deletion BilibiliLive/Component/Video/NewVideoPlayerViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ class VideoPlayerViewModel {
var nextProvider: VideoNextProvider?

private var playInfo: PlayInfo
private let danmuProvider = VideoDanmuProvider()
private let danmuProvider = VideoDanmuProvider(enableDanmuFilter: Settings.enableDanmuFilter,
enableDanmuRemoveDup: Settings.enableDanmuRemoveDup)
private var videoDetail: VideoDetail?
private var cancellable = Set<AnyCancellable>()
private var playPlugin: CommonPlayerPlugin?
Expand Down
16 changes: 14 additions & 2 deletions BilibiliLive/Component/Video/VideoDanmuProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@ struct Danmu: Codable {
}

class VideoDanmuProvider: DanmuProviderProtocol {
var cid: Int!
private var cid: Int!
private let enableDanmuFilter: Bool
private let enableDanmuRemoveDup: Bool
private var allDanmus = [Danmu]()
private var playingDanmus = [Danmu]()

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

init(enableDanmuFilter: Bool, enableDanmuRemoveDup: Bool) {
self.enableDanmuFilter = enableDanmuFilter
self.enableDanmuRemoveDup = enableDanmuRemoveDup
}

func initVideo(cid id: Int, startPos: Int) async {
cid = id
upDanmus.removeAll()
Expand Down Expand Up @@ -108,7 +115,12 @@ class VideoDanmuProvider: DanmuProviderProtocol {
var dms = reply.elems
.filter { $0.mode <= 5 }

if Settings.enableDanmuFilter {
if enableDanmuRemoveDup {
var set = Set<String>()
dms = dms.filter { set.insert($0.content).inserted }
}

if enableDanmuFilter {
dms = dms.filter {
VideoDanmuFilter.shared.accept($0.content)
}
Expand Down
33 changes: 25 additions & 8 deletions BilibiliLive/Module/Live/LiveDanMuProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,19 @@ import SwiftyJSON

class LiveDanMuProvider: DanmuProviderProtocol {
let observerPlayerTime = false
let enableDanmuRemoveDup: Bool
var onSendTextModel = PassthroughSubject<DanmakuTextCellModel, Never>()

private var websocket: WebSocketRequest?
private var heartBeatTimer: Timer?
private let roomID: Int
private var token = ""
private var danmuSet = Set<String>()
private var danmuSetClearTimer: Timer?

init(roomID: Int) {
init(roomID: Int, removeDup: Bool) {
self.roomID = roomID
enableDanmuRemoveDup = removeDup
}

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

func start() async throws {
stop()
let info = try await WebRequest.requestDanmuServerInfo(roomID: roomID)
guard let server = info.host_list.first else {
Logger.info("Get room server info Fail")
Expand All @@ -45,11 +50,20 @@ class LiveDanMuProvider: DanmuProviderProtocol {
websocket = AF.webSocketRequest(to: "wss://\(server.host):\(server.wss_port)/sub", headers: afheaders).streamMessageEvents { [weak self] event in
self?.handleWebsocketEvent(event: event)
}

if enableDanmuRemoveDup {
danmuSetClearTimer = Timer.scheduledTimer(withTimeInterval: 60, repeats: true) {
[weak self] _ in
self?.danmuSet.removeAll(keepingCapacity: true)
}
}
}

func stop() {
websocket?.close(sending: .normalClosure)
heartBeatTimer?.invalidate()
danmuSet.removeAll()
danmuSetClearTimer?.invalidate()
}

private func setupHeartBeat() {
Expand Down Expand Up @@ -122,35 +136,38 @@ extension LiveDanMuProvider {
case "DANMU_MSG":
if let str = json["info"][1].string {
let model = DanmakuTextCellModel(str: str)
onSendTextModel.send(model)
sentDanmuModel(model)
}
case "DM_INTERACTION":
guard let data = json["data"]["data"].string else { return }
let comboArr = JSON(parseJSON: data)["combo"]
for combo in comboArr.arrayValue {
if let str = combo["content"].string {
let model = DanmakuTextCellModel(str: str)
onSendTextModel.send(model)
sentDanmuModel(model)
}
}
case "SUPER_CHAT_MESSAGE":
if let str = json["data"]["message"].string {
let model = DanmakuTextCellModel(str: str)
model.type = .top
model.displayTime = 60
sentDanmuModel(model)
}
default:
break
}
}
}

private func getDanMu(data: [JSON]) -> [String] {
return data.filter {
$0["cmd"].stringValue == "DANMU_MSG"
}.compactMap { json in
json["info"][1].string
private func sentDanmuModel(_ model: DanmakuTextCellModel) {
if enableDanmuRemoveDup {
if danmuSet.contains(model.text) {
return
}
danmuSet.insert(model.text)
}
onSendTextModel.send(model)
}
}

Expand Down
2 changes: 1 addition & 1 deletion BilibiliLive/Module/Live/LivePlayerViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ class LivePlayerViewModel {
}

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

try? await danMuProvider?.start()
Expand Down
1 change: 1 addition & 0 deletions BilibiliLive/Module/Personal/SettingsViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@ class SettingsViewController: UIViewController {
}
}
}
Toggle(title: "移除重复弹幕", setting: Settings.enableDanmuRemoveDup, onChange: Settings.enableDanmuRemoveDup.toggle())
Actions(title: "弹幕大小", message: "默认为36", current: Settings.danmuSize.title, options: DanmuSize.allCases, optionString: DanmuSize.allCases.map({ $0.title })) {
Settings.danmuSize = $0
}
Expand Down

0 comments on commit 5d17aec

Please sign in to comment.