Skip to content

Commit

Permalink
fix #574
Browse files Browse the repository at this point in the history
  • Loading branch information
kingslay committed Oct 10, 2023
1 parent 160c752 commit c227eea
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 56 deletions.
21 changes: 19 additions & 2 deletions Sources/KSPlayer/Subtitle/KSSubtitle.swift
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,7 @@ open class SubtitleModel: ObservableObject {
public var url: URL? {
didSet {
subtitleInfos.removeAll()
searchSubtitle(query: nil, languages: [])
subtitleDataSouces.forEach { datasouce in
addSubtitle(dataSouce: datasouce)
}
Expand Down Expand Up @@ -330,10 +331,26 @@ open class SubtitleModel: ObservableObject {
}
}

public func searchSubtitle(query: String?, languages: [String]) {
subtitleDataSouces.forEach { dataSouce in
if let dataSouce = dataSouce as? SearchSubtitleDataSouce {
subtitleInfos.removeAll { info in
dataSouce.infos.contains {
$0 === info
}
}
Task {
try? await dataSouce.searchSubtitle(query: query, languages: languages)
subtitleInfos.append(contentsOf: dataSouce.infos)
}
}
}
}

public func addSubtitle(dataSouce: SubtitleDataSouce) {
if let dataSouce = dataSouce as? SearchSubtitleDataSouce {
if let dataSouce = dataSouce as? FileURLSubtitleDataSouce {
Task {
try? await dataSouce.searchSubtitle(url: url)
try? await dataSouce.searchSubtitle(fileURL: url)
subtitleInfos.append(contentsOf: dataSouce.infos)
}
} else {
Expand Down
116 changes: 62 additions & 54 deletions Sources/KSPlayer/Subtitle/SubtitleDataSouce.swift
Original file line number Diff line number Diff line change
Expand Up @@ -62,107 +62,98 @@ public protocol SubtitleDataSouce: AnyObject {
var infos: [any SubtitleInfo] { get }
}

public protocol FileURLSubtitleDataSouce: SubtitleDataSouce {
func searchSubtitle(fileURL: URL?) async throws
}

public protocol SearchSubtitleDataSouce: SubtitleDataSouce {
func searchSubtitle(url: URL?) async throws
func searchSubtitle(query: String?, languages: [String]) async throws
}

public extension KSOptions {
static var subtitleDataSouces: [SubtitleDataSouce] = [DirectorySubtitleDataSouce()]
}

public extension SubtitleDataSouce {
func addCache(subtitleID: String, downloadURL: URL) {
CacheDataSouce.singleton.addCache(subtitleID: subtitleID, downloadURL: downloadURL)
func addCache(query: String, downloadURL: URL) {
CacheDataSouce.singleton.addCache(query: query, downloadURL: downloadURL)
}
}

public class CacheDataSouce: SearchSubtitleDataSouce {
public static let singleton = CacheDataSouce()
public var infos = [any SubtitleInfo]()
private let cacheFolder = (NSTemporaryDirectory() as NSString).appendingPathComponent("KSSubtitleCache")
private var srtCacheInfoPath: String
private let srtCacheInfoPath: String
// 因为plist不能保存URL
private var srtInfoCaches = [String: String]()
private var srtInfoCaches: [String: [String]]
private init() {
let cacheFolder = (NSTemporaryDirectory() as NSString).appendingPathComponent("KSSubtitleCache")
if !FileManager.default.fileExists(atPath: cacheFolder) {
try? FileManager.default.createDirectory(atPath: cacheFolder, withIntermediateDirectories: true, attributes: nil)
}
srtCacheInfoPath = (cacheFolder as NSString).appendingPathComponent("KSSrtInfo.plist")
srtInfoCaches = (NSMutableDictionary(contentsOfFile: srtCacheInfoPath) as? [String: [String]]) ?? [String: [String]]()
}

public func searchSubtitle(url: URL?) async throws {
public func searchSubtitle(query: String?, languages _: [String] = ["zh-cn"]) async throws {
infos = [any SubtitleInfo]()
guard let url else {
guard let query else {
return
}
srtCacheInfoPath = (cacheFolder as NSString).appendingPathComponent("KSSrtInfo_\(url.lastPathComponent).plist")
if FileManager.default.fileExists(atPath: srtCacheInfoPath), let files = NSMutableDictionary(contentsOfFile: srtCacheInfoPath) as? [String: String] {
srtInfoCaches = files.filter { FileManager.default.fileExists(atPath: $1) }
if srtInfoCaches.isEmpty {
infos = []
} else {
let array = srtInfoCaches.map { subtitleID, downloadURL -> (any SubtitleInfo) in
let info = URLSubtitleInfo(subtitleID: subtitleID, name: (downloadURL as NSString).lastPathComponent, url: URL(fileURLWithPath: downloadURL))
info.comment = "本地"
return info
}
infos = array
}
if srtInfoCaches.count != files.count {
(srtInfoCaches as NSDictionary).write(toFile: srtCacheInfoPath, atomically: false)
}
} else {
srtInfoCaches = [String: String]()
infos = []
}
infos = srtInfoCaches[query]?.map { downloadURL -> (any SubtitleInfo) in
let info = URLSubtitleInfo(url: URL(fileURLWithPath: downloadURL))
info.comment = "local"
return info
} ?? [any SubtitleInfo]()
}

public func addCache(subtitleID: String, downloadURL: URL) {
srtInfoCaches[subtitleID] = downloadURL.path
public func addCache(query: String, downloadURL: URL) {
var array = srtInfoCaches[query] ?? [String]()
array.append(downloadURL.path)
srtInfoCaches[query] = array
(srtInfoCaches as NSDictionary).write(toFile: srtCacheInfoPath, atomically: false)
}
}

public class URLSubtitleDataSouce: SubtitleDataSouce {
public let infos: [any SubtitleInfo]
public var infos: [any SubtitleInfo]
public init(urls: [URL]) {
infos = urls.map { URLSubtitleInfo(url: $0) }
}
}

public class DirectorySubtitleDataSouce: SearchSubtitleDataSouce {
public class DirectorySubtitleDataSouce: FileURLSubtitleDataSouce {
public var infos = [any SubtitleInfo]()
public init() {}

public func searchSubtitle(url: URL?) async throws {
public func searchSubtitle(fileURL: URL?) async throws {
infos = [any SubtitleInfo]()
guard let url else {
guard let fileURL else {
return
}
if url.isFileURL {
let subtitleURLs: [URL] = (try? FileManager.default.contentsOfDirectory(at: url.deletingLastPathComponent(), includingPropertiesForKeys: nil).filter(\.isSubtitle)) ?? []
let contents = subtitleURLs.map { URLSubtitleInfo(url: $0) }.sorted { left, right in
if fileURL.isFileURL {
let subtitleURLs: [URL] = (try? FileManager.default.contentsOfDirectory(at: fileURL.deletingLastPathComponent(), includingPropertiesForKeys: nil).filter(\.isSubtitle)) ?? []
infos = subtitleURLs.map { URLSubtitleInfo(url: $0) }.sorted { left, right in
left.name < right.name
}
infos.append(contentsOf: contents)
}
}
}

public class ShooterSubtitleDataSouce: SearchSubtitleDataSouce {
public class ShooterSubtitleDataSouce: FileURLSubtitleDataSouce {
public var infos = [any SubtitleInfo]()
public init() {}
public func searchSubtitle(url: URL?) async throws {
public func searchSubtitle(fileURL: URL?) async throws {
infos = [any SubtitleInfo]()
guard let url else {
guard let fileURL else {
return
}
guard url.isFileURL, let url = URL(string: "https://www.shooter.cn/api/subapi.php")?
.add(queryItems: ["format": "json", "pathinfo": url.path, "filehash": url.shooterFilehash])
guard fileURL.isFileURL, let searchApi = URL(string: "https://www.shooter.cn/api/subapi.php")?
.add(queryItems: ["format": "json", "pathinfo": fileURL.path, "filehash": fileURL.shooterFilehash])
else {
return
}
var request = URLRequest(url: url)
var request = URLRequest(url: searchApi)
request.httpMethod = "POST"
let (data, _) = try await URLSession.shared.data(for: request)
guard let json = try JSONSerialization.jsonObject(with: data) as? [[String: Any]] else {
Expand Down Expand Up @@ -191,12 +182,11 @@ public class AssrtSubtitleDataSouce: SearchSubtitleDataSouce {
self.token = token
}

public func searchSubtitle(url: URL?) async throws {
public func searchSubtitle(query: String?, languages _: [String] = ["zh-cn"]) async throws {
infos = [any SubtitleInfo]()
guard let url else {
guard let query else {
return
}
let query = url.deletingPathExtension().lastPathComponent
guard let searchApi = URL(string: "https://api.assrt.net/v1/sub/search")?.add(queryItems: ["q": query]) else {
return
}
Expand Down Expand Up @@ -260,22 +250,40 @@ public class OpenSubtitleDataSouce: SearchSubtitleDataSouce {
private let username: String?
private let password: String?
private let apiKey: String
private let languages: [String]
public var infos = [any SubtitleInfo]()
public init(apiKey: String, languages: [String] = ["zh-cn"], username: String? = nil, password: String? = nil) {
public init(apiKey: String, username: String? = nil, password: String? = nil) {
self.apiKey = apiKey
self.languages = languages
self.username = username
self.password = password
}

public func searchSubtitle(url: URL?) async throws {
public func searchSubtitle(query: String?, languages: [String] = ["zh-cn"]) async throws {
try await searchSubtitle(query: query, imdbID: 0, tmdbID: 0, languages: languages)
}

public func searchSubtitle(query: String?, imdbID: Int?, tmdbID: Int?, languages: [String] = ["zh-cn"]) async throws {
var queryItems = [String: String]()
if let query {
queryItems["query"] = query
}
if let imdbID {
queryItems["imbd_id"] = String(imdbID)
}
if let tmdbID {
queryItems["tmdb_id"] = String(tmdbID)
}
if queryItems.isEmpty {
return
}
queryItems["languages"] = languages.joined(separator: ",")
}

public func searchSubtitle(queryItems: [String: String]) async throws {
infos = [any SubtitleInfo]()
guard let url else {
if queryItems.isEmpty {
return
}
let query = url.deletingPathExtension().lastPathComponent
guard let searchApi = URL(string: "https://api.opensubtitles.com/api/v1/subtitles")?.add(queryItems: ["query": query, "languages": languages.joined(separator: ",")]) else {
guard let searchApi = URL(string: "https://api.opensubtitles.com/api/v1/subtitles")?.add(queryItems: queryItems) else {
return
}
var request = URLRequest(url: searchApi)
Expand Down

0 comments on commit c227eea

Please sign in to comment.