├── README.md ├── bbb-stream-control.cron ├── bbb-stream-control.service ├── controller.py └── var_www_html ├── index.html ├── video-js.css └── video.min.js /README.md: -------------------------------------------------------------------------------- 1 | # Description 2 | 3 | This is a small orchestration script allows you to let your BBB users stream their rooms automatically (via a setting in each room's configuration). 4 | It is build around https://github.com/aau-zid/BigBlueButton-liveStreaming and uses custom patches to Greenlight from this fork: https://github.com/ichdasich/greenlight/tree/streaming 5 | Streaming is supported with a local rtmp instance on nginx, producing HLS, which is then made available via HTTP using a small site relying on https://github.com/videojs/video.js 6 | 7 | # Architecture 8 | - A cron job executes the controller every minute (YMMV) 9 | - If the controller detects a running room with streaming enabled, for which no docker process can be found, it starts a container for streaming. 10 | - nginx consumes the procued rtmp (with the room-path as streaming key) and then produces HLS, which is made available via HTTPS 11 | - A regex based nginx location and a small index.html then provide a web-view of the streams (if they are running) 12 | 13 | # Configuration overview 14 | 15 | ## controller.py 16 | - Change the password in the psql connect string 17 | - `BBB_URL` = Your BBB server or loadbalancer endpoint 18 | - `BBB_SECRET` = Your BBB secret 19 | - `BBB_RTMP_PATH` = `'rtmp://192.168.178.23:1935/live/'`; The IP and port on which nginx listens for rtmp connections; Firewall from the internet 20 | - `BBB_WEB_STREAM` = `'https://bbb.example.com/streams/'`; The base-URL of your streams. Individual streams will look like `https://bbb.example.com/streams/xyz-123-zyx-412/`, depending on the room's path. 21 | - `BBB_RES` = Resolution for the stream, e.g., `'1920x1080'`; The higher the resolution, the higher the load on the machine. 22 | 23 | ## index.html 24 | - Set URL in `src` variable according to your infrastructure (could be done better, i know) 25 | - Update `poster=` according to your infrastructure (background for videos before playing) 26 | 27 | # Installation Instructions 28 | 29 | 1. Git clone the latest greenlite streaming fork 30 | 31 | `git clone -b streaming https://github.com/ichdasich/greenlight.git` 32 | 33 | 2. Compile it with docker / run it - follow the Customize install instructions from BBB page. Make sure to merge it with the newest upstream release for greenlight! Also, make sure to add `streaming` to the enabled features list in `.env` 34 | 35 | 3. Git clone bbb-stream-controll 36 | `git clone https://github.com/ichdasich/bbb-stream-controll` 37 | 38 | 4. Install psycopg 39 | `apt-get install python3-psycopg2` 40 | 41 | 5. Install docker python 42 | `apt-get install python3-docker` 43 | 44 | 6. Install RTMP for nginx 45 | `apt-get install libnginx-mod-rtmp` 46 | 47 | 7. Create folders for nginx: 48 | ``` 49 | mkdir /var/www/html/hls/ 50 | mkdir /var/www/html/streams/ 51 | chown www-data:www-data /var/www/html/hls/ 52 | ``` 53 | 54 | 8. Activate rtmp in nginx by adding the following lines to `/etc/nginx/nginx.conf`. Make sure to replace the listen IP. Do not listen publicly or firewall accordingly. 55 | 56 | ``` 57 | rtmp { 58 | server { 59 | listen LISTENIP:1935; 60 | chunk_size 4096; 61 | allow publish 10.0.0.0/8; 62 | allow publish 172.16.0.0/12; 63 | allow publish 192.168.0.0/16; 64 | deny publish all; 65 | 66 | allow play all; 67 | 68 | application live { 69 | live on; 70 | hls on; 71 | hls_path /var/www/html/hls/; 72 | hls_fragment 3; 73 | hls_playlist_length 60; 74 | record off; 75 | } 76 | } 77 | } 78 | ``` 79 | 80 | 9. In your greenlight vhost (the nginx proxy), add, before the `location / {` statement, the following: 81 | ``` 82 | location ~ "/streams/[^/]+/$" { 83 | try_files $uri $1/index.html; 84 | 85 | } 86 | ``` 87 | 88 | 10. Restart nginx: `service nginx restart` 89 | 90 | 11. Install and configure controller.py; Adjust configuration variables as indicated above 91 | ``` 92 | mkdir /opt/bbb-stream-control/ 93 | cp ./controller.py /opt/bbb-stream-control/ 94 | chmod +x /opt/bbb-stream-control/controller.py 95 | ``` 96 | 97 | 12. Pull the container (to speed up things on first try): `docker image pull aauzid/bigbluebutton-livestreaming` 98 | 99 | 100 | 13. Install `CRON` or `DAEMON` method for execution 101 | 102 | - Install the cronjob running the script every minute: 103 | 104 | `cp bbb-stream-control.cron /etc/cron.d/bbb-stream-control` 105 | 106 | **OR** 107 | 108 | - Install SystemD service that runs every 10-30 seconds 109 | 110 | ``` 111 | cp bbb-stream-control.service /etc/systemd/system 112 | systemctl enable bbb-stream-control 113 | systemctl start bbb-stream-control 114 | ``` 115 | - set `DAEMON=True` in `controller.py` 116 | 117 | 14. Place `var_www_html/index.html` into `/var/www/html/streams/` and adjust according to the config instructions above (change HLS URL) 118 | 119 | 15. Place `var_www_html/video.min.js` and `var_www_html/video-js.css` into `/var/www/html/` 120 | 121 | 122 | # Caveats 123 | - This is a hacky sollution, which (mostly) works; Use at your own judgement 124 | - Cron and containers currently run as root; Planning to fix that in the future 125 | - There is no authentication in front of active streams 126 | - Streaming can be rather resource heavy on your frontend; Be careful. Technically, this setup also works with dedicated hosts for the streaming containers and serving the HLS content. 127 | 128 | 129 | -------------------------------------------------------------------------------- /bbb-stream-control.cron: -------------------------------------------------------------------------------- 1 | SHELL=/bin/sh 2 | PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin 3 | 4 | * * * * * root /opt/bbb-stream-control/controller.py 5 | -------------------------------------------------------------------------------- /bbb-stream-control.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=BBB Live Stream Control 3 | Wants=network.target 4 | After=network.target 5 | 6 | [Service] 7 | Type=simple 8 | ExecStart=/opt/bbb-stream-control/controller.py 9 | StandardOutput=syslog 10 | StandardError=syslog 11 | ExecStop=/bin/kill -s QUIT $MAINPID 12 | Restart=on-failure 13 | RestartSec=10s 14 | 15 | [Install] 16 | WantedBy=multi-user.target -------------------------------------------------------------------------------- /controller.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # Creative Commons Legal Code 3 | # 4 | # CC0 1.0 Universal 5 | # 6 | # CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE 7 | # LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN 8 | # ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS 9 | # INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES 10 | # REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS 11 | # PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM 12 | # THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED 13 | # HEREUNDER. 14 | # 15 | # Statement of Purpose 16 | # 17 | # The laws of most jurisdictions throughout the world automatically confer 18 | # exclusive Copyright and Related Rights (defined below) upon the creator 19 | # and subsequent owner(s) (each and all, an "owner") of an original work of 20 | # authorship and/or a database (each, a "Work"). 21 | # 22 | # Certain owners wish to permanently relinquish those rights to a Work for 23 | # the purpose of contributing to a commons of creative, cultural and 24 | # scientific works ("Commons") that the public can reliably and without fear 25 | # of later claims of infringement build upon, modify, incorporate in other 26 | # works, reuse and redistribute as freely as possible in any form whatsoever 27 | # and for any purposes, including without limitation commercial purposes. 28 | # These owners may contribute to the Commons to promote the ideal of a free 29 | # culture and the further production of creative, cultural and scientific 30 | # works, or to gain reputation or greater distribution for their Work in 31 | # part through the use and efforts of others. 32 | # 33 | # For these and/or other purposes and motivations, and without any 34 | # expectation of additional consideration or compensation, the person 35 | # associating CC0 with a Work (the "Affirmer"), to the extent that he or she 36 | # is an owner of Copyright and Related Rights in the Work, voluntarily 37 | # elects to apply CC0 to the Work and publicly distribute the Work under its 38 | # terms, with knowledge of his or her Copyright and Related Rights in the 39 | # Work and the meaning and intended legal effect of CC0 on those rights. 40 | # 41 | # 1. Copyright and Related Rights. A Work made available under CC0 may be 42 | # protected by copyright and related or neighboring rights ("Copyright and 43 | # Related Rights"). Copyright and Related Rights include, but are not 44 | # limited to, the following: 45 | # 46 | # i. the right to reproduce, adapt, distribute, perform, display, 47 | # communicate, and translate a Work; 48 | # ii. moral rights retained by the original author(s) and/or performer(s); 49 | # iii. publicity and privacy rights pertaining to a person's image or 50 | # likeness depicted in a Work; 51 | # iv. rights protecting against unfair competition in regards to a Work, 52 | # subject to the limitations in paragraph 4(a), below; 53 | # v. rights protecting the extraction, dissemination, use and reuse of data 54 | # in a Work; 55 | # vi. database rights (such as those arising under Directive 96/9/EC of the 56 | # European Parliament and of the Council of 11 March 1996 on the legal 57 | # protection of databases, and under any national implementation 58 | # thereof, including any amended or successor version of such 59 | # directive); and 60 | # vii. other similar, equivalent or corresponding rights throughout the 61 | # world based on applicable law or treaty, and any national 62 | # implementations thereof. 63 | # 64 | # 2. Waiver. To the greatest extent permitted by, but not in contravention 65 | # of, applicable law, Affirmer hereby overtly, fully, permanently, 66 | # irrevocably and unconditionally waives, abandons, and surrenders all of 67 | # Affirmer's Copyright and Related Rights and associated claims and causes 68 | # of action, whether now known or unknown (including existing as well as 69 | # future claims and causes of action), in the Work (i) in all territories 70 | # worldwide, (ii) for the maximum duration provided by applicable law or 71 | # treaty (including future time extensions), (iii) in any current or future 72 | # medium and for any number of copies, and (iv) for any purpose whatsoever, 73 | # including without limitation commercial, advertising or promotional 74 | # purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each 75 | # member of the public at large and to the detriment of Affirmer's heirs and 76 | # successors, fully intending that such Waiver shall not be subject to 77 | # revocation, rescission, cancellation, termination, or any other legal or 78 | # equitable action to disrupt the quiet enjoyment of the Work by the public 79 | # as contemplated by Affirmer's express Statement of Purpose. 80 | # 81 | # 3. Public License Fallback. Should any part of the Waiver for any reason 82 | # be judged legally invalid or ineffective under applicable law, then the 83 | # Waiver shall be preserved to the maximum extent permitted taking into 84 | # account Affirmer's express Statement of Purpose. In addition, to the 85 | # extent the Waiver is so judged Affirmer hereby grants to each affected 86 | # person a royalty-free, non transferable, non sublicensable, non exclusive, 87 | # irrevocable and unconditional license to exercise Affirmer's Copyright and 88 | # Related Rights in the Work (i) in all territories worldwide, (ii) for the 89 | # maximum duration provided by applicable law or treaty (including future 90 | # time extensions), (iii) in any current or future medium and for any number 91 | # of copies, and (iv) for any purpose whatsoever, including without 92 | # limitation commercial, advertising or promotional purposes (the 93 | # "License"). The License shall be deemed effective as of the date CC0 was 94 | # applied by Affirmer to the Work. Should any part of the License for any 95 | # reason be judged legally invalid or ineffective under applicable law, such 96 | # partial invalidity or ineffectiveness shall not invalidate the remainder 97 | # of the License, and in such case Affirmer hereby affirms that he or she 98 | # will not (i) exercise any of his or her remaining Copyright and Related 99 | # Rights in the Work or (ii) assert any associated claims and causes of 100 | # action with respect to the Work, in either case contrary to Affirmer's 101 | # express Statement of Purpose. 102 | # 103 | # 4. Limitations and Disclaimers. 104 | # 105 | # a. No trademark or patent rights held by Affirmer are waived, abandoned, 106 | # surrendered, licensed or otherwise affected by this document. 107 | # b. Affirmer offers the Work as-is and makes no representations or 108 | # warranties of any kind concerning the Work, express, implied, 109 | # statutory or otherwise, including without limitation warranties of 110 | # title, merchantability, fitness for a particular purpose, non 111 | # infringement, or the absence of latent or other defects, accuracy, or 112 | # the present or absence of errors, whether or not discoverable, all to 113 | # the greatest extent permissible under applicable law. 114 | # c. Affirmer disclaims responsibility for clearing rights of other persons 115 | # that may apply to the Work or any use thereof, including without 116 | # limitation any person's Copyright and Related Rights in the Work. 117 | # Further, Affirmer disclaims responsibility for obtaining any necessary 118 | # consents, permissions or other rights required for any use of the 119 | # Work. 120 | # d. Affirmer understands and acknowledges that Creative Commons is not a 121 | # party to this document and has no duty or obligation with respect to 122 | # this CC0 or use of the Work. 123 | 124 | import sys 125 | import re 126 | import hashlib 127 | import requests 128 | import docker 129 | import json 130 | import time 131 | from xml.etree import ElementTree 132 | 133 | import psycopg2 134 | conn_auth = psycopg2.connect("dbname=greenlight_production user=postgres password=PASSWORD host=localhost") 135 | 136 | DAEMON=False 137 | BBB_URL = "https://bbb.example.com/bigbluebutton/" 138 | BBB_SECRET = "BBB_SECRET" 139 | BBB_RTMP_PATH = 'rtmp://192.168.178.23:1935/live/' 140 | BBB_WEB_STREAM = 'https://bbb.example.com/streams/' 141 | BBB_RES = '1920x1080' 142 | 143 | client = docker.from_env() 144 | 145 | def get_running_rooms(): 146 | 147 | URL = BBB_URL 148 | secret = BBB_SECRET 149 | 150 | APIURL=URL + 'api/' 151 | 152 | apimethod='getMeetings' 153 | querystring='' 154 | 155 | h = hashlib.sha1((apimethod+querystring+secret).encode('utf-8')) 156 | checksum = h.hexdigest() 157 | 158 | if len(querystring) > 0: 159 | querystring = querystring + '&' 160 | 161 | requesturl = APIURL + apimethod + '?' + querystring + 'checksum=' + checksum 162 | 163 | response = requests.get(requesturl) 164 | tree = ElementTree.fromstring(response.content) 165 | 166 | if tree.find('returncode').text != 'SUCCESS': 167 | print('error getting API data') 168 | sys.exit(1) 169 | meetings = tree.find('meetings') 170 | 171 | mids = {} 172 | if meetings: 173 | for m in meetings.iter('meeting'): 174 | user_no = m.find('participantCount').text 175 | users = [] 176 | for u in m.find('attendees').iter('attendee'): 177 | users.append(u.find('fullName').text) 178 | meetid = m.find('meetingID').text 179 | meetid_int = m.find('internalMeetingID').text 180 | mids[meetid] = {'bbb_meet_id': meetid_int, 'users': users, 'user_no': int(user_no) } 181 | return mids 182 | 183 | def check_streaming_rooms(meetingids): 184 | streaming_rooms = {} 185 | cur = conn_auth.cursor() 186 | 187 | for bbbid in meetingids.keys(): 188 | cur.execute("SELECT uid,attendee_pw,room_settings FROM rooms WHERE bbb_id = %s;", (bbbid,)) 189 | res = cur.fetchall() 190 | if res: 191 | roompath = res[0][0] 192 | attendeepw = res[0][1] 193 | roomdata = json.loads(res[0][2]) 194 | if 'streaming' in roomdata: 195 | if roomdata['streaming'] == True: 196 | meetingids[bbbid]['roompath'] = roompath 197 | meetingids[bbbid]['attendeepw'] = attendeepw 198 | meetingids[bbbid]['roomdata'] = dict(roomdata) 199 | streaming_rooms[bbbid] = meetingids[bbbid] 200 | return streaming_rooms 201 | 202 | def check_container_running(bbbid): 203 | try: 204 | container = client.containers.get('strm_'+bbbid) 205 | except docker.errors.NotFound: 206 | return False 207 | return True 208 | 209 | def start_streaming(meetingids): 210 | streamCount=0 211 | client.containers.prune() 212 | for bbbid in meetingids.keys(): 213 | dockerenv = { 214 | 'BBB_URL': BBB_URL, 215 | 'TZ': 'Europe/Vienna', 216 | 'BBB_RESOLUTION': BBB_RES, 217 | 'BBB_START_MEETING': 'false', 218 | 'BBB_MEETING_ID': bbbid, 219 | 'FFMPEG_STREAM_THREADS': '0', 220 | 'BBB_STREAM_URL': BBB_RTMP_PATH + meetingids[bbbid]['roompath'], 221 | 'FFMPEG_STREAM_VIDEO_BITRATE': '4000', 222 | 'BBB_SECRET': BBB_SECRET, 223 | 'BBB_SHOW_CHAT': 'false', 224 | 'BBB_USER_NAME': 'Streaming User', 225 | 'BBB_CHAT_STREAM_URL': BBB_WEB_STREAM+meetingids[bbbid]['roompath']+'/', 226 | 'BBB_ATTENDEE_PASSWORD': meetingids[bbbid]['attendeepw'] 227 | } 228 | 229 | if not check_container_running(bbbid) and meetingids[bbbid]['user_no'] > 0 and not 'Streaming User' in meetingids[bbbid]['users']: 230 | container = client.containers.run('aauzid/bigbluebutton-livestreaming', name='strm_'+bbbid, shm_size='2gb', environment=dockerenv, detach=True) 231 | streamCount += 1 232 | print('Started container strm_'+bbbid+'\n') 233 | return streamCount 234 | def terminate_orphaned(meetingids): 235 | containers = client.containers.list() 236 | for container in containers: 237 | if '/strm_' == container.attrs['Name'][:6]: 238 | name = container.attrs['Name'][6:] 239 | 240 | if not name in meetingids: 241 | container.kill() 242 | else: 243 | if meetingids[name]['user_no'] == 1 and 'Streaming User' in meetingids[name]['users']: 244 | container.kill() 245 | print('Stopping container /strm_' == container.attrs['Name'][:6]) 246 | client.containers.prune() 247 | 248 | while True: 249 | delayTimout = 10 250 | mids = get_running_rooms() 251 | stream_mids = check_streaming_rooms(mids) 252 | retVal=start_streaming(stream_mids) 253 | if retVal > 0: 254 | # Delay next loop a little to allow container to start 255 | delayTimout = 30 256 | terminate_orphaned(stream_mids) 257 | if DAEMON: 258 | time.sleep(delayTimout) 259 | else: 260 | break 261 | -------------------------------------------------------------------------------- /var_www_html/index.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 5 | 6 | 7 | 8 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /var_www_html/video-js.css: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | .vjs-modal-dialog .vjs-modal-dialog-content, .video-js .vjs-modal-dialog, .vjs-button > .vjs-icon-placeholder:before, .video-js .vjs-big-play-button .vjs-icon-placeholder:before { 3 | position: absolute; 4 | top: 0; 5 | left: 0; 6 | width: 100%; 7 | height: 100%; 8 | } 9 | 10 | .vjs-button > .vjs-icon-placeholder:before, .video-js .vjs-big-play-button .vjs-icon-placeholder:before { 11 | text-align: center; 12 | } 13 | 14 | @font-face { 15 | font-family: VideoJS; 16 | src: url(data:application/font-woff;charset=utf-8;base64,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) format("woff"); 17 | font-weight: normal; 18 | font-style: normal; 19 | } 20 | .vjs-icon-play, .video-js .vjs-play-control .vjs-icon-placeholder, .video-js .vjs-big-play-button .vjs-icon-placeholder:before { 21 | font-family: VideoJS; 22 | font-weight: normal; 23 | font-style: normal; 24 | } 25 | .vjs-icon-play:before, .video-js .vjs-play-control .vjs-icon-placeholder:before, .video-js .vjs-big-play-button .vjs-icon-placeholder:before { 26 | content: "\f101"; 27 | } 28 | 29 | .vjs-icon-play-circle { 30 | font-family: VideoJS; 31 | font-weight: normal; 32 | font-style: normal; 33 | } 34 | .vjs-icon-play-circle:before { 35 | content: "\f102"; 36 | } 37 | 38 | .vjs-icon-pause, .video-js .vjs-play-control.vjs-playing .vjs-icon-placeholder { 39 | font-family: VideoJS; 40 | font-weight: normal; 41 | font-style: normal; 42 | } 43 | .vjs-icon-pause:before, .video-js .vjs-play-control.vjs-playing .vjs-icon-placeholder:before { 44 | content: "\f103"; 45 | } 46 | 47 | .vjs-icon-volume-mute, .video-js .vjs-mute-control.vjs-vol-0 .vjs-icon-placeholder { 48 | font-family: VideoJS; 49 | font-weight: normal; 50 | font-style: normal; 51 | } 52 | .vjs-icon-volume-mute:before, .video-js .vjs-mute-control.vjs-vol-0 .vjs-icon-placeholder:before { 53 | content: "\f104"; 54 | } 55 | 56 | .vjs-icon-volume-low, .video-js .vjs-mute-control.vjs-vol-1 .vjs-icon-placeholder { 57 | font-family: VideoJS; 58 | font-weight: normal; 59 | font-style: normal; 60 | } 61 | .vjs-icon-volume-low:before, .video-js .vjs-mute-control.vjs-vol-1 .vjs-icon-placeholder:before { 62 | content: "\f105"; 63 | } 64 | 65 | .vjs-icon-volume-mid, .video-js .vjs-mute-control.vjs-vol-2 .vjs-icon-placeholder { 66 | font-family: VideoJS; 67 | font-weight: normal; 68 | font-style: normal; 69 | } 70 | .vjs-icon-volume-mid:before, .video-js .vjs-mute-control.vjs-vol-2 .vjs-icon-placeholder:before { 71 | content: "\f106"; 72 | } 73 | 74 | .vjs-icon-volume-high, .video-js .vjs-mute-control .vjs-icon-placeholder { 75 | font-family: VideoJS; 76 | font-weight: normal; 77 | font-style: normal; 78 | } 79 | .vjs-icon-volume-high:before, .video-js .vjs-mute-control .vjs-icon-placeholder:before { 80 | content: "\f107"; 81 | } 82 | 83 | .vjs-icon-fullscreen-enter, .video-js .vjs-fullscreen-control .vjs-icon-placeholder { 84 | font-family: VideoJS; 85 | font-weight: normal; 86 | font-style: normal; 87 | } 88 | .vjs-icon-fullscreen-enter:before, .video-js .vjs-fullscreen-control .vjs-icon-placeholder:before { 89 | content: "\f108"; 90 | } 91 | 92 | .vjs-icon-fullscreen-exit, .video-js.vjs-fullscreen .vjs-fullscreen-control .vjs-icon-placeholder { 93 | font-family: VideoJS; 94 | font-weight: normal; 95 | font-style: normal; 96 | } 97 | .vjs-icon-fullscreen-exit:before, .video-js.vjs-fullscreen .vjs-fullscreen-control .vjs-icon-placeholder:before { 98 | content: "\f109"; 99 | } 100 | 101 | .vjs-icon-square { 102 | font-family: VideoJS; 103 | font-weight: normal; 104 | font-style: normal; 105 | } 106 | .vjs-icon-square:before { 107 | content: "\f10a"; 108 | } 109 | 110 | .vjs-icon-spinner { 111 | font-family: VideoJS; 112 | font-weight: normal; 113 | font-style: normal; 114 | } 115 | .vjs-icon-spinner:before { 116 | content: "\f10b"; 117 | } 118 | 119 | .vjs-icon-subtitles, .video-js .vjs-subs-caps-button .vjs-icon-placeholder, 120 | .video-js.video-js:lang(en-GB) .vjs-subs-caps-button .vjs-icon-placeholder, 121 | .video-js.video-js:lang(en-IE) .vjs-subs-caps-button .vjs-icon-placeholder, 122 | .video-js.video-js:lang(en-AU) .vjs-subs-caps-button .vjs-icon-placeholder, 123 | .video-js.video-js:lang(en-NZ) .vjs-subs-caps-button .vjs-icon-placeholder, .video-js .vjs-subtitles-button .vjs-icon-placeholder { 124 | font-family: VideoJS; 125 | font-weight: normal; 126 | font-style: normal; 127 | } 128 | .vjs-icon-subtitles:before, .video-js .vjs-subs-caps-button .vjs-icon-placeholder:before, 129 | .video-js.video-js:lang(en-GB) .vjs-subs-caps-button .vjs-icon-placeholder:before, 130 | .video-js.video-js:lang(en-IE) .vjs-subs-caps-button .vjs-icon-placeholder:before, 131 | .video-js.video-js:lang(en-AU) .vjs-subs-caps-button .vjs-icon-placeholder:before, 132 | .video-js.video-js:lang(en-NZ) .vjs-subs-caps-button .vjs-icon-placeholder:before, .video-js .vjs-subtitles-button .vjs-icon-placeholder:before { 133 | content: "\f10c"; 134 | } 135 | 136 | .vjs-icon-captions, .video-js:lang(en) .vjs-subs-caps-button .vjs-icon-placeholder, 137 | .video-js:lang(fr-CA) .vjs-subs-caps-button .vjs-icon-placeholder, .video-js .vjs-captions-button .vjs-icon-placeholder { 138 | font-family: VideoJS; 139 | font-weight: normal; 140 | font-style: normal; 141 | } 142 | .vjs-icon-captions:before, .video-js:lang(en) .vjs-subs-caps-button .vjs-icon-placeholder:before, 143 | .video-js:lang(fr-CA) .vjs-subs-caps-button .vjs-icon-placeholder:before, .video-js .vjs-captions-button .vjs-icon-placeholder:before { 144 | content: "\f10d"; 145 | } 146 | 147 | .vjs-icon-chapters, .video-js .vjs-chapters-button .vjs-icon-placeholder { 148 | font-family: VideoJS; 149 | font-weight: normal; 150 | font-style: normal; 151 | } 152 | .vjs-icon-chapters:before, .video-js .vjs-chapters-button .vjs-icon-placeholder:before { 153 | content: "\f10e"; 154 | } 155 | 156 | .vjs-icon-share { 157 | font-family: VideoJS; 158 | font-weight: normal; 159 | font-style: normal; 160 | } 161 | .vjs-icon-share:before { 162 | content: "\f10f"; 163 | } 164 | 165 | .vjs-icon-cog { 166 | font-family: VideoJS; 167 | font-weight: normal; 168 | font-style: normal; 169 | } 170 | .vjs-icon-cog:before { 171 | content: "\f110"; 172 | } 173 | 174 | .vjs-icon-circle, .vjs-seek-to-live-control .vjs-icon-placeholder, .video-js .vjs-volume-level, .video-js .vjs-play-progress { 175 | font-family: VideoJS; 176 | font-weight: normal; 177 | font-style: normal; 178 | } 179 | .vjs-icon-circle:before, .vjs-seek-to-live-control .vjs-icon-placeholder:before, .video-js .vjs-volume-level:before, .video-js .vjs-play-progress:before { 180 | content: "\f111"; 181 | } 182 | 183 | .vjs-icon-circle-outline { 184 | font-family: VideoJS; 185 | font-weight: normal; 186 | font-style: normal; 187 | } 188 | .vjs-icon-circle-outline:before { 189 | content: "\f112"; 190 | } 191 | 192 | .vjs-icon-circle-inner-circle { 193 | font-family: VideoJS; 194 | font-weight: normal; 195 | font-style: normal; 196 | } 197 | .vjs-icon-circle-inner-circle:before { 198 | content: "\f113"; 199 | } 200 | 201 | .vjs-icon-hd { 202 | font-family: VideoJS; 203 | font-weight: normal; 204 | font-style: normal; 205 | } 206 | .vjs-icon-hd:before { 207 | content: "\f114"; 208 | } 209 | 210 | .vjs-icon-cancel, .video-js .vjs-control.vjs-close-button .vjs-icon-placeholder { 211 | font-family: VideoJS; 212 | font-weight: normal; 213 | font-style: normal; 214 | } 215 | .vjs-icon-cancel:before, .video-js .vjs-control.vjs-close-button .vjs-icon-placeholder:before { 216 | content: "\f115"; 217 | } 218 | 219 | .vjs-icon-replay, .video-js .vjs-play-control.vjs-ended .vjs-icon-placeholder { 220 | font-family: VideoJS; 221 | font-weight: normal; 222 | font-style: normal; 223 | } 224 | .vjs-icon-replay:before, .video-js .vjs-play-control.vjs-ended .vjs-icon-placeholder:before { 225 | content: "\f116"; 226 | } 227 | 228 | .vjs-icon-facebook { 229 | font-family: VideoJS; 230 | font-weight: normal; 231 | font-style: normal; 232 | } 233 | .vjs-icon-facebook:before { 234 | content: "\f117"; 235 | } 236 | 237 | .vjs-icon-gplus { 238 | font-family: VideoJS; 239 | font-weight: normal; 240 | font-style: normal; 241 | } 242 | .vjs-icon-gplus:before { 243 | content: "\f118"; 244 | } 245 | 246 | .vjs-icon-linkedin { 247 | font-family: VideoJS; 248 | font-weight: normal; 249 | font-style: normal; 250 | } 251 | .vjs-icon-linkedin:before { 252 | content: "\f119"; 253 | } 254 | 255 | .vjs-icon-twitter { 256 | font-family: VideoJS; 257 | font-weight: normal; 258 | font-style: normal; 259 | } 260 | .vjs-icon-twitter:before { 261 | content: "\f11a"; 262 | } 263 | 264 | .vjs-icon-tumblr { 265 | font-family: VideoJS; 266 | font-weight: normal; 267 | font-style: normal; 268 | } 269 | .vjs-icon-tumblr:before { 270 | content: "\f11b"; 271 | } 272 | 273 | .vjs-icon-pinterest { 274 | font-family: VideoJS; 275 | font-weight: normal; 276 | font-style: normal; 277 | } 278 | .vjs-icon-pinterest:before { 279 | content: "\f11c"; 280 | } 281 | 282 | .vjs-icon-audio-description, .video-js .vjs-descriptions-button .vjs-icon-placeholder { 283 | font-family: VideoJS; 284 | font-weight: normal; 285 | font-style: normal; 286 | } 287 | .vjs-icon-audio-description:before, .video-js .vjs-descriptions-button .vjs-icon-placeholder:before { 288 | content: "\f11d"; 289 | } 290 | 291 | .vjs-icon-audio, .video-js .vjs-audio-button .vjs-icon-placeholder { 292 | font-family: VideoJS; 293 | font-weight: normal; 294 | font-style: normal; 295 | } 296 | .vjs-icon-audio:before, .video-js .vjs-audio-button .vjs-icon-placeholder:before { 297 | content: "\f11e"; 298 | } 299 | 300 | .vjs-icon-next-item { 301 | font-family: VideoJS; 302 | font-weight: normal; 303 | font-style: normal; 304 | } 305 | .vjs-icon-next-item:before { 306 | content: "\f11f"; 307 | } 308 | 309 | .vjs-icon-previous-item { 310 | font-family: VideoJS; 311 | font-weight: normal; 312 | font-style: normal; 313 | } 314 | .vjs-icon-previous-item:before { 315 | content: "\f120"; 316 | } 317 | 318 | .vjs-icon-picture-in-picture-enter, .video-js .vjs-picture-in-picture-control .vjs-icon-placeholder { 319 | font-family: VideoJS; 320 | font-weight: normal; 321 | font-style: normal; 322 | } 323 | .vjs-icon-picture-in-picture-enter:before, .video-js .vjs-picture-in-picture-control .vjs-icon-placeholder:before { 324 | content: "\f121"; 325 | } 326 | 327 | .vjs-icon-picture-in-picture-exit, .video-js.vjs-picture-in-picture .vjs-picture-in-picture-control .vjs-icon-placeholder { 328 | font-family: VideoJS; 329 | font-weight: normal; 330 | font-style: normal; 331 | } 332 | .vjs-icon-picture-in-picture-exit:before, .video-js.vjs-picture-in-picture .vjs-picture-in-picture-control .vjs-icon-placeholder:before { 333 | content: "\f122"; 334 | } 335 | 336 | .video-js { 337 | display: block; 338 | vertical-align: top; 339 | box-sizing: border-box; 340 | color: #fff; 341 | background-color: #000; 342 | position: relative; 343 | padding: 0; 344 | font-size: 10px; 345 | line-height: 1; 346 | font-weight: normal; 347 | font-style: normal; 348 | font-family: Arial, Helvetica, sans-serif; 349 | word-break: initial; 350 | } 351 | .video-js:-moz-full-screen { 352 | position: absolute; 353 | } 354 | .video-js:-webkit-full-screen { 355 | width: 100% !important; 356 | height: 100% !important; 357 | } 358 | 359 | .video-js[tabindex="-1"] { 360 | outline: none; 361 | } 362 | 363 | .video-js *, 364 | .video-js *:before, 365 | .video-js *:after { 366 | box-sizing: inherit; 367 | } 368 | 369 | .video-js ul { 370 | font-family: inherit; 371 | font-size: inherit; 372 | line-height: inherit; 373 | list-style-position: outside; 374 | margin-left: 0; 375 | margin-right: 0; 376 | margin-top: 0; 377 | margin-bottom: 0; 378 | } 379 | 380 | .video-js.vjs-fluid, 381 | .video-js.vjs-16-9, 382 | .video-js.vjs-4-3 { 383 | width: 100%; 384 | max-width: 100%; 385 | height: 0; 386 | } 387 | 388 | .video-js.vjs-16-9 { 389 | padding-top: 56.25%; 390 | } 391 | 392 | .video-js.vjs-4-3 { 393 | padding-top: 75%; 394 | } 395 | 396 | .video-js.vjs-fill { 397 | width: 100%; 398 | height: 100%; 399 | } 400 | 401 | .video-js .vjs-tech { 402 | position: absolute; 403 | top: 0; 404 | left: 0; 405 | width: 100%; 406 | height: 100%; 407 | } 408 | 409 | body.vjs-full-window { 410 | padding: 0; 411 | margin: 0; 412 | height: 100%; 413 | } 414 | 415 | .vjs-full-window .video-js.vjs-fullscreen { 416 | position: fixed; 417 | overflow: hidden; 418 | z-index: 1000; 419 | left: 0; 420 | top: 0; 421 | bottom: 0; 422 | right: 0; 423 | } 424 | 425 | .video-js.vjs-fullscreen:not(.vjs-ios-native-fs) { 426 | width: 100% !important; 427 | height: 100% !important; 428 | padding-top: 0 !important; 429 | } 430 | 431 | .video-js.vjs-fullscreen.vjs-user-inactive { 432 | cursor: none; 433 | } 434 | 435 | .vjs-hidden { 436 | display: none !important; 437 | } 438 | 439 | .vjs-disabled { 440 | opacity: 0.5; 441 | cursor: default; 442 | } 443 | 444 | .video-js .vjs-offscreen { 445 | height: 1px; 446 | left: -9999px; 447 | position: absolute; 448 | top: 0; 449 | width: 1px; 450 | } 451 | 452 | .vjs-lock-showing { 453 | display: block !important; 454 | opacity: 1; 455 | visibility: visible; 456 | } 457 | 458 | .vjs-no-js { 459 | padding: 20px; 460 | color: #fff; 461 | background-color: #000; 462 | font-size: 18px; 463 | font-family: Arial, Helvetica, sans-serif; 464 | text-align: center; 465 | width: 300px; 466 | height: 150px; 467 | margin: 0px auto; 468 | } 469 | 470 | .vjs-no-js a, 471 | .vjs-no-js a:visited { 472 | color: #66A8CC; 473 | } 474 | 475 | .video-js .vjs-big-play-button { 476 | font-size: 3em; 477 | line-height: 1.5em; 478 | height: 1.63332em; 479 | width: 3em; 480 | display: block; 481 | position: absolute; 482 | top: 10px; 483 | left: 10px; 484 | padding: 0; 485 | cursor: pointer; 486 | opacity: 1; 487 | border: 0.06666em solid #fff; 488 | background-color: #2B333F; 489 | background-color: rgba(43, 51, 63, 0.7); 490 | border-radius: 0.3em; 491 | transition: all 0.4s; 492 | } 493 | .vjs-big-play-centered .vjs-big-play-button { 494 | top: 50%; 495 | left: 50%; 496 | margin-top: -0.81666em; 497 | margin-left: -1.5em; 498 | } 499 | 500 | .video-js:hover .vjs-big-play-button, 501 | .video-js .vjs-big-play-button:focus { 502 | border-color: #fff; 503 | background-color: #73859f; 504 | background-color: rgba(115, 133, 159, 0.5); 505 | transition: all 0s; 506 | } 507 | 508 | .vjs-controls-disabled .vjs-big-play-button, 509 | .vjs-has-started .vjs-big-play-button, 510 | .vjs-using-native-controls .vjs-big-play-button, 511 | .vjs-error .vjs-big-play-button { 512 | display: none; 513 | } 514 | 515 | .vjs-has-started.vjs-paused.vjs-show-big-play-button-on-pause .vjs-big-play-button { 516 | display: block; 517 | } 518 | 519 | .video-js button { 520 | background: none; 521 | border: none; 522 | color: inherit; 523 | display: inline-block; 524 | font-size: inherit; 525 | line-height: inherit; 526 | text-transform: none; 527 | text-decoration: none; 528 | transition: none; 529 | -webkit-appearance: none; 530 | -moz-appearance: none; 531 | appearance: none; 532 | } 533 | 534 | .vjs-control .vjs-button { 535 | width: 100%; 536 | height: 100%; 537 | } 538 | 539 | .video-js .vjs-control.vjs-close-button { 540 | cursor: pointer; 541 | height: 3em; 542 | position: absolute; 543 | right: 0; 544 | top: 0.5em; 545 | z-index: 2; 546 | } 547 | .video-js .vjs-modal-dialog { 548 | background: rgba(0, 0, 0, 0.8); 549 | background: linear-gradient(180deg, rgba(0, 0, 0, 0.8), rgba(255, 255, 255, 0)); 550 | overflow: auto; 551 | } 552 | 553 | .video-js .vjs-modal-dialog > * { 554 | box-sizing: border-box; 555 | } 556 | 557 | .vjs-modal-dialog .vjs-modal-dialog-content { 558 | font-size: 1.2em; 559 | line-height: 1.5; 560 | padding: 20px 24px; 561 | z-index: 1; 562 | } 563 | 564 | .vjs-menu-button { 565 | cursor: pointer; 566 | } 567 | 568 | .vjs-menu-button.vjs-disabled { 569 | cursor: default; 570 | } 571 | 572 | .vjs-workinghover .vjs-menu-button.vjs-disabled:hover .vjs-menu { 573 | display: none; 574 | } 575 | 576 | .vjs-menu .vjs-menu-content { 577 | display: block; 578 | padding: 0; 579 | margin: 0; 580 | font-family: Arial, Helvetica, sans-serif; 581 | overflow: auto; 582 | } 583 | 584 | .vjs-menu .vjs-menu-content > * { 585 | box-sizing: border-box; 586 | } 587 | 588 | .vjs-scrubbing .vjs-control.vjs-menu-button:hover .vjs-menu { 589 | display: none; 590 | } 591 | 592 | .vjs-menu li { 593 | list-style: none; 594 | margin: 0; 595 | padding: 0.2em 0; 596 | line-height: 1.4em; 597 | font-size: 1.2em; 598 | text-align: center; 599 | text-transform: lowercase; 600 | } 601 | 602 | .vjs-menu li.vjs-menu-item:focus, 603 | .vjs-menu li.vjs-menu-item:hover, 604 | .js-focus-visible .vjs-menu li.vjs-menu-item:hover { 605 | background-color: #73859f; 606 | background-color: rgba(115, 133, 159, 0.5); 607 | } 608 | 609 | .vjs-menu li.vjs-selected, 610 | .vjs-menu li.vjs-selected:focus, 611 | .vjs-menu li.vjs-selected:hover, 612 | .js-focus-visible .vjs-menu li.vjs-selected:hover { 613 | background-color: #fff; 614 | color: #2B333F; 615 | } 616 | 617 | .vjs-menu li.vjs-menu-title { 618 | text-align: center; 619 | text-transform: uppercase; 620 | font-size: 1em; 621 | line-height: 2em; 622 | padding: 0; 623 | margin: 0 0 0.3em 0; 624 | font-weight: bold; 625 | cursor: default; 626 | } 627 | 628 | .vjs-menu-button-popup .vjs-menu { 629 | display: none; 630 | position: absolute; 631 | bottom: 0; 632 | width: 10em; 633 | left: -3em; 634 | height: 0em; 635 | margin-bottom: 1.5em; 636 | border-top-color: rgba(43, 51, 63, 0.7); 637 | } 638 | 639 | .vjs-menu-button-popup .vjs-menu .vjs-menu-content { 640 | background-color: #2B333F; 641 | background-color: rgba(43, 51, 63, 0.7); 642 | position: absolute; 643 | width: 100%; 644 | bottom: 1.5em; 645 | max-height: 15em; 646 | } 647 | 648 | .vjs-layout-tiny .vjs-menu-button-popup .vjs-menu .vjs-menu-content, 649 | .vjs-layout-x-small .vjs-menu-button-popup .vjs-menu .vjs-menu-content { 650 | max-height: 5em; 651 | } 652 | 653 | .vjs-layout-small .vjs-menu-button-popup .vjs-menu .vjs-menu-content { 654 | max-height: 10em; 655 | } 656 | 657 | .vjs-layout-medium .vjs-menu-button-popup .vjs-menu .vjs-menu-content { 658 | max-height: 14em; 659 | } 660 | 661 | .vjs-layout-large .vjs-menu-button-popup .vjs-menu .vjs-menu-content, 662 | .vjs-layout-x-large .vjs-menu-button-popup .vjs-menu .vjs-menu-content, 663 | .vjs-layout-huge .vjs-menu-button-popup .vjs-menu .vjs-menu-content { 664 | max-height: 25em; 665 | } 666 | 667 | .vjs-workinghover .vjs-menu-button-popup.vjs-hover .vjs-menu, 668 | .vjs-menu-button-popup .vjs-menu.vjs-lock-showing { 669 | display: block; 670 | } 671 | 672 | .video-js .vjs-menu-button-inline { 673 | transition: all 0.4s; 674 | overflow: hidden; 675 | } 676 | 677 | .video-js .vjs-menu-button-inline:before { 678 | width: 2.222222222em; 679 | } 680 | 681 | .video-js .vjs-menu-button-inline:hover, 682 | .video-js .vjs-menu-button-inline:focus, 683 | .video-js .vjs-menu-button-inline.vjs-slider-active, 684 | .video-js.vjs-no-flex .vjs-menu-button-inline { 685 | width: 12em; 686 | } 687 | 688 | .vjs-menu-button-inline .vjs-menu { 689 | opacity: 0; 690 | height: 100%; 691 | width: auto; 692 | position: absolute; 693 | left: 4em; 694 | top: 0; 695 | padding: 0; 696 | margin: 0; 697 | transition: all 0.4s; 698 | } 699 | 700 | .vjs-menu-button-inline:hover .vjs-menu, 701 | .vjs-menu-button-inline:focus .vjs-menu, 702 | .vjs-menu-button-inline.vjs-slider-active .vjs-menu { 703 | display: block; 704 | opacity: 1; 705 | } 706 | 707 | .vjs-no-flex .vjs-menu-button-inline .vjs-menu { 708 | display: block; 709 | opacity: 1; 710 | position: relative; 711 | width: auto; 712 | } 713 | 714 | .vjs-no-flex .vjs-menu-button-inline:hover .vjs-menu, 715 | .vjs-no-flex .vjs-menu-button-inline:focus .vjs-menu, 716 | .vjs-no-flex .vjs-menu-button-inline.vjs-slider-active .vjs-menu { 717 | width: auto; 718 | } 719 | 720 | .vjs-menu-button-inline .vjs-menu-content { 721 | width: auto; 722 | height: 100%; 723 | margin: 0; 724 | overflow: hidden; 725 | } 726 | 727 | .video-js .vjs-control-bar { 728 | display: none; 729 | width: 100%; 730 | position: absolute; 731 | bottom: 0; 732 | left: 0; 733 | right: 0; 734 | height: 3em; 735 | background-color: #2B333F; 736 | background-color: rgba(43, 51, 63, 0.7); 737 | } 738 | 739 | .vjs-has-started .vjs-control-bar { 740 | display: flex; 741 | visibility: visible; 742 | opacity: 1; 743 | transition: visibility 0.1s, opacity 0.1s; 744 | } 745 | 746 | .vjs-has-started.vjs-user-inactive.vjs-playing .vjs-control-bar { 747 | visibility: visible; 748 | opacity: 0; 749 | transition: visibility 1s, opacity 1s; 750 | } 751 | 752 | .vjs-controls-disabled .vjs-control-bar, 753 | .vjs-using-native-controls .vjs-control-bar, 754 | .vjs-error .vjs-control-bar { 755 | display: none !important; 756 | } 757 | 758 | .vjs-audio.vjs-has-started.vjs-user-inactive.vjs-playing .vjs-control-bar { 759 | opacity: 1; 760 | visibility: visible; 761 | } 762 | 763 | .vjs-has-started.vjs-no-flex .vjs-control-bar { 764 | display: table; 765 | } 766 | 767 | .video-js .vjs-control { 768 | position: relative; 769 | text-align: center; 770 | margin: 0; 771 | padding: 0; 772 | height: 100%; 773 | width: 4em; 774 | flex: none; 775 | } 776 | 777 | .vjs-button > .vjs-icon-placeholder:before { 778 | font-size: 1.8em; 779 | line-height: 1.67; 780 | } 781 | 782 | .video-js .vjs-control:focus:before, 783 | .video-js .vjs-control:hover:before, 784 | .video-js .vjs-control:focus { 785 | text-shadow: 0em 0em 1em white; 786 | } 787 | 788 | .video-js .vjs-control-text { 789 | border: 0; 790 | clip: rect(0 0 0 0); 791 | height: 1px; 792 | overflow: hidden; 793 | padding: 0; 794 | position: absolute; 795 | width: 1px; 796 | } 797 | 798 | .vjs-no-flex .vjs-control { 799 | display: table-cell; 800 | vertical-align: middle; 801 | } 802 | 803 | .video-js .vjs-custom-control-spacer { 804 | display: none; 805 | } 806 | 807 | .video-js .vjs-progress-control { 808 | cursor: pointer; 809 | flex: auto; 810 | display: flex; 811 | align-items: center; 812 | min-width: 4em; 813 | touch-action: none; 814 | } 815 | 816 | .video-js .vjs-progress-control.disabled { 817 | cursor: default; 818 | } 819 | 820 | .vjs-live .vjs-progress-control { 821 | display: none; 822 | } 823 | 824 | .vjs-liveui .vjs-progress-control { 825 | display: flex; 826 | align-items: center; 827 | } 828 | 829 | .vjs-no-flex .vjs-progress-control { 830 | width: auto; 831 | } 832 | 833 | .video-js .vjs-progress-holder { 834 | flex: auto; 835 | transition: all 0.2s; 836 | height: 0.3em; 837 | } 838 | 839 | .video-js .vjs-progress-control .vjs-progress-holder { 840 | margin: 0 10px; 841 | } 842 | 843 | .video-js .vjs-progress-control:hover .vjs-progress-holder { 844 | font-size: 1.6666666667em; 845 | } 846 | 847 | .video-js .vjs-progress-control:hover .vjs-progress-holder.disabled { 848 | font-size: 1em; 849 | } 850 | 851 | .video-js .vjs-progress-holder .vjs-play-progress, 852 | .video-js .vjs-progress-holder .vjs-load-progress, 853 | .video-js .vjs-progress-holder .vjs-load-progress div { 854 | position: absolute; 855 | display: block; 856 | height: 100%; 857 | margin: 0; 858 | padding: 0; 859 | width: 0; 860 | } 861 | 862 | .video-js .vjs-play-progress { 863 | background-color: #fff; 864 | } 865 | .video-js .vjs-play-progress:before { 866 | font-size: 0.9em; 867 | position: absolute; 868 | right: -0.5em; 869 | top: -0.3333333333em; 870 | z-index: 1; 871 | } 872 | 873 | .video-js .vjs-load-progress { 874 | background: rgba(115, 133, 159, 0.5); 875 | } 876 | 877 | .video-js .vjs-load-progress div { 878 | background: rgba(115, 133, 159, 0.75); 879 | } 880 | 881 | .video-js .vjs-time-tooltip { 882 | background-color: #fff; 883 | background-color: rgba(255, 255, 255, 0.8); 884 | border-radius: 0.3em; 885 | color: #000; 886 | float: right; 887 | font-family: Arial, Helvetica, sans-serif; 888 | font-size: 1em; 889 | padding: 6px 8px 8px 8px; 890 | pointer-events: none; 891 | position: absolute; 892 | top: -3.4em; 893 | visibility: hidden; 894 | z-index: 1; 895 | } 896 | 897 | .video-js .vjs-progress-holder:focus .vjs-time-tooltip { 898 | display: none; 899 | } 900 | 901 | .video-js .vjs-progress-control:hover .vjs-time-tooltip, 902 | .video-js .vjs-progress-control:hover .vjs-progress-holder:focus .vjs-time-tooltip { 903 | display: block; 904 | font-size: 0.6em; 905 | visibility: visible; 906 | } 907 | 908 | .video-js .vjs-progress-control.disabled:hover .vjs-time-tooltip { 909 | font-size: 1em; 910 | } 911 | 912 | .video-js .vjs-progress-control .vjs-mouse-display { 913 | display: none; 914 | position: absolute; 915 | width: 1px; 916 | height: 100%; 917 | background-color: #000; 918 | z-index: 1; 919 | } 920 | 921 | .vjs-no-flex .vjs-progress-control .vjs-mouse-display { 922 | z-index: 0; 923 | } 924 | 925 | .video-js .vjs-progress-control:hover .vjs-mouse-display { 926 | display: block; 927 | } 928 | 929 | .video-js.vjs-user-inactive .vjs-progress-control .vjs-mouse-display { 930 | visibility: hidden; 931 | opacity: 0; 932 | transition: visibility 1s, opacity 1s; 933 | } 934 | 935 | .video-js.vjs-user-inactive.vjs-no-flex .vjs-progress-control .vjs-mouse-display { 936 | display: none; 937 | } 938 | 939 | .vjs-mouse-display .vjs-time-tooltip { 940 | color: #fff; 941 | background-color: #000; 942 | background-color: rgba(0, 0, 0, 0.8); 943 | } 944 | 945 | .video-js .vjs-slider { 946 | position: relative; 947 | cursor: pointer; 948 | padding: 0; 949 | margin: 0 0.45em 0 0.45em; 950 | /* iOS Safari */ 951 | -webkit-touch-callout: none; 952 | /* Safari */ 953 | -webkit-user-select: none; 954 | /* Konqueror HTML */ 955 | /* Firefox */ 956 | -moz-user-select: none; 957 | /* Internet Explorer/Edge */ 958 | -ms-user-select: none; 959 | /* Non-prefixed version, currently supported by Chrome and Opera */ 960 | user-select: none; 961 | background-color: #73859f; 962 | background-color: rgba(115, 133, 159, 0.5); 963 | } 964 | 965 | .video-js .vjs-slider.disabled { 966 | cursor: default; 967 | } 968 | 969 | .video-js .vjs-slider:focus { 970 | text-shadow: 0em 0em 1em white; 971 | box-shadow: 0 0 1em #fff; 972 | } 973 | 974 | .video-js .vjs-mute-control { 975 | cursor: pointer; 976 | flex: none; 977 | } 978 | .video-js .vjs-volume-control { 979 | cursor: pointer; 980 | margin-right: 1em; 981 | display: flex; 982 | } 983 | 984 | .video-js .vjs-volume-control.vjs-volume-horizontal { 985 | width: 5em; 986 | } 987 | 988 | .video-js .vjs-volume-panel .vjs-volume-control { 989 | visibility: visible; 990 | opacity: 0; 991 | width: 1px; 992 | height: 1px; 993 | margin-left: -1px; 994 | } 995 | 996 | .video-js .vjs-volume-panel { 997 | transition: width 1s; 998 | } 999 | .video-js .vjs-volume-panel.vjs-hover .vjs-volume-control, .video-js .vjs-volume-panel:active .vjs-volume-control, .video-js .vjs-volume-panel:focus .vjs-volume-control, .video-js .vjs-volume-panel .vjs-volume-control:active, .video-js .vjs-volume-panel.vjs-hover .vjs-mute-control ~ .vjs-volume-control, .video-js .vjs-volume-panel .vjs-volume-control.vjs-slider-active { 1000 | visibility: visible; 1001 | opacity: 1; 1002 | position: relative; 1003 | transition: visibility 0.1s, opacity 0.1s, height 0.1s, width 0.1s, left 0s, top 0s; 1004 | } 1005 | .video-js .vjs-volume-panel.vjs-hover .vjs-volume-control.vjs-volume-horizontal, .video-js .vjs-volume-panel:active .vjs-volume-control.vjs-volume-horizontal, .video-js .vjs-volume-panel:focus .vjs-volume-control.vjs-volume-horizontal, .video-js .vjs-volume-panel .vjs-volume-control:active.vjs-volume-horizontal, .video-js .vjs-volume-panel.vjs-hover .vjs-mute-control ~ .vjs-volume-control.vjs-volume-horizontal, .video-js .vjs-volume-panel .vjs-volume-control.vjs-slider-active.vjs-volume-horizontal { 1006 | width: 5em; 1007 | height: 3em; 1008 | margin-right: 0; 1009 | } 1010 | .video-js .vjs-volume-panel.vjs-hover .vjs-volume-control.vjs-volume-vertical, .video-js .vjs-volume-panel:active .vjs-volume-control.vjs-volume-vertical, .video-js .vjs-volume-panel:focus .vjs-volume-control.vjs-volume-vertical, .video-js .vjs-volume-panel .vjs-volume-control:active.vjs-volume-vertical, .video-js .vjs-volume-panel.vjs-hover .vjs-mute-control ~ .vjs-volume-control.vjs-volume-vertical, .video-js .vjs-volume-panel .vjs-volume-control.vjs-slider-active.vjs-volume-vertical { 1011 | left: -3.5em; 1012 | transition: left 0s; 1013 | } 1014 | .video-js .vjs-volume-panel.vjs-volume-panel-horizontal.vjs-hover, .video-js .vjs-volume-panel.vjs-volume-panel-horizontal:active, .video-js .vjs-volume-panel.vjs-volume-panel-horizontal.vjs-slider-active { 1015 | width: 10em; 1016 | transition: width 0.1s; 1017 | } 1018 | .video-js .vjs-volume-panel.vjs-volume-panel-horizontal.vjs-mute-toggle-only { 1019 | width: 4em; 1020 | } 1021 | 1022 | .video-js .vjs-volume-panel .vjs-volume-control.vjs-volume-vertical { 1023 | height: 8em; 1024 | width: 3em; 1025 | left: -3000em; 1026 | transition: visibility 1s, opacity 1s, height 1s 1s, width 1s 1s, left 1s 1s, top 1s 1s; 1027 | } 1028 | 1029 | .video-js .vjs-volume-panel .vjs-volume-control.vjs-volume-horizontal { 1030 | transition: visibility 1s, opacity 1s, height 1s 1s, width 1s, left 1s 1s, top 1s 1s; 1031 | } 1032 | 1033 | .video-js.vjs-no-flex .vjs-volume-panel .vjs-volume-control.vjs-volume-horizontal { 1034 | width: 5em; 1035 | height: 3em; 1036 | visibility: visible; 1037 | opacity: 1; 1038 | position: relative; 1039 | transition: none; 1040 | } 1041 | 1042 | .video-js.vjs-no-flex .vjs-volume-control.vjs-volume-vertical, 1043 | .video-js.vjs-no-flex .vjs-volume-panel .vjs-volume-control.vjs-volume-vertical { 1044 | position: absolute; 1045 | bottom: 3em; 1046 | left: 0.5em; 1047 | } 1048 | 1049 | .video-js .vjs-volume-panel { 1050 | display: flex; 1051 | } 1052 | 1053 | .video-js .vjs-volume-bar { 1054 | margin: 1.35em 0.45em; 1055 | } 1056 | 1057 | .vjs-volume-bar.vjs-slider-horizontal { 1058 | width: 5em; 1059 | height: 0.3em; 1060 | } 1061 | 1062 | .vjs-volume-bar.vjs-slider-vertical { 1063 | width: 0.3em; 1064 | height: 5em; 1065 | margin: 1.35em auto; 1066 | } 1067 | 1068 | .video-js .vjs-volume-level { 1069 | position: absolute; 1070 | bottom: 0; 1071 | left: 0; 1072 | background-color: #fff; 1073 | } 1074 | .video-js .vjs-volume-level:before { 1075 | position: absolute; 1076 | font-size: 0.9em; 1077 | } 1078 | 1079 | .vjs-slider-vertical .vjs-volume-level { 1080 | width: 0.3em; 1081 | } 1082 | .vjs-slider-vertical .vjs-volume-level:before { 1083 | top: -0.5em; 1084 | left: -0.3em; 1085 | } 1086 | 1087 | .vjs-slider-horizontal .vjs-volume-level { 1088 | height: 0.3em; 1089 | } 1090 | .vjs-slider-horizontal .vjs-volume-level:before { 1091 | top: -0.3em; 1092 | right: -0.5em; 1093 | } 1094 | 1095 | .video-js .vjs-volume-panel.vjs-volume-panel-vertical { 1096 | width: 4em; 1097 | } 1098 | 1099 | .vjs-volume-bar.vjs-slider-vertical .vjs-volume-level { 1100 | height: 100%; 1101 | } 1102 | 1103 | .vjs-volume-bar.vjs-slider-horizontal .vjs-volume-level { 1104 | width: 100%; 1105 | } 1106 | 1107 | .video-js .vjs-volume-vertical { 1108 | width: 3em; 1109 | height: 8em; 1110 | bottom: 8em; 1111 | background-color: #2B333F; 1112 | background-color: rgba(43, 51, 63, 0.7); 1113 | } 1114 | 1115 | .video-js .vjs-volume-horizontal .vjs-menu { 1116 | left: -2em; 1117 | } 1118 | 1119 | .vjs-poster { 1120 | display: inline-block; 1121 | vertical-align: middle; 1122 | background-repeat: no-repeat; 1123 | background-position: 50% 50%; 1124 | background-size: contain; 1125 | background-color: #000000; 1126 | cursor: pointer; 1127 | margin: 0; 1128 | padding: 0; 1129 | position: absolute; 1130 | top: 0; 1131 | right: 0; 1132 | bottom: 0; 1133 | left: 0; 1134 | height: 100%; 1135 | } 1136 | 1137 | .vjs-has-started .vjs-poster { 1138 | display: none; 1139 | } 1140 | 1141 | .vjs-audio.vjs-has-started .vjs-poster { 1142 | display: block; 1143 | } 1144 | 1145 | .vjs-using-native-controls .vjs-poster { 1146 | display: none; 1147 | } 1148 | 1149 | .video-js .vjs-live-control { 1150 | display: flex; 1151 | align-items: flex-start; 1152 | flex: auto; 1153 | font-size: 1em; 1154 | line-height: 3em; 1155 | } 1156 | 1157 | .vjs-no-flex .vjs-live-control { 1158 | display: table-cell; 1159 | width: auto; 1160 | text-align: left; 1161 | } 1162 | 1163 | .video-js:not(.vjs-live) .vjs-live-control, 1164 | .video-js.vjs-liveui .vjs-live-control { 1165 | display: none; 1166 | } 1167 | 1168 | .video-js .vjs-seek-to-live-control { 1169 | cursor: pointer; 1170 | flex: none; 1171 | display: inline-flex; 1172 | height: 100%; 1173 | padding-left: 0.5em; 1174 | padding-right: 0.5em; 1175 | font-size: 1em; 1176 | line-height: 3em; 1177 | width: auto; 1178 | min-width: 4em; 1179 | } 1180 | 1181 | .vjs-no-flex .vjs-seek-to-live-control { 1182 | display: table-cell; 1183 | width: auto; 1184 | text-align: left; 1185 | } 1186 | 1187 | .video-js.vjs-live:not(.vjs-liveui) .vjs-seek-to-live-control, 1188 | .video-js:not(.vjs-live) .vjs-seek-to-live-control { 1189 | display: none; 1190 | } 1191 | 1192 | .vjs-seek-to-live-control.vjs-control.vjs-at-live-edge { 1193 | cursor: auto; 1194 | } 1195 | 1196 | .vjs-seek-to-live-control .vjs-icon-placeholder { 1197 | margin-right: 0.5em; 1198 | color: #888; 1199 | } 1200 | 1201 | .vjs-seek-to-live-control.vjs-control.vjs-at-live-edge .vjs-icon-placeholder { 1202 | color: red; 1203 | } 1204 | 1205 | .video-js .vjs-time-control { 1206 | flex: none; 1207 | font-size: 1em; 1208 | line-height: 3em; 1209 | min-width: 2em; 1210 | width: auto; 1211 | padding-left: 1em; 1212 | padding-right: 1em; 1213 | } 1214 | 1215 | .vjs-live .vjs-time-control { 1216 | display: none; 1217 | } 1218 | 1219 | .video-js .vjs-current-time, 1220 | .vjs-no-flex .vjs-current-time { 1221 | display: none; 1222 | } 1223 | 1224 | .video-js .vjs-duration, 1225 | .vjs-no-flex .vjs-duration { 1226 | display: none; 1227 | } 1228 | 1229 | .vjs-time-divider { 1230 | display: none; 1231 | line-height: 3em; 1232 | } 1233 | 1234 | .vjs-live .vjs-time-divider { 1235 | display: none; 1236 | } 1237 | 1238 | .video-js .vjs-play-control { 1239 | cursor: pointer; 1240 | } 1241 | 1242 | .video-js .vjs-play-control .vjs-icon-placeholder { 1243 | flex: none; 1244 | } 1245 | 1246 | .vjs-text-track-display { 1247 | position: absolute; 1248 | bottom: 3em; 1249 | left: 0; 1250 | right: 0; 1251 | top: 0; 1252 | pointer-events: none; 1253 | } 1254 | 1255 | .video-js.vjs-user-inactive.vjs-playing .vjs-text-track-display { 1256 | bottom: 1em; 1257 | } 1258 | 1259 | .video-js .vjs-text-track { 1260 | font-size: 1.4em; 1261 | text-align: center; 1262 | margin-bottom: 0.1em; 1263 | } 1264 | 1265 | .vjs-subtitles { 1266 | color: #fff; 1267 | } 1268 | 1269 | .vjs-captions { 1270 | color: #fc6; 1271 | } 1272 | 1273 | .vjs-tt-cue { 1274 | display: block; 1275 | } 1276 | 1277 | video::-webkit-media-text-track-display { 1278 | transform: translateY(-3em); 1279 | } 1280 | 1281 | .video-js.vjs-user-inactive.vjs-playing video::-webkit-media-text-track-display { 1282 | transform: translateY(-1.5em); 1283 | } 1284 | 1285 | .video-js .vjs-picture-in-picture-control { 1286 | cursor: pointer; 1287 | flex: none; 1288 | } 1289 | .video-js .vjs-fullscreen-control { 1290 | cursor: pointer; 1291 | flex: none; 1292 | } 1293 | .vjs-playback-rate > .vjs-menu-button, 1294 | .vjs-playback-rate .vjs-playback-rate-value { 1295 | position: absolute; 1296 | top: 0; 1297 | left: 0; 1298 | width: 100%; 1299 | height: 100%; 1300 | } 1301 | 1302 | .vjs-playback-rate .vjs-playback-rate-value { 1303 | pointer-events: none; 1304 | font-size: 1.5em; 1305 | line-height: 2; 1306 | text-align: center; 1307 | } 1308 | 1309 | .vjs-playback-rate .vjs-menu { 1310 | width: 4em; 1311 | left: 0em; 1312 | } 1313 | 1314 | .vjs-error .vjs-error-display .vjs-modal-dialog-content { 1315 | font-size: 1.4em; 1316 | text-align: center; 1317 | } 1318 | 1319 | .vjs-error .vjs-error-display:before { 1320 | color: #fff; 1321 | content: "X"; 1322 | font-family: Arial, Helvetica, sans-serif; 1323 | font-size: 4em; 1324 | left: 0; 1325 | line-height: 1; 1326 | margin-top: -0.5em; 1327 | position: absolute; 1328 | text-shadow: 0.05em 0.05em 0.1em #000; 1329 | text-align: center; 1330 | top: 50%; 1331 | vertical-align: middle; 1332 | width: 100%; 1333 | } 1334 | 1335 | .vjs-loading-spinner { 1336 | display: none; 1337 | position: absolute; 1338 | top: 50%; 1339 | left: 50%; 1340 | margin: -25px 0 0 -25px; 1341 | opacity: 0.85; 1342 | text-align: left; 1343 | border: 6px solid rgba(43, 51, 63, 0.7); 1344 | box-sizing: border-box; 1345 | background-clip: padding-box; 1346 | width: 50px; 1347 | height: 50px; 1348 | border-radius: 25px; 1349 | visibility: hidden; 1350 | } 1351 | 1352 | .vjs-seeking .vjs-loading-spinner, 1353 | .vjs-waiting .vjs-loading-spinner { 1354 | display: block; 1355 | -webkit-animation: vjs-spinner-show 0s linear 0.3s forwards; 1356 | animation: vjs-spinner-show 0s linear 0.3s forwards; 1357 | } 1358 | 1359 | .vjs-loading-spinner:before, 1360 | .vjs-loading-spinner:after { 1361 | content: ""; 1362 | position: absolute; 1363 | margin: -6px; 1364 | box-sizing: inherit; 1365 | width: inherit; 1366 | height: inherit; 1367 | border-radius: inherit; 1368 | opacity: 1; 1369 | border: inherit; 1370 | border-color: transparent; 1371 | border-top-color: white; 1372 | } 1373 | 1374 | .vjs-seeking .vjs-loading-spinner:before, 1375 | .vjs-seeking .vjs-loading-spinner:after, 1376 | .vjs-waiting .vjs-loading-spinner:before, 1377 | .vjs-waiting .vjs-loading-spinner:after { 1378 | -webkit-animation: vjs-spinner-spin 1.1s cubic-bezier(0.6, 0.2, 0, 0.8) infinite, vjs-spinner-fade 1.1s linear infinite; 1379 | animation: vjs-spinner-spin 1.1s cubic-bezier(0.6, 0.2, 0, 0.8) infinite, vjs-spinner-fade 1.1s linear infinite; 1380 | } 1381 | 1382 | .vjs-seeking .vjs-loading-spinner:before, 1383 | .vjs-waiting .vjs-loading-spinner:before { 1384 | border-top-color: white; 1385 | } 1386 | 1387 | .vjs-seeking .vjs-loading-spinner:after, 1388 | .vjs-waiting .vjs-loading-spinner:after { 1389 | border-top-color: white; 1390 | -webkit-animation-delay: 0.44s; 1391 | animation-delay: 0.44s; 1392 | } 1393 | 1394 | @keyframes vjs-spinner-show { 1395 | to { 1396 | visibility: visible; 1397 | } 1398 | } 1399 | @-webkit-keyframes vjs-spinner-show { 1400 | to { 1401 | visibility: visible; 1402 | } 1403 | } 1404 | @keyframes vjs-spinner-spin { 1405 | 100% { 1406 | transform: rotate(360deg); 1407 | } 1408 | } 1409 | @-webkit-keyframes vjs-spinner-spin { 1410 | 100% { 1411 | -webkit-transform: rotate(360deg); 1412 | } 1413 | } 1414 | @keyframes vjs-spinner-fade { 1415 | 0% { 1416 | border-top-color: #73859f; 1417 | } 1418 | 20% { 1419 | border-top-color: #73859f; 1420 | } 1421 | 35% { 1422 | border-top-color: white; 1423 | } 1424 | 60% { 1425 | border-top-color: #73859f; 1426 | } 1427 | 100% { 1428 | border-top-color: #73859f; 1429 | } 1430 | } 1431 | @-webkit-keyframes vjs-spinner-fade { 1432 | 0% { 1433 | border-top-color: #73859f; 1434 | } 1435 | 20% { 1436 | border-top-color: #73859f; 1437 | } 1438 | 35% { 1439 | border-top-color: white; 1440 | } 1441 | 60% { 1442 | border-top-color: #73859f; 1443 | } 1444 | 100% { 1445 | border-top-color: #73859f; 1446 | } 1447 | } 1448 | .vjs-chapters-button .vjs-menu ul { 1449 | width: 24em; 1450 | } 1451 | 1452 | .video-js .vjs-subs-caps-button + .vjs-menu .vjs-captions-menu-item .vjs-menu-item-text .vjs-icon-placeholder { 1453 | vertical-align: middle; 1454 | display: inline-block; 1455 | margin-bottom: -0.1em; 1456 | } 1457 | 1458 | .video-js .vjs-subs-caps-button + .vjs-menu .vjs-captions-menu-item .vjs-menu-item-text .vjs-icon-placeholder:before { 1459 | font-family: VideoJS; 1460 | content: ""; 1461 | font-size: 1.5em; 1462 | line-height: inherit; 1463 | } 1464 | 1465 | .video-js .vjs-audio-button + .vjs-menu .vjs-main-desc-menu-item .vjs-menu-item-text .vjs-icon-placeholder { 1466 | vertical-align: middle; 1467 | display: inline-block; 1468 | margin-bottom: -0.1em; 1469 | } 1470 | 1471 | .video-js .vjs-audio-button + .vjs-menu .vjs-main-desc-menu-item .vjs-menu-item-text .vjs-icon-placeholder:before { 1472 | font-family: VideoJS; 1473 | content: " "; 1474 | font-size: 1.5em; 1475 | line-height: inherit; 1476 | } 1477 | 1478 | .video-js:not(.vjs-fullscreen).vjs-layout-small .vjs-current-time, 1479 | .video-js:not(.vjs-fullscreen).vjs-layout-small .vjs-time-divider, 1480 | .video-js:not(.vjs-fullscreen).vjs-layout-small .vjs-duration, 1481 | .video-js:not(.vjs-fullscreen).vjs-layout-small .vjs-remaining-time, 1482 | .video-js:not(.vjs-fullscreen).vjs-layout-small .vjs-playback-rate, 1483 | .video-js:not(.vjs-fullscreen).vjs-layout-small .vjs-chapters-button, 1484 | .video-js:not(.vjs-fullscreen).vjs-layout-small .vjs-descriptions-button, 1485 | .video-js:not(.vjs-fullscreen).vjs-layout-small .vjs-captions-button, 1486 | .video-js:not(.vjs-fullscreen).vjs-layout-small .vjs-subtitles-button, 1487 | .video-js:not(.vjs-fullscreen).vjs-layout-small .vjs-audio-button, 1488 | .video-js:not(.vjs-fullscreen).vjs-layout-small .vjs-volume-control, .video-js:not(.vjs-fullscreen).vjs-layout-x-small .vjs-current-time, 1489 | .video-js:not(.vjs-fullscreen).vjs-layout-x-small .vjs-time-divider, 1490 | .video-js:not(.vjs-fullscreen).vjs-layout-x-small .vjs-duration, 1491 | .video-js:not(.vjs-fullscreen).vjs-layout-x-small .vjs-remaining-time, 1492 | .video-js:not(.vjs-fullscreen).vjs-layout-x-small .vjs-playback-rate, 1493 | .video-js:not(.vjs-fullscreen).vjs-layout-x-small .vjs-chapters-button, 1494 | .video-js:not(.vjs-fullscreen).vjs-layout-x-small .vjs-descriptions-button, 1495 | .video-js:not(.vjs-fullscreen).vjs-layout-x-small .vjs-captions-button, 1496 | .video-js:not(.vjs-fullscreen).vjs-layout-x-small .vjs-subtitles-button, 1497 | .video-js:not(.vjs-fullscreen).vjs-layout-x-small .vjs-audio-button, 1498 | .video-js:not(.vjs-fullscreen).vjs-layout-x-small .vjs-volume-control, .video-js:not(.vjs-fullscreen).vjs-layout-tiny .vjs-current-time, 1499 | .video-js:not(.vjs-fullscreen).vjs-layout-tiny .vjs-time-divider, 1500 | .video-js:not(.vjs-fullscreen).vjs-layout-tiny .vjs-duration, 1501 | .video-js:not(.vjs-fullscreen).vjs-layout-tiny .vjs-remaining-time, 1502 | .video-js:not(.vjs-fullscreen).vjs-layout-tiny .vjs-playback-rate, 1503 | .video-js:not(.vjs-fullscreen).vjs-layout-tiny .vjs-chapters-button, 1504 | .video-js:not(.vjs-fullscreen).vjs-layout-tiny .vjs-descriptions-button, 1505 | .video-js:not(.vjs-fullscreen).vjs-layout-tiny .vjs-captions-button, 1506 | .video-js:not(.vjs-fullscreen).vjs-layout-tiny .vjs-subtitles-button, 1507 | .video-js:not(.vjs-fullscreen).vjs-layout-tiny .vjs-audio-button, 1508 | .video-js:not(.vjs-fullscreen).vjs-layout-tiny .vjs-volume-control { 1509 | display: none; 1510 | } 1511 | .video-js:not(.vjs-fullscreen).vjs-layout-small .vjs-volume-panel.vjs-volume-panel-horizontal:hover, 1512 | .video-js:not(.vjs-fullscreen).vjs-layout-small .vjs-volume-panel.vjs-volume-panel-horizontal:active, 1513 | .video-js:not(.vjs-fullscreen).vjs-layout-small .vjs-volume-panel.vjs-volume-panel-horizontal.vjs-slider-active, .video-js:not(.vjs-fullscreen).vjs-layout-x-small .vjs-volume-panel.vjs-volume-panel-horizontal:hover, 1514 | .video-js:not(.vjs-fullscreen).vjs-layout-x-small .vjs-volume-panel.vjs-volume-panel-horizontal:active, 1515 | .video-js:not(.vjs-fullscreen).vjs-layout-x-small .vjs-volume-panel.vjs-volume-panel-horizontal.vjs-slider-active, .video-js:not(.vjs-fullscreen).vjs-layout-tiny .vjs-volume-panel.vjs-volume-panel-horizontal:hover, 1516 | .video-js:not(.vjs-fullscreen).vjs-layout-tiny .vjs-volume-panel.vjs-volume-panel-horizontal:active, 1517 | .video-js:not(.vjs-fullscreen).vjs-layout-tiny .vjs-volume-panel.vjs-volume-panel-horizontal.vjs-slider-active { 1518 | width: auto; 1519 | width: initial; 1520 | } 1521 | .video-js:not(.vjs-fullscreen).vjs-layout-x-small:not(.vjs-liveui) .vjs-subs-caps-button, .video-js:not(.vjs-fullscreen).vjs-layout-x-small:not(.vjs-live) .vjs-subs-caps-button, .video-js:not(.vjs-fullscreen).vjs-layout-tiny .vjs-subs-caps-button { 1522 | display: none; 1523 | } 1524 | .video-js:not(.vjs-fullscreen).vjs-layout-x-small.vjs-liveui .vjs-custom-control-spacer, .video-js:not(.vjs-fullscreen).vjs-layout-tiny .vjs-custom-control-spacer { 1525 | flex: auto; 1526 | display: block; 1527 | } 1528 | .video-js:not(.vjs-fullscreen).vjs-layout-x-small.vjs-liveui.vjs-no-flex .vjs-custom-control-spacer, .video-js:not(.vjs-fullscreen).vjs-layout-tiny.vjs-no-flex .vjs-custom-control-spacer { 1529 | width: auto; 1530 | } 1531 | .video-js:not(.vjs-fullscreen).vjs-layout-x-small.vjs-liveui .vjs-progress-control, .video-js:not(.vjs-fullscreen).vjs-layout-tiny .vjs-progress-control { 1532 | display: none; 1533 | } 1534 | 1535 | .vjs-modal-dialog.vjs-text-track-settings { 1536 | background-color: #2B333F; 1537 | background-color: rgba(43, 51, 63, 0.75); 1538 | color: #fff; 1539 | height: 70%; 1540 | } 1541 | 1542 | .vjs-text-track-settings .vjs-modal-dialog-content { 1543 | display: table; 1544 | } 1545 | 1546 | .vjs-text-track-settings .vjs-track-settings-colors, 1547 | .vjs-text-track-settings .vjs-track-settings-font, 1548 | .vjs-text-track-settings .vjs-track-settings-controls { 1549 | display: table-cell; 1550 | } 1551 | 1552 | .vjs-text-track-settings .vjs-track-settings-controls { 1553 | text-align: right; 1554 | vertical-align: bottom; 1555 | } 1556 | 1557 | @supports (display: grid) { 1558 | .vjs-text-track-settings .vjs-modal-dialog-content { 1559 | display: grid; 1560 | grid-template-columns: 1fr 1fr; 1561 | grid-template-rows: 1fr; 1562 | padding: 20px 24px 0px 24px; 1563 | } 1564 | 1565 | .vjs-track-settings-controls .vjs-default-button { 1566 | margin-bottom: 20px; 1567 | } 1568 | 1569 | .vjs-text-track-settings .vjs-track-settings-controls { 1570 | grid-column: 1/-1; 1571 | } 1572 | 1573 | .vjs-layout-small .vjs-text-track-settings .vjs-modal-dialog-content, 1574 | .vjs-layout-x-small .vjs-text-track-settings .vjs-modal-dialog-content, 1575 | .vjs-layout-tiny .vjs-text-track-settings .vjs-modal-dialog-content { 1576 | grid-template-columns: 1fr; 1577 | } 1578 | } 1579 | .vjs-track-setting > select { 1580 | margin-right: 1em; 1581 | margin-bottom: 0.5em; 1582 | } 1583 | 1584 | .vjs-text-track-settings fieldset { 1585 | margin: 5px; 1586 | padding: 3px; 1587 | border: none; 1588 | } 1589 | 1590 | .vjs-text-track-settings fieldset span { 1591 | display: inline-block; 1592 | } 1593 | 1594 | .vjs-text-track-settings fieldset span > select { 1595 | max-width: 7.3em; 1596 | } 1597 | 1598 | .vjs-text-track-settings legend { 1599 | color: #fff; 1600 | margin: 0 0 5px 0; 1601 | } 1602 | 1603 | .vjs-text-track-settings .vjs-label { 1604 | position: absolute; 1605 | clip: rect(1px 1px 1px 1px); 1606 | clip: rect(1px, 1px, 1px, 1px); 1607 | display: block; 1608 | margin: 0 0 5px 0; 1609 | padding: 0; 1610 | border: 0; 1611 | height: 1px; 1612 | width: 1px; 1613 | overflow: hidden; 1614 | } 1615 | 1616 | .vjs-track-settings-controls button:focus, 1617 | .vjs-track-settings-controls button:active { 1618 | outline-style: solid; 1619 | outline-width: medium; 1620 | background-image: linear-gradient(0deg, #fff 88%, #73859f 100%); 1621 | } 1622 | 1623 | .vjs-track-settings-controls button:hover { 1624 | color: rgba(43, 51, 63, 0.75); 1625 | } 1626 | 1627 | .vjs-track-settings-controls button { 1628 | background-color: #fff; 1629 | background-image: linear-gradient(-180deg, #fff 88%, #73859f 100%); 1630 | color: #2B333F; 1631 | cursor: pointer; 1632 | border-radius: 2px; 1633 | } 1634 | 1635 | .vjs-track-settings-controls .vjs-default-button { 1636 | margin-right: 1em; 1637 | } 1638 | 1639 | @media print { 1640 | .video-js > *:not(.vjs-tech):not(.vjs-poster) { 1641 | visibility: hidden; 1642 | } 1643 | } 1644 | .vjs-resize-manager { 1645 | position: absolute; 1646 | top: 0; 1647 | left: 0; 1648 | width: 100%; 1649 | height: 100%; 1650 | border: none; 1651 | z-index: -1000; 1652 | } 1653 | 1654 | .js-focus-visible .video-js *:focus:not(.focus-visible) { 1655 | outline: none; 1656 | background: none; 1657 | } 1658 | 1659 | .video-js *:focus:not(:focus-visible), 1660 | .video-js .vjs-menu *:focus:not(:focus-visible) { 1661 | outline: none; 1662 | background: none; 1663 | } 1664 | --------------------------------------------------------------------------------