expo-video-subtitle 0.2.0 → 0.3.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.
Files changed (201) hide show
  1. package/CHANGELOG.md +184 -120
  2. package/FORK.md +32 -17
  3. package/LICENSE +21 -21
  4. package/README.md +209 -186
  5. package/android/build.gradle +32 -32
  6. package/android/src/main/AndroidManifest.xml +10 -10
  7. package/android/src/main/java/expo/modules/video/FullscreenPlayerActivity.kt +270 -258
  8. package/android/src/main/java/expo/modules/video/IntervalUpdateClock.kt +54 -54
  9. package/android/src/main/java/expo/modules/video/MediaMetadataRetriever.kt +89 -89
  10. package/android/src/main/java/expo/modules/video/PlayerViewExtension.kt +87 -87
  11. package/android/src/main/java/expo/modules/video/VideoCache.kt +109 -109
  12. package/android/src/main/java/expo/modules/video/VideoExceptions.kt +45 -45
  13. package/android/src/main/java/expo/modules/video/VideoModule.kt +446 -446
  14. package/android/src/main/java/expo/modules/video/VideoThumbnail.kt +20 -20
  15. package/android/src/main/java/expo/modules/video/VideoView.kt +461 -457
  16. package/android/src/main/java/expo/modules/video/delegates/IgnoreSameSet.kt +24 -24
  17. package/android/src/main/java/expo/modules/video/drawing/OutlineProvider.kt +217 -217
  18. package/android/src/main/java/expo/modules/video/enums/AudioMixingMode.kt +20 -20
  19. package/android/src/main/java/expo/modules/video/enums/ContentFit.kt +19 -19
  20. package/android/src/main/java/expo/modules/video/enums/ContentType.kt +22 -22
  21. package/android/src/main/java/expo/modules/video/enums/DRMType.kt +26 -26
  22. package/android/src/main/java/expo/modules/video/enums/FullscreenOrientation.kt +25 -25
  23. package/android/src/main/java/expo/modules/video/enums/PlayerStatus.kt +10 -10
  24. package/android/src/main/java/expo/modules/video/enums/VideoRange.kt +27 -27
  25. package/android/src/main/java/expo/modules/video/listeners/VideoManagerListener.kt +10 -10
  26. package/android/src/main/java/expo/modules/video/listeners/VideoPlayerListener.kt +35 -35
  27. package/android/src/main/java/expo/modules/video/listeners/VideoViewListener.kt +13 -13
  28. package/android/src/main/java/expo/modules/video/managers/AudioFocusManager.kt +242 -242
  29. package/android/src/main/java/expo/modules/video/managers/PictureInPictureManager.kt +329 -329
  30. package/android/src/main/java/expo/modules/video/managers/VideoManager.kt +194 -194
  31. package/android/src/main/java/expo/modules/video/playbackService/ExpoVideoPlaybackService.kt +267 -267
  32. package/android/src/main/java/expo/modules/video/playbackService/PlaybackServiceConnection.kt +62 -62
  33. package/android/src/main/java/expo/modules/video/playbackService/VideoMediaSessionCallback.kt +47 -47
  34. package/android/src/main/java/expo/modules/video/player/DefaultLoadControl.java +551 -551
  35. package/android/src/main/java/expo/modules/video/player/FirstFrameEventGenerator.kt +116 -116
  36. package/android/src/main/java/expo/modules/video/player/PlayerEvent.kt +172 -172
  37. package/android/src/main/java/expo/modules/video/player/VideoPlayer.kt +609 -598
  38. package/android/src/main/java/expo/modules/video/player/VideoPlayerAudioTracks.kt +126 -126
  39. package/android/src/main/java/expo/modules/video/player/VideoPlayerKeepAwake.kt +91 -91
  40. package/android/src/main/java/expo/modules/video/player/VideoPlayerLoadControl.kt +57 -57
  41. package/android/src/main/java/expo/modules/video/player/VideoPlayerSubtitles.kt +136 -136
  42. package/android/src/main/java/expo/modules/video/records/BufferOptions.kt +18 -18
  43. package/android/src/main/java/expo/modules/video/records/ButtonOptions.kt +17 -17
  44. package/android/src/main/java/expo/modules/video/records/DRMOptions.kt +27 -27
  45. package/android/src/main/java/expo/modules/video/records/FullscreenOptions.kt +14 -14
  46. package/android/src/main/java/expo/modules/video/records/PiPParams.kt +38 -38
  47. package/android/src/main/java/expo/modules/video/records/PlaybackError.kt +21 -21
  48. package/android/src/main/java/expo/modules/video/records/PlayerBuilderOptions.kt +15 -15
  49. package/android/src/main/java/expo/modules/video/records/ScrubbingModeOptions.kt +33 -33
  50. package/android/src/main/java/expo/modules/video/records/SeekTolerance.kt +30 -30
  51. package/android/src/main/java/expo/modules/video/records/SubtitleSource.kt +54 -54
  52. package/android/src/main/java/expo/modules/video/records/SubtitleStyle.kt +144 -137
  53. package/android/src/main/java/expo/modules/video/records/Tracks.kt +115 -115
  54. package/android/src/main/java/expo/modules/video/records/VideoEventPayloads.kt +79 -79
  55. package/android/src/main/java/expo/modules/video/records/VideoMetadata.kt +14 -14
  56. package/android/src/main/java/expo/modules/video/records/VideoSize.kt +16 -16
  57. package/android/src/main/java/expo/modules/video/records/VideoSource.kt +113 -113
  58. package/android/src/main/java/expo/modules/video/records/VideoThumbnailOptions.kt +26 -26
  59. package/android/src/main/java/expo/modules/video/utils/DataSourceUtils.kt +81 -81
  60. package/android/src/main/java/expo/modules/video/utils/EventDispatcherUtils.kt +43 -43
  61. package/android/src/main/java/expo/modules/video/utils/FullscreenActivityOrientationHelper.kt +120 -120
  62. package/android/src/main/java/expo/modules/video/utils/MediaSessionUtils.kt +14 -14
  63. package/android/src/main/java/expo/modules/video/utils/MutableWeakReference.kt +26 -26
  64. package/android/src/main/java/expo/modules/video/utils/PictureInPictureHelperFragment.kt +49 -49
  65. package/android/src/main/java/expo/modules/video/utils/PictureInPictureUtils.kt +96 -96
  66. package/android/src/main/java/expo/modules/video/utils/RoundedSubtitleBackground.kt +352 -0
  67. package/android/src/main/java/expo/modules/video/utils/StackingSubtitleParser.kt +4 -1
  68. package/android/src/main/java/expo/modules/video/utils/SubtitleUtils.kt +131 -78
  69. package/android/src/main/java/expo/modules/video/utils/ViewVisibilityUtils.kt +28 -28
  70. package/android/src/main/java/expo/modules/video/utils/WeakMutableSet.kt +120 -120
  71. package/android/src/main/java/expo/modules/video/utils/YogaUtils.kt +20 -20
  72. package/android/src/main/res/drawable/seek_backwards_10s.xml +25 -25
  73. package/android/src/main/res/drawable/seek_backwards_15s.xml +25 -25
  74. package/android/src/main/res/drawable/seek_backwards_5s.xml +25 -25
  75. package/android/src/main/res/drawable/seek_forwards_10s.xml +30 -30
  76. package/android/src/main/res/drawable/seek_forwards_15s.xml +31 -31
  77. package/android/src/main/res/drawable/seek_forwards_5s.xml +30 -30
  78. package/android/src/main/res/layout/fullscreen_player_activity.xml +20 -20
  79. package/android/src/main/res/layout/surface_player_view.xml +7 -7
  80. package/android/src/main/res/layout/texture_player_view.xml +7 -7
  81. package/android/src/main/res/values/styles.xml +9 -9
  82. package/app.plugin.js +1 -1
  83. package/build/NativeVideoAirPlayButtonView.js.map +1 -1
  84. package/build/NativeVideoModule.js.map +1 -1
  85. package/build/NativeVideoModule.web.js.map +1 -1
  86. package/build/NativeVideoView.js.map +1 -1
  87. package/build/VideoAirPlayButton.ios.js.map +1 -1
  88. package/build/VideoAirPlayButton.js.map +1 -1
  89. package/build/VideoAirPlayButton.types.js.map +1 -1
  90. package/build/VideoModule.js.map +1 -1
  91. package/build/VideoPlayer.js.map +1 -1
  92. package/build/VideoPlayer.types.js.map +1 -1
  93. package/build/VideoPlayer.web.js.map +1 -1
  94. package/build/VideoPlayerEvents.types.js.map +1 -1
  95. package/build/VideoThumbnail.js.map +1 -1
  96. package/build/VideoView.js.map +1 -1
  97. package/build/VideoView.types.d.ts +14 -0
  98. package/build/VideoView.types.d.ts.map +1 -1
  99. package/build/VideoView.types.js.map +1 -1
  100. package/build/VideoView.web.js.map +1 -1
  101. package/build/index.js.map +1 -1
  102. package/build/resolveAssetSource.js.map +1 -1
  103. package/build/resolveAssetSource.web.js.map +1 -1
  104. package/expo-module.config.json +9 -9
  105. package/ios/Cache/CachableRequest.swift +46 -46
  106. package/ios/Cache/CacheVideoAssetTransportProvider.swift +64 -64
  107. package/ios/Cache/CachedResource.swift +164 -164
  108. package/ios/Cache/CachingHelpers.swift +107 -107
  109. package/ios/Cache/MediaFileHandle.swift +139 -139
  110. package/ios/Cache/MediaInfo.swift +185 -185
  111. package/ios/Cache/ResourceLoaderDelegate.swift +306 -306
  112. package/ios/Cache/SynchronizedHashTable.swift +23 -23
  113. package/ios/Cache/VideoCacheManager.swift +192 -192
  114. package/ios/ContentKeyDelegate.swift +214 -214
  115. package/ios/ContentKeyManager.swift +21 -21
  116. package/ios/Enums/AudioMixingMode.swift +37 -37
  117. package/ios/Enums/ContentType.swift +11 -11
  118. package/ios/Enums/DRMType.swift +20 -20
  119. package/ios/Enums/FullscreenOrientation.swift +34 -34
  120. package/ios/Enums/KeepFullscreenOnPiPStopBehavior.swift +20 -20
  121. package/ios/Enums/PlayerStatus.swift +10 -10
  122. package/ios/Enums/VideoContentFit.swift +39 -39
  123. package/ios/Enums/VideoRange.swift +21 -21
  124. package/ios/ExpoVideo.podspec +27 -27
  125. package/ios/NowPlayingManager.swift +304 -304
  126. package/ios/OrientationAVPlayerViewController.swift +263 -263
  127. package/ios/Records/BufferOptions.swift +12 -12
  128. package/ios/Records/DRMOptions.swift +24 -24
  129. package/ios/Records/FullscreenOptions.swift +14 -14
  130. package/ios/Records/PlaybackError.swift +10 -10
  131. package/ios/Records/ScrubbingModeOptions.swift +7 -7
  132. package/ios/Records/SeekTolerance.swift +20 -20
  133. package/ios/Records/SubtitleSource.swift +32 -32
  134. package/ios/Records/SubtitleStyle.swift +118 -118
  135. package/ios/Records/Tracks.swift +229 -229
  136. package/ios/Records/VideoEventPayloads.swift +81 -81
  137. package/ios/Records/VideoMetadata.swift +16 -16
  138. package/ios/Records/VideoSize.swift +15 -15
  139. package/ios/Records/VideoSource.swift +28 -28
  140. package/ios/Thumbnails/VideoThumbnail.swift +27 -27
  141. package/ios/Thumbnails/VideoThumbnailGenerator.swift +68 -68
  142. package/ios/Thumbnails/VideoThumbnailOptions.swift +15 -15
  143. package/ios/Utils/AVAssetVariant+VideoTracks.swift +20 -20
  144. package/ios/Utils/AvAssetTrack+VideoTracks.swift +79 -79
  145. package/ios/Utils/FourCharCode+toString.swift +25 -25
  146. package/ios/Utils/HlsUriUtils.swift +27 -27
  147. package/ios/Utils/URL+MediaLibraryAssets.swift +68 -68
  148. package/ios/VideoAirPlayButtonView.swift +70 -70
  149. package/ios/VideoAsset.swift +98 -98
  150. package/ios/VideoAssetTransport/VideoAssetLoadPlan.swift +69 -69
  151. package/ios/VideoAssetTransport/VideoAssetSourceDescriptor.swift +29 -29
  152. package/ios/VideoAssetTransport/VideoAssetTransportProvider.swift +24 -24
  153. package/ios/VideoAssetTransport/VideoAssetTransportRegistry.swift +103 -103
  154. package/ios/VideoExceptions.swift +53 -53
  155. package/ios/VideoItem.swift +11 -11
  156. package/ios/VideoManager.swift +182 -182
  157. package/ios/VideoModule.swift +413 -413
  158. package/ios/VideoPlayer/DangerousPropertiesStore.swift +19 -19
  159. package/ios/VideoPlayer.swift +485 -485
  160. package/ios/VideoPlayerAudioTracks.swift +109 -109
  161. package/ios/VideoPlayerItem.swift +169 -169
  162. package/ios/VideoPlayerObserver.swift +612 -612
  163. package/ios/VideoPlayerSeeker.swift +77 -77
  164. package/ios/VideoPlayerSubtitleSideload.swift +203 -203
  165. package/ios/VideoPlayerSubtitles.swift +88 -88
  166. package/ios/VideoSourceLoader.swift +90 -90
  167. package/ios/VideoSourceLoaderListener.swift +34 -34
  168. package/ios/VideoView.swift +201 -201
  169. package/package.json +51 -51
  170. package/plugin/index.d.ts +1 -1
  171. package/plugin/index.js +1 -1
  172. package/plugin/jest.config.js +1 -1
  173. package/plugin/src/index.ts +3 -3
  174. package/plugin/src/withExpoVideo.ts +103 -103
  175. package/plugin/tsconfig.json +10 -10
  176. package/src/NativeVideoAirPlayButtonView.ts +3 -3
  177. package/src/NativeVideoModule.ts +16 -16
  178. package/src/NativeVideoModule.web.ts +4 -4
  179. package/src/NativeVideoView.ts +8 -8
  180. package/src/VideoAirPlayButton.ios.tsx +8 -8
  181. package/src/VideoAirPlayButton.tsx +14 -14
  182. package/src/VideoAirPlayButton.types.ts +39 -39
  183. package/src/VideoModule.ts +47 -47
  184. package/src/VideoPlayer.tsx +74 -74
  185. package/src/VideoPlayer.types.ts +893 -893
  186. package/src/VideoPlayer.web.tsx +470 -470
  187. package/src/VideoPlayerEvents.types.ts +332 -332
  188. package/src/VideoThumbnail.ts +31 -31
  189. package/src/VideoView.tsx +111 -111
  190. package/src/VideoView.types.ts +454 -439
  191. package/src/VideoView.web.tsx +293 -293
  192. package/src/index.ts +26 -26
  193. package/src/resolveAssetSource.ts +2 -2
  194. package/src/resolveAssetSource.web.ts +17 -17
  195. package/src/ts-declarations/react-native-assets.d.ts +22 -22
  196. package/tsconfig.json +10 -10
  197. package/.gitattributes +0 -17
  198. package/eslint.config.js +0 -4
  199. package/plugin/tsconfig.tsbuildinfo +0 -1
  200. package/tsconfig.all.json +0 -11
  201. package/tsconfig.tsbuildinfo +0 -1
