diff --git a/.eslintrc.json b/.eslintrc.json index 9e1dbaa..f85ea66 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -27,7 +27,8 @@ } }, "globals": { - "YT": "readonly" + "YT": "readonly", + "ICE_SERVERS": "readonly" }, "rules": { "indent": [ @@ -53,12 +54,15 @@ "error", "always" ], + "no-unused-vars": [ + "warn" + ], "no-console": [ - "error", + "warn", { "allow": ["info", "warn", "error"] } ], "no-inline-comments": [ - "error" + "warn" ], "spaced-comment": [ "error", diff --git a/Makefile b/Makefile index 4c4c6ba..3d1470b 100644 --- a/Makefile +++ b/Makefile @@ -18,10 +18,10 @@ lint: npx eslint src/* --ext .js,.json --fix start-client: - php -S 0.0.0.0:8000 -t build + php -S 0.0.0.0:8020 -t build start-server: - node bin/server.js 8001 + node bin/server.js 8021 # Publish package publish: build diff --git a/assets/css/components/buttons.scss b/assets/css/components/buttons.scss index e6987ba..998bbe1 100644 --- a/assets/css/components/buttons.scss +++ b/assets/css/components/buttons.scss @@ -37,4 +37,8 @@ &[disabled] .icon-loader { color: $color-primary; } + + &.active, &.active:hover { + color: $color-primary; + } } diff --git a/assets/css/components/user-list.scss b/assets/css/components/user-list.scss index 0755995..8296d85 100644 --- a/assets/css/components/user-list.scss +++ b/assets/css/components/user-list.scss @@ -19,9 +19,17 @@ border-radius: 100%; sup { - font-size: 0.6em; + font-size: 0.5em; position: absolute; - top: 0; + top: -0.2em; + right: 0; + text-shadow: 0px 0px 10px rgba(0, 0, 0, 0.66); + } + + sub { + font-size: 0.4em; + position: absolute; + bottom: -0.2em; right: 0; text-shadow: 0px 0px 10px rgba(0, 0, 0, 0.66); } @@ -34,6 +42,10 @@ color: green; } + &.streaming sub { + color: $color-primary; + } + &.loading sup { color: red; } diff --git a/assets/css/core/icons.scss b/assets/css/core/icons.scss index da78951..7e1e5f0 100644 --- a/assets/css/core/icons.scss +++ b/assets/css/core/icons.scss @@ -22,6 +22,7 @@ $icons: ( "volume-low": "\e911", "volume-medium": "\e912", "volume-none": "\e910", + "stream": "\e90f", ); @font-face { diff --git a/assets/fonts/icons.svg b/assets/fonts/icons.svg index bb065e0..84027b1 100644 --- a/assets/fonts/icons.svg +++ b/assets/fonts/icons.svg @@ -22,6 +22,7 @@ + diff --git a/assets/fonts/icons.ttf b/assets/fonts/icons.ttf index 4407077..f81f360 100644 Binary files a/assets/fonts/icons.ttf and b/assets/fonts/icons.ttf differ diff --git a/assets/fonts/icons.woff b/assets/fonts/icons.woff index 5f88f37..05cc7ce 100644 Binary files a/assets/fonts/icons.woff and b/assets/fonts/icons.woff differ diff --git a/assets/fonts/selection.json b/assets/fonts/selection.json index 8bf4b3c..50895a1 100644 --- a/assets/fonts/selection.json +++ b/assets/fonts/selection.json @@ -1 +1 @@ -{"IcoMoonType":"selection","icons":[{"icon":{"paths":["M448 304c0-26.4 21.6-48 48-48h32c26.4 0 48 21.6 48 48v32c0 26.4-21.6 48-48 48h-32c-26.4 0-48-21.6-48-48v-32z","M640 768h-256v-64h64v-192h-64v-64h192v256h64z","M512 0c-282.77 0-512 229.23-512 512s229.23 512 512 512 512-229.23 512-512-229.23-512-512-512zM512 928c-229.75 0-416-186.25-416-416s186.25-416 416-416 416 186.25 416 416-186.25 416-416 416z"],"attrs":[{},{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["info","information"],"grid":24},"attrs":[{},{},{}],"properties":{"order":1,"id":0,"prevSize":32,"code":59668,"name":"info"},"setIdx":0,"setId":4,"iconIdx":0},{"icon":{"paths":["M469.333 85.333v170.667c0 23.552 19.115 42.667 42.667 42.667s42.667-19.115 42.667-42.667v-170.667c0-23.552-19.115-42.667-42.667-42.667s-42.667 19.115-42.667 42.667zM469.333 768v170.667c0 23.552 19.115 42.667 42.667 42.667s42.667-19.115 42.667-42.667v-170.667c0-23.552-19.115-42.667-42.667-42.667s-42.667 19.115-42.667 42.667zM180.181 240.512l120.747 120.747c16.683 16.683 43.691 16.683 60.331 0s16.683-43.691 0-60.331l-120.747-120.747c-16.683-16.683-43.691-16.683-60.331 0s-16.683 43.691 0 60.331zM662.741 723.072l120.747 120.747c16.683 16.683 43.691 16.683 60.331 0s16.683-43.691 0-60.331l-120.747-120.747c-16.683-16.683-43.691-16.683-60.331 0s-16.683 43.691 0 60.331zM85.333 554.667h170.667c23.552 0 42.667-19.115 42.667-42.667s-19.115-42.667-42.667-42.667h-170.667c-23.552 0-42.667 19.115-42.667 42.667s19.115 42.667 42.667 42.667zM768 554.667h170.667c23.552 0 42.667-19.115 42.667-42.667s-19.115-42.667-42.667-42.667h-170.667c-23.552 0-42.667 19.115-42.667 42.667s19.115 42.667 42.667 42.667zM240.512 843.819l120.747-120.747c16.683-16.683 16.683-43.691 0-60.331s-43.691-16.683-60.331 0l-120.747 120.747c-16.683 16.683-16.683 43.691 0 60.331s43.691 16.683 60.331 0zM723.072 361.259l120.747-120.747c16.683-16.683 16.683-43.691 0-60.331s-43.691-16.683-60.331 0l-120.747 120.747c-16.683 16.683-16.683 43.691 0 60.331s43.691 16.683 60.331 0z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["loader"],"grid":24},"attrs":[{}],"properties":{"order":1,"id":0,"name":"loader","prevSize":32,"code":59662},"setIdx":3,"setId":1,"iconIdx":0},{"icon":{"paths":["M960 619.148v84.852h-84.852l-107.148-107.148-107.148 107.148h-84.852v-84.852l107.148-107.148-107.148-107.148v-84.852h84.852l107.148 107.148 107.148-107.148h84.852v84.852l-107.148 107.148 107.148 107.148z","M416.006 960c-8.328 0-16.512-3.25-22.634-9.374l-246.626-246.626h-114.746c-17.672 0-32-14.326-32-32v-320c0-17.672 14.328-32 32-32h114.746l246.626-246.628c9.154-9.154 22.916-11.89 34.874-6.936 11.958 4.952 19.754 16.622 19.754 29.564v832c0 12.944-7.796 24.612-19.754 29.564-3.958 1.64-8.118 2.436-12.24 2.436z"],"attrs":[{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["volume-mute","volume","audio","player"],"grid":24},"attrs":[{},{}],"properties":{"order":1,"id":3,"prevSize":32,"code":59664,"name":"volume-none"},"setIdx":3,"setId":1,"iconIdx":1},{"icon":{"paths":["M549.020 741.020c-12.286 0-24.566-4.686-33.942-14.058-18.746-18.746-18.746-49.134 0-67.88 81.1-81.1 81.1-213.058 0-294.156-18.746-18.746-18.746-49.138 0-67.882s49.136-18.744 67.882 0c118.53 118.53 118.53 311.392 0 429.922-9.372 9.368-21.656 14.054-33.94 14.054z","M416.006 960c-8.328 0-16.512-3.25-22.634-9.374l-246.626-246.626h-114.746c-17.672 0-32-14.326-32-32v-320c0-17.672 14.328-32 32-32h114.746l246.626-246.628c9.154-9.154 22.916-11.89 34.874-6.936 11.958 4.952 19.754 16.622 19.754 29.564v832c0 12.944-7.796 24.612-19.754 29.564-3.958 1.64-8.118 2.436-12.24 2.436z"],"attrs":[{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["volume-low","volume","audio","speaker","player"],"grid":24},"attrs":[{},{}],"properties":{"order":2,"id":2,"prevSize":32,"code":59665,"name":"volume-low"},"setIdx":3,"setId":1,"iconIdx":2},{"icon":{"paths":["M719.53 831.53c-12.286 0-24.566-4.686-33.942-14.056-18.744-18.744-18.744-49.136 0-67.882 131.006-131.006 131.006-344.17 0-475.176-18.744-18.746-18.744-49.138 0-67.882 18.744-18.742 49.138-18.744 67.882 0 81.594 81.59 126.53 190.074 126.53 305.466 0 115.39-44.936 223.876-126.53 305.47-9.372 9.374-21.656 14.060-33.94 14.060v0zM549.020 741.020c-12.286 0-24.566-4.686-33.942-14.058-18.746-18.746-18.746-49.134 0-67.88 81.1-81.1 81.1-213.058 0-294.156-18.746-18.746-18.746-49.138 0-67.882s49.136-18.744 67.882 0c118.53 118.53 118.53 311.392 0 429.922-9.372 9.368-21.656 14.054-33.94 14.054z","M416.006 960c-8.328 0-16.512-3.25-22.634-9.374l-246.626-246.626h-114.746c-17.672 0-32-14.326-32-32v-320c0-17.672 14.328-32 32-32h114.746l246.626-246.628c9.154-9.154 22.916-11.89 34.874-6.936 11.958 4.952 19.754 16.622 19.754 29.564v832c0 12.944-7.796 24.612-19.754 29.564-3.958 1.64-8.118 2.436-12.24 2.436z"],"attrs":[{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["volume-medium","volume","audio","speaker","player"],"grid":24},"attrs":[{},{}],"properties":{"order":3,"id":1,"prevSize":32,"code":59666,"name":"volume-medium"},"setIdx":3,"setId":1,"iconIdx":3},{"icon":{"paths":["M890.040 922.040c-12.286 0-24.566-4.686-33.942-14.056-18.744-18.746-18.744-49.136 0-67.882 87.638-87.642 135.904-204.16 135.904-328.1 0-123.938-48.266-240.458-135.904-328.098-18.744-18.746-18.744-49.138 0-67.882s49.138-18.744 67.882 0c105.77 105.772 164.022 246.4 164.022 395.98s-58.252 290.208-164.022 395.98c-9.372 9.372-21.656 14.058-33.94 14.058zM719.53 831.53c-12.286 0-24.566-4.686-33.942-14.056-18.744-18.744-18.744-49.136 0-67.882 131.006-131.006 131.006-344.17 0-475.176-18.744-18.746-18.744-49.138 0-67.882 18.744-18.742 49.138-18.744 67.882 0 81.594 81.59 126.53 190.074 126.53 305.466 0 115.39-44.936 223.876-126.53 305.47-9.372 9.374-21.656 14.060-33.94 14.060v0zM549.020 741.020c-12.286 0-24.568-4.686-33.942-14.058-18.746-18.746-18.746-49.134 0-67.88 81.1-81.1 81.1-213.058 0-294.156-18.746-18.746-18.746-49.138 0-67.882s49.136-18.744 67.882 0c118.53 118.53 118.53 311.392 0 429.922-9.372 9.368-21.656 14.054-33.94 14.054z","M416.006 960c-8.328 0-16.512-3.25-22.634-9.374l-246.626-246.626h-114.746c-17.672 0-32-14.326-32-32v-320c0-17.672 14.328-32 32-32h114.746l246.626-246.628c9.154-9.154 22.916-11.89 34.874-6.936 11.958 4.952 19.754 16.622 19.754 29.564v832c0 12.944-7.796 24.612-19.754 29.564-3.958 1.64-8.118 2.436-12.24 2.436z"],"attrs":[{},{}],"width":1088,"isMulticolor":false,"isMulticolor2":false,"tags":["volume-high","volume","audio","speaker","player"],"grid":24},"attrs":[{},{}],"properties":{"order":4,"id":0,"prevSize":32,"code":59667,"name":"volume-high"},"setIdx":3,"setId":1,"iconIdx":4},{"icon":{"paths":["M742.997 281.003c-33.28-33.323-87.381-33.323-120.661 0l-110.336 110.336-110.336-110.336c-33.28-33.323-87.381-33.323-120.661 0-33.323 33.323-33.323 87.339 0 120.661l110.293 110.336-110.293 110.336c-33.323 33.323-33.323 87.339 0 120.661 16.64 16.683 38.485 25.003 60.331 25.003s43.691-8.32 60.331-25.003l110.336-110.336 110.336 110.336c16.64 16.683 38.485 25.003 60.331 25.003s43.691-8.32 60.331-25.003c33.323-33.323 33.323-87.339 0-120.661l-110.293-110.336 110.293-110.336c33.323-33.323 33.323-87.339 0-120.661z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"tags":["times"],"grid":24},"attrs":[],"properties":{"id":1,"order":39,"prevSize":32,"code":59648,"name":"cross"},"setIdx":3,"setId":1,"iconIdx":5},{"icon":{"paths":["M724.139 266.709c-41.259-22.955-93.227-8.021-116.053 33.152l-158.421 285.099-90.667-90.667c-33.323-33.323-87.339-33.323-120.661 0s-33.323 87.339 0 120.661l170.667 170.667c16.128 16.171 37.888 25.045 60.331 25.045 3.925 0 7.893-0.256 11.819-0.853 26.496-3.712 49.749-19.627 62.763-43.051l213.333-384c22.912-41.216 8.064-93.141-33.109-116.053z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"tags":["tick"],"grid":24},"attrs":[],"properties":{"id":2,"order":35,"prevSize":32,"code":59649,"name":"check"},"setIdx":3,"setId":1,"iconIdx":6},{"icon":{"paths":["M785.664 454.656c-33.323-33.323-87.339-33.323-120.661 0l-67.669 67.669v-308.992c0-47.147-38.229-85.333-85.333-85.333-47.147 0-85.333 38.187-85.333 85.333v308.992l-67.669-67.669c-33.323-33.323-87.339-33.323-120.661 0s-33.323 87.339 0 120.661l273.664 273.664 273.664-273.664c33.323-33.323 33.323-87.296 0-120.661z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"tags":["arrow-down-thick"],"grid":24},"attrs":[],"properties":{"id":23,"order":42,"prevSize":32,"code":59650,"name":"arrow-down"},"setIdx":3,"setId":1,"iconIdx":7},{"icon":{"paths":["M725.333 384c0-58.923-23.893-112.256-62.464-150.827-38.613-38.613-91.947-62.507-150.869-62.507s-112.256 23.893-150.869 62.507c-38.571 38.571-62.464 91.904-62.464 150.827s23.893 112.256 62.464 150.827c38.613 38.613 91.947 62.507 150.869 62.507s112.256-23.893 150.869-62.507c38.571-38.571 62.464-91.904 62.464-150.827z","M256 810.667c0 42.667 96 85.333 256 85.333 150.101 0 256-42.667 256-85.333 0-85.333-100.437-170.667-256-170.667-160 0-256 85.333-256 170.667z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"tags":["user"],"grid":24},"attrs":[],"properties":{"id":40,"order":26,"prevSize":32,"code":59651,"name":"user"},"setIdx":3,"setId":1,"iconIdx":8},{"icon":{"paths":["M384 597.333c58.923 0 112.256-23.893 150.869-62.507 38.571-38.571 62.464-91.904 62.464-150.827s-23.893-112.256-62.464-150.827c-38.613-38.613-91.947-62.507-150.869-62.507s-112.256 23.893-150.869 62.507c-38.571 38.571-62.464 91.904-62.464 150.827s23.893 112.256 62.464 150.827c38.613 38.613 91.947 62.507 150.869 62.507z","M384 896c150.101 0 256-42.667 256-85.333 0-85.333-100.437-170.667-256-170.667-160 0-256 85.333-256 170.667 0 42.667 96 85.333 256 85.333z","M896 512h-85.333v-85.333c0-23.595-19.072-42.667-42.667-42.667s-42.667 19.072-42.667 42.667v85.333h-85.333c-23.595 0-42.667 19.072-42.667 42.667s19.072 42.667 42.667 42.667h85.333v85.333c0 23.595 19.072 42.667 42.667 42.667s42.667-19.072 42.667-42.667v-85.333h85.333c23.595 0 42.667-19.072 42.667-42.667s-19.072-42.667-42.667-42.667z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"tags":["user-add"],"grid":24},"attrs":[],"properties":{"id":47,"order":37,"prevSize":32,"code":59652,"name":"user-add"},"setIdx":3,"setId":1,"iconIdx":9},{"icon":{"paths":["M341.333 256c-47.104 0-85.333 38.229-85.333 85.333v341.333c0 47.104 38.229 85.333 85.333 85.333s85.333-38.229 85.333-85.333v-341.333c0-47.104-38.229-85.333-85.333-85.333z","M640 256c-47.104 0-85.333 38.229-85.333 85.333v341.333c0 47.104 38.229 85.333 85.333 85.333s85.333-38.229 85.333-85.333v-341.333c0-47.104-38.229-85.333-85.333-85.333z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"tags":["media-pause"],"grid":24},"attrs":[],"properties":{"id":48,"order":36,"prevSize":32,"code":59653,"name":"pause"},"setIdx":3,"setId":1,"iconIdx":10},{"icon":{"paths":["M400.512 748.715l15.829 63.232c5.675 22.741 29.525 41.387 52.992 41.387h42.667c23.467 0 47.317-18.645 52.992-41.387l15.829-63.232c5.675-22.741 28.8-36.096 51.328-29.611l62.592 17.92c22.571 6.443 50.688-4.864 62.379-25.216l21.333-36.992c11.691-20.352 7.552-50.304-9.344-66.645l-46.848-45.269c-16.896-16.341-16.896-43.008 0.043-59.307l46.763-45.269c16.896-16.299 21.077-46.251 9.387-66.603l-21.376-36.992c-11.733-20.352-39.808-31.659-62.336-25.216l-62.592 17.92c-22.571 6.443-45.653-6.869-51.371-29.611l-15.787-63.147c-5.675-22.699-29.525-41.344-52.992-41.344h-42.667c-23.467 0-47.317 18.645-52.992 41.387l-15.787 63.147c-5.717 22.741-28.8 36.096-51.371 29.653l-62.592-17.92c-22.571-6.485-50.688 4.864-62.379 25.173l-21.333 36.992c-11.691 20.352-7.552 50.304 9.387 66.645l46.763 45.184c16.853 16.341 16.853 43.008 0 59.349l-46.848 45.269c-16.853 16.341-21.077 46.293-9.344 66.645l21.376 36.992c11.691 20.352 39.808 31.659 62.379 25.216l62.592-17.92c22.528-6.528 45.653 6.827 51.328 29.568zM490.667 448c47.104 0 85.333 38.187 85.333 85.333 0 47.104-38.229 85.333-85.333 85.333s-85.333-38.229-85.333-85.333c0-47.147 38.229-85.333 85.333-85.333z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"tags":["cog"],"grid":24},"attrs":[],"properties":{"id":59,"order":38,"prevSize":32,"code":59654,"name":"cog"},"setIdx":3,"setId":1,"iconIdx":11},{"icon":{"paths":["M261.163 554.667c-23.595 0-42.667 19.115-42.667 42.667s19.072 42.667 42.667 42.667h62.507l-140.501 140.501c-16.683 16.683-16.683 43.648 0 60.331 8.32 8.32 19.243 12.501 30.165 12.501s21.845-4.181 30.165-12.501l145.664-145.664v72.832c0 23.552 19.072 42.667 42.667 42.667s37.504-19.115 37.504-42.667v-213.333h-208.171z","M298.667 469.333c23.552 0 42.667-19.115 42.667-42.667v-85.333h85.333c23.595 0 42.667-19.115 42.667-42.667s-19.072-42.667-42.667-42.667h-170.624l-0.043 170.667c0 23.552 19.072 42.667 42.667 42.667z","M725.333 554.667c-23.595 0-42.667 19.115-42.667 42.667v85.333h-85.333c-23.595 0-42.667 19.115-42.667 42.667s19.072 42.667 42.667 42.667h170.667v-170.667c0-23.552-19.072-42.667-42.667-42.667z","M780.501 183.168l-140.501 140.501v-67.669c0-23.552-19.072-42.667-42.667-42.667s-42.667 19.115-42.667 42.667v213.333h213.333c23.552 0 42.667-19.115 42.667-42.667s-19.072-42.667-42.667-42.667h-67.669l140.501-140.459c16.683-16.683 16.683-43.648 0-60.331s-43.648-16.725-60.331-0.043z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"tags":["arrow-minimise"],"grid":24},"attrs":[],"properties":{"id":82,"order":28,"prevSize":32,"code":59655,"name":"minimise"},"setIdx":3,"setId":1,"iconIdx":12},{"icon":{"paths":["M640 170.667c-23.595 0-42.667 19.115-42.667 42.667s19.072 42.667 42.667 42.667h67.669l-140.501 140.501c-16.683 16.683-16.683 43.648 0 60.331 8.32 8.32 19.243 12.501 30.165 12.501s21.845-4.181 30.165-12.501l140.501-140.501v67.669c0 23.552 19.072 42.667 42.667 42.667s42.667-19.115 42.667-42.667v-213.333h-213.333z","M396.501 567.168l-140.501 140.501v-67.669c0-23.552-19.072-42.667-42.667-42.667s-42.667 19.115-42.667 42.667v213.291h42.496c0.341 0 170.837 0.043 170.837 0.043 23.552 0 42.667-19.115 42.667-42.667s-19.072-42.667-42.667-42.667h-67.669l140.501-140.459c16.683-16.683 16.683-43.648 0-60.331s-43.648-16.725-60.331-0.043z","M298.667 512c23.552 0 42.667-19.115 42.667-42.667v-128h128c23.595 0 42.667-19.115 42.667-42.667s-19.072-42.667-42.667-42.667h-213.291l-0.043 213.333c0 23.552 19.072 42.667 42.667 42.667z","M725.333 512c-23.595 0-42.667 19.115-42.667 42.667v128h-128c-23.595 0-42.667 19.115-42.667 42.667s19.072 42.667 42.667 42.667h213.333v-213.333c0-23.552-19.072-42.667-42.667-42.667z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"tags":["arrow-maximise"],"grid":24},"attrs":[],"properties":{"id":83,"order":27,"prevSize":32,"code":59656,"name":"maximise"},"setIdx":3,"setId":1,"iconIdx":13},{"icon":{"paths":["M435.2 273.067c-20.821 0-39.723 8.405-53.461 21.845-101.589 98.773-253.739 246.997-253.739 246.997s152.149 148.181 253.611 246.997c13.909 13.44 32.768 21.76 53.589 21.76 42.411 0 76.8-34.347 76.8-76.757v-192-192c0-42.411-34.389-76.843-76.8-76.843z","M819.2 273.067c-20.821 0-39.723 8.405-53.461 21.845-101.589 98.773-253.739 246.997-253.739 246.997s152.149 148.181 253.611 246.997c13.909 13.44 32.768 21.76 53.589 21.76 42.411 0 76.8-34.347 76.8-76.757v-384c0-42.411-34.389-76.843-76.8-76.843z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"tags":["media-rewind"],"grid":24},"attrs":[],"properties":{"id":93,"order":34,"prevSize":32,"code":59657,"name":"backward"},"setIdx":3,"setId":1,"iconIdx":14},{"icon":{"paths":["M682.667 256h-341.333c-46.933 0-85.333 38.4-85.333 85.333v341.333c0 46.933 38.4 85.333 85.333 85.333h341.333c46.933 0 85.333-38.4 85.333-85.333v-341.333c0-46.933-38.4-85.333-85.333-85.333z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"tags":["media-stop"],"grid":24},"attrs":[],"properties":{"id":100,"order":29,"prevSize":32,"code":59658,"name":"stop"},"setIdx":3,"setId":1,"iconIdx":15},{"icon":{"paths":["M443.563 786.475c112.683-109.824 281.771-274.475 281.771-274.475s-169.088-164.651-281.771-274.475c-15.488-14.891-36.395-24.192-59.563-24.192-47.104 0-85.333 38.229-85.333 85.333v426.667c0 47.104 38.229 85.333 85.333 85.333 23.168 0 44.075-9.301 59.563-24.192z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"tags":["media-play"],"grid":24},"attrs":[],"properties":{"id":102,"order":31,"prevSize":32,"code":59659,"name":"play"},"setIdx":3,"setId":1,"iconIdx":16},{"icon":{"paths":["M642.261 294.912c-13.824-13.397-32.64-21.845-53.461-21.845-42.411 0-76.8 34.432-76.8 76.843v192 192c0 42.411 34.389 76.757 76.8 76.757 20.821 0 39.68-8.32 53.461-21.845 101.589-98.731 253.739-246.912 253.739-246.912s-152.149-148.224-253.739-246.997z","M258.261 294.912c-13.824-13.397-32.64-21.845-53.461-21.845-42.411 0-76.8 34.432-76.8 76.843v384c0 42.411 34.389 76.757 76.8 76.757 20.821 0 39.68-8.32 53.461-21.845 101.589-98.731 253.739-246.912 253.739-246.912s-152.149-148.224-253.739-246.997z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"tags":["media-fast-forward"],"grid":24},"attrs":[],"properties":{"id":103,"order":32,"prevSize":32,"code":59660,"name":"forward"},"setIdx":3,"setId":1,"iconIdx":17},{"icon":{"paths":["M725.333 682.667h-426.667c-47.104 0-85.333 38.187-85.333 85.333 0 47.104 38.229 85.333 85.333 85.333h426.667c47.104 0 85.333-38.229 85.333-85.333 0-47.147-38.229-85.333-85.333-85.333z","M786.475 452.437c-109.824-112.683-274.475-281.771-274.475-281.771s-164.651 169.088-274.475 281.771c-14.891 15.488-24.192 36.395-24.192 59.563 0 47.104 38.229 85.333 85.333 85.333h426.667c47.104 0 85.333-38.229 85.333-85.333 0-23.168-9.301-44.075-24.192-59.563z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"tags":["media-eject"],"grid":24},"attrs":[],"properties":{"id":104,"order":33,"prevSize":32,"code":59661,"name":"eject"},"setIdx":3,"setId":1,"iconIdx":18}],"height":1024,"metadata":{"name":"icons"},"preferences":{"showGlyphs":true,"showCodes":true,"showQuickUse":true,"showQuickUse2":true,"showSVGs":true,"fontPref":{"prefix":"icon-","metadata":{"fontFamily":"icons","majorVersion":1,"minorVersion":0},"metrics":{"emSize":1024,"baseline":6.25,"whitespace":50},"embed":false,"noie8":true,"ie7":false,"cssVars":true,"cssVarsFormat":"scss","showSelector":false,"showMetrics":false,"showMetadata":false,"showVersion":false},"imagePref":{"prefix":"icon-","png":true,"useClassSelector":true,"color":0,"bgColor":16777215},"historySize":50,"gridSize":16,"showGrid":false}} \ No newline at end of file +{"IcoMoonType":"selection","icons":[{"icon":{"paths":["M256.085 682.624c-47.232 0-85.504 38.272-85.419 85.376 0 47.104 38.229 85.376 85.419 85.291 47.061 0.085 85.333-38.144 85.248-85.291 0.085-47.232-38.187-85.461-85.248-85.376z","M256 170.667c-47.104 0-85.333 38.229-85.333 85.333s38.229 85.333 85.333 85.333c235.264 0 426.667 191.403 426.667 426.667 0 47.104 38.229 85.333 85.333 85.333s85.333-38.229 85.333-85.333c0-329.387-267.947-597.333-597.333-597.333z","M256 426.667c-47.104 0-85.333 38.229-85.333 85.333s38.229 85.333 85.333 85.333c94.080 0 170.667 76.544 170.667 170.667 0 47.104 38.229 85.333 85.333 85.333s85.333-38.229 85.333-85.333c0-188.203-153.131-341.333-341.333-341.333z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"tags":["rss"],"grid":24},"attrs":[],"properties":{"id":18,"order":46,"prevSize":24,"code":59663,"name":"stream"},"setIdx":0,"setId":4,"iconIdx":17},{"icon":{"paths":["M448 304c0-26.4 21.6-48 48-48h32c26.4 0 48 21.6 48 48v32c0 26.4-21.6 48-48 48h-32c-26.4 0-48-21.6-48-48v-32z","M640 768h-256v-64h64v-192h-64v-64h192v256h64z","M512 0c-282.77 0-512 229.23-512 512s229.23 512 512 512 512-229.23 512-512-229.23-512-512-512zM512 928c-229.75 0-416-186.25-416-416s186.25-416 416-416 416 186.25 416 416-186.25 416-416 416z"],"attrs":[{},{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["info","information"],"grid":24},"attrs":[{},{},{}],"properties":{"order":1,"id":0,"prevSize":24,"code":59668,"name":"info"},"setIdx":3,"setId":1,"iconIdx":0},{"icon":{"paths":["M469.333 85.333v170.667c0 23.552 19.115 42.667 42.667 42.667s42.667-19.115 42.667-42.667v-170.667c0-23.552-19.115-42.667-42.667-42.667s-42.667 19.115-42.667 42.667zM469.333 768v170.667c0 23.552 19.115 42.667 42.667 42.667s42.667-19.115 42.667-42.667v-170.667c0-23.552-19.115-42.667-42.667-42.667s-42.667 19.115-42.667 42.667zM180.181 240.512l120.747 120.747c16.683 16.683 43.691 16.683 60.331 0s16.683-43.691 0-60.331l-120.747-120.747c-16.683-16.683-43.691-16.683-60.331 0s-16.683 43.691 0 60.331zM662.741 723.072l120.747 120.747c16.683 16.683 43.691 16.683 60.331 0s16.683-43.691 0-60.331l-120.747-120.747c-16.683-16.683-43.691-16.683-60.331 0s-16.683 43.691 0 60.331zM85.333 554.667h170.667c23.552 0 42.667-19.115 42.667-42.667s-19.115-42.667-42.667-42.667h-170.667c-23.552 0-42.667 19.115-42.667 42.667s19.115 42.667 42.667 42.667zM768 554.667h170.667c23.552 0 42.667-19.115 42.667-42.667s-19.115-42.667-42.667-42.667h-170.667c-23.552 0-42.667 19.115-42.667 42.667s19.115 42.667 42.667 42.667zM240.512 843.819l120.747-120.747c16.683-16.683 16.683-43.691 0-60.331s-43.691-16.683-60.331 0l-120.747 120.747c-16.683 16.683-16.683 43.691 0 60.331s43.691 16.683 60.331 0zM723.072 361.259l120.747-120.747c16.683-16.683 16.683-43.691 0-60.331s-43.691-16.683-60.331 0l-120.747 120.747c-16.683 16.683-16.683 43.691 0 60.331s43.691 16.683 60.331 0z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["loader"],"grid":24},"attrs":[{}],"properties":{"order":1,"id":0,"name":"loader","prevSize":24,"code":59662},"setIdx":3,"setId":1,"iconIdx":1},{"icon":{"paths":["M960 619.148v84.852h-84.852l-107.148-107.148-107.148 107.148h-84.852v-84.852l107.148-107.148-107.148-107.148v-84.852h84.852l107.148 107.148 107.148-107.148h84.852v84.852l-107.148 107.148 107.148 107.148z","M416.006 960c-8.328 0-16.512-3.25-22.634-9.374l-246.626-246.626h-114.746c-17.672 0-32-14.326-32-32v-320c0-17.672 14.328-32 32-32h114.746l246.626-246.628c9.154-9.154 22.916-11.89 34.874-6.936 11.958 4.952 19.754 16.622 19.754 29.564v832c0 12.944-7.796 24.612-19.754 29.564-3.958 1.64-8.118 2.436-12.24 2.436z"],"attrs":[{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["volume-mute","volume","audio","player"],"grid":24},"attrs":[{},{}],"properties":{"order":1,"id":3,"prevSize":24,"code":59664,"name":"volume-none"},"setIdx":3,"setId":1,"iconIdx":2},{"icon":{"paths":["M549.020 741.020c-12.286 0-24.566-4.686-33.942-14.058-18.746-18.746-18.746-49.134 0-67.88 81.1-81.1 81.1-213.058 0-294.156-18.746-18.746-18.746-49.138 0-67.882s49.136-18.744 67.882 0c118.53 118.53 118.53 311.392 0 429.922-9.372 9.368-21.656 14.054-33.94 14.054z","M416.006 960c-8.328 0-16.512-3.25-22.634-9.374l-246.626-246.626h-114.746c-17.672 0-32-14.326-32-32v-320c0-17.672 14.328-32 32-32h114.746l246.626-246.628c9.154-9.154 22.916-11.89 34.874-6.936 11.958 4.952 19.754 16.622 19.754 29.564v832c0 12.944-7.796 24.612-19.754 29.564-3.958 1.64-8.118 2.436-12.24 2.436z"],"attrs":[{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["volume-low","volume","audio","speaker","player"],"grid":24},"attrs":[{},{}],"properties":{"order":2,"id":2,"prevSize":24,"code":59665,"name":"volume-low"},"setIdx":3,"setId":1,"iconIdx":3},{"icon":{"paths":["M719.53 831.53c-12.286 0-24.566-4.686-33.942-14.056-18.744-18.744-18.744-49.136 0-67.882 131.006-131.006 131.006-344.17 0-475.176-18.744-18.746-18.744-49.138 0-67.882 18.744-18.742 49.138-18.744 67.882 0 81.594 81.59 126.53 190.074 126.53 305.466 0 115.39-44.936 223.876-126.53 305.47-9.372 9.374-21.656 14.060-33.94 14.060v0zM549.020 741.020c-12.286 0-24.566-4.686-33.942-14.058-18.746-18.746-18.746-49.134 0-67.88 81.1-81.1 81.1-213.058 0-294.156-18.746-18.746-18.746-49.138 0-67.882s49.136-18.744 67.882 0c118.53 118.53 118.53 311.392 0 429.922-9.372 9.368-21.656 14.054-33.94 14.054z","M416.006 960c-8.328 0-16.512-3.25-22.634-9.374l-246.626-246.626h-114.746c-17.672 0-32-14.326-32-32v-320c0-17.672 14.328-32 32-32h114.746l246.626-246.628c9.154-9.154 22.916-11.89 34.874-6.936 11.958 4.952 19.754 16.622 19.754 29.564v832c0 12.944-7.796 24.612-19.754 29.564-3.958 1.64-8.118 2.436-12.24 2.436z"],"attrs":[{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["volume-medium","volume","audio","speaker","player"],"grid":24},"attrs":[{},{}],"properties":{"order":3,"id":1,"prevSize":24,"code":59666,"name":"volume-medium"},"setIdx":3,"setId":1,"iconIdx":4},{"icon":{"paths":["M890.040 922.040c-12.286 0-24.566-4.686-33.942-14.056-18.744-18.746-18.744-49.136 0-67.882 87.638-87.642 135.904-204.16 135.904-328.1 0-123.938-48.266-240.458-135.904-328.098-18.744-18.746-18.744-49.138 0-67.882s49.138-18.744 67.882 0c105.77 105.772 164.022 246.4 164.022 395.98s-58.252 290.208-164.022 395.98c-9.372 9.372-21.656 14.058-33.94 14.058zM719.53 831.53c-12.286 0-24.566-4.686-33.942-14.056-18.744-18.744-18.744-49.136 0-67.882 131.006-131.006 131.006-344.17 0-475.176-18.744-18.746-18.744-49.138 0-67.882 18.744-18.742 49.138-18.744 67.882 0 81.594 81.59 126.53 190.074 126.53 305.466 0 115.39-44.936 223.876-126.53 305.47-9.372 9.374-21.656 14.060-33.94 14.060v0zM549.020 741.020c-12.286 0-24.568-4.686-33.942-14.058-18.746-18.746-18.746-49.134 0-67.88 81.1-81.1 81.1-213.058 0-294.156-18.746-18.746-18.746-49.138 0-67.882s49.136-18.744 67.882 0c118.53 118.53 118.53 311.392 0 429.922-9.372 9.368-21.656 14.054-33.94 14.054z","M416.006 960c-8.328 0-16.512-3.25-22.634-9.374l-246.626-246.626h-114.746c-17.672 0-32-14.326-32-32v-320c0-17.672 14.328-32 32-32h114.746l246.626-246.628c9.154-9.154 22.916-11.89 34.874-6.936 11.958 4.952 19.754 16.622 19.754 29.564v832c0 12.944-7.796 24.612-19.754 29.564-3.958 1.64-8.118 2.436-12.24 2.436z"],"attrs":[{},{}],"width":1088,"isMulticolor":false,"isMulticolor2":false,"tags":["volume-high","volume","audio","speaker","player"],"grid":24},"attrs":[{},{}],"properties":{"order":4,"id":0,"prevSize":24,"code":59667,"name":"volume-high"},"setIdx":3,"setId":1,"iconIdx":5},{"icon":{"paths":["M742.997 281.003c-33.28-33.323-87.381-33.323-120.661 0l-110.336 110.336-110.336-110.336c-33.28-33.323-87.381-33.323-120.661 0-33.323 33.323-33.323 87.339 0 120.661l110.293 110.336-110.293 110.336c-33.323 33.323-33.323 87.339 0 120.661 16.64 16.683 38.485 25.003 60.331 25.003s43.691-8.32 60.331-25.003l110.336-110.336 110.336 110.336c16.64 16.683 38.485 25.003 60.331 25.003s43.691-8.32 60.331-25.003c33.323-33.323 33.323-87.339 0-120.661l-110.293-110.336 110.293-110.336c33.323-33.323 33.323-87.339 0-120.661z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"tags":["times"],"grid":24},"attrs":[],"properties":{"id":1,"order":39,"prevSize":24,"code":59648,"name":"cross"},"setIdx":3,"setId":1,"iconIdx":6},{"icon":{"paths":["M724.139 266.709c-41.259-22.955-93.227-8.021-116.053 33.152l-158.421 285.099-90.667-90.667c-33.323-33.323-87.339-33.323-120.661 0s-33.323 87.339 0 120.661l170.667 170.667c16.128 16.171 37.888 25.045 60.331 25.045 3.925 0 7.893-0.256 11.819-0.853 26.496-3.712 49.749-19.627 62.763-43.051l213.333-384c22.912-41.216 8.064-93.141-33.109-116.053z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"tags":["tick"],"grid":24},"attrs":[],"properties":{"id":2,"order":35,"prevSize":24,"code":59649,"name":"check"},"setIdx":3,"setId":1,"iconIdx":7},{"icon":{"paths":["M785.664 454.656c-33.323-33.323-87.339-33.323-120.661 0l-67.669 67.669v-308.992c0-47.147-38.229-85.333-85.333-85.333-47.147 0-85.333 38.187-85.333 85.333v308.992l-67.669-67.669c-33.323-33.323-87.339-33.323-120.661 0s-33.323 87.339 0 120.661l273.664 273.664 273.664-273.664c33.323-33.323 33.323-87.296 0-120.661z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"tags":["arrow-down-thick"],"grid":24},"attrs":[],"properties":{"id":23,"order":42,"prevSize":24,"code":59650,"name":"arrow-down"},"setIdx":3,"setId":1,"iconIdx":8},{"icon":{"paths":["M725.333 384c0-58.923-23.893-112.256-62.464-150.827-38.613-38.613-91.947-62.507-150.869-62.507s-112.256 23.893-150.869 62.507c-38.571 38.571-62.464 91.904-62.464 150.827s23.893 112.256 62.464 150.827c38.613 38.613 91.947 62.507 150.869 62.507s112.256-23.893 150.869-62.507c38.571-38.571 62.464-91.904 62.464-150.827z","M256 810.667c0 42.667 96 85.333 256 85.333 150.101 0 256-42.667 256-85.333 0-85.333-100.437-170.667-256-170.667-160 0-256 85.333-256 170.667z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"tags":["user"],"grid":24},"attrs":[],"properties":{"id":40,"order":26,"prevSize":24,"code":59651,"name":"user"},"setIdx":3,"setId":1,"iconIdx":9},{"icon":{"paths":["M384 597.333c58.923 0 112.256-23.893 150.869-62.507 38.571-38.571 62.464-91.904 62.464-150.827s-23.893-112.256-62.464-150.827c-38.613-38.613-91.947-62.507-150.869-62.507s-112.256 23.893-150.869 62.507c-38.571 38.571-62.464 91.904-62.464 150.827s23.893 112.256 62.464 150.827c38.613 38.613 91.947 62.507 150.869 62.507z","M384 896c150.101 0 256-42.667 256-85.333 0-85.333-100.437-170.667-256-170.667-160 0-256 85.333-256 170.667 0 42.667 96 85.333 256 85.333z","M896 512h-85.333v-85.333c0-23.595-19.072-42.667-42.667-42.667s-42.667 19.072-42.667 42.667v85.333h-85.333c-23.595 0-42.667 19.072-42.667 42.667s19.072 42.667 42.667 42.667h85.333v85.333c0 23.595 19.072 42.667 42.667 42.667s42.667-19.072 42.667-42.667v-85.333h85.333c23.595 0 42.667-19.072 42.667-42.667s-19.072-42.667-42.667-42.667z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"tags":["user-add"],"grid":24},"attrs":[],"properties":{"id":47,"order":37,"prevSize":24,"code":59652,"name":"user-add"},"setIdx":3,"setId":1,"iconIdx":10},{"icon":{"paths":["M341.333 256c-47.104 0-85.333 38.229-85.333 85.333v341.333c0 47.104 38.229 85.333 85.333 85.333s85.333-38.229 85.333-85.333v-341.333c0-47.104-38.229-85.333-85.333-85.333z","M640 256c-47.104 0-85.333 38.229-85.333 85.333v341.333c0 47.104 38.229 85.333 85.333 85.333s85.333-38.229 85.333-85.333v-341.333c0-47.104-38.229-85.333-85.333-85.333z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"tags":["media-pause"],"grid":24},"attrs":[],"properties":{"id":48,"order":36,"prevSize":24,"code":59653,"name":"pause"},"setIdx":3,"setId":1,"iconIdx":11},{"icon":{"paths":["M400.512 748.715l15.829 63.232c5.675 22.741 29.525 41.387 52.992 41.387h42.667c23.467 0 47.317-18.645 52.992-41.387l15.829-63.232c5.675-22.741 28.8-36.096 51.328-29.611l62.592 17.92c22.571 6.443 50.688-4.864 62.379-25.216l21.333-36.992c11.691-20.352 7.552-50.304-9.344-66.645l-46.848-45.269c-16.896-16.341-16.896-43.008 0.043-59.307l46.763-45.269c16.896-16.299 21.077-46.251 9.387-66.603l-21.376-36.992c-11.733-20.352-39.808-31.659-62.336-25.216l-62.592 17.92c-22.571 6.443-45.653-6.869-51.371-29.611l-15.787-63.147c-5.675-22.699-29.525-41.344-52.992-41.344h-42.667c-23.467 0-47.317 18.645-52.992 41.387l-15.787 63.147c-5.717 22.741-28.8 36.096-51.371 29.653l-62.592-17.92c-22.571-6.485-50.688 4.864-62.379 25.173l-21.333 36.992c-11.691 20.352-7.552 50.304 9.387 66.645l46.763 45.184c16.853 16.341 16.853 43.008 0 59.349l-46.848 45.269c-16.853 16.341-21.077 46.293-9.344 66.645l21.376 36.992c11.691 20.352 39.808 31.659 62.379 25.216l62.592-17.92c22.528-6.528 45.653 6.827 51.328 29.568zM490.667 448c47.104 0 85.333 38.187 85.333 85.333 0 47.104-38.229 85.333-85.333 85.333s-85.333-38.229-85.333-85.333c0-47.147 38.229-85.333 85.333-85.333z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"tags":["cog"],"grid":24},"attrs":[],"properties":{"id":59,"order":38,"prevSize":24,"code":59654,"name":"cog"},"setIdx":3,"setId":1,"iconIdx":12},{"icon":{"paths":["M261.163 554.667c-23.595 0-42.667 19.115-42.667 42.667s19.072 42.667 42.667 42.667h62.507l-140.501 140.501c-16.683 16.683-16.683 43.648 0 60.331 8.32 8.32 19.243 12.501 30.165 12.501s21.845-4.181 30.165-12.501l145.664-145.664v72.832c0 23.552 19.072 42.667 42.667 42.667s37.504-19.115 37.504-42.667v-213.333h-208.171z","M298.667 469.333c23.552 0 42.667-19.115 42.667-42.667v-85.333h85.333c23.595 0 42.667-19.115 42.667-42.667s-19.072-42.667-42.667-42.667h-170.624l-0.043 170.667c0 23.552 19.072 42.667 42.667 42.667z","M725.333 554.667c-23.595 0-42.667 19.115-42.667 42.667v85.333h-85.333c-23.595 0-42.667 19.115-42.667 42.667s19.072 42.667 42.667 42.667h170.667v-170.667c0-23.552-19.072-42.667-42.667-42.667z","M780.501 183.168l-140.501 140.501v-67.669c0-23.552-19.072-42.667-42.667-42.667s-42.667 19.115-42.667 42.667v213.333h213.333c23.552 0 42.667-19.115 42.667-42.667s-19.072-42.667-42.667-42.667h-67.669l140.501-140.459c16.683-16.683 16.683-43.648 0-60.331s-43.648-16.725-60.331-0.043z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"tags":["arrow-minimise"],"grid":24},"attrs":[],"properties":{"id":82,"order":28,"prevSize":24,"code":59655,"name":"minimise"},"setIdx":3,"setId":1,"iconIdx":13},{"icon":{"paths":["M640 170.667c-23.595 0-42.667 19.115-42.667 42.667s19.072 42.667 42.667 42.667h67.669l-140.501 140.501c-16.683 16.683-16.683 43.648 0 60.331 8.32 8.32 19.243 12.501 30.165 12.501s21.845-4.181 30.165-12.501l140.501-140.501v67.669c0 23.552 19.072 42.667 42.667 42.667s42.667-19.115 42.667-42.667v-213.333h-213.333z","M396.501 567.168l-140.501 140.501v-67.669c0-23.552-19.072-42.667-42.667-42.667s-42.667 19.115-42.667 42.667v213.291h42.496c0.341 0 170.837 0.043 170.837 0.043 23.552 0 42.667-19.115 42.667-42.667s-19.072-42.667-42.667-42.667h-67.669l140.501-140.459c16.683-16.683 16.683-43.648 0-60.331s-43.648-16.725-60.331-0.043z","M298.667 512c23.552 0 42.667-19.115 42.667-42.667v-128h128c23.595 0 42.667-19.115 42.667-42.667s-19.072-42.667-42.667-42.667h-213.291l-0.043 213.333c0 23.552 19.072 42.667 42.667 42.667z","M725.333 512c-23.595 0-42.667 19.115-42.667 42.667v128h-128c-23.595 0-42.667 19.115-42.667 42.667s19.072 42.667 42.667 42.667h213.333v-213.333c0-23.552-19.072-42.667-42.667-42.667z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"tags":["arrow-maximise"],"grid":24},"attrs":[],"properties":{"id":83,"order":27,"prevSize":24,"code":59656,"name":"maximise"},"setIdx":3,"setId":1,"iconIdx":14},{"icon":{"paths":["M435.2 273.067c-20.821 0-39.723 8.405-53.461 21.845-101.589 98.773-253.739 246.997-253.739 246.997s152.149 148.181 253.611 246.997c13.909 13.44 32.768 21.76 53.589 21.76 42.411 0 76.8-34.347 76.8-76.757v-192-192c0-42.411-34.389-76.843-76.8-76.843z","M819.2 273.067c-20.821 0-39.723 8.405-53.461 21.845-101.589 98.773-253.739 246.997-253.739 246.997s152.149 148.181 253.611 246.997c13.909 13.44 32.768 21.76 53.589 21.76 42.411 0 76.8-34.347 76.8-76.757v-384c0-42.411-34.389-76.843-76.8-76.843z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"tags":["media-rewind"],"grid":24},"attrs":[],"properties":{"id":93,"order":34,"prevSize":24,"code":59657,"name":"backward"},"setIdx":3,"setId":1,"iconIdx":15},{"icon":{"paths":["M682.667 256h-341.333c-46.933 0-85.333 38.4-85.333 85.333v341.333c0 46.933 38.4 85.333 85.333 85.333h341.333c46.933 0 85.333-38.4 85.333-85.333v-341.333c0-46.933-38.4-85.333-85.333-85.333z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"tags":["media-stop"],"grid":24},"attrs":[],"properties":{"id":100,"order":29,"prevSize":24,"code":59658,"name":"stop"},"setIdx":3,"setId":1,"iconIdx":16},{"icon":{"paths":["M443.563 786.475c112.683-109.824 281.771-274.475 281.771-274.475s-169.088-164.651-281.771-274.475c-15.488-14.891-36.395-24.192-59.563-24.192-47.104 0-85.333 38.229-85.333 85.333v426.667c0 47.104 38.229 85.333 85.333 85.333 23.168 0 44.075-9.301 59.563-24.192z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"tags":["media-play"],"grid":24},"attrs":[],"properties":{"id":102,"order":31,"prevSize":24,"code":59659,"name":"play"},"setIdx":3,"setId":1,"iconIdx":17},{"icon":{"paths":["M642.261 294.912c-13.824-13.397-32.64-21.845-53.461-21.845-42.411 0-76.8 34.432-76.8 76.843v192 192c0 42.411 34.389 76.757 76.8 76.757 20.821 0 39.68-8.32 53.461-21.845 101.589-98.731 253.739-246.912 253.739-246.912s-152.149-148.224-253.739-246.997z","M258.261 294.912c-13.824-13.397-32.64-21.845-53.461-21.845-42.411 0-76.8 34.432-76.8 76.843v384c0 42.411 34.389 76.757 76.8 76.757 20.821 0 39.68-8.32 53.461-21.845 101.589-98.731 253.739-246.912 253.739-246.912s-152.149-148.224-253.739-246.997z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"tags":["media-fast-forward"],"grid":24},"attrs":[],"properties":{"id":103,"order":32,"prevSize":24,"code":59660,"name":"forward"},"setIdx":3,"setId":1,"iconIdx":18},{"icon":{"paths":["M725.333 682.667h-426.667c-47.104 0-85.333 38.187-85.333 85.333 0 47.104 38.229 85.333 85.333 85.333h426.667c47.104 0 85.333-38.229 85.333-85.333 0-47.147-38.229-85.333-85.333-85.333z","M786.475 452.437c-109.824-112.683-274.475-281.771-274.475-281.771s-164.651 169.088-274.475 281.771c-14.891 15.488-24.192 36.395-24.192 59.563 0 47.104 38.229 85.333 85.333 85.333h426.667c47.104 0 85.333-38.229 85.333-85.333 0-23.168-9.301-44.075-24.192-59.563z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"tags":["media-eject"],"grid":24},"attrs":[],"properties":{"id":104,"order":33,"prevSize":24,"code":59661,"name":"eject"},"setIdx":3,"setId":1,"iconIdx":19}],"height":1024,"metadata":{"name":"icons"},"preferences":{"showGlyphs":true,"showCodes":true,"showQuickUse":true,"showQuickUse2":true,"showSVGs":true,"fontPref":{"prefix":"icon-","metadata":{"fontFamily":"icons","majorVersion":1,"minorVersion":0},"metrics":{"emSize":1024,"baseline":6.25,"whitespace":50},"embed":false,"noie8":true,"ie7":false,"cssVars":true,"cssVarsFormat":"scss","showSelector":false,"showMetrics":false,"showMetadata":false,"showVersion":false},"imagePref":{"prefix":"icon-","png":true,"useClassSelector":true,"color":0,"bgColor":16777215},"historySize":50,"gridSize":16,"showGrid":false}} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index dfcea74..e108eb1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,7 +18,8 @@ "redux": "^4.1.0", "redux-logger": "^3.0.6", "reset-css": "^5.0.1", - "tom32i-event-emitter.js": "^2.0.5" + "tom32i-event-emitter.js": "^2.0.5", + "webrtc-adapter": "^7.7.0" }, "devDependencies": { "@babel/core": "^7.14.0", @@ -5494,6 +5495,18 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/rtcpeerconnection-shim": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/rtcpeerconnection-shim/-/rtcpeerconnection-shim-1.2.15.tgz", + "integrity": "sha512-C6DxhXt7bssQ1nHb154lqeL0SXz5Dx4RczXZu2Aa/L1NJFnEVDxFwCBo3fqtuljhHIGceg5JKBV4XJ0gW5JKyw==", + "dependencies": { + "sdp": "^2.6.0" + }, + "engines": { + "node": ">=6.0.0", + "npm": ">=3.10.0" + } + }, "node_modules/safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", @@ -5578,6 +5591,11 @@ "url": "https://opencollective.com/webpack" } }, + "node_modules/sdp": { + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/sdp/-/sdp-2.12.0.tgz", + "integrity": "sha512-jhXqQAQVM+8Xj5EjJGVweuEzgtGWb3tmEEpl3CLP3cStInSbVHSg0QWOGQzNq8pSID4JkpeV2mPqlMDLrm0/Vw==" + }, "node_modules/semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", @@ -6439,6 +6457,19 @@ "url": "https://opencollective.com/webpack" } }, + "node_modules/webrtc-adapter": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/webrtc-adapter/-/webrtc-adapter-7.7.1.tgz", + "integrity": "sha512-TbrbBmiQBL9n0/5bvDdORc6ZfRY/Z7JnEj+EYOD1ghseZdpJ+nF2yx14k3LgQKc7JZnG7HAcL+zHnY25So9d7A==", + "dependencies": { + "rtcpeerconnection-shim": "^1.2.15", + "sdp": "^2.12.0" + }, + "engines": { + "node": ">=6.0.0", + "npm": ">=3.10.0" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -10530,6 +10561,14 @@ "glob": "^7.1.3" } }, + "rtcpeerconnection-shim": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/rtcpeerconnection-shim/-/rtcpeerconnection-shim-1.2.15.tgz", + "integrity": "sha512-C6DxhXt7bssQ1nHb154lqeL0SXz5Dx4RczXZu2Aa/L1NJFnEVDxFwCBo3fqtuljhHIGceg5JKBV4XJ0gW5JKyw==", + "requires": { + "sdp": "^2.6.0" + } + }, "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", @@ -10577,6 +10616,11 @@ "ajv-keywords": "^3.5.2" } }, + "sdp": { + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/sdp/-/sdp-2.12.0.tgz", + "integrity": "sha512-jhXqQAQVM+8Xj5EjJGVweuEzgtGWb3tmEEpl3CLP3cStInSbVHSg0QWOGQzNq8pSID4JkpeV2mPqlMDLrm0/Vw==" + }, "semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", @@ -11199,6 +11243,15 @@ "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", "dev": true }, + "webrtc-adapter": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/webrtc-adapter/-/webrtc-adapter-7.7.1.tgz", + "integrity": "sha512-TbrbBmiQBL9n0/5bvDdORc6ZfRY/Z7JnEj+EYOD1ghseZdpJ+nF2yx14k3LgQKc7JZnG7HAcL+zHnY25So9d7A==", + "requires": { + "rtcpeerconnection-shim": "^1.2.15", + "sdp": "^2.12.0" + } + }, "which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", diff --git a/package.json b/package.json index 8e310cb..b6672e1 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,8 @@ "redux": "^4.1.0", "redux-logger": "^3.0.6", "reset-css": "^5.0.1", - "tom32i-event-emitter.js": "^2.0.5" + "tom32i-event-emitter.js": "^2.0.5", + "webrtc-adapter": "^7.7.0" }, "devDependencies": { "@babel/core": "^7.14.0", diff --git a/src/client/components/Controls.js b/src/client/components/Controls.js index 8328744..e95671a 100644 --- a/src/client/components/Controls.js +++ b/src/client/components/Controls.js @@ -3,6 +3,7 @@ import PropTypes from 'prop-types'; import { connect } from 'react-redux'; import Button from '@client/components/Button'; import VolumeControl from '@client/components/VolumeControl'; +import StreamButton from '@client/components/StreamButton'; class Controls extends Component { static propTypes = { @@ -13,6 +14,12 @@ class Controls extends Component { onStop: PropTypes.func.isRequired, onBackward: PropTypes.func.isRequired, onForward: PropTypes.func.isRequired, + toggleStream: PropTypes.func, + streamable: PropTypes.bool.isRequired, + }; + + static defaultProps = { + toggleStream: null, }; constructor(props) { @@ -102,7 +109,7 @@ class Controls extends Component { } render() { - const { playing, loaded, onStop, onBackward, onForward } = this.props; + const { playing, loaded, streamable, onStop, onBackward, onForward, toggleStream } = this.props; const playIcon = loaded ? playing ? 'icon-pause' : 'icon-play' : 'icon-loader'; const screenIcon = this.fullscreen ? 'icon-minimise' : 'icon-maximise'; @@ -110,6 +117,7 @@ class Controls extends Component {
@@ -127,8 +201,11 @@ class Player extends Component { export default connect( state => ({ source: state.player.source, + duration: state.player.duration, + currentTime: state.player.currentTime, }), dispatch => ({ setShowtime: showtime => dispatch(setShowtime(showtime)), + setTimeline: (currentTime, duration) => dispatch(setTimeline(currentTime, duration)), }) )(Player); diff --git a/src/client/components/Socket.js b/src/client/components/Socket.js index 23f752f..7bf2c93 100644 --- a/src/client/components/Socket.js +++ b/src/client/components/Socket.js @@ -2,9 +2,8 @@ import { Component } from 'react'; import PropTypes from 'prop-types'; import { connect } from 'react-redux'; import { get } from '@client/container'; -import { socketOpen, socketClose, me, userAdd, userRemove, userReady } from '@client/store/room'; -import { loadVideoFromServer } from '@client/store/player'; -import { play, pause, seek, stop } from '@client/store/player'; +import { socketOpen, socketClose, me, userAdd, userRemove, userReady, userStreaming } from '@client/store/room'; +import { play, pause, seek, stop, loadVideoFromServer, setTimeline, unloadStream } from '@client/store/player'; class Socket extends Component { static propTypes = { @@ -23,11 +22,14 @@ class Socket extends Component { onUserAdd: PropTypes.func.isRequired, onUserRemove: PropTypes.func.isRequired, onUserReady: PropTypes.func.isRequired, + onUserStreaming: PropTypes.func.isRequired, onControlPlay: PropTypes.func.isRequired, onControlPause: PropTypes.func.isRequired, onControlSeek: PropTypes.func.isRequired, onControlStop: PropTypes.func.isRequired, onVideo: PropTypes.func.isRequired, + setTimeline: PropTypes.func.isRequired, + unloadStream: PropTypes.func.isRequired, }; static defaultProps = { @@ -38,11 +40,17 @@ class Socket extends Component { super(props); this.api = get('api'); + this.peer = get('peer'); this.onError = this.onError.bind(this); this.onVideoFile = this.onVideoFile.bind(this); this.onVideoUrl = this.onVideoUrl.bind(this); this.onVideoYoutube = this.onVideoYoutube.bind(this); + this.onPeerOffer = this.onPeerOffer.bind(this); + this.onPeerAnswer = this.onPeerAnswer.bind(this); + this.onPeerCandidate = this.onPeerCandidate.bind(this); + this.onPeerTimeline = this.onPeerTimeline.bind(this); + this.onPeerStop = this.onPeerStop.bind(this); } componentDidMount() { @@ -58,6 +66,7 @@ class Socket extends Component { this.api.addEventListener('user:add', this.props.onUserAdd); this.api.addEventListener('user:remove', this.props.onUserRemove); this.api.addEventListener('user:ready', this.props.onUserReady); + this.api.addEventListener('user:streaming', this.props.onUserStreaming); this.api.addEventListener('control:play', this.props.onControlPlay); this.api.addEventListener('control:pause', this.props.onControlPause); this.api.addEventListener('control:stop', this.props.onControlStop); @@ -65,6 +74,11 @@ class Socket extends Component { this.api.addEventListener('video:file', this.onVideoFile); this.api.addEventListener('video:url', this.onVideoUrl); this.api.addEventListener('video:youtube', this.onVideoYoutube); + this.api.addEventListener('peer:offer', this.onPeerOffer); + this.api.addEventListener('peer:answer', this.onPeerAnswer); + this.api.addEventListener('peer:candidate', this.onPeerCandidate); + this.api.addEventListener('peer:timeline', this.onPeerTimeline); + this.api.addEventListener('peer:stop', this.onPeerStop); } componentWillUnmount() { @@ -78,6 +92,7 @@ class Socket extends Component { this.api.removeEventListener('user:add', this.props.onUserAdd); this.api.removeEventListener('user:remove', this.props.onUserRemove); this.api.removeEventListener('user:ready', this.props.onUserReady); + this.api.removeEventListener('user:streaming', this.props.onUserStreaming); this.api.removeEventListener('control:play', this.props.onControlPlay); this.api.removeEventListener('control:pause', this.props.onControlPause); this.api.removeEventListener('control:stop', this.props.onControlStop); @@ -85,6 +100,11 @@ class Socket extends Component { this.api.removeEventListener('video:file', this.onVideoFile); this.api.removeEventListener('video:url', this.onVideoUrl); this.api.removeEventListener('video:youtube', this.onVideoYoutube); + this.api.removeEventListener('peer:offer', this.onPeerOffer); + this.api.removeEventListener('peer:answer', this.onPeerAnswer); + this.api.removeEventListener('peer:candidate', this.onPeerCandidate); + this.api.removeEventListener('peer:timeline', this.onPeerTimeline); + this.api.removeEventListener('peer:stop', this.onPeerStop); // Close connection this.api.leave(); @@ -107,22 +127,45 @@ class Socket extends Component { onVideoUrl(event) { const { name, url } = event.detail; - this.props.onVideo('url', name, url); } onVideoYoutube(event) { const { name, url } = event.detail; - this.props.onVideo('youtube', name, url); } onVideoFile(event) { const { name } = event.detail; - this.props.onVideo('file', name); } + onPeerOffer(event) { + const { description, sender } = event.detail; + this.peer.spectate(JSON.parse(description), sender); + this.props.onVideo('peer'); + } + + onPeerAnswer(event) { + const { sender, description } = event.detail; + this.peer.answer(sender, JSON.parse(description)); + } + + onPeerCandidate(event) { + const { sender, description } = event.detail; + this.peer.addCandidate(sender, JSON.parse(description)); + } + + onPeerTimeline(event) { + const { currentTime, duration } = event.detail; + this.props.setTimeline(currentTime, duration); + } + + onPeerStop() { + this.props.unloadStream(); + this.peer.clear(); + } + /** * On error * @@ -154,10 +197,13 @@ export default connect( onUserAdd: event => dispatch(userAdd(event.detail)), onUserRemove: event => dispatch(userRemove(event.detail)), onUserReady: event => dispatch(userReady(event.detail)), + onUserStreaming: event => dispatch(userStreaming(event.detail)), onControlPlay: event => dispatch(play(event.detail)), onControlPause: event => dispatch(pause(event.detail)), onControlSeek: event => dispatch(seek(event.detail)), onControlStop: event => dispatch(stop(event.detail)), onVideo: (source, name, url = null) => dispatch(loadVideoFromServer(source, name, url)), + unloadStream: () => dispatch(unloadStream()), + setTimeline: (currentTime, duration) => dispatch(setTimeline(currentTime, duration)), }) )(Socket); diff --git a/src/client/components/StreamButton.js b/src/client/components/StreamButton.js new file mode 100644 index 0000000..0af6cb9 --- /dev/null +++ b/src/client/components/StreamButton.js @@ -0,0 +1,34 @@ +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; +import { connect } from 'react-redux'; +import Button from '@client/components/Button'; + +class StreamButton extends Component { + static propTypes = { + disabled: PropTypes.bool, + active: PropTypes.bool.isRequired, + onClick: PropTypes.func.isRequired, + }; + + static defaultProps = { + disabled: false, + }; + + render() { + const { active, disabled, onClick } = this.props; + + return