Upload files to "FirefoxExtension"

This commit is contained in:
Jonas12294 2025-03-02 22:36:48 +01:00
parent 64544c4219
commit 051f36649e
5 changed files with 384 additions and 0 deletions

View File

@ -0,0 +1,86 @@
if (typeof browser === "undefined") {
var browser = chrome;
}
let autoRecordInterval = null;
let autoRecordAllowedPrefixes = []; // Global storage for allowed URL prefixes
browser.runtime.onMessage.addListener((message, sender, sendResponse) => {
if (message.action === "login") {
fetch("http://192.168.0.226:25570/api/login", {
method: "POST",
credentials: "include",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ username: message.username, password: message.password })
})
.then(response => response.json())
.then(data => {
console.log("Login response:", data);
sendResponse(data);
})
.catch(err => sendResponse({ error: err.toString() }));
return true;
} else if (message.action === "register") {
fetch("http://192.168.0.226:25570/api/register", {
method: "POST",
credentials: "include",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ username: message.username, password: message.password })
})
.then(response => response.json())
.then(data => {
console.log("Registration response:", data);
sendResponse(data);
})
.catch(err => sendResponse({ error: err.toString() }));
return true;
} else if (message.action === "startAutoRecord") {
if (message.allowedPrefixes) {
autoRecordAllowedPrefixes = message.allowedPrefixes
.split(",")
.map(s => s.trim())
.filter(s => s.length > 0);
} else {
autoRecordAllowedPrefixes = [];
}
if (autoRecordInterval) {
clearInterval(autoRecordInterval);
}
autoRecordInterval = setInterval(() => {
browser.tabs.query({ active: true, currentWindow: true }, (tabs) => {
if (tabs && tabs.length > 0) {
const currentUrl = tabs[0].url;
let recordUrl = false;
for (let prefix of autoRecordAllowedPrefixes) {
if (currentUrl.startsWith(prefix)) {
recordUrl = true;
break;
}
}
if (recordUrl) {
fetch("http://192.168.0.226:25570/record", {
method: "POST",
credentials: "include",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ url: currentUrl })
})
.then(response => response.json())
.then(data => console.log("Recorded URL:", data))
.catch(err => console.error("Recording error:", err));
} else {
console.log("URL does not match allowed prefixes, skipping: " + currentUrl);
}
}
});
}, message.interval || 10000);
sendResponse({ success: true, message: "Auto recording started" });
return true;
} else if (message.action === "stopAutoRecord") {
if (autoRecordInterval) {
clearInterval(autoRecordInterval);
autoRecordInterval = null;
}
sendResponse({ success: true, message: "Auto recording stopped" });
return true;
}
});

BIN
FirefoxExtension/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -0,0 +1,19 @@
{
"manifest_version": 2,
"name": "NovelBin Auto Recorder",
"version": "1.0",
"description": "Records the current chapter URL from NovelBin via the server, with account registration.",
"permissions": [
"tabs",
"storage",
"http://192.168.0.226:25570/*"
],
"background": {
"scripts": ["background.js"],
"persistent": true
},
"browser_action": {
"default_popup": "popup.html",
"default_icon": "icon.png"
}
}

View File