package/CHANGELOG.md CHANGED
@@ -1,120 +1,184 @@
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.
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.3.0
11
+
12
+ ### Added
13
+
14
+ - **Android:** `subtitleStyle.backgroundRadius` rounds the corners of the `backgroundColor` box, in dp.
15
+ One box is drawn per rendered line, so a caption that wraps gets two rounded boxes stacked on each
16
+ other, the way VLC and most desktop players draw them. It has no effect unless `backgroundColor` is
17
+ set to something that is not fully transparent, and `windowColor` is deliberately left rectangular
18
+ the window is the region the caption occupies, the background is the box that hugs the text.
19
+
20
+ Media3 offers nothing for this. `SubtitlePainter` renders `backgroundColor` as an Android
21
+ `BackgroundColorSpan`, which the framework paints with `canvas.drawRect`, and it paints `windowColor`
22
+ with a `canvas.drawRect` of its own; neither takes a radius, and `SubtitlePainter` and
23
+ `CanvasSubtitleOutput` are package-private and final while `SubtitleView` is final, so none of it can
24
+ be subclassed or replaced. The background is therefore drawn by a second subtitle view inserted
25
+ behind the one `PlayerView` owns, fed the same cues and configured with the same typeface, text size
26
+ and bottom padding so the two layouts match; the box itself comes from a `LineBackgroundSpan` calling
27
+ `drawRoundRect`. That view pins its edge type to `EDGE_TYPE_NONE` on purpose: `SubtitlePainter` copies
28
+ the cue text for a second edge pass and draws both layouts whenever the edge type is `outline`,
29
+ `raised` or `depressed`, which would paint the box twice and make a semi-transparent colour composite
30
+ with itself and come out darker than asked for.
31
+
32
+ Leaving `backgroundRadius` unset takes the original code path unchanged, with no extra view and no
33
+ extra listener.
34
+
35
+ ### Changed
36
+
37
+ - **Android:** the subtitle view is now reconfigured whenever a player moves between views
38
+ attaching a player, entering fullscreen, leaving it. `PlayerView` re-attaches its own subtitle view
39
+ on `setPlayer`, so nothing needed this before; the rounded background does, because it subscribes to
40
+ the `Player` rather than riding on `PlayerView`, and a view that no longer drives the player would
41
+ otherwise keep that subscription and go on drawing cues behind a surface nobody is looking at. For
42
+ anyone not using `backgroundRadius` this only means the caption style is re-applied at those
43
+ moments, which is what it already was.
44
+
45
+ ## 0.2.2
46
+
47
+ ### Changed
48
+
49
+ - The published tarball no longer carries the repo's own development configuration: `.prettierrc`,
50
+ `.gitattributes`, `eslint.config.js`, `tsconfig.all.json` and the two `*.tsbuildinfo` build caches
51
+ (260 files → 254). None of it is read from inside a consumer's `node_modules`, and
52
+ `eslint.config.js` would in fact throw if anything did load it, because it requires
53
+ `expo-module-scripts` — a devDependency, and therefore absent for consumers. Two conventions
54
+ combined to publish these: `.npmignore` excludes hidden *directories* but not hidden *files*, and
55
+ npm ignores `.gitignore` entirely once an `.npmignore` exists, so a build cache that git already
56
+ ignores still shipped. Nothing a consumer uses changed — the file list is otherwise byte-identical,
57
+ and installing the tarball into a clean project still resolves `build/`, `plugin/build/`,
58
+ `app.plugin.js`, `expo-module.config.json` and the Android/iOS sources.
59
+ - Dropped the `.npmignore` entry for `oxlint.config.mjs`, which has not existed since 0.2.0.
60
+
61
+ ## 0.2.1
62
+
63
+ ### Changed
64
+
65
+ - Repository tooling, with no effect on the published runtime: `npm run lint` is quiet again. Making
66
+ the lint step runnable in 0.2.0 exposed 377 `prettier/prettier` warnings against code that is in
67
+ fact correctly formatted. `eslint-config-universe` enables the `prettier/prettier` rule but supplies
68
+ no options of its own, and `expo-video` inherits them from the Expo monorepo's root `.prettierrc`
69
+ a file that does not come along when the package is forked out to stand on its own. Prettier
70
+ therefore fell back to its own defaults, and every source file disagreed with them about quote style
71
+ and line width. Adding the upstream options as a `.prettierrc` takes the count to zero without
72
+ reformatting a single line.
73
+
74
+ ## 0.2.0
75
+
76
+ ### Added
77
+
78
+ - **Android:** `subtitleStyle.applyEmbeddedStyles` keeps the inline formatting a subtitle track
79
+ carries instead of discarding it. Subtitle formats bring styling of their own — SubRip's `<b>`,
80
+ `<i>`, `<u>` and `<font color>` tags, and the richer per-cue styling of embedded WebVTT/TTML — and
81
+ until now every bit of it was thrown away so that `subtitleStyle` was the only thing deciding how
82
+ captions looked. `SubtitleView.setApplyEmbeddedStyles(false)` was hardcoded, and Media3 implements
83
+ that by removing every span from every cue, so an `.srt` written with `<i>` rendered upright.
84
+ Defaults to `false`, so nothing changes until you opt in. The rest of `subtitleStyle` still applies
85
+ underneath and `fontSize` still overrides any size the track asks for; the trade-off is that a cue
86
+ specifying its own colours overrides `textColor` and `windowColor` for that cue. There is no iOS
87
+ equivalent: `AVPlayerItem.textStyleRules` always composes with what the WebVTT cue declares.
88
+
89
+ ### Fixed
90
+
91
+ - **Android:** a subtitle no longer drops down a line when the subtitle *below* it ends. Cues that
92
+ are on screen together are drawn as one block anchored at its bottom, so the moment the lower cue
93
+ expired the upper one fell into its place — moving the text at exactly the spot the viewer is
94
+ reading. Every cue now keeps the same line for its whole time on screen: the line a finished cue
95
+ leaves behind is held empty, and the next cue to start reclaims the lowest empty line rather than
96
+ stacking on top, which is what keeps the block from creeping upwards. An empty line can therefore
97
+ sit below — or between — the cues still on screen, and the stack resets once nothing is left on
98
+ screen. Cues with explicit `{\anN}` positioning are still passed through untouched.
99
+ - **Android:** merging simultaneous SubRip cues no longer flattens their text. The cues were joined
100
+ through `toString()`, which erases the spans Media3's SubRip parser produces from inline tags. This
101
+ changed nothing on screen at the time, because the renderer stripped those spans anyway, but it
102
+ would have silently defeated the new `applyEmbeddedStyles` option for any overlapping cue.
103
+
104
+ ### Changed
105
+
106
+ - Repository tooling, with no effect on the published runtime: `npm run lint` runs again. The repo
107
+ had no `eslint.config.js` `expo-module configure` treats it as an optional template and never
108
+ creates one while the `oxlint.config.mjs` it did have re-exported a module that
109
+ `expo-module-scripts@56` does not ship, so the lint step in `FORK.md` §5 had never actually
110
+ executed. A `.gitattributes` now pins the working copy to LF, which stops the Prettier rule from
111
+ reporting nearly every line of every file on a Windows checkout. The single lint error this
112
+ uncovered, a non-simple expression in a `useMemo` dependency list in `VideoPlayer.web.tsx`, is
113
+ fixed by hoisting it into a variable; the value and its identity semantics are unchanged.
114
+
115
+ ## 0.1.3
116
+
117
+ ### Documentation
118
+
119
+ - Document how subtitles that are on screen at the same time are stacked, which shipped in 0.1.2 but
120
+ was only described in the changelog.
121
+ - Add a release procedure to `FORK.md`, including the rule that every version bump carries a
122
+ changelog entry.
123
+
124
+ ## 0.1.2
125
+
126
+ ### Fixed
127
+
128
+ - **Android:** subtitles that are on screen at the same time are now stacked as one block instead of
129
+ being drawn on top of each other. `.srt` files legitimately contain overlapping timestamps (two
130
+ speakers, dialogue over on-screen text), but SubRip carries no positioning, so Media3 pinned every
131
+ cue to the same spot and rendered them one over the other — Media3 does the stacking in its WebVTT
132
+ *parser* (`line = -1 - i`) and has no equivalent pass for SubRip. A `SubtitleParser` for SubRip now
133
+ splits the cue timeline at every boundary and merges the cues active in each slice into a single
134
+ multi-line cue, ordered like WebVTT: the cue that started earliest sits at the bottom. This also
135
+ makes Android match the iOS output, which already stacked because sideloaded SRT is converted to
136
+ WebVTT there. Cues with explicit `{\anN}` positioning are left untouched.
137
+ - **Android:** selecting a `subtitleTrack` whose id is not among the available tracks no longer
138
+ leaves the previously selected track on screen. The cleared track-selection parameters were only
139
+ applied when a matching track was found, so an unmatched assignment silently did nothing; the
140
+ selection is now cleared and a warning is logged.
141
+ - **Android:** `subtitleStyle.bottomOffset` is reset to the default when it is omitted, instead of
142
+ keeping the value from a previously applied style.
143
+
144
+ ## 0.1.1
145
+
146
+ ### Fixed
147
+
148
+ - **Android:** `subtitleStyle.fontFamily` now resolves custom fonts bundled with the app, the same way
149
+ React Native resolves a `<Text>` component's `fontFamily`. It is looked up as an Android font
150
+ resource (`res/font`, where `expo-font`'s config plugin puts fonts) and then through React Native's
151
+ font manager, which covers the `assets/fonts/<name>.ttf` convention and fonts registered at runtime.
152
+ Previously only the built-in system families worked: `Typeface.create` silently fell back to the
153
+ default typeface for any bundled font, so `fontFamily` appeared to do nothing on Android while
154
+ working on iOS.
155
+
156
+ ### Documentation
157
+
158
+ - Document font support and the silent-fallback behaviour for unresolved family names.
159
+
160
+ ## 0.1.0
161
+
162
+ Initial release. Based on `expo-video` **56.1.4** (Expo SDK 56).
163
+
164
+ ### Added
165
+
166
+ - **External (sideloaded) subtitles** via `VideoSource.subtitleTracks`. Attach WebVTT or SubRip
167
+ subtitle files (local or remote) to any source — most importantly progressive **MP4**, which,
168
+ unlike HLS/DASH manifests, cannot advertise its own subtitle renditions. Sideloaded tracks are
169
+ merged into the media and surface through `availableSubtitleTracks`, so they are selected with
170
+ `subtitleTrack` exactly like embedded tracks.
171
+ - Android: merged with `MediaItem.SubtitleConfiguration` (Media3 wraps them in a `MergingMediaSource`).
172
+ - iOS: merged into an `AVMutableComposition` as a `.text` track. SRT is converted to WebVTT, remote
173
+ files are cached locally first, and per-track time ranges are clamped to the video duration.
174
+ Applies to progressive, non-DRM sources on the asynchronous loading path.
175
+ - **Custom subtitle styling** via the `VideoView` `subtitleStyle` prop: `textColor`, `backgroundColor`,
176
+ `windowColor`, `fontSize`, `fontFamily`, `bold`, `edgeType`, `edgeColor`, and `bottomOffset`.
177
+ Applies to embedded and sideloaded tracks alike.
178
+ - Android: `CaptionStyleCompat` on the `PlayerView` subtitle view.
179
+ - iOS: `AVPlayerItem.textStyleRules`.
180
+
181
+ ### Changed
182
+
183
+ - The Android `publication` block and the iOS prebuild artifacts are removed, so the modified
184
+ Kotlin and Swift are compiled from source instead of resolving a precompiled AAR/XCFramework.
package/FORK.md CHANGED
@@ -5,9 +5,10 @@ and (b) pull a newer `expo-video` release into it **without losing the subtitle
5
5
 
6
6
  - **Baseline:** `expo-video@56.1.4` (Expo SDK 56), as published on npm.
7
7
  - **Native module name:** unchanged (`ExpoVideo`) — this is a drop-in replacement, not a coexisting package.
8
- - **Design principle:** the fork is deliberately **surgical and additive**. 5 new files hold almost all
9
- of the logic (505 lines); the 14 touched upstream files receive ~130 added lines and only ~29 removed
10
- ones. Nothing upstream is rewritten, so a version bump is a small, mechanical re-apply.
8
+ - **Design principle:** the fork is deliberately **surgical and additive**. 7 new source files hold
9
+ almost all of the logic (~1,200 lines); the 19 touched upstream files receive ~450 added lines and
10
+ only ~44 removed ones. Nothing upstream is rewritten the removals are call-site signatures and a
11
+ handful of rewritten function bodies — so a version bump is a small, mechanical re-apply.
11
12
 
12
13
  ---
13
14
 
@@ -23,18 +24,20 @@ Measured against the published `expo-video@56.1.4` tarball. `+`/`-` are added/re
23
24
  | `ios/Records/SubtitleStyle.swift` | 118 | Record for caption styling; hex→ARGB parsing; builds `[AVTextStyleRule]`. |
24
25
  | `ios/VideoPlayerSubtitleSideload.swift` | 203 | Builds the `AVMutableComposition`, downloads remote subs, SRT→WebVTT converter. |
25
26
  | `android/…/records/SubtitleSource.kt` | 54 | Record → `MediaItem.SubtitleConfiguration` + MIME resolution. |
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. |
27
+ | `android/…/records/SubtitleStyle.kt` | 144 | Record → `CaptionStyleCompat`; hex colour parsing; font-family resolution (`res/font` → `ReactFontManager`); the `applyEmbeddedStyles` flag, which `SubtitleUtils` reads directly rather than `toCaptionStyle`. |
28
+ | `android/…/utils/StackingSubtitleParser.kt` | 300 | `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. |
29
+ | `android/…/utils/RoundedSubtitleBackground.kt` | 352 | Draws `subtitleStyle.backgroundRadius` as rounded boxes, which Media3 cannot do at all: it paints `backgroundColor` as a framework `BackgroundColorSpan` and `windowColor` with `canvas.drawRect`, neither takes a radius, and `SubtitlePainter`/`CanvasSubtitleOutput` are package-private final while `SubtitleView` is final. A second `SubtitleView` is inserted behind `PlayerView`'s own, fed from `Player.Listener.onCues`, drawing a `LineBackgroundSpan` per line. **Its `EDGE_TYPE_NONE` is load-bearing** — `SubtitlePainter` copies the cue text for an edge pass and draws both layouts when the edge type is outline/raised/depressed, which would paint the box twice and darken a semi-transparent colour. State hangs off the view's `tag`, never a map in the companion object; see the `find` KDoc for why even a `WeakHashMap` leaks here. |
28
30
  | `FORK.md`, `LICENSE` | — | This guide; MIT licence (upstream copyright preserved). |
29
31
  | `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
32
  | `.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. |
33
+ | `.prettierrc` | 7 | The Expo monorepo's Prettier options, which the sources were formatted with. `eslint-config-universe` turns the `prettier/prettier` rule *on* but supplies no options, and upstream inherits them from the monorepo root — a file that does not come along when the package is forked out on its own. Without this, Prettier falls back to its own defaults and reports 377 warnings against correctly formatted code. Only `printWidth` and `singleQuote` differ from Prettier 2's defaults today; the rest are written out because they are what upstream uses, and `trailingComma` guards against a bump to Prettier 3, whose default is `"all"`. |
31
34
 
32
35
  ### Modified — upstream files carrying fork edits (re-apply these after a sync)
33
36
 
34
37
  | File | Δ | What to re-apply |
35
38
  | --- | --- | --- |
36
39
  | `src/VideoPlayer.types.ts` | +59 | `subtitleTracks?: SubtitleSource[]` on `VideoSourceObject`; the exported `SubtitleSource` type. |
37
- | `src/VideoView.types.ts` | +114 | `subtitleStyle?: SubtitleStyle` on `VideoViewProps`; `SubtitleStyle` + `SubtitleEdgeType` types. |
40
+ | `src/VideoView.types.ts` | +129 | `subtitleStyle?: SubtitleStyle` on `VideoViewProps`; `SubtitleStyle` + `SubtitleEdgeType` types. |
38
41
  | `src/index.ts` | +2 | Export `SubtitleStyle`, `SubtitleEdgeType` (`SubtitleSource` rides on `export type *`). |
39
42
  | `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. |
40
43
  | `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.** |
@@ -44,14 +47,16 @@ Measured against the published `expo-video@56.1.4` tarball. `+`/`-` are added/re
44
47
  | `ios/VideoView.swift` | +8 | `subtitleStyle` property; forward it when `player` is (re)assigned. |
45
48
  | `ios/VideoModule.swift` | +4 | `Prop("subtitleStyle")`. |
46
49
  | `android/…/records/VideoSource.kt` | +9 / −2 | `subtitleTracks` field; `setSubtitleConfigurations(…)` in `toMediaItem()`; subtitle key in `toMediaId()`. |
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`). |
48
- | `android/…/VideoView.kt` | +12 / −5 | `subtitleStyle` property; pass it at all 4 `configureSubtitleView` call sites + the captioning listener. |
50
+ | `android/…/utils/SubtitleUtils.kt` | +92 / −21 | `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`). |
51
+ | `android/…/VideoView.kt` | +16 / −5 | `subtitleStyle` property; pass it at all 4 `configureSubtitleView` call sites + the captioning listener. |
49
52
  | `android/…/VideoModule.kt` | +4 | `Prop("subtitleStyle")`. |
