Skip to content

Commit 69b834c

Browse files
committed
feat: 支持屏蔽词同步
1 parent e49f52f commit 69b834c

File tree

6 files changed

+133
-3
lines changed

6 files changed

+133
-3
lines changed

BilibiliLive.xcodeproj/project.pbxproj

+4
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@
9595
49A441CD293F6DFD0007606C /* FollowUpsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49A441CC293F6DFD0007606C /* FollowUpsViewController.swift */; };
9696
49ADA8392D0BCD79004801EF /* MainActor+Safe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49ADA8382D0BCD71004801EF /* MainActor+Safe.swift */; };
9797
49ADA83D2D0C0FC2004801EF /* BvidConvertor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49ADA83C2D0C0FC2004801EF /* BvidConvertor.swift */; };
98+
49ADA83F2D0C1ADF004801EF /* VideoDanmuFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49ADA83E2D0C1ADF004801EF /* VideoDanmuFilter.swift */; };
9899
49D250A02C118FA700173908 /* URLPlayPlugin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49D2509F2C118FA700173908 /* URLPlayPlugin.swift */; };
99100
49D250A22C11A82B00173908 /* AVPlayerMetaUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49D250A12C11A82B00173908 /* AVPlayerMetaUtils.swift */; };
100101
49D39F28263AD40000F14497 /* WebRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49D39F27263AD40000F14497 /* WebRequest.swift */; };
@@ -301,6 +302,7 @@
301302
49A441CC293F6DFD0007606C /* FollowUpsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FollowUpsViewController.swift; sourceTree = "<group>"; };
302303
49ADA8382D0BCD71004801EF /* MainActor+Safe.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MainActor+Safe.swift"; sourceTree = "<group>"; };
303304
49ADA83C2D0C0FC2004801EF /* BvidConvertor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BvidConvertor.swift; sourceTree = "<group>"; };
305+
49ADA83E2D0C1ADF004801EF /* VideoDanmuFilter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoDanmuFilter.swift; sourceTree = "<group>"; };
304306
49D2509F2C118FA700173908 /* URLPlayPlugin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLPlayPlugin.swift; sourceTree = "<group>"; };
305307
49D250A12C11A82B00173908 /* AVPlayerMetaUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AVPlayerMetaUtils.swift; sourceTree = "<group>"; };
306308
49D39F27263AD40000F14497 /* WebRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebRequest.swift; sourceTree = "<group>"; };
@@ -421,6 +423,7 @@
421423
2806E5212C16011B00164C10 /* ReplyCell.swift */,
422424
2806E5222C16011B00164C10 /* ReplyCell.xib */,
423425
49389D6128AFEA2900B9DAFD /* VideoDanmuProvider.swift */,
426+
49ADA83E2D0C1ADF004801EF /* VideoDanmuFilter.swift */,
424427
497CF2322C16EDAC006E1488 /* MaskProvider */,
425428
492AD70C2BFF33DF007221C8 /* VideoPlayerViewController.swift */,
426429
492AD70E2BFF6761007221C8 /* NewVideoPlayerViewModel.swift */,
@@ -918,6 +921,7 @@
918921
AEA6AB1628FFE951007CE72E /* SettingsViewController.swift in Sources */,
919922
49389D8928B0A1B700B9DAFD /* UIViewController+Ext.swift in Sources */,
920923
AE2B41572914C02000BF2B0B /* Int.swift in Sources */,
924+
49ADA83F2D0C1ADF004801EF /* VideoDanmuFilter.swift in Sources */,
921925
498CF2932B63AABE0009793E /* memory.c in Sources */,
922926
49ADA8392D0BCD79004801EF /* MainActor+Safe.swift in Sources */,
923927
498CF2A72B63AABE0009793E /* decode.c in Sources */,

BilibiliLive/Component/Settings.swift

+3
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,9 @@ enum Settings {
104104

105105
@UserDefaultCodable("Settings.SponsorBlockType", defaultValue: SponsorBlockType.none)
106106
static var enableSponsorBlock: SponsorBlockType
107+
108+
@UserDefault("Settings.danmuFilter", defaultValue: false)
109+
static var enableDanmuFilter: Bool
107110
}
108111

