diff options
author | 2020-09-23 04:14:20 +0530 | |
---|---|---|
committer | 2020-09-22 23:44:20 +0100 | |
commit | 62df97a366923de638c0f45def3f76caa302a0c9 (patch) | |
tree | d38b73d7143df11be897069533605cba0cb0687a | |
parent | Update adaptable dark mode to work on all platforms (#834) (diff) | |
download | ferdium-app-62df97a366923de638c0f45def3f76caa302a0c9.tar.gz ferdium-app-62df97a366923de638c0f45def3f76caa302a0c9.tar.zst ferdium-app-62df97a366923de638c0f45def3f76caa302a0c9.zip |
Patch getDisplayMedia for screen sharing in all services (#802)
Co-authored-by: Gautam Singh <gautamsi@users.noreply.github.com>
-rw-r--r-- | src/webview/recipe.js | 131 |
1 files changed, 126 insertions, 5 deletions
diff --git a/src/webview/recipe.js b/src/webview/recipe.js index c6724e35a..675f8e311 100644 --- a/src/webview/recipe.js +++ b/src/webview/recipe.js | |||
@@ -1,5 +1,5 @@ | |||
1 | /* eslint-disable import/first */ | 1 | /* eslint-disable import/first */ |
2 | import { ipcRenderer, remote } from 'electron'; | 2 | import { ipcRenderer, remote, desktopCapturer } from 'electron'; |
3 | import path from 'path'; | 3 | import path from 'path'; |
4 | import { autorun, computed, observable } from 'mobx'; | 4 | import { autorun, computed, observable } from 'mobx'; |
5 | import fs from 'fs-extra'; | 5 | import fs from 'fs-extra'; |
@@ -32,6 +32,69 @@ import { isDevMode } from '../environment'; | |||
32 | 32 | ||
33 | const debug = require('debug')('Ferdi:Plugin'); | 33 | const debug = require('debug')('Ferdi:Plugin'); |
34 | 34 | ||
35 | const screenShareCss = ` | ||
36 | .desktop-capturer-selection { | ||
37 | position: fixed; | ||
38 | top: 0; | ||
39 | left: 0; | ||
40 | width: 100%; | ||
41 | height: 100vh; | ||
42 | background: rgba(30,30,30,.75); | ||
43 | color: #fff; | ||
44 | z-index: 10000000; | ||
45 | display: flex; | ||
46 | align-items: center; | ||
47 | justify-content: center; | ||
48 | } | ||
49 | .desktop-capturer-selection__scroller { | ||
50 | width: 100%; | ||
51 | max-height: 100vh; | ||
52 | overflow-y: auto; | ||
53 | } | ||
54 | .desktop-capturer-selection__list { | ||
55 | max-width: calc(100% - 100px); | ||
56 | margin: 50px; | ||
57 | padding: 0; | ||
58 | display: flex; | ||
59 | flex-wrap: wrap; | ||
60 | list-style: none; | ||
61 | overflow: hidden; | ||
62 | justify-content: center; | ||
63 | } | ||
64 | .desktop-capturer-selection__item { | ||
65 | display: flex; | ||
66 | margin: 4px; | ||
67 | } | ||
68 | .desktop-capturer-selection__btn { | ||
69 | display: flex; | ||
70 | flex-direction: column; | ||
71 | align-items: stretch; | ||
72 | width: 145px; | ||
73 | margin: 0; | ||
74 | border: 0; | ||
75 | border-radius: 3px; | ||
76 | padding: 4px; | ||
77 | background: #252626; | ||
78 | text-align: left; | ||
79 | transition: background-color .15s, box-shadow .15s; | ||
80 | } | ||
81 | .desktop-capturer-selection__btn:hover, | ||
82 | .desktop-capturer-selection__btn:focus { | ||
83 | background: rgba(98,100,167,.8); | ||
84 | } | ||
85 | .desktop-capturer-selection__thumbnail { | ||
86 | width: 100%; | ||
87 | height: 81px; | ||
88 | object-fit: cover; | ||
89 | } | ||
90 | .desktop-capturer-selection__name { | ||
91 | margin: 6px 0 6px; | ||
92 | white-space: nowrap; | ||
93 | text-overflow: ellipsis; | ||
94 | overflow: hidden; | ||
95 | } | ||
96 | `; | ||
97 | |||
35 | class RecipeController { | 98 | class RecipeController { |
36 | @observable settings = { | 99 | @observable settings = { |
37 | overrideSpellcheckerLanguage: false, | 100 | overrideSpellcheckerLanguage: false, |
@@ -128,14 +191,15 @@ class RecipeController { | |||
128 | } | 191 | } |
129 | 192 | ||
130 | async loadUserFiles(recipe, config) { | 193 | async loadUserFiles(recipe, config) { |
194 | const styles = document.createElement('style'); | ||
195 | styles.innerHTML = screenShareCss; | ||
196 | |||
131 | const userCss = path.join(recipe.path, 'user.css'); | 197 | const userCss = path.join(recipe.path, 'user.css'); |
132 | if (await fs.exists(userCss)) { | 198 | if (await fs.exists(userCss)) { |
133 | const data = await fs.readFile(userCss); | 199 | const data = await fs.readFile(userCss); |
134 | const styles = document.createElement('style'); | 200 | styles.innerHTML += data.toString(); |
135 | styles.innerHTML = data.toString(); | ||
136 | |||
137 | document.querySelector('head').appendChild(styles); | ||
138 | } | 201 | } |
202 | document.querySelector('head').appendChild(styles); | ||
139 | 203 | ||
140 | const userJs = path.join(recipe.path, 'user.js'); | 204 | const userJs = path.join(recipe.path, 'user.js'); |
141 | if (await fs.exists(userJs)) { | 205 | if (await fs.exists(userJs)) { |
@@ -386,3 +450,60 @@ window.open = (url, frameName, features) => { | |||
386 | if (isDevMode) { | 450 | if (isDevMode) { |
387 | window.log = console.log; | 451 | window.log = console.log; |
388 | } | 452 | } |
453 | |||
454 | // Patch getDisplayMedia for screen sharing | ||
455 | window.navigator.mediaDevices.getDisplayMedia = () => new Promise(async (resolve, reject) => { | ||
456 | try { | ||
457 | const sources = await desktopCapturer.getSources({ types: ['screen', 'window'] }); | ||
458 | |||
459 | const selectionElem = document.createElement('div'); | ||
460 | selectionElem.classList = 'desktop-capturer-selection'; | ||
461 | selectionElem.innerHTML = ` | ||
462 | <div class="desktop-capturer-selection__scroller"> | ||
463 | <ul class="desktop-capturer-selection__list"> | ||
464 | ${sources.map(({ | ||
465 | id, name, thumbnail, | ||
466 | }) => ` | ||
467 | <li class="desktop-capturer-selection__item"> | ||
468 | <button class="desktop-capturer-selection__btn" data-id="${id}" title="${name}"> | ||
469 | <img class="desktop-capturer-selection__thumbnail" src="${thumbnail.toDataURL()}" /> | ||
470 | <span class="desktop-capturer-selection__name">${name}</span> | ||
471 | </button> | ||
472 | </li> | ||
473 | `).join('')} | ||
474 | </ul> | ||
475 | </div> | ||
476 | `; | ||
477 | document.body.appendChild(selectionElem); | ||
478 | |||
479 | document.querySelectorAll('.desktop-capturer-selection__btn') | ||
480 | .forEach((button) => { | ||
481 | button.addEventListener('click', async () => { | ||
482 | try { | ||
483 | const id = button.getAttribute('data-id'); | ||
484 | const mediaSource = sources.find(source => source.id === id); | ||
485 | if (!mediaSource) { | ||
486 | throw new Error(`Source with id ${id} does not exist`); | ||
487 | } | ||
488 | |||
489 | const stream = await window.navigator.mediaDevices.getUserMedia({ | ||
490 | audio: false, | ||
491 | video: { | ||
492 | mandatory: { | ||
493 | chromeMediaSource: 'desktop', | ||
494 | chromeMediaSourceId: mediaSource.id, | ||
495 | }, | ||
496 | }, | ||
497 | }); | ||
498 | resolve(stream); | ||
499 | |||
500 | selectionElem.remove(); | ||
501 | } catch (err) { | ||
502 | reject(err); | ||
503 | } | ||
504 | }); | ||
505 | }); | ||
506 | } catch (err) { | ||
507 | reject(err); | ||
508 | } | ||
509 | }); | ||