在本文中,我们将开发一个 chrome 扩展,用户可以使用它创建对应于不同时间戳的书签,将它们存储在某处(目前在 chrome 本地存储中),并检索书签(存储为带时间戳的 youtube 视频链接)。
代码托管在这里:GitHub。主扩展的视频解释器可以在这里找到(在主扩展的 repo 中)。请注意,在撰写本文时,该项目仍在进行中。
让我们开始吧。从广义上讲,我们将这篇文章分为 3 个部分。在第一部分中,我们将连接扩展程序,以便我们可以在 Chrome 中访问我们正在开发的扩展程序。在第二部分,我们将看看一个基本的扩展,并讨论代码和架构。在第三部分,我们将开发主要扩展。
1. 在开发过程中测试我们的扩展
为了在开发阶段测试和调试我们的扩展,我们将按照以下步骤启动和运行基本扩展。
- 创建如上所示的 manifest.json 文件和项目结构,或从文章顶部的链接下载它们。
- 从浏览器转到 chrome://extensions。
- 将“开发人员模式”切换为“开”。
- 单击“加载未打包”选项以加载扩展文件夹以进行测试、调试和进一步开发。
- 此时,您应该会在 chrome 地址栏的右侧看到您的扩展程序。
现在我们已经在 chrome 上加载了我们的扩展文件夹,我们准备构建一个基本的 chrome 扩展并测试它。
2. 基本的 Chrome 扩展 – 你好!
我们将构建一个扩展,它会说:“嗨,那里!”当用户单击扩展图标时。代码可以在这里找到。
为此,我们需要以下文件。
- manifest.json – 保存有关 Chrome 扩展程序的信息。
- popup.html – 说,“嗨,那里!”当用户点击扩展图标时。
- popup.js – 此时此文件没有重要的工作。虽然,我们会把它留在这里。
- background.js – 加载具有基本后端功能的扩展。不需要的嗨,有!延期。
- jQuery.js – 我们将包含 jQuery 来帮助开发。
1. manifest.json 文件
{
"name": "Hi, there! Extension",
"version": "1.0",
"description": "I greet",
"permissions": ["activeTab"],
"options_page": "options.html",
"background": {
"scripts": ["background.js"],
"persistent": false
},
"browser_action": {
"default_popup": "popup.html",
"default_title": "Hi, there Extension"
},
"manifest_version": 2
}
让我们更详细地查看 manifest.json 文件中的键值对。
- name – 这是扩展的名称。在浏览器屏幕快照中,您可以看到“嗨,那里!延期。
- version – 这是扩展的版本。它被认为是 1.0,因为当我们将它上传到 chrome 网上商店进行审核时,它最初是 1.0。在开发阶段,您可以将其命名为 0.0,然后是 0.1,依此类推。
- description – 扩展的描述。保持简洁是一个很好的做法。
- 权限– 权限键值对包含扩展需要访问才能正常工作的不同权限。该值是一个字符串数组。数组的元素可以是已知字符串,也可以是模式匹配(通常用于匹配网址)。例如,https://youtube.com/* -> 授予对域名为 youtube.com 的所有链接的扩展名的权限。此处,“*”是通配符模式。另请注意,此处声明的某些权限可能也需要用户的明确批准。您可以在官方文档中阅读有关权限的更多信息。
- options_page – 选项页面用于为用户提供更多选项。用户可以通过右键单击扩展程序并单击菜单中的“选项”按钮或从“chrome://extensions”页面转到选项页面来访问选项页面。上述清单中使用的设置将导致 options.html 页面在新选项卡中打开。也可以以嵌入的方式在同一选项卡中打开“选项”页面。在基本的“嗨,在那里!”扩展,我们不需要这个选项。您可以在官方文档中阅读有关“选项”的更多信息。也许在这里添加更多
- background – 背景脚本在此处声明。后台脚本用于监听事件并对它们做出反应,因为扩展是一个事件驱动的范例。后台页面在需要时加载,空闲时卸载,即后台脚本在执行操作时将继续运行,并在操作执行后卸载。在我们的“嗨,在那里!”扩展,我们还没有使用后台脚本功能。您还可以注意到“persistent”键被设置为 false,因为这是标准做法,正如文档中提到的,我们应该将“persistent”设置为 true 的唯一时间是当扩展使用 chrome.webRequest API 时阻止或修改网络请求,我们没有这样做。
- browser_action – 扩展程序使用 browser_action 将图标放在 chrome 地址栏的右侧。然后扩展程序监听点击,当点击图标时,它会做一些事情。在我们的例子中,它打开包含 Hi, there! 的 popup.html 页面。问候。 ‘default_title’ 字段值是一个字符串,当用户将鼠标悬停在扩展程序的图标上时会显示该字符串。
- manifest_version – 在撰写本文时,我们鼓励开发人员试用即将推出的 manifest_version 3。但是,版本 2 仍然可用且熟悉,因此我们将使用版本 2。对于版本 3,你可以从这里开始。
2. popup.html 文件
HTML
Hi, there!
HTML
Youtube video Bookmarker
xx:xx
Bookmarked points
Javascript
'use strict';
$(function() {
//retrieve data from local for already stored notes
// chrome.runtime.sendMessage({ method: "getbookmarks" })
//todo, not connected to background.js
// $('#bookmark_ulist > li > span > a').on("click", function() {
// console.log('li clicked event fired');
}) //todo
//todo
//make same page reload of youtube video to bookmarked point
$('#bookmarkdesc').focus(function() {
console.log('focus bookmark description input field') //executing
//for sending a message
chrome.runtime.sendMessage({ method: "gettimestampforcurrentpoint" });
//for listening any message which comes from runtime
chrome.runtime.onMessage.addListener(tsvalue);
var ts, tslink;
function tsvalue(msg) {
// Do your work here
if (msg.method == "tsfind") {
ts = msg.tsvaltopopup;
tslink = msg.fl;
// console.log('ts tslink' + ts + ' ' + tslink)
$('#submitbookmark').on('click', function() {
// console.log('submitnote button clicked')
//#bookmark_ulist
var bookmarkinput = $('#bookmarkdesc').val();
// console.log('#bookmarkinput val ' + bookmarkinput);
$('#bookmark_ulist').append('' + ts +
' - ' +
bookmarkinput +
' ');
console.log('list item appended to bookmark_ulist')
// chrome.storage.local.set({ "bklocal": bookmarkinput,
// "tslocal": ts, "vidlinklocal": tslink })
//popup > bg > fg while setting
//while getting, see..
// chrome.runtime.sendMessage({ method: "setlocalstorage",
// bookmarkvalue: bookmarkinput, timestamp: ts, vidlink: tslink})
});
$('#currts').text(msg.tsvaltopopup)
$('#receiptts').text('got timestamp')
// makeentryinstorage(bookmarkinput, ts, tslink);
}
}
})
// });
// chrome.storage.local.set({ note: inputnote,
//timestamp: time, videolink: link });
// function makeentryinstorage(bookmarkinput, time, link) {
//chrome.runtime.sendMessage({ method: "storeinlocal", note: bookmarkinput,
// timestamp: time, videolink: link });
// } //todo
// makeentryinstorage(bookmarkinput, ts, tslink);
// $('#pointsli').append('' +
// noteinput + ' ');
// console.log('msg obj popup.js ' + msg);
// console.log('popupjs noteinput ' + noteinput);
// $('#pointsli').append('' +
// noteinput + ' ');
// { method: "tsfind", tsvaltopopup: msg.tsval, fl: msg.finallink }
Javascript
"use strict";
// to check connection of fg with bg
chrome.runtime.onMessage.addListener(checktimestamp);
function checktimestamp(msg) {
// Do your work here
if (msg.method == "gettimestampforcurrentpoint") {
console.log("bg.js gettimestampforcurrrentpoint called");
chrome.tabs.executeScript(null, { file: "./gettimestamp.js" }, () => {
console.log("injected gettimestamp.js file into YT window DOM.");
// gettimestamp.js will execute now in main chrome window which
// is running youtube.com/somevideo
});
}
}
// first this runs
chrome.tabs.onActivated.addListener((tab) => {
console.log(tab);
chrome.tabs.get(tab.tabId, (c) => {
// console.log(c.url);
if (/^https:\/\/www\.youtube/.test(c.url)) {
// above pattern tests for the youtube hostname.
// If youtube is running in the active tab,
// it injects ./foreground.js in DOM.
chrome.tabs.executeScript(null, { file: "./foreground.js" }, () => {
console.log("i injected fg using bg script in youtube webpages");
});
}
});
// fetch data from local storage
// var windowlink;
// chrome.tabs.get(tab.tabId, a => {
// windowlink = a.url;
// });
// console.log('testretrieval bg.js')
// chrome.runtime.sendMessage({ method: "testretrieval" });
});
// chrome.browserAction.onClicked.addListener(function(tab) {
// console.log('browser action called' + tab);
// // // Run the following code when the popup is opened
// });
//for sending a message
// chrome.runtime.sendMessage({greeting: "hello"}, function(response) {
// });
// chrome.runtime.onMessage.addListener(retrievenotes)
// function retrievenotes(msg) {
// if (msg.method == "getnotes") {
// //todo
// }
// }
// chrome.runtime.onMessage.addListener(storelocal); //todo
// function storelocal(msg) { //todo
// if (msg.method == "storeinlocal") {
// chrome.storage.local.set({ note: inputnote, timestamp: time,
// videolink: link });
// }
// }
chrome.runtime.onMessage.addListener(getcurrenttimestamp);
function getcurrenttimestamp(msg) {
if (msg.method == "sendtimestamptobg") {
var temp1 = msg.tsvalue;
var temp2 = msg.finallink;
console.log("msg.tsvalue value: " + msg.tsval);
console.log("msg.finallink " + msg.finallink);
//tsval and finallink being received properly in the bg consolelog
chrome.runtime.sendMessage({
method: "tsfind",
tsvaltopopup: temp1,
fl: temp2,
});
// , function() {
// console.log('tsval to popup');
// })
}
}
chrome.runtime.onMessage.addListener(localstorageset);
function localstorageset(msg) {
if (msg.method == "setlocalstorage") {
console.log("setlocalstorage background.js"); //called
// chrome.runtime.sendMessage({ method: "setlocalstorage",
// bookmarkvalue: bookmarkinput, timestamp: ts, vidlink: tslink })
// chrome.storage.local.set({ "bklocal": msg.bookmarkvalue,
// "tslocal": msg.timestamp, "vidlinklocal": msg.vidlink })
// chrome.storage.local.set({ "password": "123" })
// chrome.runtime.sendMessage({ method: "localstoragesetrequest",
// pass: "hellopass" });
}
}
// chrome.runtime.onInstalled.addListener(function() {
// chrome.storage.sync.set({color: '#3aa757'}, function() {
// console.log('The color is green.');
// });
// chrome.declarativeContent.onPageChanged.removeRules(undefined, function() {
// chrome.declarativeContent.onPageChanged.addRules([{
// conditions: [new chrome.declarativeContent.PageStateMatcher({
// pageUrl: {hostEquals: 'developer.chrome.com'},
// })],
// actions: [new chrome.declarativeContent.ShowPageAction()]
// }]);
// });
// });
Javascript
var result1 = document
.querySelector(
"#movie_player > div.ytp-chrome-bottom >div.ytp-progress-bar-container >div.ytp-progress-bar"
)
.getAttribute("aria-valuetext");
//example of result1 is 1 Hours 48 Minutes 31 Seconds of 2 Hours 56 Minutes 33 Seconds.
// Here, the timestamp is 01:48:31 in hh:mm:ss format out of a 02:56:33 long video.
// construct link to exact point here
var temparr = result1.split(" ");
var tshhmmss_string;
if (temparr[6] == "Hours") {
tshhmmss_string = +"00:" + temparr[0] + ":" + temparr[2];
} else if (temparr[1] == "Hours") {
tshhmmss_string = temparr[0] + ":" + temparr[2] + ":" + temparr[4];
} else if (temparr[6] == "Minutes") {
tshhmmss_string = "00:" + temparr[0] + ":" + temparr[2];
}
console.log("gettimestamp.js " + result1);
var windowlink = window.location.href;
// note that values like https://www.youtube.com/watch?v=JaIU4CteN50,
// https://youtu.be/JaIU4CteN50?t=88,
// https://www.youtube.com/watch?v=PlSr4_moZGA&list=PLqM7alHXFySGnMRMboNceiibQw5ZU-ix9,
// https://youtu.be/PlSr4_moZGA?list=PLqM7alHXFySGnMRMboNceiibQw5ZU-ix9&t=104
// can be stored in pagelink.
console.log("gettimestamp.js windowlink " + windowlink);
// find index of v= substring
var idx = windowlink.indexOf("v=");
// return index from where the 'v=' substring starts in the windowlink.
// For example, in https://www.youtube.com/watch?v=JaIU4CteN50, idx = 30.
// indexOf function returns -1 if the substring is not found in the string.
console.log("gettimestamp.js idx value " + idx);
// console.log('tres gettimestamp.js ' + tres); fine - format hh:mm:ss
// console.log('typeof tres gettimestamp.js ' + typeof(tres));
//working fine - returns string
function getseconds(timestamphhmmss) {
var x = timestamphhmmss.split(":");
var seconds = parseInt(x[0]) * 60 * 60 + parseInt(x[1]) * 60 + parseInt(x[2]);
console.log("seconds calculated gettimestamp.js getinseconds" + seconds);
return seconds;
} //function working fine
var timeinseconds = getseconds(tshhmmss_string); //working fine - returns number
// console.log('tsinsec gettimestamp.js ' + tsinsec); fine
var windowlinkfinal;
if (idx == -1) {
windowlink = "https://youtube.com";
//in case of substring not found, i.e. bad case, store youtube.com as default.
} else {
windowlinkfinal =
"https://youtube.com/watch?v=" +
windowlink.substr(idx + 2, 11) +
"&t=" +
timeinseconds;
console.log("gettimestamp.js windowlinkfinal " + windowlinkfinal);
} // pagelinkfinal fine
chrome.runtime.sendMessage({
method: "sendtimestamptobg",
tsvalue: tshhmmss_string,
finallink: windowlinkfinal,
});
基本 Chrome 扩展程序如何工作?
在我们“加载解压”chrome 扩展后,将处理 manifest.json 文件。此后,运行“后台”以初始化扩展并侦听其他事件。现在,我们已经从开发的角度了解了 chrome 扩展,我们将看看我们想要构建的主要扩展——YouTube 书签扩展。
主要扩展 – YouTube 书签
可以在此处找到 YouTube 书签扩展的视频演示。
扩展的特点:
- 在 Chrome 扩展程序中的 youtube.com 标签上工作,以便为视频中的点添加书签。
- 当用户单击 popup.html 窗口中的 标签时,扩展会记录 标签处于“焦点”状态的时间戳。在从 标签中获取输入后,它会将其附加到 popup.html 的“书签点”部分,如解说视频中所见。
项目目录结构:
源代码:
1.由于扩展程序将访问和存储网址,即 youtube 视频地址,因此必须查看我们可以从 DOM 访问的不同类型的时间戳。
如果一个运行
var result1 = document.querySelector('#movie_player >
div.ytp-chrome-bottom > div.ytp-progress-bar-container >
div.ytp-progress-bar').getAttribute("aria-valuetext");
它将以 word 格式给出时间戳,定义如下。我们鼓励您在可通过按“Ctrl+Shift+J”访问的 chrome 窗口控制台中运行上述查询选择器。
下面是可以通过运行上面的查询选择器以 word 格式检索的时间戳类型。
1 Hours 48 Minutes 31 Seconds of 2 Hours 56 Minutes 33 Seconds
//for video greater than 1 hours long and the current
//timestamp being greater than 1 hour too.
-> 0 Minutes 46 Seconds of 2 Hours 56 Minutes 33 Seconds
//for video greater than 1 hours long and
//current timestamp < 1 minute
-> 8 Minutes 33 Seconds of 2 Hours 56 Minutes 33 Seconds
//for video greater than 1 hours long and
//current timestamp >= 1 minute and less than 1 hour
-> 0 Minutes 0 Seconds of 0 Minutes 56 Seconds
//for video less than 1 minute long and
//current timestamp < 1 minute
2.清单.json:
{
"name": "Youtube video bookmarker",
"version": "1.0",
"description": "An extension that bookmarks time points in youtube video",
"permissions": ["activeTab", "declarativeContent",
"storage", "tabs", "https://www.youtube.com/*"],
"options_page": "options.html",
"background": {
"scripts": ["background.js"],
"persistent": false
},
"externally_connectable": {
"matches": ["*://*.youtube.com/*"]
},
"browser_action": {
"default_popup": "popup.html",
"default_title": "YouTube Video Bookmarker - GFG"
},
"manifest_version": 2
}
manifest.json文件的字段定义如下:
- 名称、版本、描述、browser_action。 manifest_version, options_page, –在之前的 manifest.json 中已经有足够的细节
- 权限–字符串数组。
- activeTab – 可以访问活动选项卡
- storage – 可以访问 chrome 的存储 API。
- https://youtube.com/* – 基于模式的主机名,如果需要操作和工作扩展,可以访问该主机名
- tabs – 可以访问“tabs”API。
- declarativeContent – 根据当前页面的内容采取行动。
3. popup.html:
HTML
Youtube video Bookmarker
xx:xx
Bookmarked points
这里我们有popup.html 文件的实现:
- 我们有 2 个 标签。
- #bookmarktakerdiv – 将书签和时间戳作为用户的输入。
- #bookmarklistdiv – 保存已为当前视频拍摄的书签的无序列表。此处的“当前视频”是指当前在当前活动的选项卡上播放的视频。
- 我们有 1 个
- (#bookmark_ulist) 保存超链接书签及其时间戳。
4. popup.js:
Javascript
'use strict'; $(function() { //retrieve data from local for already stored notes // chrome.runtime.sendMessage({ method: "getbookmarks" }) //todo, not connected to background.js // $('#bookmark_ulist > li > span > a').on("click", function() { // console.log('li clicked event fired'); }) //todo //todo //make same page reload of youtube video to bookmarked point $('#bookmarkdesc').focus(function() { console.log('focus bookmark description input field') //executing //for sending a message chrome.runtime.sendMessage({ method: "gettimestampforcurrentpoint" }); //for listening any message which comes from runtime chrome.runtime.onMessage.addListener(tsvalue); var ts, tslink; function tsvalue(msg) { // Do your work here if (msg.method == "tsfind") { ts = msg.tsvaltopopup; tslink = msg.fl; // console.log('ts tslink' + ts + ' ' + tslink) $('#submitbookmark').on('click', function() { // console.log('submitnote button clicked') //#bookmark_ulist var bookmarkinput = $('#bookmarkdesc').val(); // console.log('#bookmarkinput val ' + bookmarkinput); $('#bookmark_ulist').append('
- ' + ts + ' - ' + bookmarkinput + '
'); console.log('list item appended to bookmark_ulist') // chrome.storage.local.set({ "bklocal": bookmarkinput, // "tslocal": ts, "vidlinklocal": tslink }) //popup > bg > fg while setting //while getting, see.. // chrome.runtime.sendMessage({ method: "setlocalstorage", // bookmarkvalue: bookmarkinput, timestamp: ts, vidlink: tslink}) }); $('#currts').text(msg.tsvaltopopup) $('#receiptts').text('got timestamp') // makeentryinstorage(bookmarkinput, ts, tslink); } } }) // }); // chrome.storage.local.set({ note: inputnote, //timestamp: time, videolink: link }); // function makeentryinstorage(bookmarkinput, time, link) { //chrome.runtime.sendMessage({ method: "storeinlocal", note: bookmarkinput, // timestamp: time, videolink: link }); // } //todo // makeentryinstorage(bookmarkinput, ts, tslink); // $('#pointsli').append('- ' + // noteinput + '
'); // console.log('msg obj popup.js ' + msg); // console.log('popupjs noteinput ' + noteinput); // $('#pointsli').append('- ' + // noteinput + '
'); // { method: "tsfind", tsvaltopopup: msg.tsval, fl: msg.finallink }下面的列表解释了我们为 popup.js 采取的方法:
- 当用户单击由 id ‘ bookmarkdesc ‘ 唯一标识的 标签时,该事件将使用 { method: “ gettimestampforcurrentpoint ” } 对象触发。这个事件由 background.js 捕获,我们稍后会看到。
- 函数tsvalue () 从 background.js 中触发,将视频信息从浏览器窗口框架传输到扩展窗口框架。
- 在tsvalue ()函数内部,’# submitbookmark ‘ 按钮上的点击事件将包含时间戳的
- 元素和由带时间戳的 YouTube视频链接超链接的书签附加到 popup.html 中的 #bookmark_ulist。
- 所以,再次解释一下,在用户点击扩展图标后,如果视频是主浏览器窗口框架中的 YouTube 视频,时间戳和书签被内置到一个
- 元素中,该元素被附加到
- 中弹出窗口.html。
- 如您所见,popup.js 为 popup.html 添加了交互性,并使用事件驱动范例与 background.js 进行通信。
5.背景.js
Javascript
"use strict"; // to check connection of fg with bg chrome.runtime.onMessage.addListener(checktimestamp); function checktimestamp(msg) { // Do your work here if (msg.method == "gettimestampforcurrentpoint") { console.log("bg.js gettimestampforcurrrentpoint called"); chrome.tabs.executeScript(null, { file: "./gettimestamp.js" }, () => { console.log("injected gettimestamp.js file into YT window DOM."); // gettimestamp.js will execute now in main chrome window which // is running youtube.com/somevideo }); } } // first this runs chrome.tabs.onActivated.addListener((tab) => { console.log(tab); chrome.tabs.get(tab.tabId, (c) => { // console.log(c.url); if (/^https:\/\/www\.youtube/.test(c.url)) { // above pattern tests for the youtube hostname. // If youtube is running in the active tab, // it injects ./foreground.js in DOM. chrome.tabs.executeScript(null, { file: "./foreground.js" }, () => { console.log("i injected fg using bg script in youtube webpages"); }); } }); // fetch data from local storage // var windowlink; // chrome.tabs.get(tab.tabId, a => { // windowlink = a.url; // }); // console.log('testretrieval bg.js') // chrome.runtime.sendMessage({ method: "testretrieval" }); }); // chrome.browserAction.onClicked.addListener(function(tab) { // console.log('browser action called' + tab); // // // Run the following code when the popup is opened // }); //for sending a message // chrome.runtime.sendMessage({greeting: "hello"}, function(response) { // }); // chrome.runtime.onMessage.addListener(retrievenotes) // function retrievenotes(msg) { // if (msg.method == "getnotes") { // //todo // } // } // chrome.runtime.onMessage.addListener(storelocal); //todo // function storelocal(msg) { //todo // if (msg.method == "storeinlocal") { // chrome.storage.local.set({ note: inputnote, timestamp: time, // videolink: link }); // } // } chrome.runtime.onMessage.addListener(getcurrenttimestamp); function getcurrenttimestamp(msg) { if (msg.method == "sendtimestamptobg") { var temp1 = msg.tsvalue; var temp2 = msg.finallink; console.log("msg.tsvalue value: " + msg.tsval); console.log("msg.finallink " + msg.finallink); //tsval and finallink being received properly in the bg consolelog chrome.runtime.sendMessage({ method: "tsfind", tsvaltopopup: temp1, fl: temp2, }); // , function() { // console.log('tsval to popup'); // }) } } chrome.runtime.onMessage.addListener(localstorageset); function localstorageset(msg) { if (msg.method == "setlocalstorage") { console.log("setlocalstorage background.js"); //called // chrome.runtime.sendMessage({ method: "setlocalstorage", // bookmarkvalue: bookmarkinput, timestamp: ts, vidlink: tslink }) // chrome.storage.local.set({ "bklocal": msg.bookmarkvalue, // "tslocal": msg.timestamp, "vidlinklocal": msg.vidlink }) // chrome.storage.local.set({ "password": "123" }) // chrome.runtime.sendMessage({ method: "localstoragesetrequest", // pass: "hellopass" }); } } // chrome.runtime.onInstalled.addListener(function() { // chrome.storage.sync.set({color: '#3aa757'}, function() { // console.log('The color is green.'); // }); // chrome.declarativeContent.onPageChanged.removeRules(undefined, function() { // chrome.declarativeContent.onPageChanged.addRules([{ // conditions: [new chrome.declarativeContent.PageStateMatcher({ // pageUrl: {hostEquals: 'developer.chrome.com'}, // })], // actions: [new chrome.declarativeContent.ShowPageAction()] // }]); // }); // });
让我们看看我们在 background.js 文件中做了什么:
- 当用户点击 字段制作书签时,在后台脚本中,调用 checktimestamp ()函数将gettimestamp .js 脚本注入浏览器窗口。正如文件名所暗示的那样,它将为我们提供当前时间戳和带时间戳的 YouTube视频链接,我们将使用eventListener – getcurrenttimestamp 收听。
- 函数getcurrenttimestamp将在从使用对象属性 {msg.method = ‘ sendtimestamptobg ‘} 触发的事件接收到时间戳(以秒为单位)和带时间戳的视频链接后,将其发送到 popup.js(扩展的上下文/帧)。此事件侦听从gettimestamp .js 脚本发送的消息。
6. 获取时间戳.js
Javascript
var result1 = document .querySelector( "#movie_player > div.ytp-chrome-bottom >div.ytp-progress-bar-container >div.ytp-progress-bar" ) .getAttribute("aria-valuetext"); //example of result1 is 1 Hours 48 Minutes 31 Seconds of 2 Hours 56 Minutes 33 Seconds. // Here, the timestamp is 01:48:31 in hh:mm:ss format out of a 02:56:33 long video. // construct link to exact point here var temparr = result1.split(" "); var tshhmmss_string; if (temparr[6] == "Hours") { tshhmmss_string = +"00:" + temparr[0] + ":" + temparr[2]; } else if (temparr[1] == "Hours") { tshhmmss_string = temparr[0] + ":" + temparr[2] + ":" + temparr[4]; } else if (temparr[6] == "Minutes") { tshhmmss_string = "00:" + temparr[0] + ":" + temparr[2]; } console.log("gettimestamp.js " + result1); var windowlink = window.location.href; // note that values like https://www.youtube.com/watch?v=JaIU4CteN50, // https://youtu.be/JaIU4CteN50?t=88, // https://www.youtube.com/watch?v=PlSr4_moZGA&list=PLqM7alHXFySGnMRMboNceiibQw5ZU-ix9, // https://youtu.be/PlSr4_moZGA?list=PLqM7alHXFySGnMRMboNceiibQw5ZU-ix9&t=104 // can be stored in pagelink. console.log("gettimestamp.js windowlink " + windowlink); // find index of v= substring var idx = windowlink.indexOf("v="); // return index from where the 'v=' substring starts in the windowlink. // For example, in https://www.youtube.com/watch?v=JaIU4CteN50, idx = 30. // indexOf function returns -1 if the substring is not found in the string. console.log("gettimestamp.js idx value " + idx); // console.log('tres gettimestamp.js ' + tres); fine - format hh:mm:ss // console.log('typeof tres gettimestamp.js ' + typeof(tres)); //working fine - returns string function getseconds(timestamphhmmss) { var x = timestamphhmmss.split(":"); var seconds = parseInt(x[0]) * 60 * 60 + parseInt(x[1]) * 60 + parseInt(x[2]); console.log("seconds calculated gettimestamp.js getinseconds" + seconds); return seconds; } //function working fine var timeinseconds = getseconds(tshhmmss_string); //working fine - returns number // console.log('tsinsec gettimestamp.js ' + tsinsec); fine var windowlinkfinal; if (idx == -1) { windowlink = "https://youtube.com"; //in case of substring not found, i.e. bad case, store youtube.com as default. } else { windowlinkfinal = "https://youtube.com/watch?v=" + windowlink.substr(idx + 2, 11) + "&t=" + timeinseconds; console.log("gettimestamp.js windowlinkfinal " + windowlinkfinal); } // pagelinkfinal fine chrome.runtime.sendMessage({ method: "sendtimestamptobg", tsvalue: tshhmmss_string, finallink: windowlinkfinal, });
让我们看看我们在上面的gettimestamp.js文件中做了什么:
- gettimestamp.js脚本在浏览器框架/上下文中运行。此脚本使用querySelector提取 word 格式的时间戳,将其转换为hh:mm:ss格式,以秒为单位。
- 它还会获取当前的视频链接并将其转换为通用格式。
hh:mm:ss格式的时间戳和带时间戳的视频链接由background.js文件发出以供使用。该事件由 ‘ method: “sendtimestamptobg” ‘ 键标识。
进一步发展范围供您试用
随时在 repo 上提出 PR 或问题。直接 WIP 正在将其连接到 chrome.localStorage。
- 将扩展程序连接到本地数据库或 Firebase 以实现解耦数据存储。
- 存储数据时的数据结构研究与实现。
- 与 Chrome 的本地存储断开连接,并使用“同步存储”,以便其他设备上也可以使用书签
- 改进扩展的 UI/UX
- 设计图标并将它们存储在用于自定义扩展图标的项目目录中