#javascript #asynchronous #google-chrome-extension
#javascript #асинхронный #google-chrome-расширение
Вопрос:
У меня была эта идея для нового расширения Chrome: он должен создать QR-код ссылки для текущего открытого веб-сайта, отображаемый в popup.html который можно легко отсканировать с помощью смартфона. Если вы смотрите видео на YouTube, текущее время видео также должно быть встроено в QR-код, что позволяет продолжить просмотр видео непосредственно в приложении YouTube на смартфоне.
Пока все хорошо. Но теперь у меня следующая проблема: это расширение отлично работает на всех веб-сайтах. Только на Youtube, похоже, существует проблема с асинхронностью прослушивателя onmessage и отправкой сообщения в contentScript (запрашивающий текущее время просмотренного видео на YouTube). В консоли отладки я получаю следующие ошибки:
Непроверенный runtime.lastError: не удалось установить соединение. Принимающий конец не существует.
… получение этого после попытки выполнить строку 7 из background.js
Ответ на обработку ошибок: TypeError: не удается прочитать свойство ‘videoTime’ неопределенного
в chrome-extension://…../background.js:8:70
… получение этого после попытки выполнить строку 8 из background.js
popup.js
$(function() {
chrome.runtime.sendMessage({text: 'sendURL'}, function(response) {
$('#qr-code').attr('src', getQRCodeImgURL(response.url));
});
});
function getQRCodeImgURL(url) {
var qrCodeURL = new URL('http://api.qrserver.com/v1/create-qr-code/');
qrCodeURL.searchParams.set('data', encodeURI(url));
qrCodeURL.searchParams.set('size', '200x200');
return qrCodeURL;
}
background.js
chrome.runtime.onMessage.addListener(function (message, sender, sendResponse) {
if (message.text == 'sendURL') {
chrome.tabs.query({active: true, /* lastFocusedWindow: true */}, function (tabs) {
var currentURL = new URL(tabs[0].url);
if (currentURL.href.indexOf('youtube.com/watch?v=') >= 0) { // if current website is youtube
chrome.tabs.sendMessage(tabs[0].id, { text: 'sendVideoTime' }, function (response) {
const ytVideoTime = timeStringToSeconds(response.videoTime);
var ytURL = new URL('https://youtu.be/');
ytURL.pathname = '/' currentURL.searchParams.get('v');
ytURL.searchParams.set('t', ytVideoTime);
currentURL = ytURL;
sendResponse({ url: currentURL.href });
});
} else {
sendResponse({ url: currentURL.href });
}
});
}
return true;
});
function timeStringToSeconds(timeString) {
var seconds = 0;
var hms = timeString.split(':');
if (hms.length == 3) {
seconds = parseInt(hms[0])/* hours */ * 60 /* minutes per hour */ * 60 /* seconds per minute */;
hms.shift(); /* remove first element, for accessing first element in next step (also if hms doesnt is in this hh:mm:ss format) */
}
return seconds (parseInt(hms[0]) * 60) /* seconds per minute */ parseInt(hms[1]) /* seconds */;
}
contentScript.js
chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
if (message.text == 'sendVideoTime') {
const time = document.evaluate('//*[@id="movie_player"]/div[27]/div[2]/div[1]/div[1]/span[1]', document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue.textContent;
sendResponse({videoTime: time});
}
return true;
});
manifest.json
{
"manifest_version": 2,
"name": "URL-QR-Code-Creator",
"version": "1.0",
"description": "This extension creates a linking QR code for the currently open website, which can be easily scanned with the smartphone. If you watch a video on the YouTube website, the current time of the video is also embedded in the QR code, which makes it possible to continue watching the video directly in the YouTube app on the smartphone.",
"icons": {
"16": "images/qr-code-16px.png",
"32": "images/qr-code-32px.png",
"48": "images/qr-code-48px.png",
"64": "images/qr-code-64px.png",
"128": "images/qr-code-128px.png"
},
"browser_action": {
"default_icon": {
"16": "images/qr-code-16px.png",
"32": "images/qr-code-32px.png",
"48": "images/qr-code-48px.png",
"64": "images/qr-code-64px.png",
"128": "images/qr-code-128px.png"
},
"default_title": "show QR-Code",
"default_popup": "popup.html"
},
"background": {
"scripts": [
"background.js"
],
"persistant": false
},
"content_scripts": [
{
"matches": ["*://www.youtube.com/watch?v=*"],
"js": ["contentScript.js"]
}
],
"permissions": [
"activeTab",
"tabs"
]
}
Комментарии:
1. «Принимающая сторона не существует» сообщает вам, что в тот момент, когда сообщение было отправлено, на вкладке не был запущен скрипт содержимого. Покажите нам, как вы объявляете / вводите contentScript.js
2. Добавлен manifest.json в мой пост выше. 🙂
3. Youtube — это СПА-сайт, поэтому, когда вы сначала открываете его домашнюю страницу, а затем переходите на страницу просмотра, там не будет запущен скрипт содержимого. Вам нужно сопоставить
"*://www.youtube.com/*"
4. Изменен шаблон сопоставления на «[звезда]://www.youtube.com /[звезда]» но все равно получаю одни и те же ошибки в одно и то же время.
5. Ну, вам нужно перезагрузить и расширение, и вкладку. Кроме того, если youtube все еще загружается, ваш сценарий содержимого еще не будет запущен, поэтому вы можете указать run_at .
Ответ №1:
Я сделал это!
Сначала я попрощался с идеей регулирования доступа к DOM youtube с помощью дополнительного скрипта контента. Поэтому я удалил contentScript.js и удалил его из manifest.json. Теперь я просто получил доступ к DOM, используя метод chrome.tabs.executeScript в background.js файл и получил результат с помощью функции обратного вызова. Довольно просто — без необходимости постоянно отправлять сообщения.