Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ext] Allow the extension to connect to dev-env #1868

Merged
merged 10 commits into from
Jan 4, 2024
4 changes: 4 additions & 0 deletions .github/workflows/browser-extension-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,13 @@ jobs:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- uses: actions/setup-node@v2
with:
node-version: '18'

- name: Check extension version in the manifest
run: |
node prepareExtension.js
ext_version=$(python -c 'import json; print(json.load(open("src/manifest.json"))["version"])')
tag_exist=$(git tag -l "browser-extension-v$ext_version" | wc -l)
echo "ext_version=$ext_version" >> $GITHUB_ENV
Expand Down
5 changes: 5 additions & 0 deletions .github/workflows/e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ jobs:
with:
node-version: '18'

- name: Prepare extension
working-directory: browser-extension
run: |
node prepareExtension.js

- uses: cypress-io/github-action@v5
with:
working-directory: tests
Expand Down
1 change: 1 addition & 0 deletions browser-extension/.eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
src/config.js
3 changes: 3 additions & 0 deletions browser-extension/.gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
*.zip
node_modules/
src/manifest.json
src/config.js
src/importWrappers/
10 changes: 10 additions & 0 deletions browser-extension/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,16 @@ available here:
yarn install
```

### Prepare the extension

Before loading the extension into your browser, you need to run `node prepareExtension.js`. It will generate `manifest.json`, `config.js` and the import wrappers (small scripts that allow us to use ECMAScript modules in content scripts).

By default, `prepareExtension.js` creates an extension that connects to the production Tournesol website. If you want to connect to your development servers instead, you can specify a `TOURNESOL_ENV` environment variable. For example:

```
TOURNESOL_ENV=dev-env node prepareExtension.js
```

### Code Quality

We use `ESLint` to find and fix problems in the JavaScript code.
Expand Down
3 changes: 2 additions & 1 deletion browser-extension/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ TARGET_BASENAME='tournesol_extension.zip'

pushd ${SCRIPT_PATH} > /dev/null

node prepareExtension.js

# zip the sources
pushd ${SOURCE_DIR} > /dev/null
zip -r -FS ../${TARGET_BASENAME} *
Expand All @@ -23,4 +25,3 @@ popd > /dev/null
# zip the license
zip ${TARGET_BASENAME} LICENSE
popd > /dev/null

1 change: 1 addition & 0 deletions browser-extension/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"name": "tournesol-extension",
"license": "AGPL-3.0-or-later",
"type": "module",
"scripts": {
"lint": "eslint .",
"lint:fix": "eslint --fix ."
Expand Down
120 changes: 120 additions & 0 deletions browser-extension/prepareExtension.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
/* eslint-env node */

import {
getForEnv,
generateImportWrappers,
writeManifest,
writeConfig,
} from './prepareTools.js';

const env = process.env.TOURNESOL_ENV || 'production';

const manifest = {
name: 'Tournesol Extension',
version: '3.4.0',
description: 'Open Tournesol directly from YouTube',
permissions: [
...getForEnv(
{
production: ['https://tournesol.app/', 'https://api.tournesol.app/'],
'dev-env': [
'http://localhost/',
'http://localhost:3000/',
'http://localhost:8000/',
],
},
env
),
'https://www.youtube.com/',
'activeTab',
'contextMenus',
'storage',
'webNavigation',
'webRequest',
'webRequestBlocking',
],
manifest_version: 2,
icons: {
64: 'Logo64.png',
128: 'Logo128.png',
512: 'Logo512.png',
},
background: {
page: 'background.html',
persistent: true,
},
browser_action: {
default_icon: {
16: 'Logo16.png',
64: 'Logo64.png',
},
default_title: 'Tournesol actions',
default_popup: 'browserAction/menu.html',
},
content_scripts: [
{
matches: ['https://*.youtube.com/*'],
js: ['displayHomeRecommendations.js', 'displaySearchRecommendations.js'],
css: ['addTournesolRecommendations.css'],
run_at: 'document_start',
all_frames: true,
},
{
matches: ['https://*.youtube.com/*'],
js: ['addVideoStatistics.js', 'addModal.js', 'addRateButtons.js'],
css: ['addVideoStatistics.css', 'addModal.css', 'addRateButtons.css'],
run_at: 'document_end',
all_frames: true,
},
{
matches: getForEnv(
{
production: ['https://tournesol.app/*'],
'dev-env': ['http://localhost:3000/*'],
},
env
),
js: [
'fetchTournesolToken.js',
'fetchTournesolRecommendationsLanguages.js',
],
run_at: 'document_end',
all_frames: true,
},
],
options_ui: {
page: 'options/options.html',
open_in_tab: true,
},
default_locale: 'en',
web_accessible_resources: [
'Logo128.png',
'html/*',
'images/*',
'utils.js',
'models/*',
'config.js',
],
};

const config = getForEnv(
{
production: {
frontendUrl: 'https://tournesol.app/',
frontendHostEquals: 'tournesol.app',
GresilleSiffle marked this conversation as resolved.
Show resolved Hide resolved
apiUrl: 'https://api.tournesol.app/',
},
'dev-env': {
frontendUrl: 'http://localhost:3000/',
frontendHostEquals: 'localhost:3000',
apiUrl: 'http://localhost:8000/',
},
},
env
);

(async () => {
await generateImportWrappers(manifest);
await writeManifest(manifest, 'src/manifest.json');
await writeConfig(config, 'src/config.js');
})();
45 changes: 45 additions & 0 deletions browser-extension/prepareTools.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/* eslint-env node */

import { writeFile, mkdir } from 'node:fs/promises';
import { dirname, join } from 'node:path';

export const getForEnv = (object, env) => {
const result = object[env];
if (result === undefined) {
throw new Error(
`No value found for the environment ${JSON.stringify(env)}`
);
}
return result;
};

export const generateImportWrappers = async (manifest) => {
await Promise.all(
manifest['content_scripts'].map(async (contentScript) => {
await Promise.all(
contentScript.js.map(async (js, i) => {
const content = `import(chrome.runtime.getURL('../${js}'));\n`;
const newJs = join('importWrappers', js);
const path = join('src', newJs);
await mkdir(dirname(path), { recursive: true });
await writeFile(path, content);
contentScript.js[i] = newJs;
manifest['web_accessible_resources'].push(js);
})
);
})
);
};

export const writeManifest = async (manifest, outputPath) => {
const content = JSON.stringify(manifest, null, 2);
await writeFile(outputPath, content);
};

export const writeConfig = async (config, outputPath) => {
let content = '';
for (let [key, value] of Object.entries(config)) {
content += `export const ${key} = ${JSON.stringify(value)};\n`;
}
await writeFile(outputPath, content);
};
4 changes: 3 additions & 1 deletion browser-extension/src/addModal.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
* This content script is meant to be run on each YouTube page.
*/

import { frontendUrl } from './config.js';

// unique HTML id of the extension modal
const EXT_MODAL_ID = 'x-tournesol-modal';
// the value of the CSS property display used to make the modal visible
Expand All @@ -15,7 +17,7 @@ const EXT_MODAL_INVISIBLE_STATE = 'none';
// unique HTML id of the Tournesol iframe
const IFRAME_TOURNESOL_ID = 'x-tournesol-iframe';
// URL of the Tournesol login page
const IFRAME_TOURNESOL_LOGIN_URL = 'https://tournesol.app/login?embed=1&dnt=1';
const IFRAME_TOURNESOL_LOGIN_URL = `${frontendUrl}login?embed=1&dnt=1`;

/**
* YouTube doesnt completely load a page, so content script doesn't
Expand Down
4 changes: 3 additions & 1 deletion browser-extension/src/addRateButtons.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
* This content script is meant to be run on each YouTube video page.
*/

import { frontendUrl } from './config.js';

const TS_ACTIONS_ROW_ID = 'ts-video-actions-row';
const TS_ACTIONS_ROW_BEFORE_REF = 'bottom-row';

Expand Down Expand Up @@ -114,7 +116,7 @@ function addRateButtons() {
chrome.runtime.sendMessage({
message: 'displayModal',
modalOptions: {
src: `https://tournesol.app/comparison?embed=1&utm_source=extension&utm_medium=frame&uidA=yt%3A${videoId}`,
src: `${frontendUrl}comparison?embed=1&utm_source=extension&utm_medium=frame&uidA=yt%3A${videoId}`,
height: '90vh',
},
});
Expand Down
6 changes: 3 additions & 3 deletions browser-extension/src/addVideoStatistics.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
// This part is called on connection for the first time on youtube.com/*
/* ********************************************************************* */

