Upload files to "FirefoxExtension"
This commit is contained in:
parent
64544c4219
commit
051f36649e
86
FirefoxExtension/background.js
Normal file
86
FirefoxExtension/background.js
Normal 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
BIN
FirefoxExtension/icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
19
FirefoxExtension/manifest.json
Normal file
19
FirefoxExtension/manifest.json
Normal 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"
|
||||||
|
}
|
||||||
|
}
|
79
FirefoxExtension/popup.html
Normal file
79
FirefoxExtension/popup.html
Normal 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
200
FirefoxExtension/popup.js
Normal 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);
|
||||||
|
});
|
Loading…
x
Reference in New Issue
Block a user