Music_Player3/relax.offline.mp3.music/MP/Common/Tool(工具封装)/MP_WebWork.swift
2024-06-03 09:48:39 +08:00

210 lines
9.2 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// MP_WebWork.swift
// MusicPlayer
//
// Created by Mr.Zhou on 2024/4/30.
//
import Foundation
import WebKit
import Alamofire
///WebViewbase.js
class MP_WebWork:NSObject {
//
static let shared = MP_WebWork()
///web()
private var webView:WKWebView?
///
private lazy var homePath = "https://music.youtube.com/"
private var jsPath:String = "https://music.youtube.com/"
///
private var codeFunctionName:String!
///
var signatureTimestamp:Int!
private override init() {
super.init()
//webView
webView = .init(frame: .zero)
webView?.navigationDelegate = self
webView?.uiDelegate = self
// webView?.customUserAgent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36"
}
deinit {
webView = nil
}
/// 访youtube
func pingYoutubeHome() {
//
let request = URLRequest(url: .init(string: homePath)!)
//web
webView?.load(request)
}
///base.js
private func getBasePath(_ jsContent:String) {
let pattern = "s/player/[0-9a-fA-F]{8}/player_ias.vflset/[a-zA-Z_]+/base\\.js"
guard let regex = try? NSRegularExpression(pattern: pattern, options: .dotMatchesLineSeparators) else {
print("Regular expression compilation failed")
return
}
//
let nsRange = NSRange(jsContent.startIndex..<jsContent.endIndex, in: jsContent)
let matches = regex.matches(in: jsContent, options: [], range: nsRange)
//
if let first = matches.first {
//
if let swiftRange = Range(first.range, in: jsContent) {
let matchedString = String(jsContent[swiftRange])
//base.js
self.jsPath = self.jsPath + matchedString
print("Current base.JavaScript path:\(self.jsPath)")
//
// MPPositive_BrowseLoadViewModel.shared.reloadBrowseLists()
//
if let baseUrl = URL(string: self.jsPath) {
let request = URLRequest(url: baseUrl)
webView?.load(request)
}
}
}
}
/// JSweb
/// - Parameter signatureString:
func excuteJavaScript(_ signatureString:String, completion:@escaping((String) -> Void)){
//webView
guard webView != nil, codeFunctionName != nil else {
return
}
//webView
let function = "_yt_player.SNa('\(signatureString)');"
//
webView?.evaluateJavaScript(function){result,error in
if let error = error {
print("Code Error:\(error)")
}
if let result = result as? String {
//
completion(result)
}
}
}
///
private func regexFunction(_ jsContent:String) -> String? {
var result:String?
//
let pattern = "\\w+=function\\(a\\)\\{[^}]*?a=a\\.split\\(\\\"\\\"\\);"
// 使NSRegularExpression
guard let regex = try? NSRegularExpression(pattern: pattern, options: .dotMatchesLineSeparators) else {
print("Regular expression compilation failed")
return result
}
//
let matches = regex.matches(in: jsContent, options: [], range: NSRange(location: 0, length: jsContent.utf16.count))
//
for match in matches {
if let range = Range(match.range(at: 0), in: jsContent) {
//
let functionbody = String(jsContent[range])
//=
let results = functionbody.split(separator: "=").map(String.init)
//
result = results[0]
}
}
return result
}
///
private func getSignatureTimestamp(_ jsContent:String) -> Int?{
let regexPattern = "signatureTimestamp:(\\d+)"
guard let regex = try? NSRegularExpression(pattern: regexPattern, options: .dotMatchesLineSeparators) else {
print("Regular expression compilation failed")
return nil
}
let range = NSRange(jsContent.startIndex..<jsContent.endIndex, in: jsContent)
let matches = regex.matches(in: jsContent, options: [], range: range)
if let first = matches.first {
if let matchRange = Range(first.range(at: 1), in: jsContent) {
let matchedNumber = String(jsContent[matchRange])
print(matchedNumber)
return Int(matchedNumber)
}
return nil
}
return nil
}
}
//MARK: - navigationDelegate
extension MP_WebWork: WKNavigationDelegate, WKUIDelegate {
func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse, decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void){
guard let url = navigationResponse.response.url, url.lastPathComponent == "base.js", codeFunctionName == nil else {
decisionHandler(.allow) // JavaScript
return
}
//base.js
decisionHandler(.cancel)
// 使URLSessionbase.js
let task = URLSession.shared.dataTask(with: url){ [weak self] data, response, error in
guard let self = self, let data = data, error == nil else {
print("Request base.JavaScript error: \(error?.localizedDescription ?? "")")
decisionHandler(.allow)
return
}
// JavaScript
guard let jsContent = String(data: data, encoding: .utf8) else {
decisionHandler(.allow)
return
}
guard let function = regexFunction(jsContent), let timeValue = getSignatureTimestamp(jsContent) else {
decisionHandler(.allow)
return
}
//,
signatureTimestamp = timeValue
codeFunctionName = function
//
let code = "g.SNa=\(codeFunctionName!);"
let pattern = "\(codeFunctionName!)=function\\(a\\)\\{[^\\}]*\\};"
let regex = try? NSRegularExpression(pattern: pattern, options: .dotMatchesLineSeparators)
let nsRange = NSRange(jsContent.startIndex..<jsContent.endIndex, in: jsContent)
let matches = regex?.matches(in: jsContent, options: [], range: nsRange)
if let match = matches?.first {
let replacementString = "\(jsContent[Range(match.range, in: jsContent)!])\n\(code)"
let newJavaScript = jsContent.replacingOccurrences(of: jsContent[Range(match.range, in: jsContent)!], with: replacementString)
DispatchQueue.main.async {
// JavaScriptwebView
webView.evaluateJavaScript(newJavaScript) { result,error in
if let error = error {
print("注入代码失败:\(error)")
}else {
print("注入代码完成")
//
// NotificationCenter.notificationKey.post(notificationName: .js_edit_completion)
}
}
}
}
}
task.resume()
}
// WKNavigationDelegate
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
//
webView.evaluateJavaScript("document.documentElement.outerHTML", completionHandler: { [weak self] (result, error) in
//js
if let content = result as? String {
if self?.jsPath != "https://music.youtube.com/" {
//base.js
}else {
//base.js
self?.getBasePath(content)
}
} else if let error = error {
print("Error getting JavaScript content: \(error.localizedDescription)")
}
})
}
}