├── .gitattributes ├── .gitignore ├── LICENSE ├── README.md ├── assets ├── bbb-sprite.jpg └── top-17.jpg ├── create.js ├── output ├── bbb-thumbnails.vtt └── top-17-thumbnails.vtt └── package.json /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows image file caches 2 | Thumbs.db 3 | ehthumbs.db 4 | 5 | # Folder config file 6 | Desktop.ini 7 | 8 | # Recycle Bin used on file shares 9 | $RECYCLE.BIN/ 10 | 11 | # Windows Installer files 12 | *.cab 13 | *.msi 14 | *.msm 15 | *.msp 16 | 17 | # Windows shortcuts 18 | *.lnk 19 | 20 | # node 21 | node_modules/ 22 | debug.log 23 | 24 | # VSC 25 | .vscode 26 | 27 | .eslintcache -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | rmp-create-vtt-thumbnails is released under MIT License. 4 | Terms are outlined below (from opensource.org) 5 | 6 | Radiant Media Player | https://www.radiantmediaplayer.com 7 | Copyright (c) 2020 Radiant Media Player 8 | Radiant Media Player is a commercial HTML5 media player, not covered by this MIT license. 9 | Radiant Media Player license can be found here: https://www.radiantmediaplayer.com/terms-of-service.html. 10 | You may request a free trial for Radiant Media Player at: https://www.radiantmediaplayer.com/free-trial.html. 11 | 12 | Permission is hereby granted, free of charge, to any person obtaining a copy of 13 | this software and associated documentation files (the "Software"), to deal in 14 | the Software without restriction, including without limitation the rights to 15 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 16 | of the Software, and to permit persons to whom the Software is furnished to do 17 | so, subject to the following conditions: 18 | 19 | The above copyright notice and this permission notice shall be included in all 20 | copies or substantial portions of the Software. 21 | 22 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 27 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 28 | IN THE SOFTWARE. 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # rmp-create-vtt-thumbnails 2 | 3 | A helper script to easily create VTT files that works with [Radiant Media Player preview thumbnails feature](https://www.radiantmediaplayer.com/docs/latest/preview-thumbnails.html) (could work with other players that follow the same VTT-based preview thumbnails implementation). 4 | 5 | This process has been tested for node.js 8.11+ on Windows 10 and Ubuntu 16 LTS. 6 | 7 | ## Documentation sections 8 | - [Create the mosaic of images](#create-the-mosaic-of-images) 9 | - [Create a VTT file that documents the mosaic of thumbnails](#create-a-vtt-file-that-documents-the-mosaic-of-thumbnails) 10 | - [Parameters documentation](#parameters-documentation) 11 | - [Issues](#issues) 12 | - [License for rmp-create-vtt-thumbnails](#license-for-rmp-create-vtt-thumbnails) 13 | - [Radiant Media Player](#radiant-media-player) 14 | 15 | ## Create the mosaic of images 16 | 17 | First you will need to create a mosaic of thumbnails with FFmpeg: 18 | 19 | - install [FFmpeg](https://www.ffmpeg.org/download.html) for your platform 20 | - get a MP4 file from the video you want to extract thumbnails from - a low quality version of that video will do 21 | - use the below command line to create the mosaic of iamges: 22 | 23 | ```bash 24 | ffmpeg -i input.mp4 -filter_complex "select='not(mod(n,120))',scale=128:72,tile=11x11" -frames:v 1 -qscale:v 3 -an mosaic.jpg 25 | ``` 26 | A couple of things to notice from the above commande line: 27 | 28 | - select='not(mod(n,120))': this is where we tell FFmpeg to only extract 1 frame every 120 frames (one frame every 5 seconds for a input.mp4 which runs at 24 FPS). 29 | - scale=128:72,tile=11x11: here we tell FFmpeg that the width of each item within the mosaic image should be 128px width and 72px height. In the above example of content has a 16:9 aspect ratio. The width of each item within the mosaic must be 128px. The height should be adjusted based on your content aspect ratio. We then need to tell FFmpeg what tile size should be used. In this case we need 11x11 because 596 (duration) / 5 (gap between each thumbnail frame) ~ 120 frames. So we need a mosaic that can hold at least 120 frames - the closest being 11x11 = 121 frames. 30 | - qscale:v you can adjust this value to reduce or augment the size/quality of your thumbnails (the lower the qscale:v value the better quality). 31 | 32 | ## Create a VTT file that documents the mosaic of thumbnails 33 | 34 | The WebVTT file consists of a list of cues with the following data: 35 | 36 | - The time-range the current thumbnail represents. Note that the range needs to be in (HH:)MM:SS.MMM format. Only this exact notation will be parsed. 37 | - The URI to the thumbnail for this time-range. The URI is relative to the WebVTT file location (not to the page). Each individual image from the mosaic of thumbnails can be located by appending its coordinates using spatial media fragment (xywh format). You can also have one specific URI for each image. 38 | 39 | To automatically create that VTT file, install the create.js script from this repository: 40 | ``` 41 | git clone https://github.com/radiantmediaplayer/rmp-create-vtt-thumbnails.git 42 | cd rmp-create-vtt-thumbnails 43 | node create.js 596 assets/bbb-sprite.jpg output/bbb-thumbnails.vtt 5 128 72 11 44 | ``` 45 | See assets/ folder for ready-to-use mosaic image examples. See output/ folder for examples of VTT files generated with the create.js script. 46 | 47 | ## Parameters documentation 48 | 49 | `node create.js duration spriteFileLocation outputVTTFileName gapBetweenFrames thumbnailWidth thumbnailHeight tileSize` 50 | 51 | All parameters are mandatory. 52 | 53 | `duration`: content duration in seconds 54 | 55 | `spriteFileLocation`: location for the mosaic image (a.k.a. sprite image) to reference in the resulting VTT file 56 | 57 | `outputVTTFileName`: location for the produced output VTT file 58 | 59 | `gapBetweenFrames`: the gap in seconds between frame extraction (value used for generating the mosaic image with FFmpeg) 60 | 61 | `thumbnailWidth`: the width of each thumbnail within the mosaic 62 | 63 | `thumbnailHeight`: the height of each thumbnail within the mosaic 64 | 65 | `tileSize`: the tile format used to generate the mosaic (value used for generating the mosaic image with FFmpeg: 11 for 11x11, 6 for 6x6 ...) 66 | 67 | ## Issues 68 | Issues should be submitted in this GitHub page. We will do our best to review them. 69 | 70 | ## License for rmp-create-vtt-thumbnails 71 | rmp-create-vtt-thumbnails is released under MIT. 72 | 73 | ## Radiant Media Player 74 | Radiant Media Player is a commercial HTML5 media player, not covered by the above MIT license. 75 | 76 | Radiant Media Player license can be found here: [https://www.radiantmediaplayer.com/terms-of-service.html](https://www.radiantmediaplayer.com/terms-of-service.html). 77 | 78 | You may request a free trial for Radiant Media Player at: [https://www.radiantmediaplayer.com/free-trial.html](https://www.radiantmediaplayer.com/free-trial.html). 79 | 80 | [Back to documentation sections](#documentation-sections) 81 | -------------------------------------------------------------------------------- /assets/bbb-sprite.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radiantmediaplayer/rmp-create-vtt-thumbnails/ad5f1832d09aed5a885a4fbbd43f1b6fb1491bc7/assets/bbb-sprite.jpg -------------------------------------------------------------------------------- /assets/top-17.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radiantmediaplayer/rmp-create-vtt-thumbnails/ad5f1832d09aed5a885a4fbbd43f1b6fb1491bc7/assets/top-17.jpg -------------------------------------------------------------------------------- /create.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | /** 4 | * @license Copyright (c) 2015-2020 Radiant Media Player 5 | * rmp-create-vtt-thumbnails 0.1.3 | https://github.com/radiantmediaplayer/rmp-create-vtt-thumbnails 6 | */ 7 | 8 | 'use strict'; 9 | 10 | const fs = require('fs'); 11 | const eol = require('os').EOL; 12 | 13 | // function to append data to our output VTT file 14 | const _appendFileSync = function (file, data) { 15 | try { 16 | fs.appendFileSync(file, data); 17 | } catch (err) { 18 | console.log(err); 19 | } 20 | }; 21 | 22 | // function to convert second-based time to HH:MM:SS.xxxx format required for VTT compliance 23 | // see https://www.w3.org/TR/webvtt1/#webvtt-timestamp 24 | const _secondsToHRTime = function (time) { 25 | if (typeof time === 'number' && time >= 0) { 26 | let seconds = Math.floor(time % 60); 27 | let minutes = Math.floor(time * 1.0 / 60); 28 | let hours = 0; 29 | if (minutes > 59) { 30 | hours = Math.floor(time * 1.0 / 3600); 31 | minutes = Math.floor((time - hours * 3600) / 60); 32 | seconds = Math.floor(time % 60); 33 | } 34 | if (seconds < 10) { 35 | seconds = '0' + seconds; 36 | } 37 | if (minutes < 10) { 38 | minutes = '0' + minutes; 39 | } 40 | if (hours > 0) { 41 | hours = hours + ':'; 42 | } else if (hours === 0) { 43 | hours = ''; 44 | } 45 | return hours + minutes + ':' + seconds + '.000'; 46 | } else { 47 | return ''; 48 | } 49 | }; 50 | 51 | 52 | // parsing input from our command line 53 | // input params are: duration spriteFileLocation outputVTTFileName gapBetweenFrames thumbnailWidth thumbnailHeight tileSize 54 | // example: node create.js 596 assets/bbb-sprite.jpg output/bbb-thumbnails.vtt 5 128 72 11 55 | let duration; 56 | let spriteFileLocation; 57 | let outputVTTFileName; 58 | let gapBetweenFrames; 59 | let thumbnailWidth; 60 | let thumbnailHeight; 61 | let tileSize; 62 | process.argv.forEach((value, index) => { 63 | switch (index) { 64 | case 2: 65 | duration = parseInt(value); 66 | break; 67 | case 3: 68 | spriteFileLocation = (value).toString(); 69 | break; 70 | case 4: 71 | outputVTTFileName = (value).toString(); 72 | break; 73 | case 5: 74 | gapBetweenFrames = parseInt(value); 75 | break; 76 | case 6: 77 | thumbnailWidth = parseInt(value); 78 | break; 79 | case 7: 80 | thumbnailHeight = parseInt(value); 81 | break; 82 | case 8: 83 | tileSize = parseInt(value); 84 | break; 85 | default: 86 | break; 87 | } 88 | }); 89 | 90 | 91 | if (!duration || !spriteFileLocation || !outputVTTFileName || !gapBetweenFrames || !thumbnailWidth || !thumbnailHeight || !tileSize) { 92 | console.log('Error: missing or invalid parameters in the command line'); 93 | return; 94 | } 95 | 96 | // delete VTT file if already exists 97 | try { 98 | fs.unlinkSync(outputVTTFileName); 99 | console.log(outputVTTFileName + ' already exists - deleted it'); 100 | } catch (err) { 101 | if (err && err.code === 'ENOENT') { 102 | console.log(outputVTTFileName + ' does not exist - will create it'); 103 | } 104 | } 105 | 106 | // append our initial VTT data for spec compliance 107 | const initialData = 'WEBVTT' + eol + eol; 108 | _appendFileSync(outputVTTFileName, initialData); 109 | 110 | // initial variables values for our loop 111 | const itemNumber = Math.floor(duration / gapBetweenFrames) + 1; 112 | let currentTime = 0; 113 | let xCoordinates = 0; 114 | let yCoordinates = 0; 115 | let thumbnailSizeString = ',' + thumbnailWidth + ',' + thumbnailHeight + eol + eol; 116 | 117 | // for each item append VTT data 118 | for (let i = 0, len = itemNumber; i <= len; i++) { 119 | if (currentTime > duration) { 120 | break; 121 | } 122 | let startTime = _secondsToHRTime(currentTime); 123 | currentTime += gapBetweenFrames; 124 | let endTime = _secondsToHRTime(currentTime); 125 | if (!startTime || !endTime) { 126 | console.log('Error: could not determine startTime or endTime for VTT item number ' + i + ' - exit'); 127 | return; 128 | } 129 | let string = startTime + ' --> ' + endTime + eol; 130 | string += spriteFileLocation + '#xywh=' + xCoordinates + ',' + yCoordinates; 131 | string += thumbnailSizeString; 132 | xCoordinates += thumbnailWidth; 133 | if (xCoordinates > (thumbnailWidth * (tileSize - 1))) { 134 | yCoordinates += thumbnailHeight; 135 | xCoordinates = 0; 136 | } 137 | _appendFileSync(outputVTTFileName, string); 138 | } 139 | 140 | -------------------------------------------------------------------------------- /output/bbb-thumbnails.vtt: -------------------------------------------------------------------------------- 1 | WEBVTT 2 | 3 | 00:00.000 --> 00:05.000 4 | assets/bbb-sprite.jpg#xywh=0,0,128,72 5 | 6 | 00:05.000 --> 00:10.000 7 | assets/bbb-sprite.jpg#xywh=128,0,128,72 8 | 9 | 00:10.000 --> 00:15.000 10 | assets/bbb-sprite.jpg#xywh=256,0,128,72 11 | 12 | 00:15.000 --> 00:20.000 13 | assets/bbb-sprite.jpg#xywh=384,0,128,72 14 | 15 | 00:20.000 --> 00:25.000 16 | assets/bbb-sprite.jpg#xywh=512,0,128,72 17 | 18 | 00:25.000 --> 00:30.000 19 | assets/bbb-sprite.jpg#xywh=640,0,128,72 20 | 21 | 00:30.000 --> 00:35.000 22 | assets/bbb-sprite.jpg#xywh=768,0,128,72 23 | 24 | 00:35.000 --> 00:40.000 25 | assets/bbb-sprite.jpg#xywh=896,0,128,72 26 | 27 | 00:40.000 --> 00:45.000 28 | assets/bbb-sprite.jpg#xywh=1024,0,128,72 29 | 30 | 00:45.000 --> 00:50.000 31 | assets/bbb-sprite.jpg#xywh=1152,0,128,72 32 | 33 | 00:50.000 --> 00:55.000 34 | assets/bbb-sprite.jpg#xywh=1280,0,128,72 35 | 36 | 00:55.000 --> 01:00.000 37 | assets/bbb-sprite.jpg#xywh=0,72,128,72 38 | 39 | 01:00.000 --> 01:05.000 40 | assets/bbb-sprite.jpg#xywh=128,72,128,72 41 | 42 | 01:05.000 --> 01:10.000 43 | assets/bbb-sprite.jpg#xywh=256,72,128,72 44 | 45 | 01:10.000 --> 01:15.000 46 | assets/bbb-sprite.jpg#xywh=384,72,128,72 47 | 48 | 01:15.000 --> 01:20.000 49 | assets/bbb-sprite.jpg#xywh=512,72,128,72 50 | 51 | 01:20.000 --> 01:25.000 52 | assets/bbb-sprite.jpg#xywh=640,72,128,72 53 | 54 | 01:25.000 --> 01:30.000 55 | assets/bbb-sprite.jpg#xywh=768,72,128,72 56 | 57 | 01:30.000 --> 01:35.000 58 | assets/bbb-sprite.jpg#xywh=896,72,128,72 59 | 60 | 01:35.000 --> 01:40.000 61 | assets/bbb-sprite.jpg#xywh=1024,72,128,72 62 | 63 | 01:40.000 --> 01:45.000 64 | assets/bbb-sprite.jpg#xywh=1152,72,128,72 65 | 66 | 01:45.000 --> 01:50.000 67 | assets/bbb-sprite.jpg#xywh=1280,72,128,72 68 | 69 | 01:50.000 --> 01:55.000 70 | assets/bbb-sprite.jpg#xywh=0,144,128,72 71 | 72 | 01:55.000 --> 02:00.000 73 | assets/bbb-sprite.jpg#xywh=128,144,128,72 74 | 75 | 02:00.000 --> 02:05.000 76 | assets/bbb-sprite.jpg#xywh=256,144,128,72 77 | 78 | 02:05.000 --> 02:10.000 79 | assets/bbb-sprite.jpg#xywh=384,144,128,72 80 | 81 | 02:10.000 --> 02:15.000 82 | assets/bbb-sprite.jpg#xywh=512,144,128,72 83 | 84 | 02:15.000 --> 02:20.000 85 | assets/bbb-sprite.jpg#xywh=640,144,128,72 86 | 87 | 02:20.000 --> 02:25.000 88 | assets/bbb-sprite.jpg#xywh=768,144,128,72 89 | 90 | 02:25.000 --> 02:30.000 91 | assets/bbb-sprite.jpg#xywh=896,144,128,72 92 | 93 | 02:30.000 --> 02:35.000 94 | assets/bbb-sprite.jpg#xywh=1024,144,128,72 95 | 96 | 02:35.000 --> 02:40.000 97 | assets/bbb-sprite.jpg#xywh=1152,144,128,72 98 | 99 | 02:40.000 --> 02:45.000 100 | assets/bbb-sprite.jpg#xywh=1280,144,128,72 101 | 102 | 02:45.000 --> 02:50.000 103 | assets/bbb-sprite.jpg#xywh=0,216,128,72 104 | 105 | 02:50.000 --> 02:55.000 106 | assets/bbb-sprite.jpg#xywh=128,216,128,72 107 | 108 | 02:55.000 --> 03:00.000 109 | assets/bbb-sprite.jpg#xywh=256,216,128,72 110 | 111 | 03:00.000 --> 03:05.000 112 | assets/bbb-sprite.jpg#xywh=384,216,128,72 113 | 114 | 03:05.000 --> 03:10.000 115 | assets/bbb-sprite.jpg#xywh=512,216,128,72 116 | 117 | 03:10.000 --> 03:15.000 118 | assets/bbb-sprite.jpg#xywh=640,216,128,72 119 | 120 | 03:15.000 --> 03:20.000 121 | assets/bbb-sprite.jpg#xywh=768,216,128,72 122 | 123 | 03:20.000 --> 03:25.000 124 | assets/bbb-sprite.jpg#xywh=896,216,128,72 125 | 126 | 03:25.000 --> 03:30.000 127 | assets/bbb-sprite.jpg#xywh=1024,216,128,72 128 | 129 | 03:30.000 --> 03:35.000 130 | assets/bbb-sprite.jpg#xywh=1152,216,128,72 131 | 132 | 03:35.000 --> 03:40.000 133 | assets/bbb-sprite.jpg#xywh=1280,216,128,72 134 | 135 | 03:40.000 --> 03:45.000 136 | assets/bbb-sprite.jpg#xywh=0,288,128,72 137 | 138 | 03:45.000 --> 03:50.000 139 | assets/bbb-sprite.jpg#xywh=128,288,128,72 140 | 141 | 03:50.000 --> 03:55.000 142 | assets/bbb-sprite.jpg#xywh=256,288,128,72 143 | 144 | 03:55.000 --> 04:00.000 145 | assets/bbb-sprite.jpg#xywh=384,288,128,72 146 | 147 | 04:00.000 --> 04:05.000 148 | assets/bbb-sprite.jpg#xywh=512,288,128,72 149 | 150 | 04:05.000 --> 04:10.000 151 | assets/bbb-sprite.jpg#xywh=640,288,128,72 152 | 153 | 04:10.000 --> 04:15.000 154 | assets/bbb-sprite.jpg#xywh=768,288,128,72 155 | 156 | 04:15.000 --> 04:20.000 157 | assets/bbb-sprite.jpg#xywh=896,288,128,72 158 | 159 | 04:20.000 --> 04:25.000 160 | assets/bbb-sprite.jpg#xywh=1024,288,128,72 161 | 162 | 04:25.000 --> 04:30.000 163 | assets/bbb-sprite.jpg#xywh=1152,288,128,72 164 | 165 | 04:30.000 --> 04:35.000 166 | assets/bbb-sprite.jpg#xywh=1280,288,128,72 167 | 168 | 04:35.000 --> 04:40.000 169 | assets/bbb-sprite.jpg#xywh=0,360,128,72 170 | 171 | 04:40.000 --> 04:45.000 172 | assets/bbb-sprite.jpg#xywh=128,360,128,72 173 | 174 | 04:45.000 --> 04:50.000 175 | assets/bbb-sprite.jpg#xywh=256,360,128,72 176 | 177 | 04:50.000 --> 04:55.000 178 | assets/bbb-sprite.jpg#xywh=384,360,128,72 179 | 180 | 04:55.000 --> 05:00.000 181 | assets/bbb-sprite.jpg#xywh=512,360,128,72 182 | 183 | 05:00.000 --> 05:05.000 184 | assets/bbb-sprite.jpg#xywh=640,360,128,72 185 | 186 | 05:05.000 --> 05:10.000 187 | assets/bbb-sprite.jpg#xywh=768,360,128,72 188 | 189 | 05:10.000 --> 05:15.000 190 | assets/bbb-sprite.jpg#xywh=896,360,128,72 191 | 192 | 05:15.000 --> 05:20.000 193 | assets/bbb-sprite.jpg#xywh=1024,360,128,72 194 | 195 | 05:20.000 --> 05:25.000 196 | assets/bbb-sprite.jpg#xywh=1152,360,128,72 197 | 198 | 05:25.000 --> 05:30.000 199 | assets/bbb-sprite.jpg#xywh=1280,360,128,72 200 | 201 | 05:30.000 --> 05:35.000 202 | assets/bbb-sprite.jpg#xywh=0,432,128,72 203 | 204 | 05:35.000 --> 05:40.000 205 | assets/bbb-sprite.jpg#xywh=128,432,128,72 206 | 207 | 05:40.000 --> 05:45.000 208 | assets/bbb-sprite.jpg#xywh=256,432,128,72 209 | 210 | 05:45.000 --> 05:50.000 211 | assets/bbb-sprite.jpg#xywh=384,432,128,72 212 | 213 | 05:50.000 --> 05:55.000 214 | assets/bbb-sprite.jpg#xywh=512,432,128,72 215 | 216 | 05:55.000 --> 06:00.000 217 | assets/bbb-sprite.jpg#xywh=640,432,128,72 218 | 219 | 06:00.000 --> 06:05.000 220 | assets/bbb-sprite.jpg#xywh=768,432,128,72 221 | 222 | 06:05.000 --> 06:10.000 223 | assets/bbb-sprite.jpg#xywh=896,432,128,72 224 | 225 | 06:10.000 --> 06:15.000 226 | assets/bbb-sprite.jpg#xywh=1024,432,128,72 227 | 228 | 06:15.000 --> 06:20.000 229 | assets/bbb-sprite.jpg#xywh=1152,432,128,72 230 | 231 | 06:20.000 --> 06:25.000 232 | assets/bbb-sprite.jpg#xywh=1280,432,128,72 233 | 234 | 06:25.000 --> 06:30.000 235 | assets/bbb-sprite.jpg#xywh=0,504,128,72 236 | 237 | 06:30.000 --> 06:35.000 238 | assets/bbb-sprite.jpg#xywh=128,504,128,72 239 | 240 | 06:35.000 --> 06:40.000 241 | assets/bbb-sprite.jpg#xywh=256,504,128,72 242 | 243 | 06:40.000 --> 06:45.000 244 | assets/bbb-sprite.jpg#xywh=384,504,128,72 245 | 246 | 06:45.000 --> 06:50.000 247 | assets/bbb-sprite.jpg#xywh=512,504,128,72 248 | 249 | 06:50.000 --> 06:55.000 250 | assets/bbb-sprite.jpg#xywh=640,504,128,72 251 | 252 | 06:55.000 --> 07:00.000 253 | assets/bbb-sprite.jpg#xywh=768,504,128,72 254 | 255 | 07:00.000 --> 07:05.000 256 | assets/bbb-sprite.jpg#xywh=896,504,128,72 257 | 258 | 07:05.000 --> 07:10.000 259 | assets/bbb-sprite.jpg#xywh=1024,504,128,72 260 | 261 | 07:10.000 --> 07:15.000 262 | assets/bbb-sprite.jpg#xywh=1152,504,128,72 263 | 264 | 07:15.000 --> 07:20.000 265 | assets/bbb-sprite.jpg#xywh=1280,504,128,72 266 | 267 | 07:20.000 --> 07:25.000 268 | assets/bbb-sprite.jpg#xywh=0,576,128,72 269 | 270 | 07:25.000 --> 07:30.000 271 | assets/bbb-sprite.jpg#xywh=128,576,128,72 272 | 273 | 07:30.000 --> 07:35.000 274 | assets/bbb-sprite.jpg#xywh=256,576,128,72 275 | 276 | 07:35.000 --> 07:40.000 277 | assets/bbb-sprite.jpg#xywh=384,576,128,72 278 | 279 | 07:40.000 --> 07:45.000 280 | assets/bbb-sprite.jpg#xywh=512,576,128,72 281 | 282 | 07:45.000 --> 07:50.000 283 | assets/bbb-sprite.jpg#xywh=640,576,128,72 284 | 285 | 07:50.000 --> 07:55.000 286 | assets/bbb-sprite.jpg#xywh=768,576,128,72 287 | 288 | 07:55.000 --> 08:00.000 289 | assets/bbb-sprite.jpg#xywh=896,576,128,72 290 | 291 | 08:00.000 --> 08:05.000 292 | assets/bbb-sprite.jpg#xywh=1024,576,128,72 293 | 294 | 08:05.000 --> 08:10.000 295 | assets/bbb-sprite.jpg#xywh=1152,576,128,72 296 | 297 | 08:10.000 --> 08:15.000 298 | assets/bbb-sprite.jpg#xywh=1280,576,128,72 299 | 300 | 08:15.000 --> 08:20.000 301 | assets/bbb-sprite.jpg#xywh=0,648,128,72 302 | 303 | 08:20.000 --> 08:25.000 304 | assets/bbb-sprite.jpg#xywh=128,648,128,72 305 | 306 | 08:25.000 --> 08:30.000 307 | assets/bbb-sprite.jpg#xywh=256,648,128,72 308 | 309 | 08:30.000 --> 08:35.000 310 | assets/bbb-sprite.jpg#xywh=384,648,128,72 311 | 312 | 08:35.000 --> 08:40.000 313 | assets/bbb-sprite.jpg#xywh=512,648,128,72 314 | 315 | 08:40.000 --> 08:45.000 316 | assets/bbb-sprite.jpg#xywh=640,648,128,72 317 | 318 | 08:45.000 --> 08:50.000 319 | assets/bbb-sprite.jpg#xywh=768,648,128,72 320 | 321 | 08:50.000 --> 08:55.000 322 | assets/bbb-sprite.jpg#xywh=896,648,128,72 323 | 324 | 08:55.000 --> 09:00.000 325 | assets/bbb-sprite.jpg#xywh=1024,648,128,72 326 | 327 | 09:00.000 --> 09:05.000 328 | assets/bbb-sprite.jpg#xywh=1152,648,128,72 329 | 330 | 09:05.000 --> 09:10.000 331 | assets/bbb-sprite.jpg#xywh=1280,648,128,72 332 | 333 | 09:10.000 --> 09:15.000 334 | assets/bbb-sprite.jpg#xywh=0,720,128,72 335 | 336 | 09:15.000 --> 09:20.000 337 | assets/bbb-sprite.jpg#xywh=128,720,128,72 338 | 339 | 09:20.000 --> 09:25.000 340 | assets/bbb-sprite.jpg#xywh=256,720,128,72 341 | 342 | 09:25.000 --> 09:30.000 343 | assets/bbb-sprite.jpg#xywh=384,720,128,72 344 | 345 | 09:30.000 --> 09:35.000 346 | assets/bbb-sprite.jpg#xywh=512,720,128,72 347 | 348 | 09:35.000 --> 09:40.000 349 | assets/bbb-sprite.jpg#xywh=640,720,128,72 350 | 351 | 09:40.000 --> 09:45.000 352 | assets/bbb-sprite.jpg#xywh=768,720,128,72 353 | 354 | 09:45.000 --> 09:50.000 355 | assets/bbb-sprite.jpg#xywh=896,720,128,72 356 | 357 | 09:50.000 --> 09:55.000 358 | assets/bbb-sprite.jpg#xywh=1024,720,128,72 359 | 360 | 09:55.000 --> 10:00.000 361 | assets/bbb-sprite.jpg#xywh=1152,720,128,72 362 | 363 | -------------------------------------------------------------------------------- /output/top-17-thumbnails.vtt: -------------------------------------------------------------------------------- 1 | WEBVTT 2 | 3 | 00:00.000 --> 00:05.000 4 | assets/top-17.jpg#xywh=0,0,128,68 5 | 6 | 00:05.000 --> 00:10.000 7 | assets/top-17.jpg#xywh=128,0,128,68 8 | 9 | 00:10.000 --> 00:15.000 10 | assets/top-17.jpg#xywh=256,0,128,68 11 | 12 | 00:15.000 --> 00:20.000 13 | assets/top-17.jpg#xywh=384,0,128,68 14 | 15 | 00:20.000 --> 00:25.000 16 | assets/top-17.jpg#xywh=512,0,128,68 17 | 18 | 00:25.000 --> 00:30.000 19 | assets/top-17.jpg#xywh=640,0,128,68 20 | 21 | 00:30.000 --> 00:35.000 22 | assets/top-17.jpg#xywh=0,68,128,68 23 | 24 | 00:35.000 --> 00:40.000 25 | assets/top-17.jpg#xywh=128,68,128,68 26 | 27 | 00:40.000 --> 00:45.000 28 | assets/top-17.jpg#xywh=256,68,128,68 29 | 30 | 00:45.000 --> 00:50.000 31 | assets/top-17.jpg#xywh=384,68,128,68 32 | 33 | 00:50.000 --> 00:55.000 34 | assets/top-17.jpg#xywh=512,68,128,68 35 | 36 | 00:55.000 --> 01:00.000 37 | assets/top-17.jpg#xywh=640,68,128,68 38 | 39 | 01:00.000 --> 01:05.000 40 | assets/top-17.jpg#xywh=0,136,128,68 41 | 42 | 01:05.000 --> 01:10.000 43 | assets/top-17.jpg#xywh=128,136,128,68 44 | 45 | 01:10.000 --> 01:15.000 46 | assets/top-17.jpg#xywh=256,136,128,68 47 | 48 | 01:15.000 --> 01:20.000 49 | assets/top-17.jpg#xywh=384,136,128,68 50 | 51 | 01:20.000 --> 01:25.000 52 | assets/top-17.jpg#xywh=512,136,128,68 53 | 54 | 01:25.000 --> 01:30.000 55 | assets/top-17.jpg#xywh=640,136,128,68 56 | 57 | 01:30.000 --> 01:35.000 58 | assets/top-17.jpg#xywh=0,204,128,68 59 | 60 | 01:35.000 --> 01:40.000 61 | assets/top-17.jpg#xywh=128,204,128,68 62 | 63 | 01:40.000 --> 01:45.000 64 | assets/top-17.jpg#xywh=256,204,128,68 65 | 66 | 01:45.000 --> 01:50.000 67 | assets/top-17.jpg#xywh=384,204,128,68 68 | 69 | 01:50.000 --> 01:55.000 70 | assets/top-17.jpg#xywh=512,204,128,68 71 | 72 | 01:55.000 --> 02:00.000 73 | assets/top-17.jpg#xywh=640,204,128,68 74 | 75 | 02:00.000 --> 02:05.000 76 | assets/top-17.jpg#xywh=0,272,128,68 77 | 78 | 02:05.000 --> 02:10.000 79 | assets/top-17.jpg#xywh=128,272,128,68 80 | 81 | 02:10.000 --> 02:15.000 82 | assets/top-17.jpg#xywh=256,272,128,68 83 | 84 | 02:15.000 --> 02:20.000 85 | assets/top-17.jpg#xywh=384,272,128,68 86 | 87 | 02:20.000 --> 02:25.000 88 | assets/top-17.jpg#xywh=512,272,128,68 89 | 90 | 02:25.000 --> 02:30.000 91 | assets/top-17.jpg#xywh=640,272,128,68 92 | 93 | 02:30.000 --> 02:35.000 94 | assets/top-17.jpg#xywh=0,340,128,68 95 | 96 | 02:35.000 --> 02:40.000 97 | assets/top-17.jpg#xywh=128,340,128,68 98 | 99 | 02:40.000 --> 02:45.000 100 | assets/top-17.jpg#xywh=256,340,128,68 101 | 102 | 02:45.000 --> 02:50.000 103 | assets/top-17.jpg#xywh=384,340,128,68 104 | 105 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rmp-create-vtt-thumbnails", 3 | "version": "0.1.3", 4 | "author": "Radiant Media Player ", 5 | "description": "Generate a VTT file and mosaic of thumbnails for Radiant Media Player preview thumbnails feature", 6 | "repository": { 7 | "type": "git", 8 | "url": "git+https://github.com/radiantmediaplayer/rmp-create-vtt-thumbnails.git" 9 | }, 10 | "main": "create.js", 11 | "keywords": [ 12 | "thumbnails", 13 | "thumbnail", 14 | "preview", 15 | "VTT", 16 | "ffmpeg", 17 | "image", 18 | "sprite", 19 | "video", 20 | "html5", 21 | "player" 22 | ], 23 | "license": "MIT", 24 | "bugs": { 25 | "url": "https://github.com/radiantmediaplayer/rmp-create-vtt-thumbnails/issues" 26 | }, 27 | "homepage": "https://www.radiantmediaplayer.com/docs/latest/preview-thumbnails.html" 28 | } 29 | --------------------------------------------------------------------------------