Skip to content

Commit ed39edf

Browse files
authored
Merge pull request #353 from rdkcentral/feature/SubtitlePlugin
Feature/subtitle plugin
2 parents eec40ff + f3066e0 commit ed39edf

File tree

5 files changed

+453
-0
lines changed

5 files changed

+453
-0
lines changed

docs/plugins/subtitles.md

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
# Subtitles
2+
3+
You can use the *Subtitles* plugin to easily display Subtitles (or Closed Captions) in your App.
4+
5+
The plugin comes with some basic styling of Subtitles and offers the option to customize them, such as font size, colors, and positioning.
6+
7+
> The Subtitles plugins in the Lightning-SDK only offers an API for displaying Subtitles.
8+
9+
> Retrieving subtitles from a video stream or a remote API is not part of the Plugin's functionality as it's very App and / or Platform specific.
10+
11+
## Usage
12+
13+
If you want to display Subtitles in your App, first import the Subtitles plugin from the Lightning SDK:
14+
15+
```js
16+
import { Subtitles } from '@lightningjs/sdk'
17+
```
18+
19+
## Available Methods
20+
21+
### show
22+
23+
Sets the visibility of Subtitles to `true`, to display Subtitles.
24+
25+
```js
26+
Subtitles.show()
27+
```
28+
29+
### hide
30+
31+
Sets the visibility of Subtitles to `false`, to hide Subtitles.
32+
33+
```js
34+
Subtitles.hide()
35+
```
36+
37+
### text
38+
39+
Sets the text of the Subtitles text.
40+
41+
```js
42+
Subtitles.text('Subtitle Text')
43+
```
44+
45+
### clear
46+
47+
Clears the text of the Subtitles text.
48+
49+
```js
50+
Subtitles.clear()
51+
```
52+
53+
### styles
54+
55+
Sets the styles of the Subtitles text. This is a short hand method for setting the following styles: `fontFamily`, `fontSize`, `fontColor`, `backgroundColor`, `textAlign`. If any of these styles are not set, the default values will be used.
56+
57+
```js
58+
Subtitles.styles({
59+
fontFamily: 'sans-serif',
60+
fontSize: 45,
61+
fontColor: 0xffffffff,
62+
backgroundColor: 0x90000000,
63+
textAlign: 'center',
64+
})
65+
```
66+
### fontFamily
67+
68+
Sets the `fontFamily` style of the Subtitles text.
69+
70+
```js
71+
Subtitles.fontFamily('sans-serif')
72+
```
73+
74+
### fontSize
75+
76+
Sets the `fontSize` style of the Subtitles text.
77+
78+
```js
79+
Subtitles.fontSize(50)
80+
```
81+
82+
### fontColor
83+
84+
Sets the `fontColor` style of the Subtitles text
85+
86+
```js
87+
Subtitles.fontColor(0xffffffff)
88+
```
89+
90+
### backgroundColor
91+
92+
Sets the `backgroundColor` style of the Subtitles text
93+
94+
```js
95+
Subtitles.backgroundColor(0x90000000)
96+
```
97+
98+
### textAlign
99+
100+
Sets the `textAlign` style of the Subtitles text
101+
102+
```js
103+
Subtitles.textAlign('center')
104+
```
105+
106+
### position
107+
108+
Sets the x and y positions of the Subtitles text.
109+
110+
`x` value must be either a number or one of the following options: `'left'`, `'center'`, `'right'`. The default value for `x` is `'center'`.
111+
112+
`y` value must be either a number or one of the following options: `'top'`, `'center'`, `'bottom'`. The default value for `y` is 'bottom'.
113+
114+
```js
115+
Subtitles.position('center', 'top')
116+
Subtitles.position(100, 100)
117+
```
118+
119+
### viewport
120+
121+
Sets the width and height for the viewport of the Subtitles text. The viewport is the area in which the Subtitles text will be displayed. By default, Subtitles assumes the viewport is the same size as the App. If your video player is smaller, you can set the viewport to match the size of the video player to correctly position the Subtitles text.
122+
123+
The first argument is the width of the viewport, the second argument is the height of the viewport.
124+
125+
126+
```js
127+
Subtitles.viewport(854, 480)
128+
```
129+
130+
### maxWidth
131+
132+
Sets the maximum width of the Subtitles text.
133+
134+
```js
135+
Subtitles.maxWidth(1200)
136+
```
137+
138+
### maxLines
139+
140+
Sets the maximum number of lines for the Subtitles text.
141+
142+
```js
143+
Subtitles.maxLines(2)
144+
```

index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,4 @@ export { default as TV } from './src/TV'
4343
export { default as Utils } from './src/Utils'
4444
export { default as VideoPlayer } from './src/VideoPlayer'
4545
export { default as Metadata } from './src/Metadata'
46+
export { default as Subtitles } from './src/Subtitles'

