Open videos via URL scheme

This commit is contained in:
Arkadiusz Fal
2021-10-24 11:16:04 +02:00
parent 8e0af22b94
commit 60c7027429
18 changed files with 230 additions and 189 deletions

View File

@@ -1,8 +0,0 @@
//
// AppDelegate.swift
// Pearvidious
//
// Created by Arkadiusz Fal on 20/10/2021.
//
import Foundation

View File

@@ -4,16 +4,20 @@ import Foundation
extension Defaults.Keys {
static let invidiousInstanceID = "default-invidious-instance"
static let pipedInstanceID = "default-piped-instance"
static let privateAccountID = "default-private-invidious-account"
static let instances = Key<[Instance]>("instances", default: [
.init(app: .piped, id: pipedInstanceID, name: "Public", url: "https://pipedapi.kavin.rocks"),
.init(app: .invidious, id: invidiousInstanceID, name: "Private", url: "https://invidious.home.arekf.net")
])
static let accounts = Key<[Account]>("accounts", default: [
.init(instanceID: invidiousInstanceID,
name: "arekf",
url: "https://invidious.home.arekf.net",
sid: "ki55SJbaQmm0bOxUWctGAQLYPQRgk-CXDPw5Dp4oBmI=")
.init(
id: privateAccountID,
instanceID: invidiousInstanceID,
name: "arekf",
url: "https://invidious.home.arekf.net",
sid: "ki55SJbaQmm0bOxUWctGAQLYPQRgk-CXDPw5Dp4oBmI="
)
])
static let lastAccountID = Key<Account.ID?>("lastAccountID")
static let lastInstanceID = Key<Instance.ID?>("lastInstanceID")

View File

@@ -34,6 +34,10 @@ struct ContentView: View {
#endif
}
.onAppear(perform: configure)
.handlesExternalEvents(preferring: Set(["*"]), allowing: Set(["*"]))
.onOpenURL(perform: handleOpenedURL)
.environmentObject(accounts)
.environmentObject(instances)
.environmentObject(navigation)
@@ -113,6 +117,25 @@ struct ContentView: View {
navigation.presentingWelcomeScreen = true
}
func handleOpenedURL(_ url: URL) {
guard !accounts.current.isNil else {
return
}
let parser = VideoURLParser(url: url)
guard let id = parser.id else {
return
}
accounts.api.video(id).load().onSuccess { response in
if let video: Video = response.typedContent() {
self.player.playNow(video, at: parser.time)
self.player.presentPlayer()
}
}
}
}
struct ContentView_Previews: PreviewProvider {

View File

@@ -3,10 +3,15 @@ import SwiftUI
@main
struct PearvidiousApp: App {
#if os(macOS)
@NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
#endif
var body: some Scene {
WindowGroup {
ContentView()
}
.handlesExternalEvents(matching: Set(["*"]))
#if !os(tvOS)
.commands {
SidebarCommands()

View File

@@ -0,0 +1,78 @@
import Foundation
struct VideoURLParser {
let url: URL
var id: String? {
if urlComponents?.host == "youtu.be", let path = urlComponents?.path {
return String(path.suffix(from: path.index(path.startIndex, offsetBy: 1)))
}
return queryItemValue("v")
}
var time: TimeInterval? {
guard let time = queryItemValue("t") else {
return nil
}
let timeComponents = parseTime(time)
guard !timeComponents.isEmpty,
let hours = TimeInterval(timeComponents["hours"] ?? "0"),
let minutes = TimeInterval(timeComponents["minutes"] ?? "0"),
let seconds = TimeInterval(timeComponents["seconds"] ?? "0")
else {
if let time = TimeInterval(time) {
return time
}
return nil
}
return seconds + (minutes * 60) + (hours * 60 * 60)
}
func queryItemValue(_ name: String) -> String? {
queryItems.first { $0.name == name }?.value
}
private var queryItems: [URLQueryItem] {
urlComponents?.queryItems ?? []
}
private var urlComponents: URLComponents? {
URLComponents(url: url, resolvingAgainstBaseURL: false)
}
private func parseTime(_ time: String) -> [String: String] {
let results = timeRegularExpression.matches(
in: time,
range: NSRange(time.startIndex..., in: time)
)
guard let match = results.first else {
return [:]
}
var components: [String: String] = [:]
for name in ["hours", "minutes", "seconds"] {
let matchRange = match.range(withName: name)
if let substringRange = Range(matchRange, in: time) {
let capture = String(time[substringRange])
components[name] = capture
}
}
return components
}
private var timeRegularExpression: NSRegularExpression {
try! NSRegularExpression(
pattern: "(?:(?<hours>[0-9+])+h)?(?:(?<minutes>[0-9]+)m)?(?:(?<seconds>[0-9]*)s)?",
options: .caseInsensitive
)
}
}

View File

@@ -31,7 +31,6 @@ struct HorizontalCells: View {
.padding(.vertical, 10)
#endif
}
.id(items.map(\.id).joined())
#if os(tvOS)
.frame(height: 560)
#else

View File

@@ -17,7 +17,6 @@ struct VerticalCells: View {
}
.padding()
}
.id(items.map(\.id).joined())
.edgesIgnoringSafeArea(.horizontal)
#if os(macOS)
.background()