@ -0,0 +1,79 @@
<!DOCTYPE html>
<html>
<head>
<title>NovelBin Auto Recorder</title>
<style>
body {
font-family: Arial, sans-serif;
padding: 10px;
}
.resizable {
resize: both;
overflow: auto;
border: 1px solid #ccc;
padding: 10px;
margin-bottom: 10px;
}
input[type="text"],
input[type="password"] {
width: 100%;
box-sizing: border-box;
padding: 5px;
margin-bottom: 5px;
}
button {
margin: 5px 0;
}
#authSection, #recorderSection, #chapterListSection {
min-width: 300px;
}
#chapterList li {
list-style: none;
padding: 3px 0;
border-bottom: 1px solid #ccc;
}
</style>
</head>
<body>
<!-- Authentication Section -->
<div id="authSection" class="resizable">
<div id="loginSection">
<h2>Login</h2>
<input type="text" id="loginUsername" placeholder="Username"><br/>
<input type="password" id="loginPassword" placeholder="Password"><br/>
<button id="loginBtn">Login</button>
<p>Don't have an account? <a href="#" id="showRegisterLink">Register here</a></p>
</div>
<div id="registerSection" style="display: none;">
<h2>Register</h2>
<input type="text" id="registerUsername" placeholder="Username"><br/>
<input type="password" id="registerPassword" placeholder="Password"><br/>
<input type="password" id="registerConfirmPassword" placeholder="Confirm Password"><br/>
<button id="registerBtn">Register</button>
<p>Already have an account? <a href="#" id="showLoginLink">Login here</a></p>
</div>
</div>
<!-- Recorder Section -->
<div id="recorderSection" class="resizable" style="display: none;">
<h2>Auto Record Settings</h2>
<label>
<input type="checkbox" id="autoRecordToggle"> Auto Record Current Chapter URL
</label><br/>
<input type="text" id="allowedPrefixes" placeholder="Enter allowed URL prefixes (comma separated)"><br/>
<button id="openResizableBtn">Open Resizable Window</button><br/>
<button id="logoutBtn">Logout</button>
</div>
<!-- Chapter List Section -->
<div id="chapterListSection" class="resizable" style="display: none;">
<h2>Recorded Chapters</h2>
<input type="text" id="searchQuery" placeholder="Search chapters..."><br/>
<input type="text" id="excludeWords" placeholder="Exclude words (comma separated)"><br/>
<ul id="chapterList"></ul>
</div>
<div id="status"></div>
<script src="popup.js"></script>
</body>
</html>

200
FirefoxExtension/popup.js Normal file
View File

