В данной статье рассмотрим основные моменты при создании расширения google chrome для записи экрана и камеры. Оно может записывать целый экран, отдельное окно или вкладку. В режиме записи экрана можно вставлять окно с фронтальной камерой внутрь страницы на которой активен плагин, либо вне браузера. Также можно включить запись микрофона или звук системы. Ну и дополнительно можно осуществлять запись только с камеры.
В расширении также будет использоваться интернационализация (i18next). Для управления состоянием будет использоваться библиотека onChange. Для перемещения встраиваемой камеры по странице jquery-ui. И для стилизации видеоплеера библиотека plyr-player.
Ссылка на исходный код расширения
Первым делом нужно настроить главный файл расширения google chrome - manifest.json
"action": {
"default_popup": "html/popup.html"
},
default_popup: файл HTML, который будет отображаться в выпадающем меню, когда пользователь нажимает на значок действия. В нашем случае это будет loader, после загрузки которого мы будем вставлять iframe на страницу пользователя.
"background": {
"service_worker": "js/background.js",
"type": "module"
},
Файл background.js обязателен для всех расширений google chrome. Он может использоваться для выполнения различных задач в фоновом режиме, таких как обновление данных, отправка запросов на сервер, мониторинг веб-страниц и т.д. Это позволяет расширению работать в фоновом режиме, даже если пользователь не активен в браузере. В нашем случаем в нем нет необходимости, поэтому просто создадим его и оставим пустым.
"content_scripts": [
{
"matches": [
"https://*/*",
"http://*/*"
],
"js": [
"js/content-script.js"
]
}
],
Пожалуй, главный файл нашего расширения - это content-script.js. Он может использоваться для изменения внешнего вида и поведения веб-страницы, добавления или удаления элементов на странице, взаимодействия с содержимым страницы и т.д. matches: URL-адреса веб-страниц, на которых должен быть запущен сценарий.
"web_accessible_resources": [
{
"matches": [
"<all_urls>"
],
"resources": [
"html/popup.html",
"html/iframe.html",
"js/renderContent/camera.js",
"js/renderContent/iframe.js",
"libs/jquery-3.6.0.min.js",
"libs/jquery-ui.min.js"
]
}
],
Файл "web_accessible_resources" в Google Chrome Extension используется для определения ресурсов, которые могут быть доступны на веб-странице, даже если они находятся за пределами расширения.
"permissions": [
"tabs",
"storage",
"downloads",
"activeTab",
"scripting"
]
Ну и "permissions" является важным элементом в разработке расширений Google Chrome, позволяющим расширению запросить необходимые разрешения у пользователя, чтобы выполнить необходимые действия. Без этого файла расширение не сможет получить доступ к некоторым функциям браузера, что может ограничить его функциональность.
setTimeout(() => {
chrome.tabs.query({ active: true, currentWindow: true }, function (tabs) {
chrome.tabs.sendMessage(tabs[0].id, "open")
window.close()
})
}, 1500)
Итак в выпадающем окне popup у нас отображается loader, после загрузки которого с помощью таймера передается сообщение в content-script и закрывается наш popup с помощью window.close()
chrome.runtime.onMessage.addListener((msg, _, sendResponse) => {
const iframePlugin = document.querySelector("#record_plugin")
switch (msg) {
case "close": {
iframePlugin?.remove()
break
}
case "open": {
;(async () => {
const src = chrome.runtime.getURL("js/renderContent/iframe.js")
const contentScript = await import(src)
contentScript.renderIframe(iframePlugin)
})()
break
}
В content-script мы слушаем сообщения, которые нам приходят из popup и из нашего iframe, который мы встраиваем тут же.
Внутри iframe будет происходить основная логика расширения. За доступ к содержимому экрана, звуку системы, микрофону и камере будет отвечать класс Media с помощью методов navigator.mediaDevices.getDisplayMedia и navigator.mediaDevices.getUserMedia.
if (state.mode === "screen") {
combine = new MediaStream([
...this.screenStream.getTracks(),
...this.voiceStream.getTracks(),
])
} else {
combine = new MediaStream([
...this.cameraStream.getTracks(),
...this.voiceStream.getTracks(),
])
}
Так создается поток медиа данных который включает в себя видео и аудио треки в зависимости от режима (запись экрана или запись с камеры).
let blobData = new Blob(data, { type: "video/mp4" })
// Convert the blob data to a url
let url = URL.createObjectURL(blobData)
// Assign the url to the output video tag and anchor
output.src = url
downloadTitle.href = url
Обработка готового потока медиа данных и их помещение внутрь проигрывателя и ссылки (для скачивания видеофайла).
const player = new Plyr("#video", {
controls: [
"play-large",
"play",
"progress",
"current-time",
"volume",
"captions",
"settings",
"fullscreen",
],
})
const newMedia = new Media()
const defaultLanguage = lStorage.get("language_plugin") || "en"
newMedia.getFlowCamera()
const i18nInstance = i18next.createInstance()
await i18nInstance.init({
lng: defaultLanguage,
debug: false,
resources,
})
Итак внутри iframe сперва создаем экземпляр плеера, затем экземпляр Media для работы с потоками видео и аудио, запрашиваем доступ к камере, достаем из localStorage текущий язык и инициализируем тексты.
const initialState = {
//активность записи
recording: false,
language: defaultLanguage,
// полный экран для плеера
fullscreen: false,
// проверка на то, что запись не пустая
emptyRecord: true,
// режим - screen или camera
mode: "screen",
UIState: {
wiewIframe: "control",
switch: {
microphone: false,
camera: false,
cameraLocal: false,
audio: false,
},
},
}
Создаем стейт iframe, состояние которого будем отслеживать с помощью библиотеки onChange и в следствие этих изменений перерисовывать наш UI.
Также создаем объект со всеми необходимыми элементами, на которые навешиваем обработчики, внутри которых будет меняться наш стейт.
Таким образом, в данной статье мы в общих чертах рассмотрели создание расширения google chrome для записи экрана и камеры. Исходный код - для более детального ознакомления с расширением.
Комментарии (8)
fk0
00.00.0000 00:00+1А зачем такой экстеншн, когда есть программы записывающие окно с десктопа. Мне кажется, это несколько более универсально.
Кстати, интересно было бы знать, а как экстеншен работает в ситуации, когда окно браузера скрыто. Свёрнуто или перекрыто другим окном. Ведь по идее тогда само окно, или его часть не обновляется, если там даже что-то и меняется, и записывать нечего. Или браузер в неком своем буфере окна обновляет всегда, просто обновления на уровне X11 или Win32 GDI не делается для свёрнутых окон? В такой ситуации приходилось браузер сажать в Xvfb, чтоб пока с него там картинка записывается можно было с другими программами на компьютере работать. И чтоб можно было несколько браузеров разом запустить.
И со звуком интересно как? Не с микрофона, а из видео в браузере. Если у нас положим десять браузеров и мы с них фильмы хотим сграбить. Опять же приходилось через pulseaudio их растаскивать на разные виртуальные (monitor) девайсы, а с них уже записывать.
Andchir
Непонятно куда все эти файлы положить и что сделать, чтобы браузер увидел это расширение.
igorg599 Автор
Скачиваете архив с github и распаковываете его, затем переходите в "Меню браузера" --> "Дополнительные инструменты" --> "Расширения", там включаете "Режим разработчика", жмете на кнопку "Загрузить распакованное расширение", загружаете и можно пользоваться.
alexshipin
Отлично, а можно тоже самое, только в внутри статьи? ))
aosavonin
Соглашусь, было бы здорово если бы автор расписал с чего начать для песочницы. По шагам по пунктам.