Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: 支持移除重复弹幕 #131

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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