-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
52 changed files
with
2,242 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
FIREBASE_API_KEY=<fill-me> | ||
FIREBASE_AUTH_DOMAIN=<fill-me> | ||
FIREBASE_PROJECT_ID=<fill-me> | ||
FIREBASE_STORAGE_BUCKET=<fill-me> | ||
FIREBASE_MESSAGING_SENDER_ID=<fill-me> | ||
FIREBASE_APP_ID=<fill-me> | ||
FIREBASE_MEASUREMENT_ID=<fill-me> | ||
CLIENT_ID=<fill-me> | ||
EXTENSION_KEY=<fill-me> | ||
BACKEND_URL=<fill-me> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
npm-debug.log | ||
coverage/ | ||
node_modules/ | ||
package-lock.json | ||
/vendor/ | ||
/*.zip | ||
dist/ | ||
.env | ||
|
||
server/.env | ||
server/firebaseServiceAccountKey.json | ||
server/.env | ||
server/data | ||
**/__pycache__/** | ||
server/.venv | ||
server/model/* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
|
||
# Change Log |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
The MIT License (MIT) | ||
|
||
Copyright (c) 2023 Ian Lee | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to deal | ||
in the Software without restriction, including without limitation the rights | ||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
copies of the Software, and to permit persons to whom the Software is | ||
furnished to do so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in all | ||
copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
SOFTWARE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,13 @@ | ||
|
||
# Manga Reader Browser Extension | ||
# Veebee Browser Extension | ||
|
||
**Install: [Chrome](https://chrome.google.com/webstore/detail/manga-reader/eabnmbpmoencafnpbobahdeamaljhoef)** | ||
Uses Google Vision, DeepL, GPT, and [manga-ocr](https://github.com/kha-white/manga-ocr) to help you with translating and/or learning new languages while browing the internet in a Chrome Browser. One great use case is for reading manga but you can use it on most content on the web. | ||
|
||
![](assets/example.png) | ||
|
||
# Origins | ||
**Install: [Chrome](https://chrome.google.com/webstore/detail/manga-reader/eabnmbpmoencafnpbobahdeamaljhoef)** | ||
|
||
Note that the extension won't work on certain origins: | ||
Note that the extension won't work on certain origins, such as: | ||
|
||
- chrome origins like: `chrome://` and `chrome-extension://` | ||
- the official chrome web store: `https://chrome.google.com/webstore/category/extensions` | ||
|
@@ -21,17 +23,30 @@ Note that the extension won't work on certain origins: | |
## Build Backend Locally | ||
|
||
1. Fill in the `server/.env_template` and rename it to `server/.env` | ||
2. Set up GCP project with the correct (Optional if you comment out the GCP related stuff) | ||
2. Set up GCP project (Optional if you comment out the GCP related stuff) | ||
3. Create your `server/firebaseServiceAccountKey.json` (Optional if you comment out the authentication stuff) | ||
4. Set up Firestore (Optional if you comment out the Firestore related code) | ||
5. `pip install -r requirements.txt` | ||
6. `python3 main.py` | ||
|
||
# Contact | ||
|
||
Please send any feedback or inquiries to [email protected] | ||
|
||
This is an early Proof of Concept. If users like it, I am willing to invest more time to add various features, such as translating an entire page at a time, adding side panel to allow more space for translation details, and chat mode with GPT. Another obvious one is to add more languages. Any other feedback is very welcome! | ||
|
||
|
||
# Acknowledgments | ||
|
||
Learned a lot about Chrome extensions from | ||
https://github.com/RasikaWarade/chrome-extension-mv3-firebase-boilerplate | ||
https://github.com/simov/screenshot-capture | ||
|
||
# License | ||
|
||
The MIT License (MIT) | ||
|
||
Copyright (c) 2023-present Ian Lee <[email protected]> (https://github.com/ianbbqzy/manga-reader) | ||
Copyright (c) 2023-present Ian Lee <[email protected]> (https://github.com/ianbbqzy/veebee) | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to deal | ||
|
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,156 @@ | ||
// for stuff that doesn't involve the DOM of the web page the user is viewing | ||
|
||
// Set default config values | ||
chrome.storage.sync.get((config) => { | ||
if (!config.api) { | ||
chrome.storage.sync.set({api: 'deepl'}) | ||
} | ||
|
||
if (!config.source_lang) { | ||
chrome.storage.sync.set({source_lang: 'Japanese'}) | ||
} | ||
|
||
if (!config.target_lang) { | ||
chrome.storage.sync.set({target_lang: 'English'}) | ||
} | ||
|
||
if (config.icon === undefined) { | ||
config.icon = false | ||
chrome.storage.sync.set({icon: false}) | ||
} | ||
|
||
chrome.action.setIcon({ | ||
path: [16, 19, 38, 48, 128].reduce((all, size) => ( | ||
color = config.icon ? 'light' : 'dark', | ||
all[size] = `/icons/${color}/${size}x${size}.png`, | ||
all | ||
), {}) | ||
}) | ||
}) | ||
|
||
// This is triggered when extension icon is clicked. This is the main entry point | ||
// for screenshot capture. | ||
// It injects the content script into the active tab. | ||
chrome.action.onClicked.addListener((tab) => { | ||
pingContentScript(tab, 'initCrop'); | ||
}) | ||
|
||
// take-screenshot is received when keyboard shortcut is triggered, as defined in manifest.json | ||
// This is another entry point for screenshot capture. | ||
chrome.commands.onCommand.addListener((command) => { | ||
if (command === 'take-screenshot') { | ||
chrome.tabs.query({active: true, currentWindow: true}, (tabs) => { | ||
pingContentScript(tabs[0], 'initCrop'); | ||
}) | ||
} | ||
}) | ||
|
||
// capture request is received when the user cropping by the user is done. | ||
// active rquest is received when | ||
chrome.runtime.onMessage.addListener((req, sender, res) => { | ||
if (req.message === 'capture') { | ||
chrome.tabs.query({active: true, currentWindow: true}, (tabs) => { | ||
chrome.tabs.captureVisibleTab(tabs[0].windowId, (image) => { | ||
res({message: 'image', image: image}) | ||
}) | ||
}) | ||
} | ||
else if (req.message === 'active') { | ||
// Change the extension icon and title based on whether the user is cropping | ||
if (req.active) { | ||
chrome.storage.sync.get(() => { | ||
chrome.action.setTitle({tabId: sender.tab.id, title: 'Crop'}) | ||
chrome.action.setBadgeText({tabId: sender.tab.id, text: '◩'}) | ||
}) | ||
} | ||
else { | ||
chrome.action.setTitle({tabId: sender.tab.id, title: 'Crop Initialized'}) | ||
chrome.action.setBadgeText({tabId: sender.tab.id, text: ''}) | ||
} | ||
} | ||
return true | ||
}) | ||
|
||
// Create context menu option | ||
chrome.runtime.onInstalled.addListener(() => { | ||
chrome.contextMenus.create({ | ||
id: 'translate-menu', | ||
// chrome replaces %s with whatever is highlighted | ||
title: 'Translate %s', | ||
// selects what's hightlighted by the cursor? | ||
contexts: ['selection'] | ||
}); | ||
}); | ||
|
||
// Handle when context menu is clicked | ||
chrome.contextMenus.onClicked.addListener((info, tab) => { | ||
console.log(info.menuItemId) | ||
if (info.menuItemId === "translate-menu") { | ||
// Let content script know that a text translation is initialized. | ||
// This has to be done in background script in case the content | ||
// script has not been initialized. | ||
pingContentScript(tab, 'initTextTranslation'); | ||
|
||
// continue with the translation process. | ||
chrome.storage.sync.get((config) => { | ||
if (!config.idToken) { | ||
pingContentScript(tab, "Please login first. Right click on the extension icon and click on options.") | ||
} else { | ||
callTranslateWithText(info.selectionText, config.source_lang, config.target_lang, config.api, config.idToken) | ||
.then(response => { | ||
pingContentScript(tab, response) | ||
}) | ||
.catch(error => { | ||
console.error(`error: ${error.message}`); | ||
pingContentScript(tab, `error: ${error.message}`) | ||
}); | ||
} | ||
}) | ||
} | ||
}); | ||
|
||
async function callTranslateWithText(text, source_lang, target_lang, api, idToken) { | ||
const url = "__BACKEND_URL__"; | ||
const headers = new Headers(); | ||
headers.append('Authorization', `Bearer ${idToken}`); | ||
headers.append('Content-Type', `application/json`); | ||
|
||
try { | ||
const resp = await fetch(url + '/translate-text?api=' + api + '&source_lang=' + source_lang + '&target_lang=' + target_lang, { | ||
method: 'POST', | ||
headers: headers, | ||
body: JSON.stringify({ | ||
'text': text | ||
}) | ||
}).then(res => res.json()) | ||
if (resp.error) { | ||
return `Translation: ${resp.error}`; | ||
} | ||
return `Translation: ${resp.translation}`; | ||
} catch (err) { | ||
return `Translation: ${err.message}`; | ||
} | ||
} | ||
|
||
// Sends a message to the content script | ||
// If it doesn't receive a response within a specific timeout, it | ||
// determines that content script is not initialized and it will initialize it. | ||
// After another small timeout, it'll try to send the message again. | ||
function pingContentScript(tab, message) { | ||
chrome.tabs.sendMessage(tab.id, {message: message}, (res) => { | ||
if (res) { | ||
// if response is received before the timeout is triggered | ||
// clears the timeout call | ||
clearTimeout(timeout) | ||
} | ||
}) | ||
|
||
var timeout = setTimeout(() => { | ||
chrome.scripting.insertCSS({files: ['css/content.css'], target: {tabId: tab.id}}) | ||
chrome.scripting.executeScript({files: ['content.js'], target: {tabId: tab.id}}) | ||
|
||
setTimeout(() => { | ||
chrome.tabs.sendMessage(tab.id, {message: message}) | ||
}, 100) | ||
}, 100) | ||
} |
Oops, something went wrong.