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