Skip to content

Commit

Permalink
[RELEASE: 1.1] Voiranime support & more
Browse files Browse the repository at this point in the history
  • Loading branch information
daisseur committed Oct 25, 2024
1 parent 2228586 commit dc287d8
Show file tree
Hide file tree
Showing 9 changed files with 227 additions and 53 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ node_modules
package-lock.json
*.log
*.crx
*.pem
log
62 changes: 61 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,61 @@
# SyncExt
# AnimeSync-Extension

## Introduction

AnimeSync Extension est une extension de navigateur qui permet aux utilisateurs de synchroniser leur expérience de streaming d'anime sur plusieurs sites avec d'autres en temps réel.

## Explication du projet

AnimeSync-Extension est une extension web qui utilise WebSockets pour établir une connexion en temps réel entre les utilisateurs qui regardent le même épisode d'anime.

## Fonctionnalités

* Synchronisation en temps réel du streaming d'anime
* Prise en charge de plusieurs lecteurs sur différents sites :
+ Anime-sama.fr :
- [x] (1) Vidmoly
- [x] (2) Video.sibnet
- [x] (3) Sendvid
+ Voiranime.com :
- [x] MyTV (vidmoly)
- [ ] ~~MOON (non supporté)~~
- [x] VOE (richardstorehalf)
- [x] Stape (streamstape)

## Installation

### Option 1 : Télécharger le fichier .crx

