aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPinapelz <yukais@pinapelz.com>2025-05-20 00:50:25 -0700
committerPinapelz <yukais@pinapelz.com>2025-05-20 00:50:25 -0700
commit3c239a83f6cba3eb7a602b7b2e3b83d90c8def51 (patch)
tree68fd22cc582749f02fe657f6bafd72707466549e
parent85eacdbb3e6518a92ebc521af0c8a62e72deedd6 (diff)
implement per-video auto save
-rw-r--r--content-script.js98
-rw-r--r--manifest.json50
-rw-r--r--popup.html12
-rw-r--r--popup.js28
4 files changed, 139 insertions, 49 deletions
diff --git a/content-script.js b/content-script.js
index 1d14fa7..dbfd11a 100644
--- a/content-script.js
+++ b/content-script.js
@@ -13,21 +13,32 @@
var paster = document.createElement("button");
var adder = document.createElement("button");
var copier = document.createElement("button");
- var offset = 5;
var copyMode = 0;
+ var videoId = location.search.split(/.+v=|&/)[1] || "";
const storedOffset = localStorage.getItem("offset");
- offset = storedOffset !== null ? parseInt(storedOffset) : 5;
+ const storedAutoSave = localStorage.getItem("autosave");
+ var offset = storedOffset !== null ? parseInt(storedOffset) : 5;
+ var autosave = storedAutoSave !== null ? storedAutoSave : true;
- browser.runtime.onMessage.addListener((message) => {
+ const browserAPI = typeof browser !== "undefined" ? browser : chrome;
+
+ browserAPI.runtime.onMessage.addListener((message) => {
if (message.type === "SET_OFFSET") {
offset = message.offset;
localStorage.setItem("offset", offset);
}
+ if (message.type === "SET_AUTOSAVE") {
+ autosave = message.autosave;
+ localStorage.setItem("autosave", autosave);
+ }
});
+ let isLoaded = false; // Flag to track if timestamps are loaded
+
function closePane() {
if (confirm("Close timestamp tool?")) {
+ saveTimestamps();
pane.remove();
cancelAnimationFrame(nowid);
window.removeEventListener("beforeunload", warn);
@@ -37,30 +48,27 @@
function updateStamp(stamp, time) {
stamp.innerHTML = formatTime(time);
stamp.dataset.time = time;
- stamp.href =
- "https://youtu.be/" +
- location.search.split(/.+v=|&/)[1] +
- "?t=" +
- time;
+ stamp.href = "https://youtu.be/" + videoId + "?t=" + time;
+ saveTimestamps();
}
function clickStamp(e) {
if (e.target.dataset.time) {
e.preventDefault();
- document.querySelector("video").currentTime =
- e.target.dataset.time;
+ document.querySelector("video").currentTime = e.target.dataset.time;
} else if (e.target.classList.contains("remove-timestamp")) {
e.preventDefault();
var li = e.target.parentElement;
li.remove();
+ saveTimestamps();
} else if (e.target.dataset.increment) {
e.preventDefault();
var li = e.target.parentElement;
var a = li.children[3];
var time =
- parseInt(a.dataset.time) +
- parseInt(e.target.dataset.increment);
+ parseInt(a.dataset.time) + parseInt(e.target.dataset.increment);
updateStamp(a, time);
+ saveTimestamps();
}
}
@@ -104,6 +112,9 @@
li.appendChild(a);
li.appendChild(text);
list.appendChild(li);
+ text.addEventListener("change", saveTimestamps);
+ text.addEventListener("blur", saveTimestamps);
+
return text;
}
@@ -122,6 +133,7 @@
text.value = note;
}
list.appendChild(nowli);
+ saveTimestamps();
}
function formatTime(time) {
@@ -138,13 +150,12 @@
function addStamp() {
var time = Math.max(
0,
- Math.floor(
- document.querySelector("video").currentTime - offset,
- ),
+ Math.floor(document.querySelector("video").currentTime - offset)
);
var text = newLi(time);
list.appendChild(nowli);
text.focus();
+ saveTimestamps();
}
function resetCopier() {
@@ -203,6 +214,54 @@
});
}
+ function saveTimestamps() {
+ if (!isLoaded || !videoId) return;
+ let timestamps = [];
+ for (let i = 0; i < list.children.length - 1; i++) {
+ const li = list.children[i];
+ const a = li.querySelector("a");
+ const note = li.querySelector("input").value;
+
+ timestamps.push({
+ time: parseInt(a.dataset.time),
+ note: note,
+ });
+ }
+
+ localStorage.setItem(
+ `yt-timestamps-${videoId}`,
+ JSON.stringify(timestamps)
+ );
+ }
+
+ function loadTimestamps() {
+ if (!videoId) return;
+
+ const savedData = localStorage.getItem(`yt-timestamps-${videoId}`);
+ if (!savedData) {
+ isLoaded = true;
+ return;
+ }
+
+ try {
+ const timestamps = JSON.parse(savedData);
+ while (list.children.length > 1) {
+ list.removeChild(list.firstChild);
+ }
+ timestamps.forEach((item) => {
+ const text = newLi(item.time);
+ text.value = item.note || "";
+ });
+ list.appendChild(nowli);
+
+ isLoaded = true; // Mark as loaded after successful parsing
+ showToast("Timestamps loaded");
+ } catch (e) {
+ console.error("Error loading timestamps:", e);
+ isLoaded = true; // Mark as loaded even if an error occurs
+ }
+ }
+
var toast = document.createElement("div");
toast.id = "ytls-toast";
document.body.appendChild(toast);
@@ -240,6 +299,8 @@
adder.addEventListener("click", addStamp);
copier.addEventListener("click", copyList);
window.addEventListener("beforeunload", warn);
+ window.addEventListener("beforeunload", saveTimestamps);
+
pane.appendChild(exit);
nowli.appendChild(nowa);
nowli.appendChild(nowtext);
@@ -252,5 +313,12 @@
pane.appendChild(buttons);
document.body.appendChild(pane);
box.focus();
+ paster.disabled = true;
+ adder.disabled = true;
+ copier.disabled = true;
+ loadTimestamps();
+ paster.disabled = false;
+ adder.disabled = false;
+ copier.disabled = false;
}
})();
diff --git a/manifest.json b/manifest.json
index 77a8f55..eba16de 100644
--- a/manifest.json
+++ b/manifest.json
@@ -1,27 +1,27 @@
{
- "manifest_version": 3,
- "name": "QuickStamper",
- "version": "1.0",
- "description": "A tool for generating timestamps on YouTube videos or livestreams",
- "browser_specific_settings": {
- "gecko": {
- "id": "ytquickstamper@pinapelz.com"
- }
- },
- "permissions": ["activeTab", "scripting", "clipboardWrite"],
- "icons": {
- "48": "icons/icon.png"
- },
- "action": {
- "default_popup": "popup.html",
- "default_icon": {
- "48": "icons/icon.png"
- }
- },
- "web_accessible_resources": [
- {
- "resources": ["styles.css"],
- "matches": ["<all_urls>"]
- }
- ]
+ "manifest_version": 3,
+ "name": "QuickStamper",
+ "version": "1.0",
+ "description": "A tool for generating timestamps on YouTube videos or livestreams",
+ "browser_specific_settings": {
+ "gecko": {
+ "id": "ytquickstamper@pinapelz.com"
+ }
+ },
+ "permissions": ["activeTab", "scripting", "clipboardWrite", "storage"],
+ "icons": {
+ "48": "icons/icon.png"
+ },
+ "action": {
+ "default_popup": "popup.html",
+ "default_icon": {
+ "48": "icons/icon.png"
+ }
+ },
+ "web_accessible_resources": [
+ {
+ "resources": ["styles.css"],
+ "matches": ["<all_urls>"]
+ }
+ ]
}
diff --git a/popup.html b/popup.html
index 97887f6..58560f7 100644
--- a/popup.html
+++ b/popup.html
@@ -59,12 +59,16 @@
<button id="activate">Launch Timestamp Tool</button>
<div>
<label for="offset">Offset (sec):</label>
- <input type="number"
- id="offset"
- value="5"
+ <input type="number"
+ id="offset"
title="Offset each timestamp by this many seconds, ex. 3 = 3s before each timestamp, -3 = 3s after each timestamp"
>
+ <label for="autosave">Autosave</label>
+ <input type="checkbox"
+ id="autosave"
+ title="Automatically save timestamps for each video">
+ </input>
</div>
<script src="popup.js"></script>
</body>
-</html> \ No newline at end of file
+</html>
diff --git a/popup.js b/popup.js
index 649720a..60c2cfe 100644
--- a/popup.js
+++ b/popup.js
@@ -1,7 +1,10 @@
+// Dynamically detect the browser API
+const browserAPI = typeof browser !== 'undefined' ? browser : chrome;
+
document.getElementById('activate').addEventListener('click', () => {
- browser.tabs.query({ active: true, currentWindow: true }).then((tabs) => {
+ browserAPI.tabs.query({ active: true, currentWindow: true }, (tabs) => {
if (tabs[0].url.includes('youtube.com/watch')) {
- browser.scripting.executeScript({
+ browserAPI.scripting.executeScript({
target: { tabId: tabs[0].id },
files: ['content-script.js']
});
@@ -11,10 +14,25 @@ document.getElementById('activate').addEventListener('click', () => {
document.getElementById('offset').addEventListener('input', () => {
const offset = parseInt(document.getElementById('offset').value, 10);
- browser.tabs.query({ active: true, currentWindow: true }).then((tabs) => {
- browser.tabs.sendMessage(tabs[0].id, { type: 'SET_OFFSET', offset: offset });
+ console.log(offset)
+ browserAPI.tabs.query({ active: true, currentWindow: true }, (tabs) => {
+ browserAPI.tabs.sendMessage(tabs[0].id, { type: 'SET_OFFSET', offset: offset });
localStorage.setItem('offset', offset);
});
});
-localStorage.getItem('offset') !== null ? document.getElementById('offset').value = localStorage.getItem('offset') : document.getElementById('offset').value = 5; \ No newline at end of file
+document.getElementById('autosave').addEventListener('input', () => {
+ const autosaveStatus = document.getElementById('autosave').checked;
+ browserAPI.tabs.query({ active: true, currentWindow: true }, (tabs) => {
+ browserAPI.tabs.sendMessage(tabs[0].id, { type: 'SET_AUTOSAVE', autosave: autosaveStatus });
+ localStorage.setItem('autosave', autosaveStatus);
+ });
+});
+
+localStorage.getItem('offset') !== null
+ ? document.getElementById('offset').value = localStorage.getItem('offset')
+ : document.getElementById('offset').value = 5;
+
+ localStorage.getItem('autosave') !== null
+ ? document.getElementById('autosave').checked = (localStorage.getItem('autosave') === 'true')
+ : document.getElementById('autosave').checked = true;
send patches to the email below
yukais@pinapelz.com
include the subject [PATCH repo_name]
pinapelz.com
homepage