expo-video-subtitle 0.1.2 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.gitattributes +17 -0
- package/CHANGELOG.md +120 -70
- package/FORK.md +116 -15
- package/LICENSE +21 -21
- package/README.md +186 -134
- package/android/build.gradle +32 -32
- package/android/src/main/AndroidManifest.xml +10 -10
- package/android/src/main/java/expo/modules/video/FullscreenPlayerActivity.kt +258 -258
- package/android/src/main/java/expo/modules/video/IntervalUpdateClock.kt +54 -54
- package/android/src/main/java/expo/modules/video/MediaMetadataRetriever.kt +89 -89
- package/android/src/main/java/expo/modules/video/PlayerViewExtension.kt +87 -87
- package/android/src/main/java/expo/modules/video/VideoCache.kt +109 -109
- package/android/src/main/java/expo/modules/video/VideoExceptions.kt +45 -45
- package/android/src/main/java/expo/modules/video/VideoModule.kt +446 -446
- package/android/src/main/java/expo/modules/video/VideoThumbnail.kt +20 -20
- package/android/src/main/java/expo/modules/video/VideoView.kt +457 -457
- package/android/src/main/java/expo/modules/video/delegates/IgnoreSameSet.kt +24 -24
- package/android/src/main/java/expo/modules/video/drawing/OutlineProvider.kt +217 -217
- package/android/src/main/java/expo/modules/video/enums/AudioMixingMode.kt +20 -20
- package/android/src/main/java/expo/modules/video/enums/ContentFit.kt +19 -19
- package/android/src/main/java/expo/modules/video/enums/ContentType.kt +22 -22
- package/android/src/main/java/expo/modules/video/enums/DRMType.kt +26 -26
- package/android/src/main/java/expo/modules/video/enums/FullscreenOrientation.kt +25 -25
- package/android/src/main/java/expo/modules/video/enums/PlayerStatus.kt +10 -10
- package/android/src/main/java/expo/modules/video/enums/VideoRange.kt +27 -27
- package/android/src/main/java/expo/modules/video/listeners/VideoManagerListener.kt +10 -10
- package/android/src/main/java/expo/modules/video/listeners/VideoPlayerListener.kt +35 -35
- package/android/src/main/java/expo/modules/video/listeners/VideoViewListener.kt +13 -13
- package/android/src/main/java/expo/modules/video/managers/AudioFocusManager.kt +242 -242
- package/android/src/main/java/expo/modules/video/managers/PictureInPictureManager.kt +329 -329
- package/android/src/main/java/expo/modules/video/managers/VideoManager.kt +194 -194
- package/android/src/main/java/expo/modules/video/playbackService/ExpoVideoPlaybackService.kt +267 -267
- package/android/src/main/java/expo/modules/video/playbackService/PlaybackServiceConnection.kt +62 -62
- package/android/src/main/java/expo/modules/video/playbackService/VideoMediaSessionCallback.kt +47 -47
- package/android/src/main/java/expo/modules/video/player/DefaultLoadControl.java +551 -551
- package/android/src/main/java/expo/modules/video/player/FirstFrameEventGenerator.kt +116 -116
- package/android/src/main/java/expo/modules/video/player/PlayerEvent.kt +172 -172
- package/android/src/main/java/expo/modules/video/player/VideoPlayer.kt +598 -598
- package/android/src/main/java/expo/modules/video/player/VideoPlayerAudioTracks.kt +126 -126
- package/android/src/main/java/expo/modules/video/player/VideoPlayerKeepAwake.kt +91 -91
- package/android/src/main/java/expo/modules/video/player/VideoPlayerLoadControl.kt +57 -57
- package/android/src/main/java/expo/modules/video/player/VideoPlayerSubtitles.kt +136 -136
- package/android/src/main/java/expo/modules/video/records/BufferOptions.kt +18 -18
- package/android/src/main/java/expo/modules/video/records/ButtonOptions.kt +17 -17
- package/android/src/main/java/expo/modules/video/records/DRMOptions.kt +27 -27
- package/android/src/main/java/expo/modules/video/records/FullscreenOptions.kt +14 -14
- package/android/src/main/java/expo/modules/video/records/PiPParams.kt +38 -38
- package/android/src/main/java/expo/modules/video/records/PlaybackError.kt +21 -21
- package/android/src/main/java/expo/modules/video/records/PlayerBuilderOptions.kt +15 -15
- package/android/src/main/java/expo/modules/video/records/ScrubbingModeOptions.kt +33 -33
- package/android/src/main/java/expo/modules/video/records/SeekTolerance.kt +30 -30
- package/android/src/main/java/expo/modules/video/records/SubtitleSource.kt +54 -54
- package/android/src/main/java/expo/modules/video/records/SubtitleStyle.kt +137 -131
- package/android/src/main/java/expo/modules/video/records/Tracks.kt +115 -115
- package/android/src/main/java/expo/modules/video/records/VideoEventPayloads.kt +79 -79
- package/android/src/main/java/expo/modules/video/records/VideoMetadata.kt +14 -14
- package/android/src/main/java/expo/modules/video/records/VideoSize.kt +16 -16
- package/android/src/main/java/expo/modules/video/records/VideoSource.kt +113 -113
- package/android/src/main/java/expo/modules/video/records/VideoThumbnailOptions.kt +26 -26
- package/android/src/main/java/expo/modules/video/utils/DataSourceUtils.kt +81 -81
- package/android/src/main/java/expo/modules/video/utils/EventDispatcherUtils.kt +43 -43
- package/android/src/main/java/expo/modules/video/utils/FullscreenActivityOrientationHelper.kt +120 -120
- package/android/src/main/java/expo/modules/video/utils/MediaSessionUtils.kt +14 -14
- package/android/src/main/java/expo/modules/video/utils/MutableWeakReference.kt +26 -26
- package/android/src/main/java/expo/modules/video/utils/PictureInPictureHelperFragment.kt +49 -49
- package/android/src/main/java/expo/modules/video/utils/PictureInPictureUtils.kt +96 -96
- package/android/src/main/java/expo/modules/video/utils/StackingSubtitleParser.kt +110 -24
- package/android/src/main/java/expo/modules/video/utils/SubtitleUtils.kt +78 -73
- package/android/src/main/java/expo/modules/video/utils/ViewVisibilityUtils.kt +28 -28
- package/android/src/main/java/expo/modules/video/utils/WeakMutableSet.kt +120 -120
- package/android/src/main/java/expo/modules/video/utils/YogaUtils.kt +20 -20
- package/android/src/main/res/drawable/seek_backwards_10s.xml +25 -25
- package/android/src/main/res/drawable/seek_backwards_15s.xml +25 -25
- package/android/src/main/res/drawable/seek_backwards_5s.xml +25 -25
- package/android/src/main/res/drawable/seek_forwards_10s.xml +30 -30
- package/android/src/main/res/drawable/seek_forwards_15s.xml +31 -31
- package/android/src/main/res/drawable/seek_forwards_5s.xml +30 -30
- package/android/src/main/res/layout/fullscreen_player_activity.xml +20 -20
- package/android/src/main/res/layout/surface_player_view.xml +7 -7
- package/android/src/main/res/layout/texture_player_view.xml +7 -7
- package/android/src/main/res/values/styles.xml +9 -9
- package/app.plugin.js +1 -1
- package/build/NativeVideoAirPlayButtonView.js.map +1 -1
- package/build/NativeVideoModule.js.map +1 -1
- package/build/NativeVideoModule.web.js.map +1 -1
- package/build/NativeVideoView.js.map +1 -1
- package/build/VideoAirPlayButton.ios.js.map +1 -1
- package/build/VideoAirPlayButton.js.map +1 -1
- package/build/VideoAirPlayButton.types.js.map +1 -1
- package/build/VideoModule.js.map +1 -1
- package/build/VideoPlayer.js.map +1 -1
- package/build/VideoPlayer.types.js.map +1 -1
- package/build/VideoPlayer.web.d.ts.map +1 -1
- package/build/VideoPlayer.web.js +5 -1
- package/build/VideoPlayer.web.js.map +1 -1
- package/build/VideoPlayerEvents.types.js.map +1 -1
- package/build/VideoThumbnail.js.map +1 -1
- package/build/VideoView.js.map +1 -1
- package/build/VideoView.types.d.ts +19 -0
- package/build/VideoView.types.d.ts.map +1 -1
- package/build/VideoView.types.js.map +1 -1
- package/build/VideoView.web.js.map +1 -1
- package/build/index.js.map +1 -1
- package/build/resolveAssetSource.js.map +1 -1
- package/build/resolveAssetSource.web.js.map +1 -1
- package/eslint.config.js +4 -0
- package/expo-module.config.json +9 -9
- package/ios/Cache/CachableRequest.swift +46 -46
- package/ios/Cache/CacheVideoAssetTransportProvider.swift +64 -64
- package/ios/Cache/CachedResource.swift +164 -164
- package/ios/Cache/CachingHelpers.swift +107 -107
- package/ios/Cache/MediaFileHandle.swift +139 -139
- package/ios/Cache/MediaInfo.swift +185 -185
- package/ios/Cache/ResourceLoaderDelegate.swift +306 -306
- package/ios/Cache/SynchronizedHashTable.swift +23 -23
- package/ios/Cache/VideoCacheManager.swift +192 -192
- package/ios/ContentKeyDelegate.swift +214 -214
- package/ios/ContentKeyManager.swift +21 -21
- package/ios/Enums/AudioMixingMode.swift +37 -37
- package/ios/Enums/ContentType.swift +11 -11
- package/ios/Enums/DRMType.swift +20 -20
- package/ios/Enums/FullscreenOrientation.swift +34 -34
- package/ios/Enums/KeepFullscreenOnPiPStopBehavior.swift +20 -20
- package/ios/Enums/PlayerStatus.swift +10 -10
- package/ios/Enums/VideoContentFit.swift +39 -39
- package/ios/Enums/VideoRange.swift +21 -21
- package/ios/ExpoVideo.podspec +27 -27
- package/ios/NowPlayingManager.swift +304 -304
- package/ios/OrientationAVPlayerViewController.swift +263 -263
- package/ios/Records/BufferOptions.swift +12 -12
- package/ios/Records/DRMOptions.swift +24 -24
- package/ios/Records/FullscreenOptions.swift +14 -14
- package/ios/Records/PlaybackError.swift +10 -10
- package/ios/Records/ScrubbingModeOptions.swift +7 -7
- package/ios/Records/SeekTolerance.swift +20 -20
- package/ios/Records/SubtitleSource.swift +32 -32
- package/ios/Records/SubtitleStyle.swift +118 -118
- package/ios/Records/Tracks.swift +229 -229
- package/ios/Records/VideoEventPayloads.swift +81 -81
- package/ios/Records/VideoMetadata.swift +16 -16
- package/ios/Records/VideoSize.swift +15 -15
- package/ios/Records/VideoSource.swift +28 -28
- package/ios/Thumbnails/VideoThumbnail.swift +27 -27
- package/ios/Thumbnails/VideoThumbnailGenerator.swift +68 -68
- package/ios/Thumbnails/VideoThumbnailOptions.swift +15 -15
- package/ios/Utils/AVAssetVariant+VideoTracks.swift +20 -20
- package/ios/Utils/AvAssetTrack+VideoTracks.swift +79 -79
- package/ios/Utils/FourCharCode+toString.swift +25 -25
- package/ios/Utils/HlsUriUtils.swift +27 -27
- package/ios/Utils/URL+MediaLibraryAssets.swift +68 -68
- package/ios/VideoAirPlayButtonView.swift +70 -70
- package/ios/VideoAsset.swift +98 -98
- package/ios/VideoAssetTransport/VideoAssetLoadPlan.swift +69 -69
- package/ios/VideoAssetTransport/VideoAssetSourceDescriptor.swift +29 -29
- package/ios/VideoAssetTransport/VideoAssetTransportProvider.swift +24 -24
- package/ios/VideoAssetTransport/VideoAssetTransportRegistry.swift +103 -103
- package/ios/VideoExceptions.swift +53 -53
- package/ios/VideoItem.swift +11 -11
- package/ios/VideoManager.swift +182 -182
- package/ios/VideoModule.swift +413 -413
- package/ios/VideoPlayer/DangerousPropertiesStore.swift +19 -19
- package/ios/VideoPlayer.swift +485 -485
- package/ios/VideoPlayerAudioTracks.swift +109 -109
- package/ios/VideoPlayerItem.swift +169 -169
- package/ios/VideoPlayerObserver.swift +612 -612
- package/ios/VideoPlayerSeeker.swift +77 -77
- package/ios/VideoPlayerSubtitleSideload.swift +203 -203
- package/ios/VideoPlayerSubtitles.swift +88 -88
- package/ios/VideoSourceLoader.swift +90 -90
- package/ios/VideoSourceLoaderListener.swift +34 -34
- package/ios/VideoView.swift +201 -201
- package/package.json +51 -51
- package/plugin/index.d.ts +1 -1
- package/plugin/index.js +1 -1
- package/plugin/jest.config.js +1 -1
- package/plugin/src/index.ts +3 -3
- package/plugin/src/withExpoVideo.ts +103 -103
- package/plugin/tsconfig.json +10 -10
- package/src/NativeVideoAirPlayButtonView.ts +3 -3
- package/src/NativeVideoModule.ts +16 -16
- package/src/NativeVideoModule.web.ts +4 -4
- package/src/NativeVideoView.ts +8 -8
- package/src/VideoAirPlayButton.ios.tsx +8 -8
- package/src/VideoAirPlayButton.tsx +14 -14
- package/src/VideoAirPlayButton.types.ts +39 -39
- package/src/VideoModule.ts +47 -47
- package/src/VideoPlayer.tsx +74 -74
- package/src/VideoPlayer.types.ts +893 -893
- package/src/VideoPlayer.web.tsx +470 -466
- package/src/VideoPlayerEvents.types.ts +332 -332
- package/src/VideoThumbnail.ts +31 -31
- package/src/VideoView.tsx +111 -111
- package/src/VideoView.types.ts +439 -419
- package/src/VideoView.web.tsx +293 -293
- package/src/index.ts +26 -26
- package/src/resolveAssetSource.ts +2 -2
- package/src/resolveAssetSource.web.ts +17 -17
- package/src/ts-declarations/react-native-assets.d.ts +22 -22
- package/tsconfig.all.json +11 -11
- package/tsconfig.json +10 -10
package/.gitattributes
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Keep the working copy at LF on every platform. Git already stores these files with LF, but a
|
|
2
|
+
# Windows checkout with core.autocrlf=true rewrites them to CRLF, and the Prettier rule that
|
|
3
|
+
# `npm run lint` enforces wants LF — which produced thousands of "Delete `␍`" warnings that buried
|
|
4
|
+
# every real finding.
|
|
5
|
+
* text=auto eol=lf
|
|
6
|
+
|
|
7
|
+
# Binary assets must never be line-ending converted.
|
|
8
|
+
*.png binary
|
|
9
|
+
*.jpg binary
|
|
10
|
+
*.jpeg binary
|
|
11
|
+
*.gif binary
|
|
12
|
+
*.ttf binary
|
|
13
|
+
*.otf binary
|
|
14
|
+
*.aar binary
|
|
15
|
+
*.jar binary
|
|
16
|
+
*.keystore binary
|
|
17
|
+
*.tgz binary
|
package/CHANGELOG.md
CHANGED
|
@@ -1,70 +1,120 @@
|
|
|
1
|
-
# Changelog
|
|
2
|
-
|
|
3
|
-
All notable changes to this package are documented here.
|
|
4
|
-
|
|
5
|
-
This package is a fork of [`expo-video`](https://github.com/expo/expo/tree/main/packages/expo-video).
|
|
6
|
-
Changes inherited from the upstream base version are not repeated here — see the
|
|
7
|
-
[upstream changelog](https://github.com/expo/expo/blob/main/packages/expo-video/CHANGELOG.md)
|
|
8
|
-
for the history of everything that isn't subtitle related.
|
|
9
|
-
|
|
10
|
-
## 0.
|
|
11
|
-
|
|
12
|
-
###
|
|
13
|
-
|
|
14
|
-
- **Android:**
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
- **Android:**
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this package are documented here.
|
|
4
|
+
|
|
5
|
+
This package is a fork of [`expo-video`](https://github.com/expo/expo/tree/main/packages/expo-video).
|
|
6
|
+
Changes inherited from the upstream base version are not repeated here — see the
|
|
7
|
+
[upstream changelog](https://github.com/expo/expo/blob/main/packages/expo-video/CHANGELOG.md)
|
|
8
|
+
for the history of everything that isn't subtitle related.
|
|
9
|
+
|
|
10
|
+
## 0.2.0
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **Android:** `subtitleStyle.applyEmbeddedStyles` keeps the inline formatting a subtitle track
|
|
15
|
+
carries instead of discarding it. Subtitle formats bring styling of their own — SubRip's `<b>`,
|
|
16
|
+
`<i>`, `<u>` and `<font color>` tags, and the richer per-cue styling of embedded WebVTT/TTML — and
|
|
17
|
+
until now every bit of it was thrown away so that `subtitleStyle` was the only thing deciding how
|
|
18
|
+
captions looked. `SubtitleView.setApplyEmbeddedStyles(false)` was hardcoded, and Media3 implements
|
|
19
|
+
that by removing every span from every cue, so an `.srt` written with `<i>` rendered upright.
|
|
20
|
+
Defaults to `false`, so nothing changes until you opt in. The rest of `subtitleStyle` still applies
|
|
21
|
+
underneath and `fontSize` still overrides any size the track asks for; the trade-off is that a cue
|
|
22
|
+
specifying its own colours overrides `textColor` and `windowColor` for that cue. There is no iOS
|
|
23
|
+
equivalent: `AVPlayerItem.textStyleRules` always composes with what the WebVTT cue declares.
|
|
24
|
+
|
|
25
|
+
### Fixed
|
|
26
|
+
|
|
27
|
+
- **Android:** a subtitle no longer drops down a line when the subtitle *below* it ends. Cues that
|
|
28
|
+
are on screen together are drawn as one block anchored at its bottom, so the moment the lower cue
|
|
29
|
+
expired the upper one fell into its place — moving the text at exactly the spot the viewer is
|
|
30
|
+
reading. Every cue now keeps the same line for its whole time on screen: the line a finished cue
|
|
31
|
+
leaves behind is held empty, and the next cue to start reclaims the lowest empty line rather than
|
|
32
|
+
stacking on top, which is what keeps the block from creeping upwards. An empty line can therefore
|
|
33
|
+
sit below — or between — the cues still on screen, and the stack resets once nothing is left on
|
|
34
|
+
screen. Cues with explicit `{\anN}` positioning are still passed through untouched.
|
|
35
|
+
- **Android:** merging simultaneous SubRip cues no longer flattens their text. The cues were joined
|
|
36
|
+
through `toString()`, which erases the spans Media3's SubRip parser produces from inline tags. This
|
|
37
|
+
changed nothing on screen at the time, because the renderer stripped those spans anyway, but it
|
|
38
|
+
would have silently defeated the new `applyEmbeddedStyles` option for any overlapping cue.
|
|
39
|
+
|
|
40
|
+
### Changed
|
|
41
|
+
|
|
42
|
+
- Repository tooling, with no effect on the published runtime: `npm run lint` runs again. The repo
|
|
43
|
+
had no `eslint.config.js` — `expo-module configure` treats it as an optional template and never
|
|
44
|
+
creates one — while the `oxlint.config.mjs` it did have re-exported a module that
|
|
45
|
+
`expo-module-scripts@56` does not ship, so the lint step in `FORK.md` §5 had never actually
|
|
46
|
+
executed. A `.gitattributes` now pins the working copy to LF, which stops the Prettier rule from
|
|
47
|
+
reporting nearly every line of every file on a Windows checkout. The single lint error this
|
|
48
|
+
uncovered, a non-simple expression in a `useMemo` dependency list in `VideoPlayer.web.tsx`, is
|
|
49
|
+
fixed by hoisting it into a variable; the value and its identity semantics are unchanged.
|
|
50
|
+
|
|
51
|
+
## 0.1.3
|
|
52
|
+
|
|
53
|
+
### Documentation
|
|
54
|
+
|
|
55
|
+
- Document how subtitles that are on screen at the same time are stacked, which shipped in 0.1.2 but
|
|
56
|
+
was only described in the changelog.
|
|
57
|
+
- Add a release procedure to `FORK.md`, including the rule that every version bump carries a
|
|
58
|
+
changelog entry.
|
|
59
|
+
|
|
60
|
+
## 0.1.2
|
|
61
|
+
|
|
62
|
+
### Fixed
|
|
63
|
+
|
|
64
|
+
- **Android:** subtitles that are on screen at the same time are now stacked as one block instead of
|
|
65
|
+
being drawn on top of each other. `.srt` files legitimately contain overlapping timestamps (two
|
|
66
|
+
speakers, dialogue over on-screen text), but SubRip carries no positioning, so Media3 pinned every
|
|
67
|
+
cue to the same spot and rendered them one over the other — Media3 does the stacking in its WebVTT
|
|
68
|
+
*parser* (`line = -1 - i`) and has no equivalent pass for SubRip. A `SubtitleParser` for SubRip now
|
|
69
|
+
splits the cue timeline at every boundary and merges the cues active in each slice into a single
|
|
70
|
+
multi-line cue, ordered like WebVTT: the cue that started earliest sits at the bottom. This also
|
|
71
|
+
makes Android match the iOS output, which already stacked because sideloaded SRT is converted to
|
|
72
|
+
WebVTT there. Cues with explicit `{\anN}` positioning are left untouched.
|
|
73
|
+
- **Android:** selecting a `subtitleTrack` whose id is not among the available tracks no longer
|
|
74
|
+
leaves the previously selected track on screen. The cleared track-selection parameters were only
|
|
75
|
+
applied when a matching track was found, so an unmatched assignment silently did nothing; the
|
|
76
|
+
selection is now cleared and a warning is logged.
|
|
77
|
+
- **Android:** `subtitleStyle.bottomOffset` is reset to the default when it is omitted, instead of
|
|
78
|
+
keeping the value from a previously applied style.
|
|
79
|
+
|
|
80
|
+
## 0.1.1
|
|
81
|
+
|
|
82
|
+
### Fixed
|
|
83
|
+
|
|
84
|
+
- **Android:** `subtitleStyle.fontFamily` now resolves custom fonts bundled with the app, the same way
|
|
85
|
+
React Native resolves a `<Text>` component's `fontFamily`. It is looked up as an Android font
|
|
86
|
+
resource (`res/font`, where `expo-font`'s config plugin puts fonts) and then through React Native's
|
|
87
|
+
font manager, which covers the `assets/fonts/<name>.ttf` convention and fonts registered at runtime.
|
|
88
|
+
Previously only the built-in system families worked: `Typeface.create` silently fell back to the
|
|
89
|
+
default typeface for any bundled font, so `fontFamily` appeared to do nothing on Android while
|
|
90
|
+
working on iOS.
|
|
91
|
+
|
|
92
|
+
### Documentation
|
|
93
|
+
|
|
94
|
+
- Document font support and the silent-fallback behaviour for unresolved family names.
|
|
95
|
+
|
|
96
|
+
## 0.1.0
|
|
97
|
+
|
|
98
|
+
Initial release. Based on `expo-video` **56.1.4** (Expo SDK 56).
|
|
99
|
+
|
|
100
|
+
### Added
|
|
101
|
+
|
|
102
|
+
- **External (sideloaded) subtitles** via `VideoSource.subtitleTracks`. Attach WebVTT or SubRip
|
|
103
|
+
subtitle files (local or remote) to any source — most importantly progressive **MP4**, which,
|
|
104
|
+
unlike HLS/DASH manifests, cannot advertise its own subtitle renditions. Sideloaded tracks are
|
|
105
|
+
merged into the media and surface through `availableSubtitleTracks`, so they are selected with
|
|
106
|
+
`subtitleTrack` exactly like embedded tracks.
|
|
107
|
+
- Android: merged with `MediaItem.SubtitleConfiguration` (Media3 wraps them in a `MergingMediaSource`).
|
|
108
|
+
- iOS: merged into an `AVMutableComposition` as a `.text` track. SRT is converted to WebVTT, remote
|
|
109
|
+
files are cached locally first, and per-track time ranges are clamped to the video duration.
|
|
110
|
+
Applies to progressive, non-DRM sources on the asynchronous loading path.
|
|
111
|
+
- **Custom subtitle styling** via the `VideoView` `subtitleStyle` prop: `textColor`, `backgroundColor`,
|
|
112
|
+
`windowColor`, `fontSize`, `fontFamily`, `bold`, `edgeType`, `edgeColor`, and `bottomOffset`.
|
|
113
|
+
Applies to embedded and sideloaded tracks alike.
|
|
114
|
+
- Android: `CaptionStyleCompat` on the `PlayerView` subtitle view.
|
|
115
|
+
- iOS: `AVPlayerItem.textStyleRules`.
|
|
116
|
+
|
|
117
|
+
### Changed
|
|
118
|
+
|
|
119
|
+
- The Android `publication` block and the iOS prebuild artifacts are removed, so the modified
|
|
120
|
+
Kotlin and Swift are compiled from source instead of resolving a precompiled AAR/XCFramework.
|
package/FORK.md
CHANGED
|
@@ -23,17 +23,20 @@ Measured against the published `expo-video@56.1.4` tarball. `+`/`-` are added/re
|
|
|
23
23
|
| `ios/Records/SubtitleStyle.swift` | 118 | Record for caption styling; hex→ARGB parsing; builds `[AVTextStyleRule]`. |
|
|
24
24
|
| `ios/VideoPlayerSubtitleSideload.swift` | 203 | Builds the `AVMutableComposition`, downloads remote subs, SRT→WebVTT converter. |
|
|
25
25
|
| `android/…/records/SubtitleSource.kt` | 54 | Record → `MediaItem.SubtitleConfiguration` + MIME resolution. |
|
|
26
|
-
| `android/…/records/SubtitleStyle.kt` |
|
|
27
|
-
| `android/…/utils/StackingSubtitleParser.kt` |
|
|
26
|
+
| `android/…/records/SubtitleStyle.kt` | 137 | Record → `CaptionStyleCompat`; hex colour parsing; font-family resolution (`res/font` → `ReactFontManager`); the `applyEmbeddedStyles` flag, which `SubtitleUtils` reads directly rather than `toCaptionStyle`. |
|
|
27
|
+
| `android/…/utils/StackingSubtitleParser.kt` | 297 | `SubtitleParser` for SubRip that segments the cue timeline and merges simultaneous cues into one stacked block, plus the `SubtitleParser.Factory` that routes SubRip to it. Assigns each cue a vertical slot it keeps for its whole time on screen — a finished cue's line is held blank (`\u200B`) so the cues above it do not drop. Merges through a `SpannableStringBuilder` so cue spans survive. |
|
|
28
28
|
| `FORK.md`, `LICENSE` | — | This guide; MIT licence (upstream copyright preserved). |
|
|
29
|
+
| `eslint.config.js` | 4 | Verbatim copy of `expo-module-scripts/templates/eslint.config.js`. **Recreate it if a sync drops it** — `expo-module configure` treats it as an *optional* template and only syncs it when it already exists, so without this file `npm run lint` dies with "ESLint couldn't find an eslint.config.js". |
|
|
30
|
+
| `.gitattributes` | 21 | Pins the working copy to LF. Git stores these files with LF, but a Windows checkout rewrites them to CRLF and the Prettier rule `npm run lint` enforces wants LF, which drowned the output in ~2800 "Delete `␍`" warnings. |
|
|
29
31
|
|
|
30
32
|
### Modified — upstream files carrying fork edits (re-apply these after a sync)
|
|
31
33
|
|
|
32
34
|
| File | Δ | What to re-apply |
|
|
33
35
|
| --- | --- | --- |
|
|
34
36
|
| `src/VideoPlayer.types.ts` | +59 | `subtitleTracks?: SubtitleSource[]` on `VideoSourceObject`; the exported `SubtitleSource` type. |
|
|
35
|
-
| `src/VideoView.types.ts` | +
|
|
37
|
+
| `src/VideoView.types.ts` | +114 | `subtitleStyle?: SubtitleStyle` on `VideoViewProps`; `SubtitleStyle` + `SubtitleEdgeType` types. |
|
|
36
38
|
| `src/index.ts` | +2 | Export `SubtitleStyle`, `SubtitleEdgeType` (`SubtitleSource` rides on `export type *`). |
|
|
39
|
+
| `src/VideoPlayer.web.tsx` | +5 / −1 | Hoist `JSON.stringify(source)` out of the `useMemo` dependency list into a `sourceKey` const. No behaviour change — it was already recomputed every render — but `react-hooks/use-memo` rejects non-simple expressions in a dependency array, and it was the single lint **error** in the package. |
|
|
37
40
|
| `src/ts-declarations/react-native-assets.d.ts` | +22 / −1 | Replace upstream's `../../../expo-asset/…` reference (monorepo-only) with standalone `declare module` shims. **Always needed outside the Expo monorepo.** |
|
|
38
41
|
| `ios/Records/VideoSource.swift` | +3 | `@Field var subtitleTracks: [SubtitleSource]?`. |
|
|
39
42
|
| `ios/VideoPlayerItem.swift` | +17 / −2 | In the **async** init: hoist `isHls` to a local, and build the sideload composition for non-HLS/non-DRM sources before `super.init(asset:)`. |
|
|
@@ -41,7 +44,7 @@ Measured against the published `expo-video@56.1.4` tarball. `+`/`-` are added/re
|
|
|
41
44
|
| `ios/VideoView.swift` | +8 | `subtitleStyle` property; forward it when `player` is (re)assigned. |
|
|
42
45
|
| `ios/VideoModule.swift` | +4 | `Prop("subtitleStyle")`. |
|
|
43
46
|
| `android/…/records/VideoSource.kt` | +9 / −2 | `subtitleTracks` field; `setSubtitleConfigurations(…)` in `toMediaItem()`; subtitle key in `toMediaId()`. |
|
|
44
|
-
| `android/…/utils/SubtitleUtils.kt` | +
|
|
47
|
+
| `android/…/utils/SubtitleUtils.kt` | +33 / −17 | `configureSubtitleView(…, customStyle)` overload and a `styleProvider` on the captioning listener. Keeps the original behaviour when no custom style is set. Passes `context` to `toCaptionStyle` for font lookup. Drives `setApplyEmbeddedStyles` from `customStyle.applyEmbeddedStyles` (upstream hardcodes `false`). |
|
|
45
48
|
| `android/…/VideoView.kt` | +12 / −5 | `subtitleStyle` property; pass it at all 4 `configureSubtitleView` call sites + the captioning listener. |
|
|
46
49
|
| `android/…/VideoModule.kt` | +4 | `Prop("subtitleStyle")`. |
|
|
47
50
|
| `android/…/utils/DataSourceUtils.kt` | +5 | `setSubtitleParserFactory(ExpoVideoSubtitleParserFactory())` on the `DefaultMediaSourceFactory`. Note this file declares `package expo.modules.video` despite living in `utils/`, so the factory needs an explicit import. |
|
|
@@ -58,10 +61,11 @@ Measured against the published `expo-video@56.1.4` tarball. `+`/`-` are added/re
|
|
|
58
61
|
| `local-maven-repo/` (Android AAR) | Upstream ships a **precompiled** `expo.modules.video` AAR. If present, Gradle resolves it and **silently ignores the modified Kotlin**. |
|
|
59
62
|
| `prebuilds/` (iOS XCFramework) | Same trap on iOS: CocoaPods links the prebuilt `ExpoVideo.xcframework` instead of compiling the modified Swift. |
|
|
60
63
|
| `spm.config.json` | Swift Package Manager prebuild config; meaningless once we build from source. |
|
|
64
|
+
| `oxlint.config.mjs` | Re-exported `expo-module-scripts/oxlint.config.base`, which does not exist in `expo-module-scripts@56` — that package lints with ESLint and ships no oxlint base. A dead file that only misled readers into thinking oxlint was the configured linter. |
|
|
61
65
|
|
|
62
66
|
> **This is the single most important thing to preserve.** If a sync re-introduces the `publication`
|
|
63
67
|
> block, `local-maven-repo/` or `prebuilds/`, the app keeps building — it just runs **upstream's**
|
|
64
|
-
> video module, and every subtitle feature silently disappears. Verify with §
|
|
68
|
+
> video module, and every subtitle feature silently disappears. Verify with §5.
|
|
65
69
|
|
|
66
70
|
### External API coupling to watch
|
|
67
71
|
|
|
@@ -105,9 +109,12 @@ Then re-apply the fork:
|
|
|
105
109
|
with real deletions are `SubtitleUtils.kt` (function rewritten), `VideoView.kt`/`FullscreenPlayerActivity.kt`
|
|
106
110
|
(call-site signatures), `VideoPlayerItem.swift` (`isHls` hoist) and the ts-declarations shim.
|
|
107
111
|
7. **Remove the Android `publication` block** from `expo-module.config.json`.
|
|
108
|
-
8. **Restore the fork's `package.json`** (§3) and keep `README.md`, `CHANGELOG.md`, `LICENSE`,
|
|
112
|
+
8. **Restore the fork's `package.json`** (§3) and keep `README.md`, `CHANGELOG.md`, `LICENSE`,
|
|
113
|
+
`FORK.md`, `eslint.config.js` and `.gitattributes`. Step 3 only replaces `src ios android plugin`,
|
|
114
|
+
so the root-level files survive on their own — but confirm it, because a missing `eslint.config.js`
|
|
115
|
+
breaks `npm run lint` in a way that reads like a tooling bug rather than a lost file.
|
|
109
116
|
9. Update the baseline version in this file, the README, and add a `CHANGELOG.md` entry.
|
|
110
|
-
10. Verify with §
|
|
117
|
+
10. Verify with §5, then commit.
|
|
111
118
|
|
|
112
119
|
---
|
|
113
120
|
|
|
@@ -127,31 +134,125 @@ Upstream's `package.json` will overwrite these if copied blindly. Keep:
|
|
|
127
134
|
|
|
128
135
|
---
|
|
129
136
|
|
|
130
|
-
## 4.
|
|
137
|
+
## 4. Releasing
|
|
131
138
|
|
|
132
|
-
|
|
139
|
+
**Every version bump gets a `CHANGELOG.md` entry — no exceptions, including one-line fixes.**
|
|
140
|
+
The changelog is the only place a consumer can see what changed between two installs, and this
|
|
141
|
+
package ships native code, so a bump can silently change runtime behaviour on a device.
|
|
142
|
+
|
|
143
|
+
For each release:
|
|
144
|
+
|
|
145
|
+
1. Decide the version (semver against the *fork's* own API, not the upstream `expo-video` version):
|
|
146
|
+
- **patch** — bug fix, no API change.
|
|
147
|
+
- **minor** — new option/prop/field, or a behaviour change consumers may notice.
|
|
148
|
+
- **major** — anything that breaks an existing call site.
|
|
149
|
+
2. Add a `## <version>` section at the top of `CHANGELOG.md`, above the previous release, grouped
|
|
150
|
+
under `### Added` / `### Fixed` / `### Changed` / `### Documentation`. Write it for someone who
|
|
151
|
+
does not know the codebase: what they will observe, and on which platform. Say *why* when the
|
|
152
|
+
cause is non-obvious — the entries for 0.1.1 and 0.1.2 are the reference for the level of detail.
|
|
153
|
+
3. `npm version <version> --no-git-tag-version`.
|
|
154
|
+
4. Update the docs the change touches — `README.md` for anything user-facing (a new option, a
|
|
155
|
+
changed rendering behaviour), and §1 of this file if files were added, removed or newly modified.
|
|
156
|
+
5. Verify with §5, then commit and push.
|
|
157
|
+
6. `npm publish` (its `prepublishOnly` cleans and rebuilds; never publish from a dirty tree).
|
|
158
|
+
|
|
159
|
+
When a release syncs a new upstream `expo-video`, note the new baseline version in the changelog
|
|
160
|
+
entry, in §1 of this file and in the README's intro line.
|
|
161
|
+
|
|
162
|
+
## 5. Verification
|
|
163
|
+
|
|
164
|
+
> **This package is standalone.** Nothing in this section may reach into an unrelated project's
|
|
165
|
+
> checkout. Verifying by overlaying the package onto some other app's `node_modules` silently mutates
|
|
166
|
+
> a repository that has nothing to do with this one, and couples a public npm package to a private
|
|
167
|
+
> codebase. If a step needs a host app, create a throwaway one for that purpose.
|
|
168
|
+
|
|
169
|
+
### Self-contained — run these on every change
|
|
133
170
|
|
|
134
171
|
```bash
|
|
135
172
|
npm run typecheck # must be clean
|
|
136
|
-
npm run lint
|
|
173
|
+
npm run lint # must exit 0; warnings are tolerated, errors are not
|
|
137
174
|
npm pack --dry-run # expect build/, plugin/build/, LICENSE, native sources;
|
|
138
175
|
# NO node_modules, prebuilds, local-maven-repo
|
|
139
176
|
```
|
|
140
177
|
|
|
141
|
-
|
|
142
|
-
|
|
178
|
+
`npm run lint` needs `eslint.config.js` at the repo root — `expo-module configure` will **not**
|
|
179
|
+
create it (it is an optional template that only gets synced when it already exists), so a sync that
|
|
180
|
+
loses the file silently breaks this step. See §1.
|
|
181
|
+
|
|
182
|
+
### Android — compiling the parser without a host app
|
|
183
|
+
|
|
184
|
+
`utils/StackingSubtitleParser.kt` imports only `android.text.*` and `androidx.media3.*`, so it
|
|
185
|
+
compiles on its own. This is the file that carries almost all of the Android subtitle logic, and it
|
|
186
|
+
is the one most likely to break when Media3 changes `SubtitleParser`, `CuesWithTiming` or `Cue`.
|
|
187
|
+
|
|
188
|
+
In a scratch directory, with `<media3>` set to `androidxMedia3Version` from `android/build.gradle`
|
|
189
|
+
and `<sdk>` to an installed Android platform:
|
|
190
|
+
|
|
191
|
+
```kotlin
|
|
192
|
+
// settings.gradle.kts -> rootProject.name = "kotlincheck"
|
|
193
|
+
// build.gradle.kts:
|
|
194
|
+
import java.util.zip.ZipFile
|
|
195
|
+
|
|
196
|
+
plugins { kotlin("jvm") version "2.1.21" }
|
|
197
|
+
repositories { google(); mavenCentral() }
|
|
198
|
+
|
|
199
|
+
val media3: Configuration by configurations.creating
|
|
200
|
+
dependencies {
|
|
201
|
+
media3("androidx.media3:media3-common:<media3>")
|
|
202
|
+
media3("androidx.media3:media3-extractor:<media3>")
|
|
203
|
+
media3("androidx.media3:media3-ui:<media3>")
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// A plain JVM compile cannot read .aar, so pull classes.jar out of each one.
|
|
207
|
+
val unpacked = layout.buildDirectory.dir("unpacked")
|
|
208
|
+
val unpackAars by tasks.registering {
|
|
209
|
+
outputs.dir(unpacked)
|
|
210
|
+
doLast {
|
|
211
|
+
val out = unpacked.get().asFile.also { it.deleteRecursively(); it.mkdirs() }
|
|
212
|
+
media3.forEach { f ->
|
|
213
|
+
if (f.name.endsWith(".aar")) {
|
|
214
|
+
ZipFile(f).use { zip ->
|
|
215
|
+
zip.getEntry("classes.jar")?.let { e ->
|
|
216
|
+
zip.getInputStream(e).use { it.copyTo(File(out, f.name.removeSuffix(".aar") + ".jar").outputStream()) }
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
} else if (f.name.endsWith(".jar")) f.copyTo(File(out, f.name), overwrite = true)
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>().configureEach {
|
|
225
|
+
dependsOn(unpackAars)
|
|
226
|
+
libraries.from(fileTree(unpacked) { include("*.jar") }, files("<sdk>/platforms/android-36/android.jar"))
|
|
227
|
+
}
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
Copy the file to `src/main/kotlin/expo/modules/video/utils/` and run `gradle compileKotlin` —
|
|
231
|
+
expect `BUILD SUCCESSFUL`. Because the class implements Media3's `SubtitleParser`, a successful
|
|
232
|
+
build also proves the three overrides still match that Media3 version's interface.
|
|
233
|
+
|
|
234
|
+
The rest of the Android sources import `expo.modules.kotlin` and `com.facebook.react`, neither of
|
|
235
|
+
which is on a public Maven repository, so they cannot be checked this way — a full build is the only
|
|
236
|
+
option for them.
|
|
237
|
+
|
|
238
|
+
### Full native build — needs a throwaway host app
|
|
239
|
+
|
|
240
|
+
Both platforms default to precompiled artifacts, so a complete check means building from source in a
|
|
241
|
+
host app. Create one for this purpose (`npx create-expo-app`), install this package into it, and
|
|
242
|
+
confirm §1's "Removed" artifacts are absent from the installed copy:
|
|
143
243
|
|
|
144
244
|
```bash
|
|
145
245
|
# Android — expect BUILD SUCCESSFUL
|
|
146
|
-
cd <app>/android && ./gradlew :expo-video:compileDebugKotlin
|
|
246
|
+
cd <scratch-app>/android && ./gradlew :expo-video-subtitle:compileDebugKotlin
|
|
147
247
|
|
|
148
248
|
# iOS — expect BUILD SUCCEEDED
|
|
149
|
-
cd <app>/ios && pod install
|
|
249
|
+
cd <scratch-app>/ios && pod install
|
|
150
250
|
xcodebuild -project Pods/Pods.xcodeproj -target ExpoVideo -sdk iphoneos \
|
|
151
251
|
-configuration Debug build CODE_SIGNING_ALLOWED=NO
|
|
152
252
|
```
|
|
153
253
|
|
|
154
|
-
|
|
254
|
+
`npm pack` the fork and install the tarball rather than editing the app's `node_modules` in place,
|
|
255
|
+
so the thing you compile is exactly what a consumer would receive.
|
|
155
256
|
|
|
156
257
|
**Smoke test in the app:** an MP4 source with `subtitleTracks` must list the tracks in
|
|
157
258
|
`player.availableSubtitleTracks`, render when selected via `player.subtitleTrack`, and visibly change
|
package/LICENSE
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
The MIT License (MIT)
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2015-present 650 Industries, Inc. (aka Expo)
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2015-present 650 Industries, Inc. (aka Expo)
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|