1
0
mirror of https://github.com/yattee/yattee.git synced 2024-12-15 14:50:32 +05:30
yattee/Shared/OpenURLHandler.swift

267 lines
8.6 KiB
Swift
Raw Normal View History

2022-06-25 04:18:57 +05:30
import CoreMedia
2021-12-25 00:50:05 +05:30
import Foundation
2022-06-25 04:18:57 +05:30
import Siesta
2021-12-25 00:50:05 +05:30
struct OpenURLHandler {
2022-11-13 04:37:23 +05:30
static var firstHandle = true
2022-06-25 04:18:57 +05:30
static let yatteeProtocol = "yattee://"
var accounts: AccountsModel { .shared }
var navigation: NavigationModel { .shared }
var recents: RecentsModel { .shared }
var player: PlayerModel { .shared }
var search: SearchModel { .shared }
2023-05-21 17:31:33 +05:30
var navigationStyle: NavigationStyle
2021-12-25 00:50:05 +05:30
func handle(_ url: URL) {
2023-05-25 21:32:24 +05:30
if Self.firstHandle {
Self.firstHandle = false
Delay.by(1) { handle(url) }
return
}
2021-12-25 00:50:05 +05:30
if accounts.current.isNil {
accounts.setCurrent(accounts.any)
}
guard !accounts.current.isNil else {
return
}
#if os(macOS)
2022-01-06 21:05:45 +05:30
guard url.host != Windows.player.location else {
2021-12-25 00:50:05 +05:30
return
}
#endif
2022-12-04 17:51:50 +05:30
guard let url = url.byReplacingYatteeProtocol() else { return }
2022-11-10 22:41:28 +05:30
let parser = URLParser(url: url)
2022-06-25 04:18:57 +05:30
switch parser.destination {
case .fileURL:
handleFileURLOpen(parser)
2022-06-25 04:18:57 +05:30
case .video:
handleVideoUrlOpen(parser)
case .playlist:
handlePlaylistUrlOpen(parser)
case .channel:
handleChannelUrlOpen(parser)
case .search:
handleSearchUrlOpen(parser)
case .favorites:
2022-12-11 20:30:20 +05:30
navigation.hideViewsAboveBrowser()
2022-11-09 19:04:04 +05:30
navigation.tabSelection = .home
2022-06-25 04:18:57 +05:30
#if os(macOS)
focusMainWindow()
#endif
case .subscriptions:
guard accounts.app.supportsSubscriptions, accounts.signedIn else { return }
2022-12-11 20:30:20 +05:30
navigation.hideViewsAboveBrowser()
2022-06-25 04:18:57 +05:30
navigation.tabSelection = .subscriptions
#if os(macOS)
focusMainWindow()
#endif
case .popular:
guard accounts.app.supportsPopular else { return }
2022-12-11 20:30:20 +05:30
navigation.hideViewsAboveBrowser()
2022-06-25 04:18:57 +05:30
navigation.tabSelection = .popular
#if os(macOS)
focusMainWindow()
#endif
case .trending:
2022-12-11 20:30:20 +05:30
navigation.hideViewsAboveBrowser()
2022-06-25 04:18:57 +05:30
navigation.tabSelection = .trending
#if os(macOS)
focusMainWindow()
#endif
default:
navigation.presentAlert(title: "Error", message: "This URL could not be opened")
#if os(macOS)
2022-08-13 20:16:45 +05:30
guard !Windows.main.isOpen else { return }
navigation.presentingAlertInVideoPlayer = true
#endif
2022-06-25 04:18:57 +05:30
}
}
private func handleFileURLOpen(_ parser: URLParser) {
guard let url = parser.fileURL else { return }
OpenVideosModel.shared.openURLs([url], removeQueueItems: false, playbackMode: .playNow)
}
2022-06-25 04:18:57 +05:30
private func handleVideoUrlOpen(_ parser: URLParser) {
guard let id = parser.videoID else {
2022-06-25 04:18:57 +05:30
navigation.presentAlert(title: "Could not open video", message: "Could not extract video ID")
2021-12-25 00:50:05 +05:30
return
}
guard id != player.currentVideo?.id else {
return
}
2021-12-25 00:50:05 +05:30
#if os(macOS)
2022-01-06 21:05:45 +05:30
Windows.main.open()
2021-12-25 00:50:05 +05:30
#endif
2022-12-21 22:43:41 +05:30
let video = Video(app: accounts.current.app!, videoID: id)
2023-05-25 21:32:24 +05:30
player.videoBeingOpened = .init(app: accounts.current.app!, videoID: id, title: "Loading video...")
player.show()
2022-12-18 18:09:39 +05:30
player
2022-12-21 22:43:41 +05:30
.playerAPI(video)?
2022-12-18 18:09:39 +05:30
.video(id)
2022-06-25 04:18:57 +05:30
.load()
.onSuccess { response in
if let video: Video = response.typedContent() {
let time = parser.time.isNil ? nil : CMTime.secondsInDefaultTimescale(TimeInterval(parser.time!))
2023-05-25 21:32:24 +05:30
Delay.by(0.5) {
self.player.playNow(video, at: time)
}
2022-06-25 04:18:57 +05:30
} else {
navigation.presentAlert(title: "Error", message: "This video could not be opened")
}
2021-12-25 00:50:05 +05:30
}
2022-06-25 04:18:57 +05:30
.onFailure { responseError in
navigation.presentAlert(title: "Could not open video", message: responseError.userMessage)
}
}
private func handlePlaylistUrlOpen(_ parser: URLParser) {
#if os(macOS)
if alertIfNoMainWindowOpen() { return }
#endif
guard let playlistID = parser.playlistID else {
navigation.presentAlert(title: "Could not open playlist", message: "Could not extract playlist ID")
return
2021-12-25 00:50:05 +05:30
}
2022-06-25 04:18:57 +05:30
accounts.api.channelPlaylist(playlistID)?
.load()
.onSuccess { response in
if var playlist: ChannelPlaylist = response.typedContent() {
playlist.id = playlistID
DispatchQueue.main.async {
NavigationModel.shared.openChannelPlaylist(
2022-06-25 04:18:57 +05:30
playlist,
2022-06-30 13:35:32 +05:30
navigationStyle: navigationStyle
2022-06-25 04:18:57 +05:30
)
}
} else {
navigation.presentAlert(title: "Could not open playlist", message: "Playlist could not be found")
}
}
.onFailure { responseError in
navigation.presentAlert(title: "Could not open playlist", message: responseError.userMessage)
}
2021-12-25 00:50:05 +05:30
}
2022-06-25 04:18:57 +05:30
private func handleChannelUrlOpen(_ parser: URLParser) {
#if os(macOS)
if alertIfNoMainWindowOpen() { return }
#endif
guard let resource = resourceForChannelUrl(parser) else {
navigation.presentAlert(title: "Could not open channel", message: "Could not extract channel information")
return
}
resource
.load()
.onSuccess { response in
2023-04-22 19:20:46 +05:30
if let page: ChannelPage = response.typedContent(),
let channel = page.channel
{
2022-06-25 04:18:57 +05:30
DispatchQueue.main.async {
NavigationModel.shared.openChannel(
2022-06-25 04:18:57 +05:30
channel,
2022-06-30 13:35:32 +05:30
navigationStyle: navigationStyle
2022-06-25 04:18:57 +05:30
)
}
} else {
navigation.presentAlert(title: "Could not open channel", message: "Channel could not be found")
}
}
.onFailure { responseError in
navigation.presentAlert(title: "Could not open channel", message: responseError.userMessage)
}
}
private func resourceForChannelUrl(_ parser: URLParser) -> Resource? {
if let id = parser.channelID {
2022-11-27 16:12:16 +05:30
return accounts.api.channel(id, contentType: .videos)
2022-06-25 04:18:57 +05:30
}
2022-06-30 05:01:51 +05:30
if let resource = resourceForUsernameUrl(parser) {
return resource
}
2022-06-25 04:18:57 +05:30
guard let name = parser.channelName else {
return nil
}
if accounts.app.supportsOpeningChannelsByName {
return accounts.api.channelByName(name)
}
if let instance = InstancesModel.shared.all.first(where: { $0.app.supportsOpeningChannelsByName }) {
2022-06-25 04:18:57 +05:30
return instance.anonymous.channelByName(name)
}
return nil
}
2022-06-30 05:01:51 +05:30
private func resourceForUsernameUrl(_ parser: URLParser) -> Resource? {
guard let username = parser.username else { return nil }
if accounts.app.supportsOpeningChannelsByName {
return accounts.api.channelByUsername(username)
}
if let instance = InstancesModel.shared.all.first(where: { $0.app.supportsOpeningChannelsByName }) {
2022-06-30 05:01:51 +05:30
return instance.anonymous.channelByUsername(username)
}
return nil
}
2022-06-25 04:18:57 +05:30
private func handleSearchUrlOpen(_ parser: URLParser) {
#if os(macOS)
if alertIfNoMainWindowOpen() { return }
#endif
NavigationModel.shared.openSearchQuery(parser.searchQuery)
2022-06-25 04:18:57 +05:30
#if os(macOS)
focusMainWindow()
#endif
}
#if os(macOS)
private func focusMainWindow() {
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
Windows.main.focus()
}
}
private func alertIfNoMainWindowOpen() -> Bool {
guard !Windows.main.isOpen else {
return false
}
navigation.presentAlert(
title: "Restart the app to open this link",
message:
"To open this link in the app you need to close and open it manually to have browser window, " +
"then you can try opening links again.\n\nThis is a limitation of SwiftUI on macOS versions earlier than Ventura."
)
navigation.presentingAlertInVideoPlayer = true
return true
}
#endif
2021-12-25 00:50:05 +05:30
}