50
53
  | `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. |
54
+ | `android/…/player/VideoPlayer.kt` | +13 / −2 | In `changeVideoView`, after `switchTargetView`: release the subtitle view the player is leaving and reconfigure the one it moves to. **Load-bearing for `backgroundRadius`** — that feature subscribes to the `Player` directly rather than riding on `PlayerView.setPlayer`, so a view that no longer drives the player keeps its subscription and goes on drawing stale cues. This is the choke point for every player move except entering fullscreen, which bypasses it (see `FullscreenPlayerActivity`). |
51
55
  | `android/…/player/VideoPlayerSubtitles.kt` | +14 / −8 | Apply the cleared track-selection parameters when the requested subtitle id matches nothing, instead of only inside the `format?.let` block. |
52
- | `android/…/FullscreenPlayerActivity.kt` | +3 / −3 | Pass `videoView.subtitleStyle` at its 2 call sites + the captioning listener. |
56
+ | `android/…/FullscreenPlayerActivity.kt` | +15 / −3 | Pass `videoView.subtitleStyle` at its 2 call sites + the captioning listener. Also release the originating `VideoView`'s subtitle view right after its own `switchTargetView` — this path bypasses `changeVideoView`, so without it the player carries two cue listeners for the whole time it is fullscreen — and release this activity's own in `onDestroy`. |
53
57
  | `package.json` | — | Fork identity + build scripts — see §3. |
54
58
  | `expo-module.config.json` | — | **Android `publication` block removed** — see §3. |
59
+ | `.npmignore` | +21 / −1 | A "Fork additions" block excluding the repo's own development config from the tarball: `.gitattributes`, `.prettierrc`, `eslint.config.js`, `tsconfig.all.json` and `*.tsbuildinfo`. Needed because the generated file only excludes hidden *directories* (`/.*/`), and because npm ignores `.gitignore` outright once an `.npmignore` exists — so the tsc build caches shipped despite git ignoring them. The `−1` drops the entry for `oxlint.config.mjs`, deleted in 0.2.0. |
55
60
  | `README.md`, `CHANGELOG.md` | — | Fork docs; do not take upstream's. |
56
61
 
57
62
  ### Removed — upstream artifacts deliberately dropped
@@ -110,9 +115,10 @@ Then re-apply the fork:
110
115
  (call-site signatures), `VideoPlayerItem.swift` (`isHls` hoist) and the ts-declarations shim.
111
116
  7. **Remove the Android `publication` block** from `expo-module.config.json`.
112
117
  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.
118
+ `FORK.md`, `eslint.config.js`, `.gitattributes` and `.prettierrc`. Step 3 only replaces
119
+ `src ios android plugin`, so the root-level files survive on their own — but confirm it, because a
120
+ missing `eslint.config.js` breaks `npm run lint` in a way that reads like a tooling bug rather than
121
+ a lost file, and a missing `.prettierrc` buries the output in warnings against correct code.
116
122
  9. Update the baseline version in this file, the README, and add a `CHANGELOG.md` entry.
117
123
  10. Verify with §5, then commit.
118
124
 
@@ -170,14 +176,23 @@ entry, in §1 of this file and in the README's intro line.
170
176
 
171
177
  ```bash
