diff --git a/FirefoxExtension/background.js b/FirefoxExtension/background.js
new file mode 100644
index 0000000..8485f9a
--- /dev/null
+++ b/FirefoxExtension/background.js
@@ -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;
+  }
+});
diff --git a/FirefoxExtension/icon.png b/FirefoxExtension/icon.png
new file mode 100644
index 0000000..f59e63c
Binary files /dev/null and b/FirefoxExtension/icon.png differ
diff --git a/FirefoxExtension/manifest.json b/FirefoxExtension/manifest.json
new file mode 100644
index 0000000..3784303
--- /dev/null
+++ b/FirefoxExtension/manifest.json
@@ -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"
+  }
+}
diff --git a/FirefoxExtension/popup.html b/FirefoxExtension/popup.html
new file mode 100644
index 0000000..f703dac
--- /dev/null
+++ b/FirefoxExtension/popup.html
@@ -0,0 +1,79 @@
+
+
+
+  NovelBin Auto Recorder
+  
+
+
+  
+  
+
+  
+  
+    
Auto Record Settings
+    
+    
+    
+    
+  
+
+  
+  
+
+  
+  
+
+
diff --git a/FirefoxExtension/popup.js b/FirefoxExtension/popup.js
new file mode 100644
index 0000000..9063f3f
--- /dev/null
+++ b/FirefoxExtension/popup.js
@@ -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);
+});