src/Subtitles/SubtitleComponent.js

Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
/*
2+
* If not stated otherwise in this file or this component's LICENSE file the
3+
* following copyright and licenses apply:
4+
*
5+
* Copyright 2020 Metrological
6+
*
7+
* Licensed under the Apache License, Version 2.0 (the License);
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
*/
19+
20+
import Lightning from '../Lightning'
21+
22+
export default class SubtitleComponent extends Lightning.Component {
23+
static _template() {
24+
return {
25+
visible: false,
26+
rect: true,
27+
color: 0x90000000,
28+
shader: { type: Lightning.shaders.RoundedRectangle, radius: 5 },
29+
Text: {
30+
y: 5,
31+
x: 20,
32+
text: {
33+
fontColor: 0xffffffff,
34+
fontSize: 38,
35+
lineHeight: 38 * 1.4,
36+
textAlign: 'center',
37+
wordWrap: true,
38+
maxLines: 3,
39+
shadow: true,
40+
shadowColor: 0xff333333,
41+
},
42+
},
43+
}
44+
}
45+
46+
_init() {
47+
this._textTextureDefaults = new Lightning.textures.TextTexture(this.stage).cloneArgs()
48+
49+
this.tag('Text').on('txLoaded', ({ _source }) => {
50+
this.w = _source.w + this.tag('Text').x * 2
51+
this.h = _source.h
52+
this.position()
53+
})
54+
}
55+
56+
get textFormat() {
57+
const textTag = this.tag('Text').text
58+
return {
59+
fontFace: textTag.fontFace || 'sans-serif',
60+
fontSize: textTag.fontSize,
61+
lineHeight: textTag.lineHeight,
62+
textAlign: textTag.textAlign,
63+
wordWrap: true,
64+
maxLines: textTag.maxLines,
65+
}
66+
}
67+
68+
show() {
69+
this.visible = true
70+
}
71+
72+
hide() {
73+
this.visible = false
74+
}
75+
76+
position() {
77+
this.x = this._calculateX(this.xPos)
78+
this.y = this._calculateY(this.yPos)
79+
}
80+
81+
set viewportW(v) {
82+
this._viewportW = v
83+
this.x = this._calculateX(this.xPos)
84+
}
85+
86+
get viewportW() {
87+
return this._viewportW || this.application.finalW
88+
}
89+
90+
set viewportH(v) {
91+
this._viewportH = v
92+
this.y = this._calculateY(this.yPos)
93+
}
94+
95+
get viewportH() {
96+
return this._viewportH || this.application.finalH
97+
}
98+
99+
_calculateX(x) {
100+
if (x === 'center') {
101+
x = (this.viewportW - this.finalW) / 2
102+
} else if (x === 'left') {
103+
x = 60
104+
} else if (x === 'right') {
105+
x = this.viewportW - this.finalW - 60
106+
}
107+
return x
108+
}
109+
110+
set xPos(v) {
111+
this._x = v
112+
this.x = this._calculateX(v)
113+
}
114+
115+
get xPos() {
116+
return this._x || 'center'
117+
}
118+
119+
_calculateY(y) {
120+
if (y === 'center') {
121+
return (this.viewportH - this.finalH) / 2
122+
} else if (y === 'top') {
123+
return 60
124+
} else if (y === 'bottom') {
125+
return this.viewportH - this.finalH - 60
126+
}
127+
return y
128+
}
129+
130+
set yPos(v) {
131+
this._y = v
132+
this.y = this._calculateY(v)
133+
}
134+
135+
get yPos() {
136+
return this._y || 'bottom'
137+
}
138+
139+
set fontFamily(v) {
140+
this.tag('Text').text.fontFace = v
141+
}
142+
143+
set fontSize(v) {
144+
this.tag('Text').text.fontSize = v
145+
this.tag('Text').text.lineHeight = v * 1.3
146+
}
147+
148+
set fontColor(v) {
149+
this.tag('Text').color = v
150+
}
151+
152+
set backgroundColor(v) {
153+
this.color = v
154+
}
155+
156+
_defineBreakpoint(text, breakpoint) {
157+
if (breakpoint >= this.maxWidth) return this.maxWidth
158+
const info = Lightning.textures.TextTexture.renderer(
159+
this.stage,
160+
this.stage.platform.getDrawingCanvas(),
161+
{
162+
...this._textTextureDefaults,
163+
...this.textFormat,
164+
...{ wordWrapWidth: breakpoint },
165+
text,
166+
}
167+
)._calculateRenderInfo()
168+
169+
if (info.width <= breakpoint && info.lines.length <= 2) {
170+
return breakpoint
171+
} else {
172+
return this._defineBreakpoint(text, breakpoint * 1.25)
173+
}
174+
}
175+
176+
set text(v) {
177+
this.alpha = 0
178+
if (v && v.length) {
179+
const breakpoint = this._defineBreakpoint(v, 640)
180+
181+
this.tag('Text').text.wordWrapWidth = breakpoint
182+
this.tag('Text').text = v
183+
this.alpha = 1
184+
}
185+
}
186+
187+
set textAlign(v) {
188+
this._textAlign = v
189+
this.tag('Text').text.textAlign = v
190+
}
191+
192+
set maxWidth(v) {
193+
this._maxWidth = v
194+
}
195+
196+
get maxWidth() {
197+
return (this._maxWidth || 1200) - this.tag('Text').x * 2
198+
}
199+
200+
set maxLines(v) {
201+
this.tag('Text').text.maxLines = v
202+
}
203+
}

0 commit comments

Comments
 (0)