1. Allez à la page des [dernières versions](https://github.com/daisseur/AnimeSync-Extension/releases/latest).
2. Téléchargez le fichier `AnimeSync-Extension.crx`.
3. Allez à la page des extensions Chrome en tapant `chrome://extensions/` dans la barre d'adresse.
4. Activez le mode développeur.
5. Faites glisser et déposez le fichier `AnimeSync-Extension.crx` sur la page des extensions.

### Option 2 : Télécharger le référentiel

1. Clonez le référentiel en utilisant `git clone https://github.com/daisseur/AnimeSync-Extension.git`.
2. Téléchargez le référentiel sous forme de fichier zip depuis la page GitHub.
3. Allez à la page des extensions Chrome en tapant `chrome://extensions/` dans la barre d'adresse.
4. Activez le mode développeur.
5. Cliquez sur "Charger non empaqueté" et sélectionnez le dossier `ext` du référentiel.

## Utilisation

1. Installez l'extension en utilisant l'une des méthodes ci-dessus.
2. Allez sur un site supporté et commencez à regarder un épisode d'anime avec un lecteur supporté.
3. Cliquez sur l'icône de l'extension dans le coin supérieur droit du navigateur.
4. Entrez l'ID de la salle ou créez une nouvelle salle.
5. Commencez à regarder et profitez de l'expérience de synchronisation avec d'autres !

## Serveur

Par défaut, l'extension utilise le serveur `aserver.daisseur.online`. Cependant, les utilisateurs avancés peuvent personnaliser le serveur en modifiant les paramètres `host` et `port` dans les options de l'extension.

## Lancement du serveur

Pour lancer le serveur, vous devez suivre les étapes suivantes :

1. Installez les dépendances en exécutant `npm i` dans le répertoire du serveur.
2. Lancez le serveur en exécutant `npm run dev`.
> __Note:__ Vous pouvez aussi très bien utiliser `deno`
7 changes: 4 additions & 3 deletions ext/background.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ let host = "aserver.daisseur.online";
let port = "0";
let url = null;

const supported_urls = ["*://*.anime-sama.fr/*", "*://v5.voiranime.com/*", "*://vidmoly.to/embed*", "*://video.sibnet.ru/shell.php?videoid=*", "*://sendvid.com/embed/*"];

const militaryAlphabet = [
'alpha',
'bravo',
Expand Down Expand Up @@ -40,7 +42,7 @@ async function getRoomUrl(url) {
const response = await fetch(api);
const data = await response.json();
if (!url) {
return data;
return Array.from(data);
}
if (data.length > 0) {
return data[0].roomId;
Expand Down Expand Up @@ -208,9 +210,8 @@ function handleIncomingMessage(data) {
}

function notifyContentScript(action, currentTime = null, timestamp = null) {
chrome.tabs.query({ url: ["*://*.anime-sama.fr/*", "*://vidmoly.to/*"] }, (tabs) => {
chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
if (tabs.length > 0) {
console.log(JSON.stringify(tabs, null, 2));
chrome.tabs.sendMessage(tabs[0].id, {
action: action,
currentTime: currentTime,
Expand Down
189 changes: 148 additions & 41 deletions ext/contentScript.js
Original file line number Diff line number Diff line change
@@ -1,60 +1,114 @@
console.log('SyncMedia API loaded');

const cssString = `
.room-panel {
position: fixed;
top: 10%;
right: 0;
width: 250px;
max-height: 80%;
background-color: rgba(255, 255, 255, 0.9);
font-family: 'Segoe UI', sans-serif;
padding: 10px;
border-radius: 5px 0 0 5px;
box-shadow: -2px 0 5px rgba(0, 0, 0, 0.5);
transition: transform 0.3s ease;
overflow-y: auto;
z-index: 1000;
}
.room-panel.collapsed {
transform: translateX(90%);
}
.room-list {
padding: 0;
margin: 0;
list-style-type: none;
}
.room-item {
margin-bottom: 5px;
}
.room-button {
width: 100%;
padding: 8px;
background-color: #007bff;
color: white;
border: none;
border-radius: 3px;
cursor: pointer;
}
.room-button:hover {
background-color: #0056b3;
}
.toggle-button {
top: 10px;
left: -25px;
width: 25px;
height: 25px;
background-color: #007bff;
color: white;
font-size: 16px;
text-align: center;
line-height: 25px;
border-radius: 50%;
cursor: pointer;
transition: background-color 0.3s;
}
.toggle-button:hover {
background-color: #0056b3;
}
`;


function initCss() {
const style = document.createElement('style');
style.textContent = cssString;
document.head.appendChild(style);
}

// Fonction pour initialiser l'écouteur de messages
function initializeMessageListener() {
chrome.runtime.onMessage.addListener((message) => {
console.log('Message received:', message);

switch(message.action) {
case 'listRooms':
{
console.log('List rooms');
try {
const roomsList = Array.from(message.rooms);
// if (roomsList.length === 0) {
// console.log('No rooms found');
// break;
// }
const popup = document.createElement('div');
popup.style.zIndex = '1000';
popup.style.position = 'absolute';
popup.style.right = '0';
popup.style.top = '50%';
popup.style.backgroundColor = 'rgba(255, 255, 255, 0.8)';
popup.style.fontFamily = 'Segoe UI';
popup.style.padding = '10px';
popup.style.borderRadius = '5px';
const ul = document.createElement('ul');
roomsList.forEach((room) => {
const li = document.createElement('li');
li.style = 'list-style-type: none; color: white; empty-cells: show; padding: 5px;';
const button = document.createElement('button');
button.textContent = room.roomId;
button.addEventListener('click', () => {
window.location.href = room.url;
});
li.appendChild(button);
ul.appendChild(li);
});
popup.appendChild(ul);
document.body.appendChild(popup);
console.log(popup);
} catch (error) {
console.error('Error:', error);
}
break;
}
createRoomPanel(message.rooms);
break;
case 'ready':
{ console.log('Ready to sync');
let url= null;
const playerDF = document.getElementById('playerDF');
const iframe = document.querySelector("iframe");
const customIframe = document.querySelector("#iframe-holder > iframe");
console.log(customIframe);
if (playerDF && playerDF.src) {
chrome.runtime.sendMessage({
action: 'redirect',
url: playerDF.src
});
// anime-sama
url = new URL(playerDF.src);
} else if (iframe && iframe.src && (!customIframe || !customIframe.src)) {
// voiranime MyTV (vidmoly)
url = new URL(iframe.src);

} else if (customIframe && customIframe.src) {
// voiranime: others
url = new URL(customIframe.src);
// if (window.location.hostname == 'v5.voiranime.com') {
// url.searchParams.set('referer', "v5.voiranime.com");
// }
} else {
console.warn('playerDF not found or src not set');
}
console.log(url);
chrome.runtime.sendMessage({
action: 'redirect',
url: url.toString()
});
break; }
default:
console.warn('Unknown action:', message.action);
Expand All @@ -64,9 +118,62 @@ function initializeMessageListener() {

// Initialiser tout
function initialize() {
initCss();
initializeMessageListener();
chrome.runtime.sendMessage({ action: 'listRooms' });
}

initialize();
document.addEventListener('DOMContentLoaded', initialize);

function createRoomPanel(rooms) {
let panel = document.querySelector('.room-panel');
let toggleButton;
let roomList;

// Si le panel n'existe pas, on le crée
if (!panel) {
panel = document.createElement('div');
panel.classList.add('room-panel');

// Bouton pour ouvrir/fermer le panel
toggleButton = document.createElement('div');
toggleButton.classList.add('toggle-button');
toggleButton.innerHTML = '➔';

toggleButton.addEventListener('click', () => {
panel.classList.toggle('collapsed');
toggleButton.innerHTML = panel.classList.contains('collapsed') ? '⬅' : '➔';
});

// Liste des salles
roomList = document.createElement('ul');
roomList.classList.add('room-list');

// Ajout des éléments au panneau
panel.appendChild(toggleButton);
panel.appendChild(roomList);
document.body.appendChild(panel);
} else {
// Récupérer les éléments existants si le panel existe déjà
toggleButton = panel.querySelector('.toggle-button');
roomList = panel.querySelector('.room-list');
roomList.innerHTML = ''; // Vider la liste existante pour la mettre à jour
}

// Ajout des salles dans la liste
rooms.forEach(room => {
const roomItem = document.createElement('li');
roomItem.classList.add('room-item');

const roomButton = document.createElement('button');
roomButton.classList.add('room-button');
roomButton.textContent = room.roomId;
roomButton.addEventListener('click', () => {
window.location.href = room.url;
});

roomItem.appendChild(roomButton);
roomList.appendChild(roomItem);
});
}
2 changes: 1 addition & 1 deletion ext/embedScript.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ function injectNewPageScript() {
player.click();
}

const video = [...document.querySelectorAll('video')].find(v => v.src.startsWith('blob:https://vidmoly.to/'));
const video = document.querySelector("video");

if (video) {
console.log("Video loaded", video);
Expand Down
9 changes: 5 additions & 4 deletions ext/manifest.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
{
"manifest_version": 3,
"name": "Video Sync Extension",
"version": "1.0",
"name": "AnimeSync-Extension",
"version": "1.1.0",
"description": "Sync anime between multiple clients",
"permissions": ["activeTab", "scripting", "storage"],
"host_permissions": [
"<all_urls>"
Expand All @@ -14,11 +15,11 @@
},
"content_scripts": [
{
"matches": ["*://*.anime-sama.fr/*"],
"matches": ["https://*.anime-sama.fr/*", "https://v5.voiranime.com/*"],
"js": ["contentScript.js"]
},
{
"matches": ["*://vidmoly.to/embed*"],
"matches": ["https://vidmoly.to/embed*", "https://video.sibnet.ru/shell.php?videoid=*", "https://sendvid.com/embed/*", "https://streamtape.com/e/*", "https://richardstorehalf.com/e/*"],
"js": ["embedScript.js"]
}
]
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "ext-syncmedia",
"name": "anime_sync-extension",
"version": "1.0.0",
"main": "server.js",
"scripts": {
Expand Down
6 changes: 5 additions & 1 deletion src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,16 @@ app.use((req: Request, res: Response, next) => {
next();
});

app.get("/", (req: Request, res: Response) => {
res.redirect("https://github.com/daisseur/AnimeSync-Extension");
})

app.get("/listRooms", (req: Request, res: Response) => {
const url = req.query.url as string;
if (url) {
res.json(getRooms().filter((room) => room.url === url));
} else {
const returnRooms = getRooms().map((room) => ({ roomId: room.roomId, url: room.url }));
const returnRooms = getRooms()
res.json(Array.from(returnRooms));
}
});
Expand Down
2 changes: 1 addition & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
// "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
// "noEmit": true, /* Disable emitting files from a compilation. */
// "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */
// "outDir": "./", /* Specify an output folder for all emitted files. */
"outDir": "./build", /* Specify an output folder for all emitted files. */
// "removeComments": true, /* Disable emitting comments. */
// "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
// "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
Expand Down

0 comments on commit dc287d8

Please sign in to comment.