Compare commits

...

58 Commits

Author SHA1 Message Date
0acf228dcd v3.6.10
- Fix: Use `list.slash` instead of deprecated syntax
- Chore: Clean up demo
2021-12-16 20:51:31 +11:00
91b19baf44 fix: use list.slash instead of deprecated syntax 2021-12-16 20:29:36 +11:00
990d636019 chore: clean up demo 2021-12-16 20:29:36 +11:00
b9c792b377 Fix repeated "an" (#2371) 2021-11-28 22:51:21 +11:00
d9f9dc770b 3.6.9 2021-10-13 21:48:22 +11:00
dca2ff8cfd chore: linting 2021-10-13 21:45:30 +11:00
cf8e9341f2 fix: revert math.div SASS fallback 2021-09-29 22:07:42 +10:00
5d1d247491 chore: minor code style tweak 2021-09-29 21:44:15 +10:00
fbf4d27cd4 chore: fix SASS build 2021-09-29 21:44:02 +10:00
e0b70d53cd fix: wrap localStorage sets in try/catch 2021-09-29 21:43:52 +10:00
9f7725cec1 chore: package upgrades 2021-09-29 21:43:09 +10:00
720cddff21 fix: add SASS div method fallback 2021-09-29 21:42:41 +10:00
1c33098c42 (fix): youtube videos duration (ref #2223). (#2224)
Co-authored-by: Denis Semionov <denis.semionov@prewise.com>
2021-09-29 21:14:43 +10:00
b256c102e8 Vimeo private videos: check for hash in src and add as a param (#2322)
* check for hash in src and add as a param

* Enable different methods of passing hash
2021-09-29 21:14:43 +10:00
a3716fc491 chore: update node version 2021-09-29 21:14:43 +10:00
14e276a11d fix: video height issue 2021-09-29 21:14:43 +10:00
fc85a63af4 Fix invalid CSS selector syntax (#2303)
https://jigsaw.w3.org/css-validator/ complains that "The selector :empty can't appear after the pseudo-element selector ::after". Switching their places, however, will validate.
2021-09-29 21:14:43 +10:00
f016a367b5 Fixed errors when Plyr instance is destroyed before constructor setTimeout() functions execute. (#2108)
Co-authored-by: Emilis Dambauskas <emilis.dambauskas@mps.fi>
2021-09-29 21:14:43 +10:00
d41a90f0dd change fullscreen element to player rootnode (#2204)
Co-authored-by: Walter van den Houten <63712489+wdfvdhouten@users.noreply.github.com>
2021-09-29 21:10:54 +10:00
9d751f4265 README: Link to svelte project (#2242) 2021-09-29 21:07:45 +10:00
ff2c224254 Added preview thumbnails setter & fixed cannot set property 'hover' of null (#2256)
* added iPad to isIos

* elements.controls can be null

* elements.controls can be null

* added previewThumbnails setter

* fixed readme formatting

* previewThumbnails setter to method
2021-09-29 21:07:15 +10:00
1135b1acac Fix types - add tagUrl in ads option with custom VAST (#2319) 2021-09-29 21:05:56 +10:00
30ffb30a97 Fixes iOS fullscreen not centered issue. (#2284) 2021-09-29 21:05:15 +10:00
d1a10386c0 chore(deps): bump ws from 7.4.3 to 7.4.6 (#2226)
Bumps [ws](https://github.com/websockets/ws) from 7.4.3 to 7.4.6.
- [Release notes](https://github.com/websockets/ws/releases)
- [Commits](https://github.com/websockets/ws/compare/7.4.3...7.4.6)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-08-25 00:13:41 +10:00
4d6ac4ade1 chore: update plyr.d.ts for right ts check (#2245) 2021-08-24 23:18:09 +10:00
c2bfe489ea Let icons load in iframes without a location (#2259)
Currently, icons will fail to load if the player is placed inside an iframe without a window.location. This adds an additional check to use `window.top.location` if the window does not have a location.
2021-08-24 23:16:30 +10:00
882952bba6 fix: fixed captions when switching source (#2261) 2021-08-24 23:15:45 +10:00
784f36921b Update video.scss (#2296) 2021-08-24 22:30:13 +10:00
b7dbdc133e chore(deps): bump path-parse from 1.0.6 to 1.0.7 (#2301)
Bumps [path-parse](https://github.com/jbgutierrez/path-parse) from 1.0.6 to 1.0.7.
- [Release notes](https://github.com/jbgutierrez/path-parse/releases)
- [Commits](https://github.com/jbgutierrez/path-parse/commits/v1.0.7)

---
updated-dependencies:
- dependency-name: path-parse
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-08-24 22:28:42 +10:00
6caa2f3fed chore(deps): bump hosted-git-info from 2.8.8 to 2.8.9 (#2268)
Bumps [hosted-git-info](https://github.com/npm/hosted-git-info) from 2.8.8 to 2.8.9.
- [Release notes](https://github.com/npm/hosted-git-info/releases)
- [Changelog](https://github.com/npm/hosted-git-info/blob/v2.8.9/CHANGELOG.md)
- [Commits](https://github.com/npm/hosted-git-info/compare/v2.8.8...v2.8.9)

---
updated-dependencies:
- dependency-name: hosted-git-info
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-07-06 08:23:00 +10:00
3a01837561 fix: allow local builds without git 2021-07-06 08:12:51 +10:00
ba4bdb335a docs: update placehold.it references 2021-07-06 08:11:23 +10:00
ba236c4753 v3.6.8 2021-05-12 23:40:37 +10:00
a204f7c1dd Merge branch 'develop' 2021-05-12 23:37:34 +10:00
bacf9122de chore: update nvmrc to 14 2021-05-12 23:37:05 +10:00
2fdc1eac94 chore: lock file 2021-05-12 23:37:05 +10:00
5fd4391cd9 fix: fullscreen issues with Vimeo (fixes #2175) 2021-05-12 23:37:05 +10:00
6991358428 Add container to FullscreenOptions (#2161) 2021-05-12 23:35:01 +10:00
b050fde276 added iPad to isIos (#2191) 2021-05-12 23:33:48 +10:00
32444c9851 v3.6.7
- Fix: remove regression caused by optional chaining and nullish coalescing in check for `window.CSS` check for aspect-ratio (fixes #2174)
2021-04-20 08:28:23 +10:00
b93dcc43ad fix: minor syntax tweak 2021-04-19 21:16:30 +10:00
6ff6ff1673 fix: syntax fix (#2176) 2021-04-19 21:13:06 +10:00
e1ff86820c v3.6.6
- Improvements to how aspect ratio is handled. Use `aspect-ratio` CSS property instead of the legacy method (still used as fallback). Also automatically determined aspect ratios are rounded to the nearast standard ratio. This fixes issues with the YouTube embeds showing a 1-2px black bar.
- Hide the YouTube poster image container when paused so that the controls underneath can be used.
2021-04-18 17:49:23 +10:00
7d22c361d1 chore: remove fastly purging logic (#2173) 2021-04-18 17:41:58 +10:00
951cccb6b0 fix: youtube poster allow clickthrough while paused (#2172) 2021-04-18 16:59:00 +10:00
438e425838 fix: aspect ratio improvements (#2171)
- Use CSS aspect-ratio (retain fallback for legacy browsers)
- Round aspect ratios (fixes YouTube black border issue)
2021-04-18 16:58:44 +10:00
ddb5ad071e chore: deploy 2021-04-17 00:30:30 +10:00
38060d986c chore: release 2021-04-17 00:27:07 +10:00
8c74396459 chore: linting 2021-04-17 00:27:07 +10:00
a09d63e8f8 chore(deps): bump is-svg from 4.2.1 to 4.3.1 (#2148)
Bumps [is-svg](https://github.com/sindresorhus/is-svg) from 4.2.1 to 4.3.1.
- [Release notes](https://github.com/sindresorhus/is-svg/releases)
- [Commits](https://github.com/sindresorhus/is-svg/compare/v4.2.1...v4.3.1)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-04-17 00:23:18 +10:00
d74af9a73d fix: regression regarding poster image 2021-04-17 00:19:57 +10:00
60310693d3 chore: packge updates, switch to cssnano 2021-04-17 00:19:41 +10:00
5d08821c9b fix: missing styles for embeds 2021-04-17 00:19:05 +10:00
3316e40e7b fix: issue with IE detection 2021-04-17 00:17:53 +10:00
dfe5985326 added Runway360 to list of sites using plyr (#2117) 2021-03-27 19:48:11 +11:00
b27ad17c59 Migrate color formatting to colorette (#2124) 2021-03-27 19:46:41 +11:00
14b8b24e14 Merge pull request #2152 from didrip/fix-vimeo-video-play-chrome-89
add all required props to vimeo iframe allow attribute - fixes #2151
2021-03-26 20:50:53 +11:00
711fc5835f add all required props to vimeo iframe allow attribute - fixes #2151 2021-03-24 14:06:50 +01:00
42 changed files with 3046 additions and 3723 deletions

2
.nvmrc
View File

@ -1 +1 @@
v12.8 16

View File

@ -1,3 +1,46 @@
### v3.6.10
- Fix: Use `list.slash` instead of deprecated syntax
- Chore: Clean up demo
### v3.6.9
- Fix: SASS issue with division (thanks @ROL4ND909 and @le0pard)
- Fix: Captions when switching sources (thanks @zexingguo)
- Fix: Icons loading within iframes (thanks @ajgagnon)
- Chore: Update TypeScript types (thanks @Jackie1210 and @AntLevin)
- Fix: iOS fullscreen centering (thanks @hemratna)
- Feat: Added getter and setter for preview thumbnails (thanks @Benny739)
- Fix: Change fullscreen element to player rootnode (thanks @Walter van den Houten)
- Fix: Fixed errors when Plyr instance is destroyed before constructor setTimeout() functions execute (thanks @emilis-ideait)
- Fix: Invalid CSS selector syntax (thanks @BjornBrandewallNaviga)
- Fix: Video height issues
- Feat: Improve support for Vimeo private videos (thanks @Frosch)
- Fix: YouTube duration issues (thanks @liesahead)
### v3.6.8
- Typings: add FullscreenOptions.container to typing files (thanks @MeguminSama!)
- Fix: added iPadOS detection to isIos util (thanks @Benny739!)
- Fix: issues with Vimeo fullscreen
### v3.6.7
- Fix: remove regression caused by optional chaining and nullish coalescing in check for `window.CSS` check for aspect-ratio (fixes #2174)
### v3.6.6
- Improvements to how aspect ratio is handled. Use `aspect-ratio` CSS property instead of the legacy method (still used as fallback). Also automatically determined aspect ratios are rounded to the nearast standard ratio. This fixes issues with the YouTube embeds showing a 1-2px black bar.
- Hide the YouTube poster image container when paused so that the controls underneath can be used.
### v3.6.5
- Migrate color formatting to colorette (thanks @jorgebucaran)
- Fix: issue with IE detection
- Fix: missing styles for embeds
- Fix: regression regarding poster image
- Add all required props to vimeo iframe allow attribute - fixes #2151 (thanks @didrip)
### v3.6.4 ### v3.6.4
- Remove unnecessary calc from media query (thanks @naomiaz) - Remove unnecessary calc from media query (thanks @naomiaz)

View File

@ -134,13 +134,13 @@ See [initialising](#initialising) for more information on advanced setups.
You can use our CDN (provided by [Fastly](https://www.fastly.com/)) for the JavaScript. There's 2 versions; one with and one without [polyfills](#polyfills). My recommendation would be to manage polyfills seperately as part of your application but to make life easier you can use the polyfilled build. You can use our CDN (provided by [Fastly](https://www.fastly.com/)) for the JavaScript. There's 2 versions; one with and one without [polyfills](#polyfills). My recommendation would be to manage polyfills seperately as part of your application but to make life easier you can use the polyfilled build.
```html ```html
<script src="https://cdn.plyr.io/3.6.4/plyr.js"></script> <script src="https://cdn.plyr.io/3.6.10/plyr.js"></script>
``` ```
...or... ...or...
```html ```html
<script src="https://cdn.plyr.io/3.6.4/plyr.polyfilled.js"></script> <script src="https://cdn.plyr.io/3.6.10/plyr.polyfilled.js"></script>
``` ```
## CSS ## CSS
@ -154,13 +154,13 @@ Include the `plyr.css` stylsheet into your `<head>`.
If you want to use our CDN (provided by [Fastly](https://www.fastly.com/)) for the default CSS, you can use the following: If you want to use our CDN (provided by [Fastly](https://www.fastly.com/)) for the default CSS, you can use the following:
```html ```html
<link rel="stylesheet" href="https://cdn.plyr.io/3.6.4/plyr.css" /> <link rel="stylesheet" href="https://cdn.plyr.io/3.6.10/plyr.css" />
``` ```
## SVG Sprite ## SVG Sprite
The SVG sprite is loaded automatically from our CDN (provided by [Fastly](https://www.fastly.com/)). To change this, see the [options](#options) below. For The SVG sprite is loaded automatically from our CDN (provided by [Fastly](https://www.fastly.com/)). To change this, see the [options](#options) below. For
reference, the CDN hosted SVG sprite can be found at `https://cdn.plyr.io/3.6.4/plyr.svg`. reference, the CDN hosted SVG sprite can be found at `https://cdn.plyr.io/3.6.10/plyr.svg`.
# Ads # Ads
@ -184,43 +184,43 @@ Here's a list of the properties and what they are used for:
| Name | Description | Default / Fallback | | Name | Description | Default / Fallback |
| ---------------------------------------------- | ------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------- | | ---------------------------------------------- | ------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------- |
| `--plyr-color-main` | The primary UI color. | ![#f03c15](https://placehold.it/15/00b3ff/000000?text=+) `#00b3ff` | | `--plyr-color-main` | The primary UI color. | ![#f03c15](https://place-hold.it/15/00b3ff/000000?text=+) `#00b3ff` |
| `--plyr-video-background` | The background color of video and poster wrappers for using alpha channel videos and poster images. | `rgba(0, 0, 0, 1)` | | `--plyr-video-background` | The background color of video and poster wrappers for using alpha channel videos and poster images. | `rgba(0, 0, 0, 1)` |
| `--plyr-tab-focus-color` | The color used for the dotted outline when an element is `:focus-visible` (equivalent) keyboard focus. | `--plyr-color-main` | | `--plyr-tab-focus-color` | The color used for the dotted outline when an element is `:focus-visible` (equivalent) keyboard focus. | `--plyr-color-main` |
| `--plyr-badge-background` | The background color for badges in the menu. | ![#4a5464](https://placehold.it/15/4a5464/000000?text=+) `#4a5464` | | `--plyr-badge-background` | The background color for badges in the menu. | ![#4a5464](https://place-hold.it/15/4a5464/000000?text=+) `#4a5464` |
| `--plyr-badge-text-color` | The text color for badges. | ![#ffffff](https://placehold.it/15/ffffff/000000?text=+) `#ffffff` | | `--plyr-badge-text-color` | The text color for badges. | ![#ffffff](https://place-hold.it/15/ffffff/000000?text=+) `#ffffff` |
| `--plyr-badge-border-radius` | The border radius used for badges. | `2px` | | `--plyr-badge-border-radius` | The border radius used for badges. | `2px` |
| `--plyr-tab-focus-color` | The color used to highlight tab (keyboard) focus. | `--plyr-color-main` | | `--plyr-tab-focus-color` | The color used to highlight tab (keyboard) focus. | `--plyr-color-main` |
| `--plyr-captions-background` | The color for the background of captions. | `rgba(0, 0, 0, 0.8)` | | `--plyr-captions-background` | The color for the background of captions. | `rgba(0, 0, 0, 0.8)` |
| `--plyr-captions-text-color` | The color used for the captions text. | ![#ffffff](https://placehold.it/15/ffffff/000000?text=+) `#ffffff` | | `--plyr-captions-text-color` | The color used for the captions text. | ![#ffffff](https://place-hold.it/15/ffffff/000000?text=+) `#ffffff` |
| `--plyr-control-icon-size` | The size of the icons used in the controls. | `18px` | | `--plyr-control-icon-size` | The size of the icons used in the controls. | `18px` |
| `--plyr-control-spacing` | The space between controls (sometimes used in a multiple - e.g. `10px / 2 = 5px`). | `10px` | | `--plyr-control-spacing` | The space between controls (sometimes used in a multiple - e.g. `10px / 2 = 5px`). | `10px` |
| `--plyr-control-padding` | The padding inside controls. | `--plyr-control-spacing * 0.7` (`7px`) | | `--plyr-control-padding` | The padding inside controls. | `--plyr-control-spacing * 0.7` (`7px`) |
| `--plyr-control-radius` | The border radius used on controls. | `3px` | | `--plyr-control-radius` | The border radius used on controls. | `3px` |
| `--plyr-control-toggle-checked-background` | The background color used for checked menu items. | `--plyr-color-main` | | `--plyr-control-toggle-checked-background` | The background color used for checked menu items. | `--plyr-color-main` |
| `--plyr-video-controls-background` | The background for the video controls. | `linear-gradient(rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.75))` | | `--plyr-video-controls-background` | The background for the video controls. | `linear-gradient(rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.75))` |
| `--plyr-video-control-color` | The text/icon color for video controls. | ![#ffffff](https://placehold.it/15/ffffff/000000?text=+) `#ffffff` | | `--plyr-video-control-color` | The text/icon color for video controls. | ![#ffffff](https://place-hold.it/15/ffffff/000000?text=+) `#ffffff` |
| `--plyr-video-control-color-hover` | The text/icon color used when video controls are `:hover`, `:focus` and `:focus-visible` (equivalent). | ![#ffffff](https://placehold.it/15/ffffff/000000?text=+) `#ffffff` | | `--plyr-video-control-color-hover` | The text/icon color used when video controls are `:hover`, `:focus` and `:focus-visible` (equivalent). | ![#ffffff](https://place-hold.it/15/ffffff/000000?text=+) `#ffffff` |
| `--plyr-video-control-background-hover` | The background color used when video controls are `:hover`, `:focus` and `:focus-visible` (equivalent). | `--plyr-color-main` | | `--plyr-video-control-background-hover` | The background color used when video controls are `:hover`, `:focus` and `:focus-visible` (equivalent). | `--plyr-color-main` |
| `--plyr-audio-controls-background` | The background for the audio controls. | ![#ffffff](https://placehold.it/15/ffffff/000000?text=+) `#ffffff` | | `--plyr-audio-controls-background` | The background for the audio controls. | ![#ffffff](https://place-hold.it/15/ffffff/000000?text=+) `#ffffff` |
| `--plyr-audio-control-color` | The text/icon color for audio controls. | ![#4a5464](https://placehold.it/15/4a5464/000000?text=+) `#4a5464` | | `--plyr-audio-control-color` | The text/icon color for audio controls. | ![#4a5464](https://place-hold.it/15/4a5464/000000?text=+) `#4a5464` |
| `--plyr-audio-control-color-hover` | The text/icon color used when audio controls are `:hover`, `:focus` and `:focus-visible` (equivalent). | ![#ffffff](https://placehold.it/15/ffffff/000000?text=+) `#ffffff` | | `--plyr-audio-control-color-hover` | The text/icon color used when audio controls are `:hover`, `:focus` and `:focus-visible` (equivalent). | ![#ffffff](https://place-hold.it/15/ffffff/000000?text=+) `#ffffff` |
| `--plyr-audio-control-background-hover` | The background color used when video controls are `:hover`, `:focus` and `:focus-visible` (equivalent). | `--plyr-color-main` | | `--plyr-audio-control-background-hover` | The background color used when video controls are `:hover`, `:focus` and `:focus-visible` (equivalent). | `--plyr-color-main` |
| `--plyr-menu-background` | The background color for menus. | `rgba(255, 255, 255, 0.9)` | | `--plyr-menu-background` | The background color for menus. | `rgba(255, 255, 255, 0.9)` |
| `--plyr-menu-color` | The text/icon color for menu items. | ![#4a5464](https://placehold.it/15/4a5464/000000?text=+) `#4a5464` | | `--plyr-menu-color` | The text/icon color for menu items. | ![#4a5464](https://place-hold.it/15/4a5464/000000?text=+) `#4a5464` |
| `--plyr-menu-shadow` | The shadow used on menus. | `0 1px 2px rgba(0, 0, 0, 0.15)` | | `--plyr-menu-shadow` | The shadow used on menus. | `0 1px 2px rgba(0, 0, 0, 0.15)` |
| `--plyr-menu-radius` | The border radius on the menu. | `4px` | | `--plyr-menu-radius` | The border radius on the menu. | `4px` |
| `--plyr-menu-arrow-size` | The size of the arrow on the bottom of the menu. | `6px` | | `--plyr-menu-arrow-size` | The size of the arrow on the bottom of the menu. | `6px` |
| `--plyr-menu-item-arrow-color` | The color of the arrows in the menu. | ![#728197](https://placehold.it/15/728197/000000?text=+) `#728197` | | `--plyr-menu-item-arrow-color` | The color of the arrows in the menu. | ![#728197](https://place-hold.it/15/728197/000000?text=+) `#728197` |
| `--plyr-menu-item-arrow-size` | The size of the arrows in the menu. | `4px` | | `--plyr-menu-item-arrow-size` | The size of the arrows in the menu. | `4px` |
| `--plyr-menu-border-color` | The border color for the bottom of the back button in the top of the sub menu pages. | ![#dcdfe5](https://placehold.it/15/dcdfe5/000000?text=+) `#dcdfe5` | | `--plyr-menu-border-color` | The border color for the bottom of the back button in the top of the sub menu pages. | ![#dcdfe5](https://place-hold.it/15/dcdfe5/000000?text=+) `#dcdfe5` |
| `--plyr-menu-border-shadow-color` | The shadow below the border of the back button in the top of the sub menu pages. | ![#ffffff](https://placehold.it/15/ffffff/000000?text=+) `#ffffff` | | `--plyr-menu-border-shadow-color` | The shadow below the border of the back button in the top of the sub menu pages. | ![#ffffff](https://place-hold.it/15/ffffff/000000?text=+) `#ffffff` |
| `--plyr-progress-loading-size` | The size of the stripes in the loading state in the scrubber. | `25px` | | `--plyr-progress-loading-size` | The size of the stripes in the loading state in the scrubber. | `25px` |
| `--plyr-progress-loading-background` | The background color on the loading state in the scrubber. | `rgba(35, 40, 47, 0.6)` | | `--plyr-progress-loading-background` | The background color on the loading state in the scrubber. | `rgba(35, 40, 47, 0.6)` |
| `--plyr-video-progress-buffered-background` | The fill color for the buffer indication in the scrubber for video. | `rgba(255, 255, 255, 0.25)` | | `--plyr-video-progress-buffered-background` | The fill color for the buffer indication in the scrubber for video. | `rgba(255, 255, 255, 0.25)` |
| `--plyr-audio-progress-buffered-background` | The fill color for the buffer indication in the scrubber for audio. | `rgba(193, 200, 209, 0.6)` | | `--plyr-audio-progress-buffered-background` | The fill color for the buffer indication in the scrubber for audio. | `rgba(193, 200, 209, 0.6)` |
| `--plyr-range-thumb-height` | The height of the scrubber handle/thumb. | `13px` | | `--plyr-range-thumb-height` | The height of the scrubber handle/thumb. | `13px` |
| `--plyr-range-thumb-background` | The background of the scrubber handle/thumb. | ![#ffffff](https://placehold.it/15/ffffff/000000?text=+) `#ffffff` | | `--plyr-range-thumb-background` | The background of the scrubber handle/thumb. | ![#ffffff](https://place-hold.it/15/ffffff/000000?text=+) `#ffffff` |
| `--plyr-range-thumb-shadow` | The shadow of the scrubber handle/thumb. | `0 1px 1px rgba(215, 26, 18, 0.15), 0 0 0 1px rgba(215, 26, 18, 0.2)` | | `--plyr-range-thumb-shadow` | The shadow of the scrubber handle/thumb. | `0 1px 1px rgba(215, 26, 18, 0.15), 0 0 0 1px rgba(215, 26, 18, 0.2)` |
| `--plyr-range-thumb-active-shadow-width` | The width of the shadow when the scrubber handle/thumb is `:active` (pressed). | `3px` | | `--plyr-range-thumb-active-shadow-width` | The width of the shadow when the scrubber handle/thumb is `:active` (pressed). | `3px` |
| `--plyr-range-track-height` | The height of the scrubber/progress track. | `5px` | | `--plyr-range-track-height` | The height of the scrubber/progress track. | `5px` |
@ -230,7 +230,7 @@ Here's a list of the properties and what they are used for:
| `--plyr-audio-range-track-background` | The background of the scrubber/progress. | `--plyr-video-progress-buffered-background` | | `--plyr-audio-range-track-background` | The background of the scrubber/progress. | `--plyr-video-progress-buffered-background` |
| `--plyr-audio-range-thumb-active-shadow-color` | The color of the shadow when the audio scrubber handle/thumb is `:active` (pressed). | `rgba(215, 26, 18, 0.1)` | | `--plyr-audio-range-thumb-active-shadow-color` | The color of the shadow when the audio scrubber handle/thumb is `:active` (pressed). | `rgba(215, 26, 18, 0.1)` |
| `--plyr-tooltip-background` | The background color for tooltips. | `rgba(255, 255, 255, 0.9)` | | `--plyr-tooltip-background` | The background color for tooltips. | `rgba(255, 255, 255, 0.9)` |
| `--plyr-tooltip-color` | The text color for tooltips. | ![#4a5464](https://placehold.it/15/4a5464/000000?text=+) `#4a5464` | | `--plyr-tooltip-color` | The text color for tooltips. | ![#4a5464](https://place-hold.it/15/4a5464/000000?text=+) `#4a5464` |
| `--plyr-tooltip-padding` | The padding for tooltips. | `calc(var(--plyr-control-spacing) / 2))` | | `--plyr-tooltip-padding` | The padding for tooltips. | `calc(var(--plyr-control-spacing) / 2))` |
| `--plyr-tooltip-arrow-size` | The size of the arrow under tooltips. | `4px` | | `--plyr-tooltip-arrow-size` | The size of the arrow under tooltips. | `4px` |
| `--plyr-tooltip-radius` | The border radius on tooltips. | `3px` | | `--plyr-tooltip-radius` | The border radius on tooltips. | `3px` |
@ -467,6 +467,7 @@ player.fullscreen.enter(); // Enter fullscreen
| `fullscreen.exit()` | - | Exit fullscreen. | | `fullscreen.exit()` | - | Exit fullscreen. |
| `fullscreen.toggle()` | - | Toggle fullscreen. | | `fullscreen.toggle()` | - | Toggle fullscreen. |
| `airplay()` | - | Trigger the airplay dialog on supported devices. | | `airplay()` | - | Trigger the airplay dialog on supported devices. |
| `setPreviewThumbnails(source: PreviewThumbnailsOptions)` | - | Sets the preview thubmnails for the current source. |
| `toggleControls(toggle)` | Boolean | Toggle the controls (video only). Takes optional truthy value to force it on/off. | | `toggleControls(toggle)` | Boolean | Toggle the controls (video only). Takes optional truthy value to force it on/off. |
| `on(event, function)` | String, Function | Add an event listener for the specified event. | | `on(event, function)` | String, Function | Add an event listener for the specified event. |
| `once(event, function)` | String, Function | Add an event listener for the specified event once. | | `once(event, function)` | String, Function | Add an event listener for the specified event once. |
@ -513,6 +514,7 @@ player.fullscreen.active; // false;
| `loop` | ✓ | ✓ | Gets or sets the current loop state of the player. The setter accepts a boolean. | | `loop` | ✓ | ✓ | Gets or sets the current loop state of the player. The setter accepts a boolean. |
| `source` | ✓ | ✓ | Gets or sets the current source for the player. The setter accepts an object. See [source setter](#the-source-setter) below for examples. | | `source` | ✓ | ✓ | Gets or sets the current source for the player. The setter accepts an object. See [source setter](#the-source-setter) below for examples. |
| `poster` | ✓ | ✓ | Gets or sets the current poster image for the player. The setter accepts a string; the URL for the updated poster image. | | `poster` | ✓ | ✓ | Gets or sets the current poster image for the player. The setter accepts a string; the URL for the updated poster image. |
| `previewThumbnails` | ✓ | ✓ | Gets or sets the current preview Thubmnail source for the player. The setter accepts a string |
| `autoplay` | ✓ | ✓ | Gets or sets the autoplay state of the player. The setter accepts a boolean. | | `autoplay` | ✓ | ✓ | Gets or sets the autoplay state of the player. The setter accepts a boolean. |
| `currentTrack` | ✓ | ✓ | Gets or sets the caption track by index. `-1` means the track is missing or captions is not active | | `currentTrack` | ✓ | ✓ | Gets or sets the caption track by index. `-1` means the track is missing or captions is not active |
| `language` | ✓ | ✓ | Gets or sets the preferred captions language for the player. The setter accepts an ISO two-letter language code. Support for the languages is dependent on the captions you include. If your captions don't have any language data, or if you have multiple tracks with the same language, you may want to use `currentTrack` instead. | | `language` | ✓ | ✓ | Gets or sets the preferred captions language for the player. The setter accepts an ISO two-letter language code. Support for the languages is dependent on the captions you include. If your captions don't have any language data, or if you have multiple tracks with the same language, you may want to use `currentTrack` instead. |
@ -791,7 +793,7 @@ Some awesome folks have made plugins for CMSs and Components for JavaScript fram
| Neos | Jon Uhlmann ([@jonnitto](https://github.com/jonnitto)) | [https://packagist.org/packages/jonnitto/plyr](https://packagist.org/packages/jonnitto/plyr) | | Neos | Jon Uhlmann ([@jonnitto](https://github.com/jonnitto)) | [https://packagist.org/packages/jonnitto/plyr](https://packagist.org/packages/jonnitto/plyr) |
| Kirby | Dominik Pschenitschni ([@dpschen](https://github.com/dpschen)) | [https://github.com/dpschen/kirby-plyrtag](https://github.com/dpschen/kirby-plyrtag) | | Kirby | Dominik Pschenitschni ([@dpschen](https://github.com/dpschen)) | [https://github.com/dpschen/kirby-plyrtag](https://github.com/dpschen/kirby-plyrtag) |
| REDAXO | FriendsOfRedaxo / skerbis ([@skerbis](https://friendsofredaxo.github.io)) | [https://github.com/FriendsOfREDAXO/plyr](https://github.com/FriendsOfREDAXO/plyr) | | REDAXO | FriendsOfRedaxo / skerbis ([@skerbis](https://friendsofredaxo.github.io)) | [https://github.com/FriendsOfREDAXO/plyr](https://github.com/FriendsOfREDAXO/plyr) |
| svelte-plyr | Ben Woodward / benwoodward ([@benwoodward](https://github.com/benwoodward)) | [https://github.com/benwoodward](https://github.com/benwoodward) | | svelte-plyr | Ben Woodward / benwoodward ([@benwoodward](https://github.com/benwoodward)) | [https://github.com/benwoodward/svelte-plyr](https://github.com/benwoodward/svelte-plyr) |
# Issues # Issues
@ -839,6 +841,7 @@ Plyr costs money to run, not only my time. I donate my time for free as I enjoy
- [Rutheneum-Bote](https://gymnasium-rutheneum.de/content/newspaper/kreativwettbewerb.php) - [Rutheneum-Bote](https://gymnasium-rutheneum.de/content/newspaper/kreativwettbewerb.php)
- [pressakey.com | Blog-Magazin für Videospiele](https://pressakey.com) - [pressakey.com | Blog-Magazin für Videospiele](https://pressakey.com)
- [STROLLÿN: Work with a View](https://strollyn.com) - [STROLLÿN: Work with a View](https://strollyn.com)
- [CFDA Runway360](https://runway360.cfda.com/)
If you want to be added to the list, open a pull request. It'd be awesome to see how you're using Plyr 😎 If you want to be added to the list, open a pull request. It'd be awesome to see how you're using Plyr 😎

View File

@ -105,14 +105,6 @@
</button> </button>
</p> </p>
<p>
Premium video monetization from
<a href="https://vi.ai/publisher-video-monetization/?aid=plyrio" target="_blank" class="no-border">
<img src="https://cdn.plyr.io/static/vi-logo-24x24.svg" alt="ai.vi" />
<span class="sr-only">ai.vi</span>
</a>
</p>
<div class="call-to-action"> <div class="call-to-action">
<a href="https://github.com/sampotts/plyr" target="_blank" class="button js-shr"> <a href="https://github.com/sampotts/plyr" target="_blank" class="button js-shr">
<svg class="icon" role="presentation"> <svg class="icon" role="presentation">

View File

@ -2,6 +2,8 @@
// Icons // Icons
// ========================================================================== // ==========================================================================
@use 'sass:math';
// Base size icon styles // Base size icon styles
.icon { .icon {
fill: currentColor; fill: currentColor;
@ -19,5 +21,5 @@ label svg {
a .icon, a .icon,
.btn .icon { .btn .icon {
margin-right: ($spacing-base / 2); margin-right: math.div($spacing-base, 4);
} }

View File

@ -2,6 +2,8 @@
// Examples // Examples
// ========================================================================== // ==========================================================================
@use 'sass:math';
// Example players // Example players
.plyr { .plyr {
border-radius: $border-radius-large; border-radius: $border-radius-large;
@ -31,6 +33,6 @@
color: $color-gray-500; color: $color-gray-500;
.icon { .icon {
margin-right: ceil($spacing-base / 6); margin-right: math.div($spacing-base, 6);
} }
} }

View File

@ -2,6 +2,8 @@
// Core // Core
// ========================================================================== // ==========================================================================
@use 'sass:math';
html, html,
body { body {
display: flex; display: flex;
@ -46,7 +48,7 @@ aside {
.icon { .icon {
fill: $color-twitter; fill: $color-twitter;
margin-right: ($spacing-base / 2); margin-right: math.div($spacing-base, 2);
} }
p { p {

View File

@ -2,6 +2,8 @@
// Mixins // Mixins
// ========================================================================== // ==========================================================================
@use 'sass:math';
// Convert a <button> into an <a> // Convert a <button> into an <a>
// --------------------------------------- // ---------------------------------------
@mixin cancel-button-styles() { @mixin cancel-button-styles() {
@ -32,7 +34,7 @@
// Leave <body> at 100%/16px // Leave <body> at 100%/16px
// --------------------------------------- // ---------------------------------------
@function calculate-rem($size) { @function calculate-rem($size) {
$rem: $size / 16; $rem: math.div($size, 16);
@return #{$rem}rem; @return #{$rem}rem;
} }

View File

@ -2,4 +2,4 @@
// Layout // Layout
// ========================================================================== // ==========================================================================
$container-max-width: 1260px; $container-max-width: 1240px;

View File

@ -1,6 +1,6 @@
{ {
"name": "plyr", "name": "plyr",
"version": "3.6.4", "version": "3.6.10",
"description": "A simple, accessible and customizable HTML5, YouTube and Vimeo media player", "description": "A simple, accessible and customizable HTML5, YouTube and Vimeo media player",
"homepage": "https://plyr.io", "homepage": "https://plyr.io",
"author": "Sam Potts <sam@potts.es>", "author": "Sam Potts <sam@potts.es>",
@ -39,19 +39,19 @@
"start": "gulp" "start": "gulp"
}, },
"devDependencies": { "devDependencies": {
"@sampotts/eslint-config": "1.1.5", "@babel/core": "^7.13.15",
"ansi-colors": "^4.1.1", "@babel/plugin-proposal-class-properties": "^7.13.0",
"autoprefixer": "^10.0.2", "@babel/preset-env": "^7.13.15",
"aws-sdk": "^2.814.0", "@sampotts/eslint-config": "1.1.7",
"@babel/core": "^7.12.10", "autoprefixer": "^10.2.5",
"@babel/preset-env": "^7.12.11", "aws-sdk": "^2.888.0",
"@babel/plugin-proposal-class-properties": "^7.12.1",
"babel-eslint": "^10.1.0", "babel-eslint": "^10.1.0",
"browser-sync": "^2.26.13", "browser-sync": "^2.26.14",
"colorette": "2.0.12",
"cssnano": "^5.0.1",
"del": "^6.0.0", "del": "^6.0.0",
"eslint": "^7.3.1", "eslint": "^7.23.0",
"fancy-log": "^1.3.3", "fancy-log": "^1.3.3",
"fastly-purge": "^1.0.1",
"git-branch": "^2.0.1", "git-branch": "^2.0.1",
"gulp": "^4.0.2", "gulp": "^4.0.2",
"gulp-awspublish": "^4.1.2", "gulp-awspublish": "^4.1.2",
@ -66,33 +66,32 @@
"gulp-postcss": "^9.0.0", "gulp-postcss": "^9.0.0",
"gulp-rename": "^2.0.0", "gulp-rename": "^2.0.0",
"gulp-replace": "^1.0.0", "gulp-replace": "^1.0.0",
"gulp-sass": "^4.1.0", "gulp-sass": "^5.0.0",
"gulp-size": "^3.0.0", "gulp-size": "^3.0.0",
"gulp-sourcemaps": "^3.0.0", "gulp-sourcemaps": "^3.0.0",
"gulp-svgstore": "^7.0.1", "gulp-svgstore": "^7.0.1",
"gulp-terser": "^2.0.0", "gulp-terser": "^2.0.1",
"postcss": "^8.1.7", "postcss": "^8.2.10",
"postcss-clean": "^1.1.0", "postcss-custom-properties": "^11.0.0",
"postcss-custom-properties": "^10.0.0",
"prettier-eslint": "^12.0.0", "prettier-eslint": "^12.0.0",
"prettier-stylelint": "^0.4.2", "prettier-stylelint": "^0.4.2",
"remark-cli": "^9.0.0", "remark-cli": "^9.0.0",
"remark-validate-links": "^10.0.2", "remark-validate-links": "^10.0.4",
"rollup": "^2.35.1", "rollup": "^2.45.2",
"rollup-plugin-babel": "^4.4.0", "rollup-plugin-babel": "^4.4.0",
"rollup-plugin-commonjs": "^10.1.0", "rollup-plugin-commonjs": "^10.1.0",
"rollup-plugin-node-resolve": "^5.2.0", "rollup-plugin-node-resolve": "^5.2.0",
"stylelint": "^13.8.0", "sass": "^1.42.1",
"stylelint": "^13.12.0",
"stylelint-config-prettier": "^8.0.2", "stylelint-config-prettier": "^8.0.2",
"stylelint-config-recommended": "^3.0.0", "stylelint-config-recommended": "^4.0.0",
"stylelint-config-sass-guidelines": "^7.1.0", "stylelint-config-sass-guidelines": "^8.0.0",
"stylelint-order": "^4.1.0", "stylelint-order": "^4.1.0",
"stylelint-scss": "^3.18.0", "stylelint-scss": "^3.19.0",
"stylelint-selector-bem-pattern": "^2.1.0", "stylelint-selector-bem-pattern": "^2.1.0"
"through2": "^4.0.2"
}, },
"dependencies": { "dependencies": {
"core-js": "^3.8.1", "core-js": "^3.10.1",
"custom-event-polyfill": "^1.0.7", "custom-event-polyfill": "^1.0.7",
"loadjs": "^4.2.0", "loadjs": "^4.2.0",
"rangetouch": "^2.0.1", "rangetouch": "^2.0.1",

View File

@ -154,7 +154,9 @@ const captions = {
} }
// Enable or disable captions based on track length // Enable or disable captions based on track length
toggleClass(this.elements.container, this.config.classNames.captions.enabled, !is.empty(tracks)); if (this.elements) {
toggleClass(this.elements.container, this.config.classNames.captions.enabled, !is.empty(tracks));
}
// Update available languages in list // Update available languages in list
if ( if (

View File

@ -61,7 +61,7 @@ const defaults = {
// Sprite (for icons) // Sprite (for icons)
loadSprite: true, loadSprite: true,
iconPrefix: 'plyr', iconPrefix: 'plyr',
iconUrl: 'https://cdn.plyr.io/3.6.4/plyr.svg', iconUrl: 'https://cdn.plyr.io/3.6.10/plyr.svg',
// Blank video (used to prevent errors on source change) // Blank video (used to prevent errors on source change)
blankVideo: 'https://cdn.plyr.io/static/blank.mp4', blankVideo: 'https://cdn.plyr.io/static/blank.mp4',
@ -398,6 +398,7 @@ const defaults = {
embed: { embed: {
provider: 'data-plyr-provider', provider: 'data-plyr-provider',
id: 'data-plyr-embed-id', id: 'data-plyr-embed-id',
hash: 'data-plyr-embed-hash',
}, },
}, },

3
src/js/controls.js vendored
View File

@ -38,7 +38,8 @@ const controls = {
// Get icon URL // Get icon URL
getIconUrl() { getIconUrl() {
const url = new URL(this.config.iconUrl, window.location); const url = new URL(this.config.iconUrl, window.location);
const cors = url.host !== window.location.host || (browser.isIE && !window.svg4everybody); const host = window.location.host ? window.location.host : window.top.location.host;
const cors = url.host !== host || (browser.isIE && !window.svg4everybody);
return { return {
url: this.config.iconUrl, url: this.config.iconUrl,

View File

@ -124,7 +124,9 @@ class Fullscreen {
return hasClass(this.target, this.player.config.classNames.fullscreen.fallback); return hasClass(this.target, this.player.config.classNames.fullscreen.fallback);
} }
const element = !this.prefix ? document.fullscreenElement : document[`${this.prefix}${this.property}Element`]; const element = !this.prefix
? this.target.getRootNode().fullscreenElement
: this.target.getRootNode()[`${this.prefix}${this.property}Element`];
return element && element.shadowRoot ? element === this.target.getRootNode().host : element === this.target; return element && element.shadowRoot ? element === this.target.getRootNode().host : element === this.target;
} }

View File

@ -73,7 +73,7 @@ const html5 = {
return; return;
} }
// If we're using an an external handler... // If we're using an external handler...
if (player.config.quality.forced && is.function(player.config.quality.onChange)) { if (player.config.quality.forced && is.function(player.config.quality.onChange)) {
player.config.quality.onChange(input); player.config.quality.onChange(input);
} else { } else {

View File

@ -10,7 +10,7 @@ import { getElement, getElements, matches, toggleClass } from './utils/elements'
import { off, on, once, toggleListener, triggerEvent } from './utils/events'; import { off, on, once, toggleListener, triggerEvent } from './utils/events';
import is from './utils/is'; import is from './utils/is';
import { silencePromise } from './utils/promise'; import { silencePromise } from './utils/promise';
import { getAspectRatio, setAspectRatio } from './utils/style'; import { getAspectRatio, getViewportSize, supportsCSS } from './utils/style';
class Listeners { class Listeners {
constructor(player) { constructor(player) {
@ -149,16 +149,16 @@ class Listeners {
break; break;
/* case 73: /* case 73:
this.setLoop('start'); this.setLoop('start');
break; break;
case 76: case 76:
this.setLoop(); this.setLoop();
break; break;
case 79: case 79:
this.setLoop('end'); this.setLoop('end');
break; */ break; */
default: default:
break; break;
@ -305,39 +305,49 @@ class Listeners {
); );
// Set a gutter for Vimeo // Set a gutter for Vimeo
const setGutter = (ratio, padding, toggle) => { const setGutter = () => {
if (!player.isVimeo || player.config.vimeo.premium) { if (!player.isVimeo || player.config.vimeo.premium) {
return; return;
} }
const target = player.elements.wrapper.firstChild; const target = elements.wrapper;
const [, y] = ratio; const { active } = player.fullscreen;
const [videoX, videoY] = getAspectRatio.call(player); const [videoWidth, videoHeight] = getAspectRatio.call(player);
const useNativeAspectRatio = supportsCSS(`aspect-ratio: ${videoWidth} / ${videoHeight}`);
target.style.maxWidth = toggle ? `${(y / videoY) * videoX}px` : null; // If not active, remove styles
target.style.margin = toggle ? '0 auto' : null; if (!active) {
}; if (useNativeAspectRatio) {
target.style.width = null;
// Resize on fullscreen change target.style.height = null;
const setPlayerSize = (measure) => { } else {
// If we don't need to measure the viewport target.style.maxWidth = null;
if (!measure) { target.style.margin = null;
return setAspectRatio.call(player); }
return;
} }
const rect = elements.container.getBoundingClientRect(); // Determine which dimension will overflow and constrain view
const { width, height } = rect; const [viewportWidth, viewportHeight] = getViewportSize();
const overflow = viewportWidth / viewportHeight > videoWidth / videoHeight;
return setAspectRatio.call(player, `${width}:${height}`); if (useNativeAspectRatio) {
target.style.width = overflow ? 'auto' : '100%';
target.style.height = overflow ? '100%' : 'auto';
} else {
target.style.maxWidth = overflow ? `${(viewportHeight / videoHeight) * videoWidth}px` : null;
target.style.margin = overflow ? '0 auto' : null;
}
}; };
// Handle resizing
const resized = () => { const resized = () => {
clearTimeout(timers.resized); clearTimeout(timers.resized);
timers.resized = setTimeout(setPlayerSize, 50); timers.resized = setTimeout(setGutter, 50);
}; };
on.call(player, elements.container, 'enterfullscreen exitfullscreen', (event) => { on.call(player, elements.container, 'enterfullscreen exitfullscreen', (event) => {
const { target, usingNative } = player.fullscreen; const { target } = player.fullscreen;
// Ignore events not from target // Ignore events not from target
if (target !== elements.container) { if (target !== elements.container) {
@ -349,26 +359,12 @@ class Listeners {
return; return;
} }
const isEnter = event.type === 'enterfullscreen';
// Set the player size when entering fullscreen to viewport size
const { padding, ratio } = setPlayerSize(isEnter);
// Set Vimeo gutter // Set Vimeo gutter
setGutter(ratio, padding, isEnter); setGutter();
// Horrible hack for Safari 14 not repainting properly on entering fullscreen // Watch for resizes
if (isEnter) { const method = event.type === 'enterfullscreen' ? on : off;
setTimeout(() => repaint(elements.container), 100); method.call(player, window, 'resize', resized);
}
// If not using native browser fullscreen API, we need to check for resizes of viewport
if (!usingNative) {
if (isEnter) {
on.call(player, window, 'resize', resized);
} else {
off.call(player, window, 'resize', resized);
}
}
}); });
}; };
@ -845,7 +841,9 @@ class Listeners {
.filter((c) => !c.contains(elements.container)) .filter((c) => !c.contains(elements.container))
.forEach((child) => { .forEach((child) => {
this.bind(child, 'mouseenter mouseleave', (event) => { this.bind(child, 'mouseenter mouseleave', (event) => {
elements.controls.hover = !player.touch && event.type === 'mouseenter'; if (elements.controls) {
elements.controls.hover = !player.touch && event.type === 'mouseenter';
}
}); });
}); });
} }

View File

@ -41,7 +41,6 @@ const media = {
// Poster image container // Poster image container
this.elements.poster = createElement('div', { this.elements.poster = createElement('div', {
class: this.config.classNames.poster, class: this.config.classNames.poster,
hidden: '',
}); });
this.elements.wrapper.appendChild(this.elements.poster); this.elements.wrapper.appendChild(this.elements.poster);

View File

@ -213,8 +213,8 @@ class Ads {
request.setAdWillPlayMuted(!this.player.muted); request.setAdWillPlayMuted(!this.player.muted);
this.loader.requestAds(request); this.loader.requestAds(request);
} catch (e) { } catch (error) {
this.onAdError(e); this.onAdError(error);
} }
}; };

View File

@ -11,7 +11,7 @@ import fetch from '../utils/fetch';
import is from '../utils/is'; import is from '../utils/is';
import loadScript from '../utils/load-script'; import loadScript from '../utils/load-script';
import { format, stripHTML } from '../utils/strings'; import { format, stripHTML } from '../utils/strings';
import { setAspectRatio } from '../utils/style'; import { roundAspectRatio, setAspectRatio } from '../utils/style';
import { buildUrlParams } from '../utils/urls'; import { buildUrlParams } from '../utils/urls';
// Parse Vimeo ID from URL // Parse Vimeo ID from URL
@ -28,6 +28,21 @@ function parseId(url) {
return url.match(regex) ? RegExp.$2 : url; return url.match(regex) ? RegExp.$2 : url;
} }
// Try to extract a hash for private videos from the URL
function parseHash(url) {
/* This regex matches a hexadecimal hash if given in any of these forms:
* - [https://player.]vimeo.com/video/{id}/{hash}[?params]
* - [https://player.]vimeo.com/video/{id}?h={hash}[&params]
* - [https://player.]vimeo.com/video/{id}?[params]&h={hash}
* - video/{id}/{hash}
* If matched, the hash is available in the named group `hash`
*/
const regex = /^.*(?:vimeo.com\/|video\/)(?:\d+)(?:\?.*&*h=|\/)+(?<hash>[\d,a-f]+)/;
const found = url.match(regex);
return found ? found.groups.hash : null;
}
// Set playback state and trigger change (only on actual change) // Set playback state and trigger change (only on actual change)
function assurePlaybackState(play) { function assurePlaybackState(play) {
if (play && !this.embed.hasPlayed) { if (play && !this.embed.hasPlayed) {
@ -71,6 +86,18 @@ const vimeo = {
const player = this; const player = this;
const config = player.config.vimeo; const config = player.config.vimeo;
const { premium, referrerPolicy, ...frameParams } = config; const { premium, referrerPolicy, ...frameParams } = config;
// Get the source URL or ID
let source = player.media.getAttribute('src');
let hash = '';
// Get from <div> if needed
if (is.empty(source)) {
source = player.media.getAttribute(player.config.attributes.embed.id);
// hash can also be set as attribute on the <div>
hash = player.media.getAttribute(player.config.attributes.embed.hash);
} else {
hash = parseHash(source);
}
const hashParam = hash ? { h: hash } : {};
// If the owner has a pro or premium account then we can hide controls etc // If the owner has a pro or premium account then we can hide controls etc
if (premium) { if (premium) {
@ -87,24 +114,21 @@ const vimeo = {
muted: player.muted, muted: player.muted,
gesture: 'media', gesture: 'media',
playsinline: !this.config.fullscreen.iosNative, playsinline: !this.config.fullscreen.iosNative,
// hash has to be added to iframe-URL
...hashParam,
...frameParams, ...frameParams,
}); });
// Get the source URL or ID
let source = player.media.getAttribute('src');
// Get from <div> if needed
if (is.empty(source)) {
source = player.media.getAttribute(player.config.attributes.embed.id);
}
const id = parseId(source); const id = parseId(source);
// Build an iframe // Build an iframe
const iframe = createElement('iframe'); const iframe = createElement('iframe');
const src = format(player.config.urls.vimeo.iframe, id, params); const src = format(player.config.urls.vimeo.iframe, id, params);
iframe.setAttribute('src', src); iframe.setAttribute('src', src);
iframe.setAttribute('allowfullscreen', ''); iframe.setAttribute('allowfullscreen', '');
iframe.setAttribute('allow', ['autoplay', 'fullscreen', 'picture-in-picture'].join('; ')); iframe.setAttribute(
'allow',
['autoplay', 'fullscreen', 'picture-in-picture', 'encrypted-media', 'accelerometer', 'gyroscope'].join('; '),
);
// Set the referrer policy if required // Set the referrer policy if required
if (!is.empty(referrerPolicy)) { if (!is.empty(referrerPolicy)) {
@ -291,7 +315,7 @@ const vimeo = {
// Set aspect ratio based on video size // Set aspect ratio based on video size
Promise.all([player.embed.getVideoWidth(), player.embed.getVideoHeight()]).then((dimensions) => { Promise.all([player.embed.getVideoWidth(), player.embed.getVideoHeight()]).then((dimensions) => {
const [width, height] = dimensions; const [width, height] = dimensions;
player.embed.ratio = [width, height]; player.embed.ratio = roundAspectRatio(width, height);
setAspectRatio.call(this); setAspectRatio.call(this);
}); });

View File

@ -11,7 +11,7 @@ import loadImage from '../utils/load-image';
import loadScript from '../utils/load-script'; import loadScript from '../utils/load-script';
import { extend } from '../utils/objects'; import { extend } from '../utils/objects';
import { format, generateId } from '../utils/strings'; import { format, generateId } from '../utils/strings';
import { setAspectRatio } from '../utils/style'; import { roundAspectRatio, setAspectRatio } from '../utils/style';
// Parse YouTube ID from URL // Parse YouTube ID from URL
function parseId(url) { function parseId(url) {
@ -90,7 +90,7 @@ const youtube = {
ui.setTitle.call(this); ui.setTitle.call(this);
// Set aspect ratio // Set aspect ratio
this.embed.ratio = [width, height]; this.embed.ratio = roundAspectRatio(width, height);
} }
setAspectRatio.call(this); setAspectRatio.call(this);

22
src/js/plyr.d.ts vendored
View File

@ -211,6 +211,11 @@ declare class Plyr {
*/ */
airplay(): void; airplay(): void;
/**
* Sets the preview thubmnails for the current source.
*/
setPreviewThumbnails(source: Plyr.PreviewThumbnailsOptions): void;
/** /**
* Toggle the controls (video only). Takes optional truthy value to force it on/off. * Toggle the controls (video only). Takes optional truthy value to force it on/off.
*/ */
@ -238,8 +243,10 @@ declare class Plyr {
/** /**
* Destroy lib instance * Destroy lib instance
* @param {Function} callback - Callback for when destroy is complete
* @param {Boolean} soft - Whether it's a soft destroy (for source changes etc)
*/ */
destroy(): void; destroy(callback?: (...args: any[]) => void, soft?: boolean): void;
} }
declare namespace Plyr { declare namespace Plyr {
@ -452,7 +459,7 @@ declare namespace Plyr {
* Allows binding of event listeners to the controls before the default handlers. See the defaults.js for available listeners. * Allows binding of event listeners to the controls before the default handlers. See the defaults.js for available listeners.
* If your handler prevents default on the event (event.preventDefault()), the default handler will not fire. * If your handler prevents default on the event (event.preventDefault()), the default handler will not fire.
*/ */
listeners?: { [key: string]: (error: PlyrEvent) => void }; listeners?: {[key: string]: (error: PlyrEvent) => void};
/** /**
* active: Toggles if captions should be active by default. language: Sets the default language to load (if available). 'auto' uses the browser language. * active: Toggles if captions should be active by default. language: Sets the default language to load (if available). 'auto' uses the browser language.
@ -526,7 +533,8 @@ declare namespace Plyr {
interface AdOptions { interface AdOptions {
enabled: boolean; enabled: boolean;
publisherId: string; publisherId?: string;
tagUrl?: string;
} }
interface SpeedOptions { interface SpeedOptions {
@ -549,6 +557,7 @@ declare namespace Plyr {
fallback?: boolean | 'force'; fallback?: boolean | 'force';
allowAudio?: boolean; allowAudio?: boolean;
iosNative?: boolean; iosNative?: boolean;
container?: string;
} }
interface CaptionOptions { interface CaptionOptions {
@ -615,6 +624,11 @@ declare namespace Plyr {
* Booleans are converted to HTML5 value-less attributes. * Booleans are converted to HTML5 value-less attributes.
*/ */
tracks?: Track[]; tracks?: Track[];
/**
* Enable or disable preview thumbnails for current source
*/
previewThumbnails?: Plyr.PreviewThumbnailsOptions;
} }
interface Source { interface Source {
@ -653,7 +667,7 @@ declare namespace Plyr {
} }
interface PlyrEvent extends CustomEvent { interface PlyrEvent extends CustomEvent {
readonly detail: { readonly plyr: Plyr }; readonly detail: {readonly plyr: Plyr};
} }
enum YoutubeState { enum YoutubeState {

View File

@ -1,6 +1,6 @@
// ========================================================================== // ==========================================================================
// Plyr // Plyr
// plyr.js v3.6.4 // plyr.js v3.6.10
// https://github.com/sampotts/plyr // https://github.com/sampotts/plyr
// License: The MIT License (MIT) // License: The MIT License (MIT)
// ========================================================================== // ==========================================================================
@ -29,7 +29,7 @@ import loadSprite from './utils/load-sprite';
import { clamp } from './utils/numbers'; import { clamp } from './utils/numbers';
import { cloneDeep, extend } from './utils/objects'; import { cloneDeep, extend } from './utils/objects';
import { silencePromise } from './utils/promise'; import { silencePromise } from './utils/promise';
import { getAspectRatio, reduceAspectRatio, setAspectRatio, validateRatio } from './utils/style'; import { getAspectRatio, reduceAspectRatio, setAspectRatio, validateAspectRatio } from './utils/style';
import { parseUrl } from './utils/urls'; import { parseUrl } from './utils/urls';
// Private properties // Private properties
@ -72,7 +72,7 @@ class Plyr {
(() => { (() => {
try { try {
return JSON.parse(this.media.getAttribute('data-plyr-config')); return JSON.parse(this.media.getAttribute('data-plyr-config'));
} catch (e) { } catch (_) {
return {}; return {};
} }
})(), })(),
@ -675,7 +675,9 @@ class Plyr {
// Set media speed // Set media speed
setTimeout(() => { setTimeout(() => {
this.media.playbackRate = speed; if (this.media) {
this.media.playbackRate = speed;
}
}, 0); }, 0);
} }
@ -916,12 +918,12 @@ class Plyr {
return; return;
} }
if (!is.string(input) || !validateRatio(input)) { if (!is.string(input) || !validateAspectRatio(input)) {
this.debug.error(`Invalid aspect ratio specified (${input})`); this.debug.error(`Invalid aspect ratio specified (${input})`);
return; return;
} }
this.config.ratio = input; this.config.ratio = reduceAspectRatio(input);
setAspectRatio.call(this); setAspectRatio.call(this);
} }
@ -956,6 +958,7 @@ class Plyr {
*/ */
set currentTrack(input) { set currentTrack(input) {
captions.set.call(this, input, false); captions.set.call(this, input, false);
captions.setup();
} }
/** /**
@ -1029,6 +1032,23 @@ class Plyr {
return this.media === document.pictureInPictureElement; return this.media === document.pictureInPictureElement;
} }
/**
* Sets the preview thubmnails for the current source
*/
setPreviewThumbnails(thumbnailSource) {
if (this.previewThumbnails && this.previewThumbnails.loaded) {
this.previewThumbnails.destroy();
this.previewThumbnails = null;
}
Object.assign(this.config.previewThumbnails, thumbnailSource);
// Create new instance if it is still enabled
if (this.config.previewThumbnails.enabled) {
this.previewThumbnails = new PreviewThumbnails(this);
}
}
/** /**
* Trigger the airplay dialog * Trigger the airplay dialog
* TODO: update player with state, support, enabled * TODO: update player with state, support, enabled

View File

@ -1,6 +1,6 @@
// ========================================================================== // ==========================================================================
// Plyr Polyfilled Build // Plyr Polyfilled Build
// plyr.js v3.6.4 // plyr.js v3.6.10
// https://github.com/sampotts/plyr // https://github.com/sampotts/plyr
// License: The MIT License (MIT) // License: The MIT License (MIT)
// ========================================================================== // ==========================================================================

View File

@ -26,7 +26,7 @@ class Storage {
window.localStorage.removeItem(test); window.localStorage.removeItem(test);
return true; return true;
} catch (e) { } catch (_) {
return false; return false;
} }
} }
@ -70,7 +70,11 @@ class Storage {
extend(storage, object); extend(storage, object);
// Update storage // Update storage
window.localStorage.setItem(this.key, JSON.stringify(storage)); try {
window.localStorage.setItem(this.key, JSON.stringify(storage));
} catch (_) {
// Do nothing
}
}; };
} }

View File

@ -88,7 +88,7 @@ const support = {
try { try {
return Boolean(type && this.media.canPlayType(type).replace(/no/, '')); return Boolean(type && this.media.canPlayType(type).replace(/no/, ''));
} catch (e) { } catch (_) {
return false; return false;
} }
}, },

View File

@ -82,6 +82,9 @@ const ui = {
// Reset time display // Reset time display
controls.timeUpdate.call(this); controls.timeUpdate.call(this);
// Reset duration display
controls.durationUpdate.call(this);
// Update the UI // Update the UI
ui.checkPlaying.call(this); ui.checkPlaying.call(this);
@ -181,13 +184,13 @@ const ui = {
.call(this) .call(this)
// Load image // Load image
.then(() => loadImage(poster)) .then(() => loadImage(poster))
.catch((err) => { .catch((error) => {
// Hide poster on error unless it's been set by another call // Hide poster on error unless it's been set by another call
if (poster === this.poster) { if (poster === this.poster) {
ui.togglePoster.call(this, false); ui.togglePoster.call(this, false);
} }
// Rethrow // Rethrow
throw err; throw error;
}) })
.then(() => { .then(() => {
// Prevent race conditions // Prevent race conditions

View File

@ -31,7 +31,7 @@ export function repaint(element, delay) {
// eslint-disable-next-line no-param-reassign // eslint-disable-next-line no-param-reassign
element.hidden = false; element.hidden = false;
} catch (e) { } catch (_) {
// Do nothing // Do nothing
} }
}, delay); }, delay);

View File

@ -4,11 +4,13 @@
// ========================================================================== // ==========================================================================
const browser = { const browser = {
isIE: /* @cc_on!@ */ false || !!document.documentMode, isIE: Boolean(window.document.documentMode),
isEdge: window.navigator.userAgent.includes('Edge'), isEdge: window.navigator.userAgent.includes('Edge'),
isWebkit: 'WebkitAppearance' in document.documentElement.style && !/Edge/.test(navigator.userAgent), isWebkit: 'WebkitAppearance' in document.documentElement.style && !/Edge/.test(navigator.userAgent),
isIPhone: /(iPhone|iPod)/gi.test(navigator.platform), isIPhone: /(iPhone|iPod)/gi.test(navigator.platform),
isIos: /(iPad|iPhone|iPod)/gi.test(navigator.platform), isIos:
(navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1) ||
/(iPad|iPhone|iPod)/gi.test(navigator.platform),
}; };
export default browser; export default browser;

View File

@ -19,7 +19,7 @@ const supportsPassiveListeners = (() => {
}); });
window.addEventListener('test', null, options); window.addEventListener('test', null, options);
window.removeEventListener('test', null, options); window.removeEventListener('test', null, options);
} catch (e) { } catch (_) {
// Do nothing // Do nothing
} }

View File

@ -17,7 +17,7 @@ export default function fetch(url, responseType = 'text') {
if (responseType === 'text') { if (responseType === 'text') {
try { try {
resolve(JSON.parse(request.responseText)); resolve(JSON.parse(request.responseText));
} catch (e) { } catch (_) {
resolve(request.responseText); resolve(request.responseText);
} }
} else { } else {
@ -35,8 +35,8 @@ export default function fetch(url, responseType = 'text') {
request.responseType = responseType; request.responseType = responseType;
request.send(); request.send();
} catch (e) { } catch (error) {
reject(e); reject(error);
} }
}); });
} }

View File

@ -51,7 +51,7 @@ const isUrl = (input) => {
try { try {
return !isEmpty(new URL(string).hostname); return !isEmpty(new URL(string).hostname);
} catch (e) { } catch (_) {
return false; return false;
} }
}; };

View File

@ -60,12 +60,16 @@ export default function loadSprite(url, id) {
} }
if (useStorage) { if (useStorage) {
window.localStorage.setItem( try {
`${prefix}-${id}`, window.localStorage.setItem(
JSON.stringify({ `${prefix}-${id}`,
content: result, JSON.stringify({
}), content: result,
); }),
);
} catch (_) {
// Do nothing
}
} }
update(container, result); update(container, result);

View File

@ -2,9 +2,39 @@
// Style utils // Style utils
// ========================================================================== // ==========================================================================
import { closest } from './arrays';
import is from './is'; import is from './is';
export function validateRatio(input) { // Check support for a CSS declaration
export function supportsCSS(declaration) {
if (!window || !window.CSS) {
return false;
}
return window.CSS.supports(declaration);
}
// Standard/common aspect ratios
const standardRatios = [
[1, 1],
[4, 3],
[3, 4],
[5, 4],
[4, 5],
[3, 2],
[2, 3],
[16, 10],
[10, 16],
[16, 9],
[9, 16],
[21, 9],
[9, 21],
[32, 9],
[9, 32],
].reduce((out, [x, y]) => ({ ...out, [x / y]: [x, y] }), {});
// Validate an aspect ratio
export function validateAspectRatio(input) {
if (!is.array(input) && (!is.string(input) || !input.includes(':'))) { if (!is.array(input) && (!is.string(input) || !input.includes(':'))) {
return false; return false;
} }
@ -14,6 +44,7 @@ export function validateRatio(input) {
return ratio.map(Number).every(is.number); return ratio.map(Number).every(is.number);
} }
// Reduce an aspect ratio to it's lowest form
export function reduceAspectRatio(ratio) { export function reduceAspectRatio(ratio) {
if (!is.array(ratio) || !ratio.every(is.number)) { if (!is.array(ratio) || !ratio.every(is.number)) {
return null; return null;
@ -26,8 +57,9 @@ export function reduceAspectRatio(ratio) {
return [width / divider, height / divider]; return [width / divider, height / divider];
} }
// Calculate an aspect ratio
export function getAspectRatio(input) { export function getAspectRatio(input) {
const parse = (ratio) => (validateRatio(ratio) ? ratio.split(':').map(Number) : null); const parse = (ratio) => (validateAspectRatio(ratio) ? ratio.split(':').map(Number) : null);
// Try provided ratio // Try provided ratio
let ratio = parse(input); let ratio = parse(input);
@ -44,10 +76,10 @@ export function getAspectRatio(input) {
// Get from HTML5 video // Get from HTML5 video
if (ratio === null && this.isHTML5) { if (ratio === null && this.isHTML5) {
const { videoWidth, videoHeight } = this.media; const { videoWidth, videoHeight } = this.media;
ratio = reduceAspectRatio([videoWidth, videoHeight]); ratio = [videoWidth, videoHeight];
} }
return ratio; return reduceAspectRatio(ratio);
} }
// Set aspect ratio for responsive container // Set aspect ratio for responsive container
@ -58,10 +90,20 @@ export function setAspectRatio(input) {
const { wrapper } = this.elements; const { wrapper } = this.elements;
const ratio = getAspectRatio.call(this, input); const ratio = getAspectRatio.call(this, input);
const [w, h] = is.array(ratio) ? ratio : [0, 0];
const padding = (100 / w) * h;
wrapper.style.paddingBottom = `${padding}%`; if (!is.array(ratio)) {
return {};
}
const [x, y] = reduceAspectRatio(ratio);
const useNative = supportsCSS(`aspect-ratio: ${x}/${y}`);
const padding = (100 / x) * y;
if (useNative) {
wrapper.style.aspectRatio = `${x}/${y}`;
} else {
wrapper.style.paddingBottom = `${padding}%`;
}
// For Vimeo we have an extra <div> to hide the standard controls and UI // For Vimeo we have an extra <div> to hide the standard controls and UI
if (this.isVimeo && !this.config.vimeo.premium && this.supported.ui) { if (this.isVimeo && !this.config.vimeo.premium && this.supported.ui) {
@ -74,10 +116,30 @@ export function setAspectRatio(input) {
this.media.style.transform = `translateY(-${offset}%)`; this.media.style.transform = `translateY(-${offset}%)`;
} }
} else if (this.isHTML5) { } else if (this.isHTML5) {
wrapper.classList.toggle(this.config.classNames.videoFixedRatio, ratio !== null); wrapper.classList.add(this.config.classNames.videoFixedRatio);
} }
return { padding, ratio }; return { padding, ratio };
} }
export default { setAspectRatio }; // Round an aspect ratio to closest standard ratio
export function roundAspectRatio(x, y, tolerance = 0.05) {
const ratio = x / y;
const closestRatio = closest(Object.keys(standardRatios), ratio);
// Check match is within tolerance
if (Math.abs(closestRatio - ratio) <= tolerance) {
return standardRatios[closestRatio];
}
// No match
return [x, y];
}
// Get the size of the viewport
// https://stackoverflow.com/questions/1248081/how-to-get-the-browser-viewport-dimensions
export function getViewportSize() {
const width = Math.max(document.documentElement.clientWidth || 0, window.innerWidth || 0);
const height = Math.max(document.documentElement.clientHeight || 0, window.innerHeight || 0);
return [width, height];
}

View File

@ -20,7 +20,7 @@ export function parseUrl(input, safe = true) {
try { try {
return new URL(url); return new URL(url);
} catch (e) { } catch (_) {
return null; return null;
} }
} }

View File

@ -20,3 +20,8 @@
.plyr--stopped.plyr__poster-enabled .plyr__poster { .plyr--stopped.plyr__poster-enabled .plyr__poster {
opacity: 1; opacity: 1;
} }
// Allow interaction with YouTube controls while paused
.plyr--youtube.plyr--paused.plyr__poster-enabled:not(.plyr--stopped) .plyr__poster {
display: none;
}

View File

@ -1,7 +1,3 @@
// ==========================================================================
// Useful functions
// ==========================================================================
@function to-percentage($input) { @function to-percentage($input) {
@return $input * 1%; @return $input * 1%;
} }

View File

@ -59,17 +59,6 @@
height: 100%; height: 100%;
} }
.plyr__video-wrapper {
height: 100%;
position: static;
}
// Vimeo requires some different styling
&.plyr--vimeo .plyr__video-wrapper {
height: 0;
position: relative;
}
// Display correct icon // Display correct icon
.plyr__control .icon--exit-fullscreen { .plyr__control .icon--exit-fullscreen {
display: block; display: block;

View File

@ -2,6 +2,8 @@
// Advertisements // Advertisements
// ========================================================================== // ==========================================================================
@use 'sass:list';
.plyr__ads { .plyr__ads {
border-radius: inherit; border-radius: inherit;
bottom: 0; bottom: 0;
@ -36,7 +38,7 @@
z-index: 3; z-index: 3;
} }
&::after:empty { &:empty::after {
display: none; display: none;
} }
} }
@ -47,7 +49,7 @@
display: block; display: block;
height: $plyr-range-track-height; height: $plyr-range-track-height;
left: 0; left: 0;
margin: -($plyr-range-track-height / 2) 0 0; margin: -(list.slash($plyr-range-track-height, 2)) 0 0;
opacity: 0.8; opacity: 0.8;
position: absolute; position: absolute;
top: 50%; top: 50%;

View File

@ -2,6 +2,8 @@
// Video styles // Video styles
// -------------------------------------------------------------- // --------------------------------------------------------------
@use 'sass:math';
// Container // Container
.plyr--video { .plyr--video {
background: var(--plyr-video-background, $plyr-video-background); background: var(--plyr-video-background, $plyr-video-background);
@ -22,33 +24,36 @@
} }
// Default to 16:9 ratio but this is set by JavaScript based on config // Default to 16:9 ratio but this is set by JavaScript based on config
$embed-padding: ((100 / 16) * 9); $embed-padding: (math.div(100, 16) * 9);
.plyr__video-embed, .plyr__video-embed,
.plyr__video-wrapper--fixed-ratio { .plyr__video-wrapper--fixed-ratio {
height: 0; @supports not (aspect-ratio: 16 / 9) {
padding-bottom: to-percentage($embed-padding); height: 0;
padding-bottom: to-percentage($embed-padding);
position: relative;
}
aspect-ratio: 16 / 9;
} }
.plyr__video-embed iframe, .plyr__video-embed iframe,
.plyr__video-wrapper--fixed-ratio video { .plyr__video-wrapper--fixed-ratio video {
border: 0; border: 0;
height: 100%;
left: 0; left: 0;
position: absolute; position: absolute;
top: 0; top: 0;
width: 100%;
} }
// If the full custom UI is supported // For Vimeo, if the full custom UI is supported
.plyr--full-ui .plyr__video-embed { .plyr--full-ui .plyr__video-embed > .plyr__video-embed__container {
$height: 240; $height: 240;
$offset: to-percentage(($height - $embed-padding) / ($height / 50)); $offset: to-percentage(math.div($height - $embed-padding, math.div($height, 50)));
padding-bottom: to-percentage($height);
// Only used for Vimeo position: relative;
> .plyr__video-embed__container { transform: translateY(-$offset);
padding-bottom: to-percentage($height);
position: relative;
transform: translateY(-$offset);
}
} }
// Controls container // Controls container

View File

@ -13,10 +13,10 @@ const babel = require('rollup-plugin-babel');
const commonjs = require('rollup-plugin-commonjs'); const commonjs = require('rollup-plugin-commonjs');
const resolve = require('rollup-plugin-node-resolve'); const resolve = require('rollup-plugin-node-resolve');
// CSS // CSS
const sass = require('gulp-sass'); const sass = require('gulp-sass')(require('sass'));
const postcss = require('gulp-postcss'); const postcss = require('gulp-postcss');
const autoprefixer = require('autoprefixer'); const autoprefixer = require('autoprefixer');
const clean = require('postcss-clean'); const cssnano = require('cssnano');
const customprops = require('postcss-custom-properties'); const customprops = require('postcss-custom-properties');
// Images // Images
const svgstore = require('gulp-svgstore'); const svgstore = require('gulp-svgstore');
@ -158,7 +158,15 @@ Object.entries(build.css).forEach(([filename, entry]) => {
.src(src) .src(src)
.pipe(plumber()) .pipe(plumber())
.pipe(sass()) .pipe(sass())
.pipe(postcss([customprops(), autoprefixer(), clean()])) .pipe(
postcss([
customprops(),
autoprefixer(),
cssnano({
preset: 'default',
}),
]),
)
.pipe(size(sizeOptions)) .pipe(size(sizeOptions))
.pipe(gulp.dest(dist)), .pipe(gulp.dest(dist)),
); );

View File

@ -10,15 +10,13 @@ const gulp = require('gulp');
const gitbranch = require('git-branch'); const gitbranch = require('git-branch');
const rename = require('gulp-rename'); const rename = require('gulp-rename');
const replace = require('gulp-replace'); const replace = require('gulp-replace');
const ansi = require('ansi-colors'); const { green, cyan, bold } = require('colorette');
const log = require('fancy-log'); const log = require('fancy-log');
const open = require('gulp-open'); const open = require('gulp-open');
const size = require('gulp-size'); const size = require('gulp-size');
const through = require('through2');
// Deployment // Deployment
const aws = require('aws-sdk'); const aws = require('aws-sdk');
const publish = require('gulp-awspublish'); const publish = require('gulp-awspublish');
const FastlyPurge = require('fastly-purge');
// Configs // Configs
const pkg = require('../package.json'); const pkg = require('../package.json');
const deploy = require('../deploy.json'); const deploy = require('../deploy.json');
@ -53,19 +51,19 @@ const paths = {
], ],
}; };
// Get credentials // Get git branch info
let credentials = {}; const currentBranch = (() => {
try { try {
credentials = require('../credentials.json'); //eslint-disable-line return gitbranch.sync();
} catch (e) { } catch (_) {
// Do nothing return null;
} }
})();
// Get branch info
const branch = { const branch = {
current: gitbranch.sync(), current: currentBranch,
master: 'master', isMaster: currentBranch === 'master',
beta: 'beta', isBeta: currentBranch === 'beta',
}; };
const maxAge = 31536000; // 1 year const maxAge = 31536000; // 1 year
@ -76,7 +74,7 @@ const options = {
}, },
}, },
demo: { demo: {
uploadPath: branch.current === branch.beta ? '/beta' : null, uploadPath: branch.isBeta ? '/beta' : null,
headers: { headers: {
'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0', 'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0',
}, },
@ -109,11 +107,8 @@ const renameFile = rename((p) => {
// Check we're on the correct branch to deploy // Check we're on the correct branch to deploy
const canDeploy = () => { const canDeploy = () => {
const allowed = [branch.master, branch.beta]; if (![branch.isMaster, branch.isBeta].some(Boolean)) {
console.error(`Must be on an allowed branch to publish! (current: ${branch.current})`);
if (!allowed.includes(branch.current)) {
console.error(`Must be on ${allowed.join(', ')} to publish! (current: ${branch.current})`);
return false; return false;
} }
@ -128,7 +123,7 @@ gulp.task('version', (done) => {
const { domain } = deploy.cdn; const { domain } = deploy.cdn;
log(`Updating version in files to ${ansi.green.bold(version)}...`); log(`Updating version in files to ${green(bold(version))}...`);
// Replace versioned URLs in source // Replace versioned URLs in source
const files = ['plyr.js', 'plyr.polyfilled.js', 'config/defaults.js']; const files = ['plyr.js', 'plyr.polyfilled.js', 'config/defaults.js'];
@ -156,7 +151,7 @@ gulp.task('cdn', (done) => {
throw new Error('No publisher instance. Check AWS configuration.'); throw new Error('No publisher instance. Check AWS configuration.');
} }
log(`Uploading ${ansi.green.bold(pkg.version)} to ${ansi.cyan(domain)}...`); log(`Uploading ${green(bold(pkg.version))} to ${cyan(domain)}...`);
// Upload to CDN // Upload to CDN
return ( return (
@ -177,41 +172,6 @@ gulp.task('cdn', (done) => {
); );
}); });
// Purge the fastly cache incase any 403/404 are cached
gulp.task('purge', () => {
if (!Object.keys(credentials).includes('fastly')) {
throw new Error('Fastly credentials required to purge cache.');
}
const { fastly } = credentials;
const list = [];
return gulp
.src(paths.upload)
.pipe(
through.obj((file, enc, cb) => {
const filename = file.path.split('/').pop();
list.push(`${versionPath}${filename.replace(minSuffix, '')}`);
cb(null);
}),
)
.on('end', () => {
const purge = new FastlyPurge(fastly.token);
list.forEach((url) => {
log(`Purging ${ansi.cyan(url)}...`);
purge.url(url, (error, result) => {
if (error) {
log.error(error);
} else if (result) {
log(result);
}
});
});
});
});
// Publish to demo bucket // Publish to demo bucket
gulp.task('demo', (done) => { gulp.task('demo', (done) => {
if (!canDeploy()) { if (!canDeploy()) {
@ -226,7 +186,7 @@ gulp.task('demo', (done) => {
throw new Error('No publisher instance. Check AWS configuration.'); throw new Error('No publisher instance. Check AWS configuration.');
} }
log(`Uploading ${ansi.green.bold(pkg.version)} to ${ansi.cyan(domain)}...`); log(`Uploading ${green(bold(pkg.version))} to ${cyan(domain)}...`);
// Replace versioned files in README.md // Replace versioned files in README.md
gulp gulp
@ -240,7 +200,7 @@ gulp.task('demo', (done) => {
const error = `${paths.demo}error.html`; const error = `${paths.demo}error.html`;
const pages = [index]; const pages = [index];
if (branch.current === branch.master) { if (branch.isMaster) {
pages.push(error); pages.push(error);
} }
@ -265,10 +225,10 @@ gulp.task('open', () => {
return gulp.src(__filename).pipe( return gulp.src(__filename).pipe(
open({ open({
uri: `https://${domain}/${branch.current === branch.beta ? 'beta' : ''}`, uri: `https://${domain}/${branch.isBeta ? 'beta' : ''}`,
}), }),
); );
}); });
// Do everything // Do everything
gulp.task('deploy', gulp.series('cdn', 'demo', 'purge', 'open')); gulp.task('deploy', gulp.series('cdn', 'demo', 'open'));

6103
yarn.lock

File diff suppressed because it is too large Load Diff