diff --git a/submodules/GalleryUI/Sources/ChatItemGalleryFooterContentNode.swift b/submodules/GalleryUI/Sources/ChatItemGalleryFooterContentNode.swift
index b2e443b830..592120b113 100644
--- a/submodules/GalleryUI/Sources/ChatItemGalleryFooterContentNode.swift
+++ b/submodules/GalleryUI/Sources/ChatItemGalleryFooterContentNode.swift
@@ -21,6 +21,7 @@ import TextSelectionNode
import UrlEscaping
import UndoUI
import ManagedAnimationNode
+import TelegramUniversalVideoContent
private let deleteImage = generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Accessory Panels/MessageSelectionTrash"), color: .white)
private let actionImage = generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Accessory Panels/MessageSelectionForward"), color: .white)
@@ -593,6 +594,14 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
break
}
}
+ } else if let media = media as? TelegramMediaWebpage, case let .Loaded(content) = media.content {
+ let type = webEmbedType(content: content)
+ switch type {
+ case .youtube, .vimeo:
+ canFullscreen = true
+ default:
+ break
+ }
}
}
diff --git a/submodules/GalleryUI/Sources/Items/UniversalVideoGalleryItem.swift b/submodules/GalleryUI/Sources/Items/UniversalVideoGalleryItem.swift
index 0758cffc8e..980337b2a2 100644
--- a/submodules/GalleryUI/Sources/Items/UniversalVideoGalleryItem.swift
+++ b/submodules/GalleryUI/Sources/Items/UniversalVideoGalleryItem.swift
@@ -774,6 +774,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
var forceEnablePiP = false
var forceEnableUserInteraction = false
var isAnimated = false
+ var isEnhancedWebPlayer = false
if let content = item.content as? NativeVideoContent {
isAnimated = content.fileReference.media.isAnimated
self.videoFramePreview = MediaPlayerFramePreview(postbox: item.context.account.postbox, fileReference: content.fileReference)
@@ -783,9 +784,12 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
let type = webEmbedType(content: content.webpageContent)
switch type {
case .youtube:
+ isEnhancedWebPlayer = true
forceEnableUserInteraction = true
disablePictureInPicture = !(item.configuration?.youtubePictureInPictureEnabled ?? false)
self.videoFramePreview = YoutubeEmbedFramePreview(context: item.context, content: content)
+ case .vimeo:
+ isEnhancedWebPlayer = true
case .iframe:
disablePlayerControls = true
default:
@@ -1122,7 +1126,14 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
}
}
- if !isWebpage, let file = file, !file.isAnimated {
+ var hasMoreButton = false
+ if isEnhancedWebPlayer {
+ hasMoreButton = true
+ } else if !isWebpage, let file = file, !file.isAnimated {
+ hasMoreButton = true
+ }
+
+ if hasMoreButton {
let moreMenuItem = UIBarButtonItem(customDisplayNode: self.moreBarButton)!
barButtonItems.append(moreMenuItem)
}
@@ -1316,6 +1327,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
if let time = item.timecode {
seek = .timecode(time)
}
+ playbackRate = item.playbackRate
}
}
videoNode.setBaseRate(playbackRate)
@@ -1922,7 +1934,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
}
}
- private func contentInfo() -> (message: Message, file: TelegramMediaFile, isWebpage: Bool)? {
+ private func contentInfo() -> (message: Message, file: TelegramMediaFile?, isWebpage: Bool)? {
guard let item = self.item else {
return nil
}
@@ -1933,16 +1945,15 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
if let m = m as? TelegramMediaFile, m.isVideo {
file = m
break
- } else if let m = m as? TelegramMediaWebpage, case let .Loaded(content) = m.content, let f = content.file, f.isVideo {
- file = f
+ } else if let m = m as? TelegramMediaWebpage, case let .Loaded(content) = m.content {
+ if let f = content.file, f.isVideo {
+ file = f
+ }
isWebpage = true
break
}
}
-
- if let file = file {
- return (message, file, isWebpage)
- }
+ return (message, file, isWebpage)
}
return nil
}
@@ -2041,7 +2052,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
c.setItems(strongSelf.contextMenuSpeedItems())
})))
- if let (message, file, isWebpage) = strongSelf.contentInfo(), !isWebpage {
+ if let (message, maybeFile, isWebpage) = strongSelf.contentInfo(), let file = maybeFile, !isWebpage {
items.append(.action(ContextMenuActionItem(text: "Save to Gallery", icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Download"), color: theme.actionSheet.primaryTextColor) }, action: { _, f in
f(.default)
diff --git a/submodules/LegacyComponents/Sources/TGCameraMainPhoneView.m b/submodules/LegacyComponents/Sources/TGCameraMainPhoneView.m
index 274e33e4be..3070c7cb47 100644
--- a/submodules/LegacyComponents/Sources/TGCameraMainPhoneView.m
+++ b/submodules/LegacyComponents/Sources/TGCameraMainPhoneView.m
@@ -282,17 +282,7 @@
} completion:nil];
};
[self addSubview:_zoomView];
-
- _flashControl.becameActive = ^
- {
- __strong TGCameraMainPhoneView *strongSelf = weakSelf;
- if (strongSelf == nil)
- return;
- if (strongSelf->_modeControl.cameraMode == PGCameraModeVideo)
- [strongSelf->_timecodeView setHidden:true animated:true];
- };
-
_flashControl.modeChanged = ^(PGCameraFlashMode mode)
{
__strong TGCameraMainPhoneView *strongSelf = weakSelf;
@@ -301,9 +291,6 @@
if (strongSelf.flashModeChanged != nil)
strongSelf.flashModeChanged(mode);
-
- if (strongSelf->_modeControl.cameraMode == PGCameraModeVideo)
- [strongSelf->_timecodeView setHidden:false animated:true];
};
_modeControl.modeChanged = ^(PGCameraMode mode, PGCameraMode previousMode)
diff --git a/submodules/TelegramUI/Resources/WebEmbed/Vimeo.html b/submodules/TelegramUI/Resources/WebEmbed/Vimeo.html
index ecea52af89..22f609f06c 100755
--- a/submodules/TelegramUI/Resources/WebEmbed/Vimeo.html
+++ b/submodules/TelegramUI/Resources/WebEmbed/Vimeo.html
@@ -9,14 +9,10 @@
-
+
+
diff --git a/submodules/TelegramUI/Resources/WebEmbed/VimeoUserScript.js b/submodules/TelegramUI/Resources/WebEmbed/VimeoUserScript.js
index daba76762d..02620c3a81 100644
--- a/submodules/TelegramUI/Resources/WebEmbed/VimeoUserScript.js
+++ b/submodules/TelegramUI/Resources/WebEmbed/VimeoUserScript.js
@@ -4,17 +4,17 @@ function initialize() {
controls.style.display = "none";
}
- var sidedock = document.getElementsByClassName("sidedock")[0];
+ var sidedock = document.getElementsByClassName("vp-sidedock")[0];
if (sidedock != null) {
sidedock.style.display = "none";
}
- var video = document.getElementsByTagName("video")[0];
- if (video != null) {
- video.setAttribute("webkit-playsinline", "");
- video.setAttribute("playsinline", "");
- video.webkitEnterFullscreen = undefined;
- }
+// var video = document.getElementsByTagName("video")[0];
+// if (video != null) {
+// video.setAttribute("webkit-playsinline", "");
+// video.setAttribute("playsinline", "");
+// video.webkitEnterFullscreen = undefined;
+// }
}
function eventFire(el, etype){
diff --git a/submodules/TelegramUI/Resources/WebEmbed/Youtube.html b/submodules/TelegramUI/Resources/WebEmbed/Youtube.html
index 8e3f1b5096..a18ee62bd6 100755
--- a/submodules/TelegramUI/Resources/WebEmbed/Youtube.html
+++ b/submodules/TelegramUI/Resources/WebEmbed/Youtube.html
@@ -60,6 +60,10 @@
player.seekTo(timestamp, true);
}
+ function setRate(rate) {
+ player.setPlaybackRate(rate);
+ }
+
function updateState() {
window.location.href = "embed://onState?failed=" + failed + "&playback=" + playbackState + "&position=" + position + "&duration=" + duration + "&download=" + downloadProgress + '&quality=' + quality + '&availableQualities=' + availableQualities + '&storyboard=' + storyboardSpec;
}
diff --git a/submodules/TelegramUniversalVideoContent/Sources/GenericEmbedImplementation.swift b/submodules/TelegramUniversalVideoContent/Sources/GenericEmbedImplementation.swift
index 731c1364b5..c525db9e45 100644
--- a/submodules/TelegramUniversalVideoContent/Sources/GenericEmbedImplementation.swift
+++ b/submodules/TelegramUniversalVideoContent/Sources/GenericEmbedImplementation.swift
@@ -71,6 +71,9 @@ final class GenericEmbedImplementation: WebEmbedImplementation {
func seek(timestamp: Double) {
}
+ func setBaseRate(_ baseRate: Double) {
+ }
+
func pageReady() {
self.status = MediaPlayerStatus(generationTimestamp: 0.0, duration: 0.0, dimensions: CGSize(), timestamp: 0.0, baseRate: 1.0, seekId: 0, status: .playing, soundEnabled: true)
self.updateStatus?(self.status)
diff --git a/submodules/TelegramUniversalVideoContent/Sources/TwitchEmbedImplementation.swift b/submodules/TelegramUniversalVideoContent/Sources/TwitchEmbedImplementation.swift
index 85fb56e6ba..58fadf788c 100644
--- a/submodules/TelegramUniversalVideoContent/Sources/TwitchEmbedImplementation.swift
+++ b/submodules/TelegramUniversalVideoContent/Sources/TwitchEmbedImplementation.swift
@@ -88,6 +88,9 @@ final class TwitchEmbedImplementation: WebEmbedImplementation {
func seek(timestamp: Double) {
}
+ func setBaseRate(_ baseRate: Double) {
+ }
+
func pageReady() {
// Queue.mainQueue().after(delay: 0.5) {
// if let onPlaybackStarted = self.onPlaybackStarted {
diff --git a/submodules/TelegramUniversalVideoContent/Sources/VimeoEmbedImplementation.swift b/submodules/TelegramUniversalVideoContent/Sources/VimeoEmbedImplementation.swift
index 453208b145..f5b911b5a0 100644
--- a/submodules/TelegramUniversalVideoContent/Sources/VimeoEmbedImplementation.swift
+++ b/submodules/TelegramUniversalVideoContent/Sources/VimeoEmbedImplementation.swift
@@ -88,6 +88,7 @@ final class VimeoEmbedImplementation: WebEmbedImplementation {
private let videoId: String
private let timestamp: Int
+ private var baseRate: Double = 1.0
private var status : MediaPlayerStatus
private var ready: Bool = false
@@ -160,12 +161,30 @@ final class VimeoEmbedImplementation: WebEmbedImplementation {
eval("seek(\(timestamp));", nil)
}
- self.status = MediaPlayerStatus(generationTimestamp: self.status.generationTimestamp, duration: self.status.duration, dimensions: self.status.dimensions, timestamp: timestamp, baseRate: 1.0, seekId: self.status.seekId + 1, status: self.status.status, soundEnabled: self.status.soundEnabled)
- if let updateStatus = self.updateStatus {
- updateStatus(self.status)
+ self.status = MediaPlayerStatus(generationTimestamp: self.status.generationTimestamp, duration: self.status.duration, dimensions: self.status.dimensions, timestamp: timestamp, baseRate: self.status.baseRate, seekId: self.status.seekId + 1, status: self.status.status, soundEnabled: self.status.soundEnabled)
+ self.updateStatus?(self.status)
+
+ self.ignorePosition = 2
+ }
+
+ func setBaseRate(_ baseRate: Double) {
+ var baseRate = baseRate
+ if baseRate < 0.5 {
+ baseRate = 0.5
+ }
+ if baseRate > 2.0 {
+ baseRate = 2.0
+ }
+ if !self.ready {
+ self.baseRate = baseRate
}
- self.ignorePosition = 2
+ if let eval = self.evalImpl {
+ eval("setRate(\(baseRate));", nil)
+ }
+
+ self.status = MediaPlayerStatus(generationTimestamp: self.status.generationTimestamp, duration: self.status.duration, dimensions: self.status.dimensions, timestamp: self.status.timestamp, baseRate: baseRate, seekId: self.status.seekId + 1, status: self.status.status, soundEnabled: true)
+ self.updateStatus?(self.status)
}
func pageReady() {
@@ -210,6 +229,11 @@ final class VimeoEmbedImplementation: WebEmbedImplementation {
}
}
+ if !self.ready {
+ self.ready = true
+ self.play()
+ }
+
if let updateStatus = self.updateStatus, let playback = playback, let duration = duration {
let playbackStatus: MediaPlayerPlaybackStatus
switch playback {
@@ -226,10 +250,12 @@ final class VimeoEmbedImplementation: WebEmbedImplementation {
if case .playing = playbackStatus, !self.started {
self.started = true
- self.onPlaybackStarted?()
+ Queue.mainQueue().after(0.5) {
+ self.onPlaybackStarted?()
+ }
}
- self.status = MediaPlayerStatus(generationTimestamp: self.status.generationTimestamp, duration: Double(duration), dimensions: self.status.dimensions, timestamp: newTimestamp, baseRate: 1.0, seekId: self.status.seekId, status: playbackStatus, soundEnabled: true)
+ self.status = MediaPlayerStatus(generationTimestamp: self.status.generationTimestamp, duration: Double(duration), dimensions: self.status.dimensions, timestamp: newTimestamp, baseRate: self.status.baseRate, seekId: self.status.seekId, status: playbackStatus, soundEnabled: true)
updateStatus(self.status)
}
}
diff --git a/submodules/TelegramUniversalVideoContent/Sources/WebEmbedPlayerNode.swift b/submodules/TelegramUniversalVideoContent/Sources/WebEmbedPlayerNode.swift
index 2de523f71a..682283a278 100644
--- a/submodules/TelegramUniversalVideoContent/Sources/WebEmbedPlayerNode.swift
+++ b/submodules/TelegramUniversalVideoContent/Sources/WebEmbedPlayerNode.swift
@@ -14,6 +14,7 @@ protocol WebEmbedImplementation {
func pause()
func togglePlayPause()
func seek(timestamp: Double)
+ func setBaseRate(_ baseRate: Double)
func pageReady()
func callback(url: URL)
@@ -170,6 +171,10 @@ final class WebEmbedPlayerNode: ASDisplayNode, WKNavigationDelegate {
self.impl.seek(timestamp: timestamp)
}
+ func setBaseRate(_ baseRate: Double) {
+ self.impl.setBaseRate(baseRate)
+ }
+
func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
}
diff --git a/submodules/TelegramUniversalVideoContent/Sources/WebEmbedVideoContent.swift b/submodules/TelegramUniversalVideoContent/Sources/WebEmbedVideoContent.swift
index d5aa2686a0..a7dfd3c409 100644
--- a/submodules/TelegramUniversalVideoContent/Sources/WebEmbedVideoContent.swift
+++ b/submodules/TelegramUniversalVideoContent/Sources/WebEmbedVideoContent.swift
@@ -172,6 +172,7 @@ final class WebEmbedVideoContentNode: ASDisplayNode, UniversalVideoContentNode {
}
func setBaseRate(_ baseRate: Double) {
+ self.playerNode.setBaseRate(baseRate)
}
func addPlaybackCompleted(_ f: @escaping () -> Void) -> Int {
diff --git a/submodules/TelegramUniversalVideoContent/Sources/YoutubeEmbedImplementation.swift b/submodules/TelegramUniversalVideoContent/Sources/YoutubeEmbedImplementation.swift
index 20affc0cb1..eb01468635 100644
--- a/submodules/TelegramUniversalVideoContent/Sources/YoutubeEmbedImplementation.swift
+++ b/submodules/TelegramUniversalVideoContent/Sources/YoutubeEmbedImplementation.swift
@@ -100,6 +100,7 @@ final class YoutubeEmbedImplementation: WebEmbedImplementation {
}
private var timestamp: Int
+ private var baseRate: Double = 1.0
private var ignoreEarlierTimestamps = false
private var status: MediaPlayerStatus
@@ -107,6 +108,8 @@ final class YoutubeEmbedImplementation: WebEmbedImplementation {
private var started = false
private var ignorePosition: Int?
+ private var isPlaying = true
+
private enum PlaybackDelay {
case none
case afterPositionUpdates(count: Int)
@@ -186,6 +189,8 @@ final class YoutubeEmbedImplementation: WebEmbedImplementation {
return
}
+ self.isPlaying = true
+
if let eval = self.evalImpl {
eval("play();", nil)
}
@@ -194,6 +199,7 @@ final class YoutubeEmbedImplementation: WebEmbedImplementation {
}
func pause() {
+ self.isPlaying = false
if let eval = self.evalImpl {
eval("pause();", nil)
}
@@ -201,9 +207,9 @@ final class YoutubeEmbedImplementation: WebEmbedImplementation {
func togglePlayPause() {
if case .playing = self.status.status {
- pause()
+ self.pause()
} else {
- play()
+ self.play()
}
}
@@ -217,12 +223,32 @@ final class YoutubeEmbedImplementation: WebEmbedImplementation {
eval("seek(\(timestamp));", nil)
}
- self.status = MediaPlayerStatus(generationTimestamp: self.status.generationTimestamp, duration: self.status.duration, dimensions: self.status.dimensions, timestamp: timestamp, baseRate: 1.0, seekId: self.status.seekId + 1, status: self.status.status, soundEnabled: true)
+ self.status = MediaPlayerStatus(generationTimestamp: self.status.generationTimestamp, duration: self.status.duration, dimensions: self.status.dimensions, timestamp: timestamp, baseRate: self.status.baseRate, seekId: self.status.seekId + 1, status: self.status.status, soundEnabled: true)
self.updateStatus?(self.status)
self.ignorePosition = 2
}
+ func setBaseRate(_ baseRate: Double) {
+ var baseRate = baseRate
+ if baseRate < 0.5 {
+ baseRate = 0.5
+ }
+ if baseRate > 2.0 {
+ baseRate = 2.0
+ }
+ if !self.ready {
+ self.baseRate = baseRate
+ }
+
+ if let eval = self.evalImpl {
+ eval("setRate(\(baseRate));", nil)
+ }
+
+ self.status = MediaPlayerStatus(generationTimestamp: self.status.generationTimestamp, duration: self.status.duration, dimensions: self.status.dimensions, timestamp: self.status.timestamp, baseRate: baseRate, seekId: self.status.seekId + 1, status: self.status.status, soundEnabled: true)
+ self.updateStatus?(self.status)
+ }
+
func pageReady() {
}
@@ -283,6 +309,7 @@ final class YoutubeEmbedImplementation: WebEmbedImplementation {
switch playback {
case 0:
if newTimestamp > Double(duration) - 1.0 {
+ self.isPlaying = false
playbackStatus = .paused
newTimestamp = 0.0
} else {
@@ -293,9 +320,9 @@ final class YoutubeEmbedImplementation: WebEmbedImplementation {
case 2:
playbackStatus = .paused
case 3:
- playbackStatus = .buffering(initial: false, whilePlaying: true, progress: 0.0, display: false)
+ playbackStatus = .buffering(initial: !self.started, whilePlaying: self.isPlaying, progress: 0.0, display: false)
default:
- playbackStatus = .buffering(initial: true, whilePlaying: false, progress: 0.0, display: false)
+ playbackStatus = .buffering(initial: true, whilePlaying: true, progress: 0.0, display: false)
}
if case .playing = playbackStatus, !self.started {
@@ -305,7 +332,7 @@ final class YoutubeEmbedImplementation: WebEmbedImplementation {
self.onPlaybackStarted?()
}
- self.status = MediaPlayerStatus(generationTimestamp: self.status.generationTimestamp, duration: Double(duration), dimensions: self.status.dimensions, timestamp: newTimestamp, baseRate: 1.0, seekId: self.status.seekId, status: playbackStatus, soundEnabled: true)
+ self.status = MediaPlayerStatus(generationTimestamp: self.status.generationTimestamp, duration: Double(duration), dimensions: self.status.dimensions, timestamp: newTimestamp, baseRate: self.status.baseRate, seekId: self.status.seekId, status: playbackStatus, soundEnabled: true)
updateStatus(self.status)
}
}
@@ -327,12 +354,20 @@ final class YoutubeEmbedImplementation: WebEmbedImplementation {
self.play()
}
+ if self.baseRate != 1.0 {
+ self.setBaseRate(self.baseRate)
+ }
+
print("YT ready in \(CFAbsoluteTimeGetCurrent() - self.benchmarkStartTime)")
Queue.mainQueue().async {
- self.play()
-
let delay = self.timestamp > 0 ? 2.8 : 2.0
+ if self.timestamp > 0 {
+ self.seek(timestamp: Double(self.timestamp))
+ self.play()
+ } else {
+ self.play()
+ }
Queue.mainQueue().after(delay, {
if !self.started {
self.play()