172
178
  npm run typecheck # must be clean
173
- npm run lint # must exit 0; warnings are tolerated, errors are not
179
+ npm run lint # expect zero output: no errors and no warnings
174
180
  npm pack --dry-run # expect build/, plugin/build/, LICENSE, native sources;
175
- # NO node_modules, prebuilds, local-maven-repo
181
+ # NO node_modules, prebuilds, local-maven-repo;
182
+ # NO dev config (.prettierrc, eslint.config.js, *.tsbuildinfo) — see §1
176
183
  ```
177
184
 
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.
185
+ The file count is a blunt but effective regression check: **254 files** as of 0.2.2. If a change moves
186
+ it, diff the list against the previous release and confirm every difference is intended
187
+ `npm pack --dry-run --json` gives a machine-readable list. Both directions matter: an unexpected
188
+ *addition* means dev clutter leaked in, an unexpected *removal* means a consumer is missing something.
189
+
190
+ `npm run lint` depends on two root files that upstream does not carry, both described in §1:
191
+ `eslint.config.js` (without it ESLint refuses to run at all) and `.prettierrc` (without it Prettier
192
+ falls back to its own defaults and reports hundreds of warnings against correctly formatted code).
193
+ Neither is created by `expo-module configure`, so a sync that loses one breaks this step in a way
194
+ that reads like a tooling bug. A `prettier/prettier` warning after a sync is far more likely to mean
195
+ the config went missing than that the code is genuinely misformatted — check that first.
181
196
 
182
197
  ### Android — compiling the parser without a host app
183
198
 
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.