diff --git a/background.html b/background.html
deleted file mode 100644
index a733cff..0000000
--- a/background.html
+++ /dev/null
@@ -1,3 +0,0 @@
-
-
-
diff --git a/bg.js b/bg.js
index 2942877..f4e82ea 100644
--- a/bg.js
+++ b/bg.js
@@ -1,151 +1,79 @@
-if (!self.browser && self.chrome) {
- browser = chrome;
-}
-
-browser.contextMenus.create({
- id: "search-on-trace.moe",
- title: "Search on trace.moe",
- contexts: ["image", "video"],
-});
-
-var imageDataURL;
-
-var handleMessage = function (request, sender, sendResponse) {
- if (request.type === "getImageDataURL" && imageDataURL) {
- sendResponse({
- imageDataURL: imageDataURL,
- });
- imageDataURL = null;
- }
- return true;
-};
-
-browser.runtime.onMessage.addListener(handleMessage);
-
-var search = function (dataURL) {
- imageDataURL = dataURL;
- browser.tabs.create({
- url: "https://trace.moe",
- });
-};
-
-var toDataURL = function (source) {
- try {
- var canvas = document.createElement("canvas");
- canvas.crossOrigin = "anonymous";
- canvas.height = 720;
- if (source.nodeName === "VIDEO") {
- canvas.width = (source.videoWidth / source.videoHeight) * canvas.height;
- } else {
- canvas.width = (source.width / source.height) * canvas.height;
- }
- canvas.getContext("2d").drawImage(source, 0, 0, canvas.width, canvas.height);
- return canvas.toDataURL("image/jpeg", 0.9);
- } catch (err) {
- return null;
- }
-};
-
-var getDataURL = function (target) {
- return new Promise(function (resolve, reject) {
- browser.tabs.query(
- {
- active: true,
- },
- function (tabs) {
- browser.tabs.sendMessage(
- tabs[0].id,
- {
- action: "getDataURL",
- target: target,
- },
- function (response) {
- if (response && response.dataURL) {
- resolve(response.dataURL);
- } else {
- reject(Error("CORS Error"));
- }
- }
- );
- }
- );
- });
-};
-
-var fetchImage = function (src) {
- var img = new Image();
- img.crossOrigin = "anonymous";
- img.onload = function () {
- search(toDataURL(this));
- };
- img.src = src;
-};
-
-var getCurrentTime = function (target) {
- return new Promise(function (resolve, reject) {
- browser.tabs.query(
- {
- active: true,
- },
- function (tabs) {
- browser.tabs.sendMessage(
- tabs[0].id,
- {
- action: "getCurrentTime",
- target: target,
- },
- function (response) {
- resolve(response.currentTime);
- }
- );
- }
- );
- });
-};
-
-var fetchVideo = function (src, currentTime) {
- var player = document.createElement("video");
- player.crossOrigin = "anonymous";
- player.src = src;
- player.width = player.videoWidth;
- player.height = player.height;
- player.currentTime = currentTime;
- player.volume = 0;
- player.onloadeddata = function () {
- search(toDataURL(player));
- };
-};
-
-browser.contextMenus.onClicked.addListener(function (info, tab) {
- if (info.srcUrl) {
- if (info.srcUrl.indexOf("blob:") === 0) {
- // must capture on context script
- // for video it will return capture at currentTime
- getDataURL(info.srcUrl).then(function (dataURL) {
- search(dataURL);
- });
- } else if (info.mediaType === "image" && info.srcUrl.indexOf("data:") === 0) {
- search(info.srcUrl);
- } else if (info.mediaType === "image") {
- getDataURL(info.srcUrl).then(
- function (dataURL) {
- search(dataURL);
- },
- function () {
- fetchImage(info.srcUrl);
- }
- );
- } else if (info.mediaType === "video") {
- getDataURL(info.srcUrl).then(
- function (dataURL) {
- search(dataURL);
- },
- function () {
- getCurrentTime(info.srcUrl).then(function (currentTime) {
- fetchVideo(info.srcUrl, currentTime);
- });
- }
- );
- }
- }
-});
+if (!self.browser && self.chrome) {
+ browser = chrome;
+}
+
+(async () => {
+ await browser.contextMenus.removeAll();
+ await browser.contextMenus.create({
+ id: "search-on-trace.moe",
+ title: "Search on trace.moe",
+ contexts: ["image", "video"],
+ });
+})();
+
+let imageDataURL = null;
+let targetSrc = null;
+let targetCurrentTime = null;
+let tempTab = null;
+let newTab = null;
+
+browser.runtime.onMessage.addListener((request, { tab }, sendResponse) => {
+ if (newTab && tab.id === newTab.id && request.type === "getImageDataURL" && imageDataURL) {
+ sendResponse({ imageDataURL });
+ imageDataURL = null;
+ newTab = null;
+ }
+ if (tempTab && tab.id === tempTab.id && request.type === "getTargetSrc" && targetSrc) {
+ browser.tabs.sendMessage(
+ tempTab.id,
+ {
+ action: "getSearchImage",
+ srcUrl: targetSrc,
+ currentTime: targetCurrentTime,
+ },
+ (response) => {
+ browser.tabs.remove(tempTab.id).catch(() => {});
+ tempTab = null;
+ if (!response) return;
+ if (response.searchImage) {
+ search(response.searchImage);
+ }
+ }
+ );
+ targetSrc = null;
+ targetCurrentTime = null;
+ }
+ return true;
+});
+
+const search = async (dataURL) => {
+ imageDataURL = dataURL;
+ newTab = await browser.tabs.create({
+ url: "https://trace.moe",
+ });
+};
+
+browser.contextMenus.onClicked.addListener(async ({ srcUrl }) => {
+ if (!srcUrl) return;
+ const activeTabs = await browser.tabs.query({ active: true });
+ browser.tabs.sendMessage(
+ activeTabs[0].id,
+ {
+ action: "getSearchImage",
+ srcUrl,
+ },
+ async (response) => {
+ if (!response) return;
+ if (response.searchImage) {
+ search(response.searchImage);
+ return;
+ }
+ targetSrc = srcUrl;
+ targetCurrentTime = response.currentTime;
+ tempTab = await browser.tabs.create({
+ active: response.currentTime !== null,
+ url: srcUrl,
+ });
+ }
+ );
+});
diff --git a/content.js b/content.js
index 7f7b221..eb31b8b 100644
--- a/content.js
+++ b/content.js
@@ -1,78 +1,53 @@
-if (!self.browser && self.chrome) {
- browser = chrome;
-}
-
-var toDataURL = function (source) {
- try {
- var canvas = document.createElement("canvas");
- canvas.crossOrigin = "anonymous";
- canvas.height = 720;
- if (source.nodeName === "VIDEO") {
- canvas.width = (source.videoWidth / source.videoHeight) * canvas.height;
- } else {
- canvas.width = (source.width / source.height) * canvas.height;
- }
- canvas.getContext("2d").drawImage(source, 0, 0, canvas.width, canvas.height);
- return canvas.toDataURL("image/jpeg", 0.9);
- } catch (err) {
- return null;
- }
-};
-
-var absolutePath = function (href) {
- var link = document.createElement("a");
- link.href = href;
- return link.protocol + "//" + link.host + link.pathname + link.search + link.hash;
-};
-
-var handleMessage = (request, sender, sendResponse) => {
- if (request.action === "getCurrentTime") {
- var currentTime = 0;
- var videos = document.querySelectorAll("video");
- for (var i = 0; i < videos.length; ++i) {
- if (absolutePath(videos[i].src).indexOf(request.target)) {
- currentTime = videos[i].currentTime;
- break;
- }
- var sources = videos[i].querySelectorAll("source");
- for (var j = 0; j < sources.length; ++j) {
- if (absolutePath(sources[j].src).indexOf(request.target)) {
- currentTime = videos[i].currentTime;
- }
- break;
- }
- }
- sendResponse({
- currentTime: currentTime,
- });
- } else if (request.action === "getDataURL") {
- //assume only one element match the blob URL
- var source = null;
- var elem = document.querySelectorAll("img, video");
-
- for (var i = 0; i < elem.length; ++i) {
- if (absolutePath(elem[i].src) === request.target) {
- source = elem[i];
- break;
- }
- var sources = elem[i].querySelectorAll("source");
- for (var j = 0; j < sources.length; ++j) {
- if (absolutePath(sources[j].src) === request.target) {
- source = elem[i];
- }
- break;
- }
- }
-
- if (source) {
- sendResponse({
- dataURL: toDataURL(source),
- });
- } else {
- alert("Failed to get search image");
- }
- }
- return true;
-};
-
-browser.runtime.onMessage.addListener(handleMessage);
+if (!self.browser && self.chrome) {
+ browser = chrome;
+}
+
+const toDataURL = (element) => {
+ try {
+ const canvas = document.createElement("canvas");
+ canvas.crossOrigin = "anonymous";
+ canvas.height = 720;
+ if (element instanceof HTMLVideoElement) {
+ canvas.width = (element.videoWidth / element.videoHeight) * canvas.height;
+ } else {
+ canvas.width = (element.width / element.height) * canvas.height;
+ }
+ canvas.getContext("2d").drawImage(element, 0, 0, canvas.width, canvas.height);
+ return canvas.toDataURL("image/jpeg", 0.9);
+ } catch (err) {
+ return null;
+ }
+};
+
+browser.runtime.sendMessage({ type: "getTargetSrc" });
+
+browser.runtime.onMessage.addListener(({ action, srcUrl, currentTime }, sender, sendResponse) => {
+ if (action === "getSearchImage" && srcUrl) {
+ //assume only one element match the src
+ const element = Array.from(document.querySelectorAll("img, video")).find(
+ (e) => e.currentSrc === srcUrl
+ );
+ if (!element) return alert("Fail to get search image");
+ if (currentTime && element instanceof HTMLVideoElement) {
+ element.pause();
+ element.volume = 0;
+ element.currentTime = currentTime;
+ element.oncanplay = () => {
+ const searchImage = toDataURL(element);
+ if (searchImage) {
+ sendResponse({ searchImage });
+ }
+ };
+ } else {
+ const searchImage = toDataURL(element);
+ if (searchImage) {
+ sendResponse({ searchImage });
+ } else {
+ sendResponse({
+ currentTime: element instanceof HTMLVideoElement ? element.currentTime : null,
+ });
+ }
+ }
+ }
+ return true;
+});
diff --git a/manifest.json b/manifest.json
index 7c9a00f..73da387 100644
--- a/manifest.json
+++ b/manifest.json
@@ -1,26 +1,26 @@
-{
- "author": "soruly",
- "background": {
- "page": "background.html"
- },
- "content_scripts": [
- {
- "js": ["content.js"],
- "matches": ["http://*/*", "https://*/*"]
- },
- {
- "js": ["trace.moe.js"],
- "matches": ["https://trace.moe/"]
- }
- ],
- "description": "Use anime screenshots to search the scene it is taken from.",
- "icons": {
- "128": "icon128.png",
- "16": "icon16.png",
- "48": "icon48.png"
- },
- "manifest_version": 2,
- "name": "Search Anime by Screenshot",
- "permissions": ["contextMenus", "activeTab", "tabs", "http://*/*", "https://*/*"],
- "version": "4.0.2"
-}
+{
+ "author": "soruly",
+ "content_scripts": [
+ {
+ "js": ["content.js"],
+ "matches": ["http://*/*", "https://*/*"]
+ },
+ {
+ "js": ["trace.moe.js"],
+ "matches": ["https://trace.moe/"]
+ }
+ ],
+ "background": {
+ "service_worker": "bg.js"
+ },
+ "description": "Use anime screenshots to search the scene it is taken from.",
+ "icons": {
+ "128": "icon128.png",
+ "16": "icon16.png",
+ "48": "icon48.png"
+ },
+ "manifest_version": 3,
+ "name": "Search Anime by Screenshot",
+ "permissions": ["contextMenus", "activeTab"],
+ "version": "5.0.0"
+}
diff --git a/trace.moe.js b/trace.moe.js
index e4a047d..79c0167 100644
--- a/trace.moe.js
+++ b/trace.moe.js
@@ -2,14 +2,8 @@ if (!self.browser && self.chrome) {
browser = chrome;
}
-browser.runtime.sendMessage(
- {
- type: "getImageDataURL",
- },
- (response) => {
- if (response && response.imageDataURL) {
- document.querySelector("#autoSearch").checked = true;
- document.querySelector("#originalImage").src = response.imageDataURL;
- }
+browser.runtime.sendMessage({ type: "getImageDataURL" }, (response) => {
+ if (response && response.imageDataURL) {
+ document.querySelector("#originalImage").src = response.imageDataURL;
}
-);
+});