import { frontendUrl } from './config.js';

var browser = browser || chrome;

document.addEventListener('yt-navigate-finish', process);
Expand Down Expand Up @@ -87,9 +89,7 @@ function process() {

// On click
statisticsButton.onclick = () => {
open(
`https://tournesol.app/entities/yt:${videoId}?utm_source=extension`
);
open(`${frontendUrl}entities/yt:${videoId}?utm_source=extension`);
};

var div =
Expand Down
4 changes: 3 additions & 1 deletion browser-extension/src/background.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import {
getSingleSetting,
} from './utils.js';

import { frontendHostEquals } from './config.js';

const oversamplingRatioForRecentVideos = 3;
const oversamplingRatioForOldVideos = 50;
// Higher means videos recommended can come from further down the recommandation list
Expand Down Expand Up @@ -363,6 +365,6 @@ chrome.webNavigation.onHistoryStateUpdated.addListener(
chrome.tabs.sendMessage(event.tabId, 'historyStateUpdated');
},
{
url: [{ hostEquals: 'tournesol.app' }],
url: [{ hostEquals: frontendHostEquals }],
}
);
7 changes: 4 additions & 3 deletions browser-extension/src/browserAction/menu.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { addRateLater } from '../utils.js';
import { frontendUrl } from '../config.js';

const i18n = chrome.i18n;

Expand All @@ -24,7 +25,7 @@ function get_current_tab_video_id() {
*/
function openTournesolHome() {
chrome.tabs.create({
url: 'https://tournesol.app?utm_source=extension&utm_medium=menu',
url: `${frontendUrl}?utm_source=extension&utm_medium=menu`,
GresilleSiffle marked this conversation as resolved.
Show resolved Hide resolved
});
}

Expand All @@ -36,7 +37,7 @@ function rateNowAction(event) {
get_current_tab_video_id().then(
(videoId) => {
chrome.tabs.create({
url: `https://tournesol.app/comparison?uidA=yt:${videoId}&utm_source=extension&utm_medium=menu`,
url: `${frontendUrl}comparison?uidA=yt:${videoId}&utm_source=extension&utm_medium=menu`,
});
},
() => {
Expand Down Expand Up @@ -93,7 +94,7 @@ function openAnalysisPageAction(event) {
get_current_tab_video_id().then(
(videoId) => {
chrome.tabs.create({
url: `https://tournesol.app/entities/yt:${videoId}?utm_source=extension&utm_medium=menu`,
url: `${frontendUrl}entities/yt:${videoId}?utm_source=extension&utm_medium=menu`,
});
},
() => {
Expand Down
Loading
Loading