Skip to content

Commit 3c908bc

Browse files
committed
Add captions APIs and improve package structure
1 parent 9793f60 commit 3c908bc

27 files changed

+1628
-983
lines changed

README.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,9 @@ let youTubePlayer = YouTubePlayer(
226226

227227
// To update during runtime update the isLoggingEnabled property
228228
youTubePlayer.isLoggingEnabled = false
229+
230+
// Additionally, you can retrieve an instance of the logger if logging is enabled.
231+
let logger: Logger? = youTubePlayer.logger()
229232
```
230233

231234
### Source
@@ -427,6 +430,28 @@ try await youTubePlayer.set(playbackRate: 1.5)
427430
try await youTubePlayer.getAvailablePlaybackRates()
428431
```
429432

433+
#### Captions
434+
435+
```swift
436+
// Sets the font size of the captions displayed in the player.
437+
try await youTubePlayer.setCaptions(fontSize: .large)
438+
439+
// Sets the language of the captions.
440+
try await youTubePlayer.setCaptions(languageCode: .german)
441+
442+
// Reloads the captions data for the video that is currently playing.
443+
try await youTubePlayer.reloadCaptions()
444+
445+
// Returns the current captions track.
446+
try await youTubePlayer.getCaptionsTrack()
447+
448+
// Returns the captions tracks.
449+
try await youTubePlayer.getCaptionsTracks()
450+
451+
// Returns the captions translation languges.
452+
try await youTubePlayer.getCaptionsTranslationLanguages()
453+
```
454+
430455
## Video Thumbnail
431456

432457
You can load a YouTube video thumbnail via the `YouTubeVideoThumbnail` object.
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
import Foundation
2+
3+
// MARK: - Captions
4+
5+
public extension YouTubePlayer {
6+
7+
/// Sets the font size of the captions displayed in the player.
8+
/// - Parameter fontSize: The font size
9+
func setCaptions(
10+
fontSize: CaptionsFontSize
11+
) async throws(APIError) {
12+
try await self.evaluate(
13+
javaScript: .youTubePlayer(
14+
functionName: "setOption",
15+
parameters: [
16+
"'captions'",
17+
"'fontSize'",
18+
String(fontSize.value)
19+
]
20+
)
21+
)
22+
}
23+
24+
/// Reloads the captions data for the video that is currently playing.
25+
func reloadCaptions() async throws(APIError) {
26+
try await self.evaluate(
27+
javaScript: .youTubePlayer(
28+
functionName: "setOption",
29+
parameters: [
30+
"'captions'",
31+
"'reload'",
32+
true
33+
]
34+
)
35+
)
36+
}
37+
38+
/// Sets the language of the captions.
39+
/// - Parameter languageCode: The language code.
40+
func setCaptions(
41+
languageCode: CaptionsLanguageCode
42+
) async throws(APIError) {
43+
struct LanguageCodeParameter: Encodable {
44+
let languageCode: CaptionsLanguageCode
45+
}
46+
let encodedLanguageCodeParameter: Data
47+
do {
48+
encodedLanguageCodeParameter = try JSONEncoder()
49+
.encode(
50+
LanguageCodeParameter(
51+
languageCode: languageCode
52+
)
53+
)
54+
} catch {
55+
throw .init(
56+
underlyingError: error,
57+
reason: "Failed to encode language code parameter"
58+
)
59+
}
60+
try await self.evaluate(
61+
javaScript: .youTubePlayer(
62+
functionName: "setOption",
63+
parameters: [
64+
"'captions'",
65+
"'track'",
66+
String(
67+
decoding: encodedLanguageCodeParameter,
68+
as: UTF8.self
69+
)
70+
]
71+
)
72+
)
73+
}
74+
75+
/// Returns the current captions track.
76+
func getCaptionsTrack() async throws(APIError) -> CaptionsTrack {
77+
try await self.evaluate(
78+
javaScript: .youTubePlayer(
79+
functionName: "getOption",
80+
parameters: [
81+
"'captions'",
82+
"'track'"
83+
]
84+
),
85+
converter: .typeCast(
86+
to: [String: Any].self
87+
)
88+
.decode()
89+
)
90+
}
91+
92+
/// Returns the captions tracks.
93+
func getCaptionsTracks() async throws(APIError) -> [CaptionsTrack] {
94+
try await self.evaluate(
95+
javaScript: .youTubePlayer(
96+
functionName: "getOption",
97+
parameters: [
98+
"'captions'",
99+
"'tracklist'"
100+
]
101+
),
102+
converter: .typeCast(
103+
to: [[String: Any]].self
104+
)
105+
.decode()
106+
)
107+
}
108+
109+
/// Returns the captions translation languges.
110+
func getCaptionsTranslationLanguages() async throws(APIError) -> [CaptionsTranslationLanguage] {
111+
try await self.evaluate(
112+
javaScript: .youTubePlayer(
113+
functionName: "getOption",
114+
parameters: [
115+
"'captions'",
116+
"'translationLanguages'"
117+
]
118+
),
119+
converter: .typeCast(
120+
to: [[String: Any]].self
121+
)
122+
.decode()
123+
)
124+
}
125+
126+
}
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
import Combine
2+
import Foundation
3+
4+
// MARK: - Events (https://developers.google.com/youtube/iframe_api_reference#Events)
5+
6+
public extension YouTubePlayer {
7+
8+
/// A Publisher that emits the current YouTube player source.
9+
var sourcePublisher: some Publisher<Source?, Never> {
10+
self.sourceSubject
11+
.receive(on: DispatchQueue.main)
12+
}
13+
14+
/// The current YouTube player state.
15+
var state: State {
16+
self.stateSubject.value
17+
}
18+
19+
/// A Publisher that emits the current YouTube player state.
20+
var statePublisher: some Publisher<State, Never> {
21+
self.stateSubject
22+
.removeDuplicates()
23+
.receive(on: DispatchQueue.main)
24+
}
25+
26+
/// The current YouTube player playback state, if available.
27+
var playbackState: PlaybackState? {
28+
self.playbackStateSubject.value
29+
}
30+
31+
/// A Boolean value that determines if the player is currently playing.
32+
var isPlaying: Bool {
33+
self.playbackState == .playing
34+
}
35+
36+
/// A Boolean value that determines if the player is currently paused.
37+
var isPaused: Bool {
38+
self.playbackState == .paused
39+
}
40+
41+
/// A Boolean value that determines if the player is currently buffering.
42+
var isBuffering: Bool {
43+
self.playbackState == .buffering
44+
}
45+
46+
/// A Boolean value that determines if the player is currently cued.
47+
var isCued: Bool {
48+
self.playbackState == .cued
49+
}
50+
51+
/// A Boolean value that determines if the player is ended.
52+
var isEnded: Bool {
53+
self.playbackState == .ended
54+
}
55+
56+
/// A Publisher that emits the current YouTube player playback state.
57+
var playbackStatePublisher: some Publisher<PlaybackState, Never> {
58+
self.playbackStateSubject
59+
.compactMap { $0 }
60+
.removeDuplicates()
61+
.receive(on: DispatchQueue.main)
62+
}
63+
64+
/// The current YouTube player playback quality, if available.
65+
var playbackQuality: PlaybackQuality? {
66+
self.playbackQualitySubject.value
67+
}
68+
69+
/// A Publisher that emits the current YouTube player playback quality.
70+
var playbackQualityPublisher: some Publisher<PlaybackQuality, Never> {
71+
self.playbackQualitySubject
72+
.compactMap { $0 }
73+
.removeDuplicates()
74+
.receive(on: DispatchQueue.main)
75+
}
76+
77+
/// The current YouTube player playback rate, if available.
78+
var playbackRate: PlaybackRate? {
79+
self.playbackRateSubject.value
80+
}
81+
82+
/// A Publisher that emits the current YouTube player playback rate.
83+
var playbackRatePublisher: some Publisher<PlaybackRate, Never> {
84+
self.playbackRateSubject
85+
.compactMap { $0 }
86+
.removeDuplicates()
87+
.receive(on: DispatchQueue.main)
88+
}
89+
90+
/// A Publisher that emits whenever autoplay or scripted video playback features were blocked.
91+
var autoplayBlockedPublisher: some Publisher<Void, Never> {
92+
self.autoplayBlockedSubject
93+
.receive(on: DispatchQueue.main)
94+
}
95+
96+
}

0 commit comments

Comments
 (0)