109112
struct MediaQuality {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
//
2+
// VideoDanmuFilter.swift
3+
// BilibiliLive
4+
//
5+
// Created by yicheng on 2024/12/13.
6+
//
7+
8+
import UIKit
9+
10+
class VideoDanmuFilter {
11+
static let shared = VideoDanmuFilter()
12+
13+
private var stringFilters = [String]()
14+
private var regexFilters = [Regex<AnyRegexOutput>]()
15+
private init() {
16+
refreshCache(rules: VideoDanmuFilterStorage.filters)
17+
}
18+
19+
func accept(_ danmu: String) -> Bool {
20+
for filter in stringFilters {
21+
if danmu.contains(filter) {
22+
return false
23+
}
24+
}
25+
26+
for filter in regexFilters {
27+
if danmu.contains(filter) {
28+
return false
29+
}
30+
}
31+
return true
32+
}
33+
34+
func autoUpdate() {
35+
if Date().timeIntervalSince(VideoDanmuFilterStorage.lastUpdate) > 60 * 60 * 24 {
36+
Task {
37+
await update()
38+
}
39+
}
40+
}
41+
42+
@discardableResult
43+
func update() async -> String {
44+
VideoDanmuFilterStorage.lastUpdate = Date()
45+
let data = await WebRequest.requestDanmuFilterList()
46+
let rules = data.rule.filter({ $0.type == 0 || $0.type == 1 })
47+
if !rules.isEmpty {
48+
VideoDanmuFilterStorage.filters = rules
49+
refreshCache(rules: rules)
50+
}
51+
return data.toast ?? ""
52+
}
53+
54+
private func refreshCache(rules: [VideoDanmuFilterData.Rule]) {
55+
stringFilters.removeAll()
56+
regexFilters.removeAll()
57+
rules.forEach { filter in
58+
switch filter.type {
59+
case 0:
60+
stringFilters.append(filter.filter)
61+
case 1:
62+
if let regex = try? Regex(filter.filter) {
63+
regexFilters.append(regex)
64+
}
65+
default:
66+
break
67+
}
68+
}
69+
}
70+
}
71+
72+
private enum VideoDanmuFilterStorage {
73+
@UserDefaultCodable("VideoDanmuFilter.filters", defaultValue: [])
74+
static var filters: [VideoDanmuFilterData.Rule]
75+
76+
@UserDefault("VideoDanmuFilter.lastUpdate", defaultValue: Date(timeIntervalSince1970: 0))
77+
static var lastUpdate: Date
78+
}
79+
80+
private extension WebRequest.EndPoint {
81+
static let danmuFilter = "https://api.bilibili.com/x/dm/filter/user"
82+
}
83+
84+
private struct VideoDanmuFilterData: Codable {
85+
struct Rule: Codable {
86+
let filter: String
87+
let type: Int
88+
}
89+
90+
let rule: [Rule]
91+
let toast: String?
92+
}
93+
94+
private extension WebRequest {
95+
static func requestDanmuFilterList() async -> VideoDanmuFilterData {
96+
do {
97+
let resp: VideoDanmuFilterData = try await request(url: EndPoint.danmuFilter)
98+
return resp
99+
} catch let err {
100+
return VideoDanmuFilterData(rule: [], toast: "\(err)")
101+
}
102+
}
103+
}

BilibiliLive/Component/Video/VideoDanmuProvider.swift

+10-2
Original file line numberDiff line numberDiff line change
@@ -107,9 +107,17 @@ class VideoDanmuProvider: DanmuProviderProtocol {
107107

108108
var dms = reply.elems
109109
.filter { $0.mode <= 5 }
110+
111+
if Settings.enableDanmuFilter {
112+
dms = dms.filter {
113+
VideoDanmuFilter.shared.accept($0.content)
114+
}
115+
}
116+
117+
var models = dms
110118
.map { Danmu(dm: $0) }
111-
dms.sort { $0.time < $1.time }
112-
segmentDanmus[idx] = dms
119+
models.sort { $0.time < $1.time }
120+
segmentDanmus[idx] = models
113121

114122
Logger.debug("[dm] cid:\(cid!) sidx:\(idx) danmu cnt: \(dms.count)")
115123
}

BilibiliLive/Module/Personal/SettingsViewController.swift

+11
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,17 @@ class SettingsViewController: UIViewController {
169169
}
170170

171171
SectionModel(title: "弹幕") {
172+
Toggle(title: "用户自定义弹幕屏蔽", setting: Settings.enableDanmuFilter, onChange: Settings.enableDanmuFilter.toggle()) {
173+
enable in
174+
if enable {
175+
Task {
176+
let toast = await VideoDanmuFilter.shared.update()
177+
let alert = UIAlertController(title: "同步结果", message: toast, preferredStyle: .alert)
178+
alert.addAction(.init(title: "Ok", style: .cancel))
179+
self.present(alert, animated: true)
180+
}
181+
}
182+
}
172183
Actions(title: "弹幕大小", message: "默认为36", current: Settings.danmuSize.title, options: DanmuSize.allCases, optionString: DanmuSize.allCases.map({ $0.title })) {
173184
Settings.danmuSize = $0
174185
}

BilibiliLive/Request/WebRequest.swift

+2-1
Original file line numberDiff line numberDiff line change
@@ -157,10 +157,11 @@ enum WebRequest {
157157
let object = try (decoder ?? JSONDecoder()).decode(T.self, from: data)
158158
complete?(.success(object))
159159
} catch let err {
160-
print("decode fail:", err)
160+
Logger.warn("decode fail: \(err)")
161161
complete?(.failure(.decodeFail(message: err.localizedDescription + String(describing: err))))
162162
}
163163
case let .failure(err):
164+
Logger.warn("request fail: \(err)")
164165
complete?(.failure(err))
165166
}
166167
}

0 commit comments

Comments
 (0)