@ -0,0 +1,200 @@
if (typeof browser === "undefined") {
var browser = chrome;
}
document.addEventListener('DOMContentLoaded', function() {
// Authentication elements
const authSection = document.getElementById('authSection');
const loginSection = document.getElementById('loginSection');
const registerSection = document.getElementById('registerSection');
const loginBtn = document.getElementById('loginBtn');
const loginUsernameInput = document.getElementById('loginUsername');
const loginPasswordInput = document.getElementById('loginPassword');
const showRegisterLink = document.getElementById('showRegisterLink');
const registerBtn = document.getElementById('registerBtn');
const registerUsernameInput = document.getElementById('registerUsername');
const registerPasswordInput = document.getElementById('registerPassword');
const registerConfirmPasswordInput = document.getElementById('registerConfirmPassword');
const showLoginLink = document.getElementById('showLoginLink');
// Recorder and list elements
const recorderSection = document.getElementById('recorderSection');
const autoRecordToggle = document.getElementById('autoRecordToggle');
const allowedPrefixesInput = document.getElementById('allowedPrefixes');
const logoutBtn = document.getElementById('logoutBtn');
const openResizableBtn = document.getElementById('openResizableBtn');
const chapterListSection = document.getElementById('chapterListSection');
const searchQueryInput = document.getElementById('searchQuery');
const excludeWordsInput = document.getElementById('excludeWords');
const chapterListElement = document.getElementById('chapterList');
const statusDiv = document.getElementById('status');
// Load stored allowedPrefixes from browser.storage
browser.storage.local.get('allowedPrefixes', function(result) {
if (result.allowedPrefixes) {
allowedPrefixesInput.value = result.allowedPrefixes;
}
});
allowedPrefixesInput.addEventListener('change', function() {
const allowedPrefixes = allowedPrefixesInput.value.trim();
browser.storage.local.set({ allowedPrefixes: allowedPrefixes });
});
// Toggle between login and registration views
showRegisterLink.addEventListener('click', function(e) {
e.preventDefault();
loginSection.style.display = "none";
registerSection.style.display = "block";
});
showLoginLink.addEventListener('click', function(e) {
e.preventDefault();
registerSection.style.display = "none";
loginSection.style.display = "block";
});
// Check login status on load
fetch("http://192.168.0.226:25570/api/status", {
method: "GET",
credentials: "include"
})
.then(response => response.json())
.then(data => {
if (data.loggedIn) {
authSection.style.display = "none";
recorderSection.style.display = "block";
chapterListSection.style.display = "block";
statusDiv.textContent = "Logged in as " + data.username;
} else {
authSection.style.display = "block";
recorderSection.style.display = "none";
chapterListSection.style.display = "none";
}
})
.catch(err => {
console.error("Error checking login status:", err);
});
// Login handler
loginBtn.addEventListener('click', function() {
const username = loginUsernameInput.value.trim();
const password = loginPasswordInput.value.trim();
if (!username || !password) {
statusDiv.textContent = "Please enter username and password.";
return;
}
browser.runtime.sendMessage({ action: "login", username, password }, (response) => {
console.log("Login response:", response);
if (response.success) {
statusDiv.textContent = response.message;
authSection.style.display = "none";
recorderSection.style.display = "block";
chapterListSection.style.display = "block";
} else {
statusDiv.textContent = response.message || "Login failed.";
}
});
});
// Registration handler
registerBtn.addEventListener('click', function() {
const username = registerUsernameInput.value.trim();
const password = registerPasswordInput.value.trim();
const confirmPassword = registerConfirmPasswordInput.value.trim();
if (!username || !password || !confirmPassword) {
statusDiv.textContent = "Please fill in all registration fields.";
return;
}
if (password !== confirmPassword) {
statusDiv.textContent = "Passwords do not match.";
return;
}
browser.runtime.sendMessage({ action: "register", username, password }, (response) => {
console.log("Registration response:", response);
if (response.success) {
statusDiv.textContent = response.message;
authSection.style.display = "none";
recorderSection.style.display = "block";
chapterListSection.style.display = "block";
} else {
statusDiv.textContent = response.message || "Registration failed.";
}
});
});
// Auto record toggle handler
autoRecordToggle.addEventListener('change', function(e) {
if (e.target.checked) {
const allowedPrefixes = allowedPrefixesInput.value.trim();
browser.runtime.sendMessage({ action: "startAutoRecord", interval: 10000, allowedPrefixes }, (response) => {
statusDiv.textContent = response.message || response.error;
});
} else {
browser.runtime.sendMessage({ action: "stopAutoRecord" }, (response) => {
statusDiv.textContent = response.message || response.error;
});
}
});
// Open resizable window button
openResizableBtn.addEventListener('click', function() {
browser.windows.create({
url: browser.runtime.getURL("popup.html"),
type: "popup",
width: 600,
height: 600
});
});
// Logout handler
logoutBtn.addEventListener('click', function() {
window.location.href = "http://192.168.0.226:25570/logout";
});
// Function to update the chapter list
function updateChapterList() {
fetch("http://192.168.0.226:25570/logs", {
method: "GET",
credentials: "include"
})
.then(response => response.json())
.then(data => {
let chapters = data.updates || [];
// Sort alphabetically by URL
chapters.sort((a, b) => a.url.localeCompare(b.url));
// Filter by search query (case-insensitive)
const searchQuery = searchQueryInput.value.trim().toLowerCase();
if (searchQuery) {
chapters = chapters.filter(item => item.url.toLowerCase().includes(searchQuery));
}
// Filter out entries with excluded words
const excludeWordsStr = excludeWordsInput.value.trim().toLowerCase();
if (excludeWordsStr) {
const excludeWords = excludeWordsStr.split(",").map(s => s.trim()).filter(s => s.length > 0);
if (excludeWords.length > 0) {
chapters = chapters.filter(item => {
for (const word of excludeWords) {
if (item.url.toLowerCase().includes(word)) {
return false;
}
}
return true;
});
}
}
// Update the chapter list UI
chapterListElement.innerHTML = "";
chapters.forEach(item => {
const li = document.createElement("li");
li.textContent = item.url + " (" + new Date(item.timestamp).toLocaleTimeString() + ")";
chapterListElement.appendChild(li);
});
})
.catch(err => {
console.error("Error fetching logs:", err);
});
}
setInterval(updateChapterList, 5000);
searchQueryInput.addEventListener('input', updateChapterList);
excludeWordsInput.addEventListener('input', updateChapterList);
});