mirror of
https://github.com/streamyfin/streamyfin.git
synced 2026-06-05 21:48:31 +01:00
wip
This commit is contained in:
@@ -34,7 +34,7 @@ const Page: React.FC = () => {
|
|||||||
|
|
||||||
return res.data;
|
return res.data;
|
||||||
},
|
},
|
||||||
enabled: !!id && !!api,
|
enabled: !!id && !!api || !!user,
|
||||||
staleTime: 0,
|
staleTime: 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -230,6 +230,8 @@ export default function page() {
|
|||||||
|
|
||||||
const { currentTime, isPlaying } = data.nativeEvent;
|
const { currentTime, isPlaying } = data.nativeEvent;
|
||||||
|
|
||||||
|
console.log("onProgress", currentTime);
|
||||||
|
|
||||||
progress.value = currentTime;
|
progress.value = currentTime;
|
||||||
const currentTimeInTicks = msToTicks(currentTime);
|
const currentTimeInTicks = msToTicks(currentTime);
|
||||||
|
|
||||||
|
|||||||
@@ -52,6 +52,10 @@ export const ItemContent: React.FC<{ item: BaseItemDto }> = React.memo(
|
|||||||
const [loadingLogo, setLoadingLogo] = useState(true);
|
const [loadingLogo, setLoadingLogo] = useState(true);
|
||||||
const [headerHeight, setHeaderHeight] = useState(350);
|
const [headerHeight, setHeaderHeight] = useState(350);
|
||||||
|
|
||||||
|
const [selectedOptions, setSelectedOptions] = useState<
|
||||||
|
SelectedOptions | undefined
|
||||||
|
>(undefined);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
defaultAudioIndex,
|
defaultAudioIndex,
|
||||||
defaultBitrate,
|
defaultBitrate,
|
||||||
@@ -59,12 +63,19 @@ export const ItemContent: React.FC<{ item: BaseItemDto }> = React.memo(
|
|||||||
defaultSubtitleIndex,
|
defaultSubtitleIndex,
|
||||||
} = useDefaultPlaySettings(item, settings);
|
} = useDefaultPlaySettings(item, settings);
|
||||||
|
|
||||||
const [selectedOptions, setSelectedOptions] = useState<SelectedOptions>({
|
useEffect(() => {
|
||||||
bitrate: defaultBitrate,
|
setSelectedOptions(() => ({
|
||||||
mediaSource: defaultMediaSource,
|
bitrate: defaultBitrate,
|
||||||
audioIndex: defaultAudioIndex,
|
mediaSource: defaultMediaSource,
|
||||||
subtitleIndex: defaultSubtitleIndex || -1,
|
subtitleIndex: defaultSubtitleIndex ?? -1,
|
||||||
});
|
audioIndex: defaultAudioIndex,
|
||||||
|
}));
|
||||||
|
}, [
|
||||||
|
defaultAudioIndex,
|
||||||
|
defaultBitrate,
|
||||||
|
defaultSubtitleIndex,
|
||||||
|
defaultMediaSource,
|
||||||
|
]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
navigation.setOptions({
|
navigation.setOptions({
|
||||||
@@ -96,6 +107,8 @@ export const ItemContent: React.FC<{ item: BaseItemDto }> = React.memo(
|
|||||||
return Boolean(logoUrl && loadingLogo);
|
return Boolean(logoUrl && loadingLogo);
|
||||||
}, [loadingLogo, logoUrl]);
|
}, [loadingLogo, logoUrl]);
|
||||||
|
|
||||||
|
if (!selectedOptions) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View
|
<View
|
||||||
className="flex-1 relative"
|
className="flex-1 relative"
|
||||||
@@ -148,7 +161,9 @@ export const ItemContent: React.FC<{ item: BaseItemDto }> = React.memo(
|
|||||||
<BitrateSelector
|
<BitrateSelector
|
||||||
className="mr-1"
|
className="mr-1"
|
||||||
onChange={(val) =>
|
onChange={(val) =>
|
||||||
setSelectedOptions((prev) => ({ ...prev, bitrate: val }))
|
setSelectedOptions(
|
||||||
|
(prev) => prev && { ...prev, bitrate: val }
|
||||||
|
)
|
||||||
}
|
}
|
||||||
selected={selectedOptions.bitrate}
|
selected={selectedOptions.bitrate}
|
||||||
/>
|
/>
|
||||||
@@ -156,10 +171,13 @@ export const ItemContent: React.FC<{ item: BaseItemDto }> = React.memo(
|
|||||||
className="mr-1"
|
className="mr-1"
|
||||||
item={item}
|
item={item}
|
||||||
onChange={(val) =>
|
onChange={(val) =>
|
||||||
setSelectedOptions((prev) => ({
|
setSelectedOptions(
|
||||||
...prev,
|
(prev) =>
|
||||||
mediaSource: val,
|
prev && {
|
||||||
}))
|
...prev,
|
||||||
|
mediaSource: val,
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
selected={selectedOptions.mediaSource}
|
selected={selectedOptions.mediaSource}
|
||||||
/>
|
/>
|
||||||
@@ -167,20 +185,26 @@ export const ItemContent: React.FC<{ item: BaseItemDto }> = React.memo(
|
|||||||
className="mr-1"
|
className="mr-1"
|
||||||
source={selectedOptions.mediaSource}
|
source={selectedOptions.mediaSource}
|
||||||
onChange={(val) =>
|
onChange={(val) =>
|
||||||
setSelectedOptions((prev) => ({
|
setSelectedOptions(
|
||||||
...prev,
|
(prev) =>
|
||||||
audioIndex: val,
|
prev && {
|
||||||
}))
|
...prev,
|
||||||
|
audioIndex: val,
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
selected={selectedOptions.audioIndex}
|
selected={selectedOptions.audioIndex}
|
||||||
/>
|
/>
|
||||||
<SubtitleTrackSelector
|
<SubtitleTrackSelector
|
||||||
source={selectedOptions.mediaSource}
|
source={selectedOptions.mediaSource}
|
||||||
onChange={(val) =>
|
onChange={(val) =>
|
||||||
setSelectedOptions((prev) => ({
|
setSelectedOptions(
|
||||||
...prev,
|
(prev) =>
|
||||||
subtitleIndex: val,
|
prev && {
|
||||||
}))
|
...prev,
|
||||||
|
subtitleIndex: val,
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
selected={selectedOptions.subtitleIndex}
|
selected={selectedOptions.subtitleIndex}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ export const MediaSourceSelector: React.FC<Props> = ({
|
|||||||
item.MediaSources?.find((x) => x.Id === selected?.Id)?.MediaStreams?.find(
|
item.MediaSources?.find((x) => x.Id === selected?.Id)?.MediaStreams?.find(
|
||||||
(x) => x.Type === "Video"
|
(x) => x.Type === "Video"
|
||||||
)?.DisplayTitle || "",
|
)?.DisplayTitle || "",
|
||||||
[item.MediaSources, selected]
|
[item, selected]
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -42,7 +42,11 @@ const useDefaultPlaySettings = (
|
|||||||
defaultMediaSource: mediaSource || undefined,
|
defaultMediaSource: mediaSource || undefined,
|
||||||
defaultBitrate: bitrate || undefined,
|
defaultBitrate: bitrate || undefined,
|
||||||
};
|
};
|
||||||
}, [item, settings]);
|
}, [
|
||||||
|
item.MediaSources,
|
||||||
|
settings?.defaultAudioLanguage,
|
||||||
|
settings?.defaultSubtitleLanguage,
|
||||||
|
]);
|
||||||
|
|
||||||
return playSettings;
|
return playSettings;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -54,7 +54,6 @@ export const useImageColors = ({
|
|||||||
|
|
||||||
// If colors are cached, use them and exit
|
// If colors are cached, use them and exit
|
||||||
if (_primary && _text) {
|
if (_primary && _text) {
|
||||||
console.info("useImageColors ~ Using cached colors for performance.");
|
|
||||||
setPrimaryColor({
|
setPrimaryColor({
|
||||||
primary: _primary,
|
primary: _primary,
|
||||||
text: _text,
|
text: _text,
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ Pod::Spec.new do |s|
|
|||||||
s.static_framework = true
|
s.static_framework = true
|
||||||
|
|
||||||
s.dependency 'ExpoModulesCore'
|
s.dependency 'ExpoModulesCore'
|
||||||
s.dependency 'MobileVLCKit'
|
s.dependency 'MobileVLCKit', '~> 3.6.1b1'
|
||||||
|
|
||||||
# Swift/Objective-C compatibility
|
# Swift/Objective-C compatibility
|
||||||
s.pod_target_xcconfig = {
|
s.pod_target_xcconfig = {
|
||||||
|
|||||||
@@ -16,17 +16,17 @@ public class VlcPlayerModule: Module {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Prop("muted") { (view: VlcPlayerView, muted: Bool) in
|
// Prop("muted") { (view: VlcPlayerView, muted: Bool) in
|
||||||
view.setMuted(muted)
|
// view.setMuted(muted)
|
||||||
}
|
// }
|
||||||
|
|
||||||
Prop("volume") { (view: VlcPlayerView, volume: Int) in
|
// Prop("volume") { (view: VlcPlayerView, volume: Int) in
|
||||||
view.setVolume(volume)
|
// view.setVolume(volume)
|
||||||
}
|
// }
|
||||||
|
|
||||||
Prop("videoAspectRatio") { (view: VlcPlayerView, ratio: String) in
|
// Prop("videoAspectRatio") { (view: VlcPlayerView, ratio: String) in
|
||||||
view.setVideoAspectRatio(ratio)
|
// view.setVideoAspectRatio(ratio)
|
||||||
}
|
// }
|
||||||
|
|
||||||
Events(
|
Events(
|
||||||
"onPlaybackStateChanged",
|
"onPlaybackStateChanged",
|
||||||
@@ -69,13 +69,13 @@ public class VlcPlayerModule: Module {
|
|||||||
return view.getSubtitleTracks()
|
return view.getSubtitleTracks()
|
||||||
}
|
}
|
||||||
|
|
||||||
AsyncFunction("setVideoCropGeometry") { (view: VlcPlayerView, geometry: String?) in
|
// AsyncFunction("setVideoCropGeometry") { (view: VlcPlayerView, geometry: String?) in
|
||||||
view.setVideoCropGeometry(geometry)
|
// view.setVideoCropGeometry(geometry)
|
||||||
}
|
// }
|
||||||
|
|
||||||
AsyncFunction("getVideoCropGeometry") { (view: VlcPlayerView) -> String? in
|
// AsyncFunction("getVideoCropGeometry") { (view: VlcPlayerView) -> String? in
|
||||||
return view.getVideoCropGeometry()
|
// return view.getVideoCropGeometry()
|
||||||
}
|
// }
|
||||||
|
|
||||||
AsyncFunction("setSubtitleURL") {
|
AsyncFunction("setSubtitleURL") {
|
||||||
(view: VlcPlayerView, url: String, name: String) in
|
(view: VlcPlayerView, url: String, name: String) in
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ class VlcPlayerView: ExpoView {
|
|||||||
required init(appContext: AppContext? = nil) {
|
required init(appContext: AppContext? = nil) {
|
||||||
super.init(appContext: appContext)
|
super.init(appContext: appContext)
|
||||||
setupView()
|
setupView()
|
||||||
setupNotifications()
|
// setupNotifications()
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Setup
|
// MARK: - Setup
|
||||||
@@ -68,6 +68,7 @@ class VlcPlayerView: ExpoView {
|
|||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
self.mediaPlayer?.play()
|
self.mediaPlayer?.play()
|
||||||
self.isPaused = false
|
self.isPaused = false
|
||||||
|
print("Play")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,6 +144,7 @@ class VlcPlayerView: ExpoView {
|
|||||||
media = VLCMedia(url: url)
|
media = VLCMedia(url: url)
|
||||||
} else {
|
} else {
|
||||||
print("Error: Invalid local file URL")
|
print("Error: Invalid local file URL")
|
||||||
|
self.onVideoError?(["error": "Invalid local file URL"])
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -155,13 +157,13 @@ class VlcPlayerView: ExpoView {
|
|||||||
media.addOptions(subtitleOptions)
|
media.addOptions(subtitleOptions)
|
||||||
print("Debug: Applied subtitle options: \(subtitleOptions)")
|
print("Debug: Applied subtitle options: \(subtitleOptions)")
|
||||||
|
|
||||||
// Apply any additional media options
|
// // Apply any additional media options
|
||||||
if let mediaOptions = mediaOptions {
|
// if let mediaOptions = mediaOptions {
|
||||||
media.addOptions(mediaOptions)
|
// media.addOptions(mediaOptions)
|
||||||
print("Debug: Applied additional media options: \(mediaOptions)")
|
// print("Debug: Applied additional media options: \(mediaOptions)")
|
||||||
} else {
|
// } else {
|
||||||
print("Debug: No additional media options provided")
|
// print("Debug: No additional media options provided")
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Apply subtitle options
|
// Apply subtitle options
|
||||||
let subtitleTrackIndex = source["subtitleTrackIndex"] as? Int ?? -1
|
let subtitleTrackIndex = source["subtitleTrackIndex"] as? Int ?? -1
|
||||||
@@ -177,19 +179,30 @@ class VlcPlayerView: ExpoView {
|
|||||||
self.mediaPlayer?.media = media
|
self.mediaPlayer?.media = media
|
||||||
|
|
||||||
if startPosition > 0 {
|
if startPosition > 0 {
|
||||||
// Wait for the media to be ready before setting the start position
|
// Create a closure to set the start position
|
||||||
NotificationCenter.default.addObserver(
|
let setStartPosition = { [weak self] in
|
||||||
forName: NSNotification.Name(rawValue: VLCMediaPlayerStateChanged), object: nil,
|
self?.mediaPlayer?.time = VLCTime(int: startPosition)
|
||||||
queue: nil
|
}
|
||||||
) { [weak self] notification in
|
|
||||||
guard let self = self, let player = self.mediaPlayer,
|
|
||||||
player.isPlaying == false
|
|
||||||
else { return }
|
|
||||||
|
|
||||||
self.mediaPlayer?.time = VLCTime(int: startPosition)
|
// Check if the media is already ready
|
||||||
NotificationCenter.default.removeObserver(
|
if self.isMediaReady {
|
||||||
self, name: NSNotification.Name(rawValue: VLCMediaPlayerStateChanged),
|
setStartPosition()
|
||||||
object: nil)
|
} else {
|
||||||
|
// If not ready, set up an observer to wait for the media to be ready
|
||||||
|
NotificationCenter.default.addObserver(
|
||||||
|
forName: .VLCMediaPlayerStateChanged, object: self.mediaPlayer, queue: .main
|
||||||
|
) { [weak self] notification in
|
||||||
|
guard let self = self, let player = self.mediaPlayer else { return }
|
||||||
|
|
||||||
|
if player.state == .playing || player.state == .paused {
|
||||||
|
// Media is ready, set the start position
|
||||||
|
setStartPosition()
|
||||||
|
|
||||||
|
// Remove the observer
|
||||||
|
NotificationCenter.default.removeObserver(
|
||||||
|
self, name: .VLCMediaPlayerStateChanged, object: player)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -200,25 +213,28 @@ class VlcPlayerView: ExpoView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func setMuted(_ muted: Bool) {
|
// TODO
|
||||||
DispatchQueue.main.async {
|
// @objc func setMuted(_ muted: Bool) {
|
||||||
self.mediaPlayer?.audio?.isMuted = muted
|
// DispatchQueue.main.async {
|
||||||
}
|
// self.mediaPlayer?.audio?.isMuted = muted
|
||||||
}
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
@objc func setVolume(_ volume: Int) {
|
// TODO
|
||||||
DispatchQueue.main.async {
|
// @objc func setVolume(_ volume: Int) {
|
||||||
self.mediaPlayer?.audio?.volume = Int32(volume)
|
// DispatchQueue.main.async {
|
||||||
}
|
// self.mediaPlayer?.audio?.volume = Int32(volume)
|
||||||
}
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
@objc func setVideoAspectRatio(_ ratio: String) {
|
// TODO
|
||||||
DispatchQueue.main.async {
|
// @objc func setVideoAspectRatio(_ ratio: String) {
|
||||||
ratio.withCString { cString in
|
// DispatchQueue.main.async {
|
||||||
self.mediaPlayer?.videoAspectRatio = UnsafeMutablePointer(mutating: cString)
|
// ratio.withCString { cString in
|
||||||
}
|
// self.mediaPlayer?.videoAspectRatio = UnsafeMutablePointer(mutating: cString)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
@objc func setAudioTrack(_ trackIndex: Int) {
|
@objc func setAudioTrack(_ trackIndex: Int) {
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
@@ -373,88 +389,97 @@ class VlcPlayerView: ExpoView {
|
|||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
@objc func setSubtitleDelay(_ delay: Int) {
|
// TODO
|
||||||
DispatchQueue.main.async {
|
// @objc func setSubtitleDelay(_ delay: Int) {
|
||||||
self.mediaPlayer?.currentVideoSubTitleDelay = NSInteger(delay)
|
// DispatchQueue.main.async {
|
||||||
}
|
// self.mediaPlayer?.currentVideoSubTitleDelay = NSInteger(delay)
|
||||||
}
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
@objc func setAudioDelay(_ delay: Int) {
|
// TODO
|
||||||
DispatchQueue.main.async {
|
// @objc func setAudioDelay(_ delay: Int) {
|
||||||
self.mediaPlayer?.currentAudioPlaybackDelay = NSInteger(delay)
|
// DispatchQueue.main.async {
|
||||||
}
|
// self.mediaPlayer?.currentAudioPlaybackDelay = NSInteger(delay)
|
||||||
}
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
@objc func takeSnapshot(_ path: String, width: Int, height: Int) {
|
// TODO
|
||||||
DispatchQueue.main.async { [weak self] in
|
// @objc func takeSnapshot(_ path: String, width: Int, height: Int) {
|
||||||
guard let self = self else { return }
|
// DispatchQueue.main.async { [weak self] in
|
||||||
self.mediaPlayer?.saveVideoSnapshot(
|
// guard let self = self else { return }
|
||||||
at: path, withWidth: Int32(width), andHeight: Int32(height))
|
// self.mediaPlayer?.saveVideoSnapshot(
|
||||||
}
|
// at: path, withWidth: Int32(width), andHeight: Int32(height))
|
||||||
}
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
@objc func setVideoCropGeometry(_ geometry: String?) {
|
// TODO
|
||||||
DispatchQueue.main.async {
|
// @objc func setVideoCropGeometry(_ geometry: String?) {
|
||||||
if let geometry = geometry, !geometry.isEmpty {
|
// DispatchQueue.main.async {
|
||||||
self.currentGeometryCString = geometry.cString(using: .utf8)
|
// if let geometry = geometry, !geometry.isEmpty {
|
||||||
self.currentGeometryCString?.withUnsafeMutableBufferPointer { buffer in
|
// self.currentGeometryCString = geometry.cString(using: .utf8)
|
||||||
self.mediaPlayer?.videoCropGeometry = buffer.baseAddress
|
// self.currentGeometryCString?.withUnsafeMutableBufferPointer { buffer in
|
||||||
}
|
// self.mediaPlayer?.videoCropGeometry = buffer.baseAddress
|
||||||
} else {
|
// }
|
||||||
self.currentGeometryCString = nil
|
// } else {
|
||||||
self.mediaPlayer?.videoCropGeometry = nil
|
// self.currentGeometryCString = nil
|
||||||
}
|
// self.mediaPlayer?.videoCropGeometry = nil
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
@objc func getVideoCropGeometry() -> String? {
|
// TODO
|
||||||
guard let cString = mediaPlayer?.videoCropGeometry else {
|
// @objc func getVideoCropGeometry() -> String? {
|
||||||
return nil
|
// guard let cString = mediaPlayer?.videoCropGeometry else {
|
||||||
}
|
// return nil
|
||||||
return String(cString: cString)
|
// }
|
||||||
}
|
// return String(cString: cString)
|
||||||
|
// }
|
||||||
|
|
||||||
@objc func setRate(_ rate: Float) {
|
// TODO
|
||||||
DispatchQueue.main.async {
|
// @objc func setRate(_ rate: Float) {
|
||||||
self.mediaPlayer?.rate = rate
|
// DispatchQueue.main.async {
|
||||||
}
|
// self.mediaPlayer?.rate = rate
|
||||||
}
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
@objc func nextChapter() {
|
// TODO
|
||||||
DispatchQueue.main.async {
|
// @objc func nextChapter() {
|
||||||
self.mediaPlayer?.nextChapter()
|
// DispatchQueue.main.async {
|
||||||
}
|
// self.mediaPlayer?.nextChapter()
|
||||||
}
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
@objc func previousChapter() {
|
// TODO
|
||||||
DispatchQueue.main.async {
|
// @objc func previousChapter() {
|
||||||
self.mediaPlayer?.previousChapter()
|
// DispatchQueue.main.async {
|
||||||
}
|
// self.mediaPlayer?.previousChapter()
|
||||||
}
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
@objc func getChapters() -> [[String: Any]]? {
|
// TODO
|
||||||
guard let currentTitleIndex = mediaPlayer?.currentTitleIndex,
|
// @objc func getChapters() -> [[String: Any]]? {
|
||||||
let chapters = mediaPlayer?.chapterDescriptions(ofTitle: currentTitleIndex)
|
// guard let currentTitleIndex = mediaPlayer?.currentTitleIndex,
|
||||||
as? [[String: Any]]
|
// let chapters = mediaPlayer?.chapterDescriptions(ofTitle: currentTitleIndex)
|
||||||
else {
|
// as? [[String: Any]]
|
||||||
return nil
|
// else {
|
||||||
}
|
// return nil
|
||||||
|
// }
|
||||||
|
|
||||||
return chapters.compactMap { chapter in
|
// return chapters.compactMap { chapter in
|
||||||
guard let name = chapter[VLCChapterDescriptionName] as? String,
|
// guard let name = chapter[VLCChapterDescriptionName] as? String,
|
||||||
let timeOffset = chapter[VLCChapterDescriptionTimeOffset] as? NSNumber,
|
// let timeOffset = chapter[VLCChapterDescriptionTimeOffset] as? NSNumber,
|
||||||
let duration = chapter[VLCChapterDescriptionDuration] as? NSNumber
|
// let duration = chapter[VLCChapterDescriptionDuration] as? NSNumber
|
||||||
else {
|
// else {
|
||||||
return nil
|
// return nil
|
||||||
}
|
// }
|
||||||
|
|
||||||
return [
|
// return [
|
||||||
"name": name,
|
// "name": name,
|
||||||
"timeOffset": timeOffset.doubleValue,
|
// "timeOffset": timeOffset.doubleValue,
|
||||||
"duration": duration.doubleValue,
|
// "duration": duration.doubleValue,
|
||||||
]
|
// ]
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
private var isStopping: Bool = false
|
private var isStopping: Bool = false
|
||||||
|
|
||||||
@@ -641,16 +666,16 @@ extension VlcPlayerView: VLCMediaPlayerDelegate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
extension VlcPlayerView: VLCMediaDelegate {
|
extension VlcPlayerView: VLCMediaDelegate {
|
||||||
func mediaMetaDataDidChange(_ aMedia: VLCMedia) {
|
// func mediaMetaDataDidChange(_ aMedia: VLCMedia) {
|
||||||
// Implement if needed
|
// // Implement if needed
|
||||||
}
|
// }
|
||||||
|
|
||||||
func mediaDidFinishParsing(_ aMedia: VLCMedia) {
|
// func mediaDidFinishParsing(_ aMedia: VLCMedia) {
|
||||||
DispatchQueue.main.async {
|
// DispatchQueue.main.async {
|
||||||
let duration = aMedia.length.intValue
|
// let duration = aMedia.length.intValue
|
||||||
self.onVideoStateChange?(["type": "MediaParsed", "duration": duration])
|
// self.onVideoStateChange?(["type": "MediaParsed", "duration": duration])
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
extension VLCMediaPlayerState {
|
extension VLCMediaPlayerState {
|
||||||
|
|||||||
Reference in New Issue
Block a user