Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
xjbeta committed Jul 6, 2023
2 parents 94ebec1 + e5c1714 commit ae414e9
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 64 deletions.
4 changes: 2 additions & 2 deletions IINA+.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -985,7 +985,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.14;
MARKETING_VERSION = 0.6.26;
MARKETING_VERSION = 0.6.27;
PRODUCT_BUNDLE_IDENTIFIER = "com.xjbeta.iina-plus";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
Expand All @@ -1010,7 +1010,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.14;
MARKETING_VERSION = 0.6.26;
MARKETING_VERSION = 0.6.27;
PRODUCT_BUNDLE_IDENTIFIER = "com.xjbeta.iina-plus";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
Expand Down
8 changes: 5 additions & 3 deletions IINA+/Utils/VideoDecoder/Bilibili.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ class Bilibili: NSObject, SupportSiteProtocol {

let bilibiliUA = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.5.1 Safari/605.1.15"

let bangumiUA = "Mozilla/5.0 (X11; Linux x86_64; rv:38.0) Gecko/20100101 Firefox/38.0 Iceweasel/38.2.1"

func liveInfo(_ url: String) -> Promise<LiveInfo> {
if SupportSites(url: url) == .bangumi {
return getBilibiliHTMLDatas(url, isBangumi: true).map {
Expand Down Expand Up @@ -93,7 +95,7 @@ class Bilibili: NSObject, SupportSiteProtocol {
func getBilibiliHTMLDatas(_ url: String, isBangumi: Bool = false) -> Promise<((playInfoData: Data, initialStateData: Data, bangumiData: Data))> {
let headers = HTTPHeaders(
["Referer": "https://www.bilibili.com/",
"User-Agent": isBangumi ? "Mozilla/5.0 (X11; Linux x86_64; rv:38.0) Gecko/20100101 Firefox/38.0 Iceweasel/38.2.1" : bilibiliUA])
"User-Agent": isBangumi ? bangumiUA : bilibiliUA])


return AF.request(url, headers: headers).responseString().map {
Expand Down Expand Up @@ -209,7 +211,7 @@ class Bilibili: NSObject, SupportSiteProtocol {

let headers = HTTPHeaders(
["Referer": "https://www.bilibili.com/",
"User-Agent": bilibiliUA])
"User-Agent": isBangumi ? bangumiUA : bilibiliUA])


return AF.request(u, headers: headers).responseData().map {
Expand Down Expand Up @@ -433,7 +435,7 @@ class Bilibili: NSObject, SupportSiteProtocol {

func getBangumiList(_ url: String,
initialStateData: Data? = nil) -> Promise<(BangumiList)> {
getBilibiliHTMLDatas(url).map {
getBilibiliHTMLDatas(url, isBangumi: true).map {
let stateJson: JSONObject = try JSONParser.JSONObjectWithData($0.initialStateData)
let state = try BangumiList(object: stateJson)
return state
Expand Down
168 changes: 109 additions & 59 deletions IINA+/Utils/VideoDecoder/KuaiShou.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,40 +11,89 @@ import PromiseKit
import Alamofire
import PMKAlamofire
import Marshal
import WebKit

class KuaiShou: NSObject, SupportSiteProtocol {

enum KuaiShouError: Error {
case invalidLink
case nilReferer
case apiLimited
case unknown
}

let initUA = 1000
let reloadTimes = 50

var cookieStorage = [String: String]()
var refererStorage = [String: String]()
var uaStorage = [String: Int]()
var cookies = ""
var cookiesDate: Date?

var prepareTask: Promise<()>?
var webView: WKWebView?
var webViewLoadingObserver: NSKeyValueObservation?


var refererStorage = [String: String]()
var reinitLimit = [String: Int]()

func liveInfo(_ url: String) -> Promise<LiveInfo> {
if let eid = getEid(url) {
reinitLimit[eid] = nil
if cookies.count == 0,
cookiesDate == nil {
if prepareTask == nil {
prepareTask = prepareCookies().ensure {
self.prepareTask = nil
}
}
return prepareTask!.then {
self.getInfo(url).map { $0 }
}
} else {
return self.getInfo(url).map { $0 }
}

return getInfo(url).map {
$0
}
}

func decodeUrl(_ url: String) -> Promise<YouGetJSON> {
getInfo(url).map {
$0.write(to: YouGetJSON(rawUrl: url))
}
getInfo(url).map {
$0.write(to: YouGetJSON(rawUrl: url))
}
}

func deleteCookies() {
HTTPCookieStorage.shared.cookies?.filter {
$0.domain.contains("kuaishou")
}.forEach(HTTPCookieStorage.shared.deleteCookie)
}

func prepareCookies() -> Promise<()> {
.init { resolver in
webView = WKWebView()
deleteCookies()

webViewLoadingObserver?.invalidate()
webViewLoadingObserver = webView?.observe(\.isLoading) { webView, _ in
guard !webView.isLoading, let url = webView.url else { return }

if url.absoluteString.contains("about") {
webView.load(.init(url: .init(string: "https://live.kuaishou.com")!))
} else {
self.webView?.evaluateJavaScript("document.cookie").done {

self.cookies = $0 as! String
self.cookiesDate = Date()
Log("KuaiShou cookies: \(self.cookies)")

self.webView = nil
self.webViewLoadingObserver?.invalidate()
self.webViewLoadingObserver = nil
resolver.fulfill(())
}.catch {
resolver.reject($0)
}
}
}

webView?.load(.init(url: .init(string: "https://livev.m.chenzhongtech.com/about/")!))
}
}

func getEid(_ url: String) -> String? {
guard let uc = URLComponents(string: url),
uc.path.starts(with: "/u/") else {
Expand All @@ -65,38 +114,28 @@ class KuaiShou: NSObject, SupportSiteProtocol {
"shareMethod": "card",
"source": 6
]


if uaStorage[eid] == nil {
uaStorage[eid] = initUA
}


let headers: HTTPHeaders = [
.userAgent("Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.0 Mobile/15E148 Safari/604.1 EID/\(eid).\(uaStorage[eid]!)"),
.userAgent("Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.0 Mobile/15E148 Safari/604.1"),
.init(name: "Origin", value: "https://livev.m.chenzhongtech.com"),
.init(name: "Cookie", value: ""),
.init(name: "Cookie", value: self.cookies),
.init(name: "Accept-Encoding", value: "gzip, deflate, br"),
.init(name: "Accept-Language", value: "zh-Hans;q=1.0")
]

var isInitRequest = false

if reinitLimit[eid] == nil {
reinitLimit[eid] = -1
}


return {
guard cookieStorage[eid] != nil && refererStorage[eid] != nil else {
guard refererStorage[eid] != nil else {
isInitRequest = true
self.reinitLimit[eid] = 0
return loadReferer(eid, headers: headers)
}
isInitRequest = true
return Promise { resolver in
let cookie = self.cookieStorage[eid]!
let ref = self.refererStorage[eid]!

var headers = headers

headers.add(name: "Cookie", value: cookie)
headers.add(name: "Referer", value: ref)

resolver.fulfill(headers)
Expand All @@ -108,41 +147,64 @@ class KuaiShou: NSObject, SupportSiteProtocol {
parameters: pars,
encoding: JSONEncoding.default,
headers: $0).responseData()
}.ensure {
let i = (self.uaStorage[eid] ?? self.initUA) + 1
self.uaStorage[eid] = i

if (i % self.reloadTimes) == 0 {
self.cookieStorage[eid] = nil
self.refererStorage[eid] = nil
}
}.then { re in
Promise { resolver in
let obj = try JSONParser.JSONObjectWithData(re.data)
let result: Int = try obj.value(for: "result")

let limit = self.reinitLimit[eid] ?? 0
let date = self.cookiesDate ?? Date()

if result == 1 {
let info = try KuaiShouInfo(object: obj)
resolver.fulfill(info)
} else if result == 2,
isInitRequest,
let limit = self.reinitLimit[eid],
limit < 2 {

limit < 3,

let date = self.cookiesDate,
date.timeIntervalSinceNow > -30 {
Log("KuaiShou API Limited, try to reinit \(eid)")

self.reinitLimit[eid] = limit + 1

after(seconds: 1).then {
self.getInfo(url)
}.done {
self.reinitLimit[eid] = -1
self.reinitLimit[eid] = 0
resolver.fulfill($0)
}.catch {
resolver.reject($0)
}
} else {
} else if limit < -15 || (limit <= -2 &&
date.timeIntervalSinceNow < -300) {

Log("KuaiShou API Limited, reload cookies")
self.reinitLimit[eid] = nil

if self.prepareTask == nil {
self.cookies = ""
self.cookiesDate = nil

self.prepareTask = self.prepareCookies().ensure {
self.prepareTask = nil
}
}

self.prepareTask!.then {
self.getInfo(url)
}.done {
resolver.fulfill($0)
}.catch {
resolver.reject($0)
}
} else if result == 2 {
self.reinitLimit[eid] = limit - 1
Log("KuaiShou API Limited, result \(result), \(eid)")
resolver.reject(KuaiShouError.apiLimited)
} else {
Log("KuaiShou API failed, result \(result), \(eid)")
resolver.reject(KuaiShouError.unknown)
}
}
}
Expand All @@ -158,27 +220,13 @@ class KuaiShou: NSObject, SupportSiteProtocol {
throw KuaiShouError.nilReferer
}

self.saveCookies(response, eid: eid)

var headers = headers

headers.add(name: "Cookie", value: self.cookieStorage[eid] ?? "")

self.refererStorage[eid] = ref
headers.add(name: "Referer", value: ref)
return headers
}
}

func saveCookies(_ response: HTTPURLResponse?, eid: String) {
guard let res = response else { return }
let cookie = HTTPCookie.cookies(withResponseHeaderFields: res.headers.dictionary, for: .init(string: "chenzhongtech.com")!)
.map {
$0.name + "=" + $0.value
}.joined(separator: "; ")

cookieStorage[eid] = cookie
}
}

struct KuaiShouInfo: Unmarshaling, LiveInfo {
Expand All @@ -197,7 +245,9 @@ struct KuaiShouInfo: Unmarshaling, LiveInfo {
init(object: Marshal.MarshaledObject) throws {
name = try object.value(for: "liveStream.user.user_name")
avatar = try object.value(for: "liveStream.user.headurl")
title = try object.value(for: "liveStream.caption")
let t: String? = try object.value(for: "liveStream.caption")

title = try t ?? object.value(for: "shareInfo.shareSubTitle")
cover = try object.value(for: "liveStream.coverUrl")
isLiving = try object.value(for: "liveStream.living")
playUrls = try object.value(for: "liveStream.multiResolutionHlsPlayUrls")
Expand Down

0 comments on commit ae414e9

Please sign in to comment.