mirror of
https://github.com/dirtydishes/dreamio.git
synced 2026-06-06 13:37:24 +00:00
add native player controls captions and close cleanup
This commit is contained in:
parent
8d4dd0870a
commit
fdeacce389
6 changed files with 265 additions and 3 deletions
|
|
@ -122,6 +122,7 @@ final class DreamioWebViewController: UIViewController {
|
|||
const addSubtitleCandidate = (entry) => {
|
||||
const rawURL = typeof entry === "string" ? entry : entry && (entry.url || entry.href || entry.src || entry.file || entry.download);
|
||||
const url = absoluteURL(rawURL);
|
||||
subtitleURLPattern.lastIndex = 0;
|
||||
if (!url || !subtitleURLPattern.test(url)) {
|
||||
subtitleURLPattern.lastIndex = 0;
|
||||
return;
|
||||
|
|
@ -517,12 +518,18 @@ final class DreamioWebViewController: UIViewController {
|
|||
const clicked = clickVisible([
|
||||
"[aria-label*='Close' i]",
|
||||
"[aria-label*='Back' i]",
|
||||
"[title*='Close' i]",
|
||||
"[title*='Back' i]",
|
||||
"button[class*='close' i]",
|
||||
"button[class*='back' i]",
|
||||
"[class*='close' i]",
|
||||
"[class*='back' i]",
|
||||
".player button",
|
||||
"[role='button']"
|
||||
]);
|
||||
const stillPlayer = /player|stream|buffer|prepar/i.test(document.body.innerText || "");
|
||||
const locationLooksPlayer = /\/(player|stream)\b/i.test(window.location.pathname || "") || /player|stream/i.test(window.location.hash || "");
|
||||
const visibleBusyPlayer = Boolean(document.querySelector("video, .player, [class*='player' i], [class*='buffer' i]"));
|
||||
const stillPlayer = locationLooksPlayer || (visibleBusyPlayer && /buffer|prepar|stream/i.test(document.body.innerText || ""));
|
||||
return { clicked, stillPlayer, href: window.location.href };
|
||||
})();
|
||||
"""#
|
||||
|
|
@ -544,7 +551,14 @@ final class DreamioWebViewController: UIViewController {
|
|||
}
|
||||
if self.webView.canGoBack {
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.4) {
|
||||
self.webView.evaluateJavaScript("(/player|stream|buffer|prepar/i).test(document.body.innerText || '')") { result, _ in
|
||||
let stillPlayerScript = #"""
|
||||
(() => {
|
||||
const locationLooksPlayer = /\/(player|stream)\b/i.test(window.location.pathname || "") || /player|stream/i.test(window.location.hash || "");
|
||||
const visibleBusyPlayer = Boolean(document.querySelector("video, .player, [class*='player' i], [class*='buffer' i]"));
|
||||
return locationLooksPlayer || (visibleBusyPlayer && /buffer|prepar|stream/i.test(document.body.innerText || ""));
|
||||
})()
|
||||
"""#
|
||||
self.webView.evaluateJavaScript(stillPlayerScript) { result, _ in
|
||||
if (result as? Bool) == true {
|
||||
self.webView.goBack()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,6 +36,13 @@ final class NativePlayerViewController: UIViewController {
|
|||
return view
|
||||
}()
|
||||
|
||||
private let tapSurfaceView: UIView = {
|
||||
let view = UIView()
|
||||
view.translatesAutoresizingMaskIntoConstraints = false
|
||||
view.backgroundColor = .clear
|
||||
return view
|
||||
}()
|
||||
|
||||
private let playPauseButton = NativePlayerViewController.iconButton(systemName: "pause.fill", label: "Play or Pause")
|
||||
private let jumpBackButton = NativePlayerViewController.iconButton(systemName: "gobackward.15", label: "Jump Back 15 Seconds")
|
||||
private let jumpForwardButton = NativePlayerViewController.iconButton(systemName: "goforward.15", label: "Jump Forward 15 Seconds")
|
||||
|
|
@ -167,6 +174,7 @@ final class NativePlayerViewController: UIViewController {
|
|||
|
||||
private func configureLayout() {
|
||||
view.addSubview(backend.view)
|
||||
view.addSubview(tapSurfaceView)
|
||||
view.addSubview(loadingView)
|
||||
view.addSubview(failureLabel)
|
||||
view.addSubview(controlsContainer)
|
||||
|
|
@ -182,7 +190,7 @@ final class NativePlayerViewController: UIViewController {
|
|||
|
||||
let tap = UITapGestureRecognizer(target: self, action: #selector(toggleControlsVisibility))
|
||||
tap.cancelsTouchesInView = false
|
||||
view.addGestureRecognizer(tap)
|
||||
tapSurfaceView.addGestureRecognizer(tap)
|
||||
|
||||
let controlRow = UIStackView(arrangedSubviews: [jumpBackButton, playPauseButton, jumpForwardButton, captionsButton])
|
||||
controlRow.translatesAutoresizingMaskIntoConstraints = false
|
||||
|
|
@ -208,6 +216,11 @@ final class NativePlayerViewController: UIViewController {
|
|||
backend.view.topAnchor.constraint(equalTo: view.topAnchor),
|
||||
backend.view.bottomAnchor.constraint(equalTo: view.bottomAnchor),
|
||||
|
||||
tapSurfaceView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
|
||||
tapSurfaceView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
|
||||
tapSurfaceView.topAnchor.constraint(equalTo: view.topAnchor),
|
||||
tapSurfaceView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
|
||||
|
||||
loadingView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
|
||||
loadingView.centerYAnchor.constraint(equalTo: view.centerYAnchor),
|
||||
|
||||
|
|
@ -338,6 +351,8 @@ final class NativePlayerViewController: UIViewController {
|
|||
}
|
||||
|
||||
private func revealControls() {
|
||||
controlsContainer.isUserInteractionEnabled = true
|
||||
closeButton.isUserInteractionEnabled = true
|
||||
UIView.animate(withDuration: 0.18) {
|
||||
self.controlsContainer.alpha = 1
|
||||
self.closeButton.alpha = 1
|
||||
|
|
@ -346,6 +361,8 @@ final class NativePlayerViewController: UIViewController {
|
|||
}
|
||||
|
||||
private func hideControls() {
|
||||
controlsContainer.isUserInteractionEnabled = false
|
||||
closeButton.isUserInteractionEnabled = false
|
||||
UIView.animate(withDuration: 0.24) {
|
||||
self.controlsContainer.alpha = 0
|
||||
self.closeButton.alpha = 0
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ final class VLCNativePlaybackBackend: NSObject, NativePlaybackBackend {
|
|||
|
||||
func play(request: NativePlaybackRequest) {
|
||||
#if canImport(MobileVLCKit)
|
||||
attachedSubtitleURLs.removeAll()
|
||||
let media = VLCMedia(url: request.playbackURL)
|
||||
let headerValue = request.headers
|
||||
.map { "\($0.key): \($0.value)" }
|
||||
|
|
@ -204,6 +205,12 @@ final class VLCNativePlaybackBackend: NSObject, NativePlaybackBackend {
|
|||
print("[DreamioVLC] attached subtitle=\(URLRedactor.redactedURLString(candidate.url.absoluteString))")
|
||||
#endif
|
||||
}
|
||||
guard !candidates.isEmpty else {
|
||||
return
|
||||
}
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 1) { [weak self] in
|
||||
self?.onSubtitleTracksChange?()
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue