@@ -3,77 +3,151 @@ import Kingfisher
33import SensitiveContentAnalysis
44import UIKit
55
6+ // The SensitiveContentAnalysis entitlement is not available for Enterprise development or for people with free accounts.
7+ // https://developer.apple.com/documentation/sensitivecontentanalysis/detecting-nudity-in-media-and-providing-intervention-options
8+ // fuck
69class SensitiveContentAnalyzer {
710 static let shared = SensitiveContentAnalyzer ( )
811
912 private let analyzer = SCSensitivityAnalyzer ( )
1013 private let cache = SensitiveContentCache . shared
14+ private let urlSession = URLSession . shared
1115
1216 private init ( ) { }
1317
1418 func analyzeImage( url: String ) async -> Bool {
15- // 1. cache
16- if let cachedResult = cache. get ( for: url) {
17- return cachedResult
19+ guard let imageURL = URL ( string: url) else {
20+ return false
21+ }
22+ do {
23+ return try await analyzeImageDownLocal ( url: imageURL)
24+ } catch {
25+ print ( " analyzeImageDownLocal error: \( error) " )
26+ return false
1827 }
1928
20- // 2. Kingfisher cache
21- // if let cachedImage = await getCachedImage(url: url) {
22- // do {
23- // let response = try await analyzer.analyzeImage(cachedImage as! CGImage)
24- // let isSensitive = response.isSensitive
25- //
26- //
27- // cache.set(url: url, isSensitive: isSensitive)
28- // return isSensitive
29- // } catch {
30- // print("Kingfisher cache fail: \(error)")
31- // }
32- // }
29+ // 1. cache
30+ // if let cachedResult = cache.get(for: url) {
31+ // return cachedResult
32+ // }
33+
34+ // // 2. Kingfisher cache
35+ // if let cachedImage = await getCachedImage(url: url) {
36+ // do {
37+ // let response = try await analyzer.analyzeImage(cachedImage as! CGImage)
38+ // let isSensitive = response.isSensitive
39+
40+ // cache.set(url: url, isSensitive: isSensitive)
41+ // return isSensitive
42+ // } catch {
43+ // print("Kingfisher cache fail: \(error)")
44+ // return false
45+ // }
46+ // }
47+ // return false
48+
49+ // var xsds = analyzer.analysisPolicy
3350
3451 // 3. analyze NetworkImage
35- do {
36- guard let imageURL = URL ( string: url) else {
37- return false
38- }
52+ // do {
53+ // guard let imageURL = URL(string: url) else {
54+ // return false
55+ // }
3956
40- let response = try await analyzer. analyzeImage ( at: imageURL)
41- let isSensitive = response. isSensitive
57+ // let response = try await analyzer.analyzeImage(at: imageURL)
58+ // let isSensitive = response.isSensitive
4259
43- cache. set ( url: url, isSensitive: isSensitive)
60+ // cache.set(url: url, isSensitive: isSensitive)
4461
45- return isSensitive
46- } catch {
47- print ( " analyze NetworkImage check faile: \( error) " )
48- return false
62+ // return isSensitive
63+ // } catch {
64+ // print("analyze NetworkImage check faile: \(error)")
65+ // return false
66+ // }
67+ }
68+
69+ private func checkPolicy( ) -> Bool {
70+ if analyzer. analysisPolicy == . disabled {
71+ false
72+ } else {
73+ true
4974 }
5075 }
5176
5277 private func getCachedImage( url: String ) async -> UIImage ? {
5378 await withCheckedContinuation { continuation in
54- guard let imageURL = URL ( string: url) else {
79+ print ( " [DEBUG] 开始检查缓存: \( url) " )
80+
81+ // check custom cache
82+ if let cachedResult = cache. get ( for: url) {
83+ print ( " [DEBUG] 自定义缓存命中 " )
5584 continuation. resume ( returning: nil )
5685 return
5786 }
5887
59- // check Kingfisher mem cache
60- let cache = ImageCache . default
61- let key = imageURL . cacheKey
88+ let kingfisherCache = ImageCache . default
89+ // 使用与KFImage相同的缓存键
90+ let key = url // 改为使用absoluteString
6291
63- if let image = cache. retrieveImageInMemoryCache ( forKey: key) {
92+ if let image = kingfisherCache. retrieveImageInMemoryCache ( forKey: key) {
93+ print ( " [DEBUG] 内存缓存命中: \( image) " )
6494 continuation. resume ( returning: image)
6595 return
6696 }
6797
68- // check Kingfisher disk cache
69- cache . retrieveImage ( forKey: key, options: nil ) { result in
98+ print ( " [DEBUG] 检查磁盘缓存... " )
99+ kingfisherCache . retrieveImage ( forKey: key, options: nil ) { result in
70100 switch result {
71101 case let . success( value) :
72- continuation. resume ( returning: value. image)
73- case . failure:
102+ if let image = value. image {
103+ print ( " [DEBUG] 磁盘缓存成功: \( image) " )
104+ continuation. resume ( returning: image)
105+ } else {
106+ print ( " [DEBUG] 磁盘缓存损坏,清理缓存 " )
107+ kingfisherCache. removeImage ( forKey: key)
108+ continuation. resume ( returning: nil )
109+ }
110+ case let . failure( error) :
111+ print ( " [DEBUG] 磁盘缓存失败: \( error) " )
74112 continuation. resume ( returning: nil )
75113 }
76114 }
77115 }
78116 }
117+
118+ private var cacheDirectory : URL {
119+ FileManager . default. temporaryDirectory
120+ . appendingPathComponent ( " SensitiveContentCache " , isDirectory: true )
121+ }
122+
123+ func analyzeImageDownLocal( url: URL ) async throws -> Bool {
124+ let cachedFile = cacheDirectory. appendingPathComponent ( url. lastPathComponent)
125+
126+ if !FileManager. default. fileExists ( atPath: cachedFile. path) {
127+ try await downloadImage ( from: url, to: cachedFile)
128+ }
129+
130+ let response = try await analyzer. analyzeImage ( at: cachedFile)
131+ return response. isSensitive
132+ }
133+
134+ private func downloadImage( from url: URL , to localURL: URL ) async throws {
135+ try FileManager . default. createDirectory (
136+ at: cacheDirectory,
137+ withIntermediateDirectories: true
138+ )
139+
140+ let ( tempURL, _) = try await urlSession. download ( from: url)
141+
142+ if FileManager . default. fileExists ( atPath: localURL. path) {
143+ try FileManager . default. removeItem ( at: localURL)
144+ }
145+ try FileManager . default. moveItem ( at: tempURL, to: localURL)
146+ }
147+
148+ func clearCache( ) throws {
149+ if FileManager . default. fileExists ( atPath: cacheDirectory. path) {
150+ try FileManager . default. removeItem ( at: cacheDirectory)
151+ }
152+ }
79153}
0 commit comments