|
|
@@ -23,14 +23,21 @@ document.addEventListener("alpine:init", () => {
|
|
|
history: {},
|
|
|
sortedHistory: [],
|
|
|
openMenus: new Set(), // Track which menus are open
|
|
|
- currentView: "playlists", // Track current view: 'playlists', 'history', or 'playlist'
|
|
|
+ currentView: "playlists", // Track current view: 'playlists', 'history', 'playlist', or 'saveChannel'
|
|
|
currentPlaylistName: "", // Track which playlist is being viewed
|
|
|
playlistsForDisplay: [], // Computed array for display
|
|
|
currentPlaylistVideos: [], // Videos for current playlist view
|
|
|
currentTab: null, // Current active tab info
|
|
|
isCurrentTabYoutube: false, // Whether current tab is YouTube
|
|
|
+ isCurrentTabChannelPage: false, // Whether current tab is YouTube videos page
|
|
|
addCurrentPageButtonText: "Add Current Page", // Button text
|
|
|
|
|
|
+ // Save channel properties
|
|
|
+ selectedCategory: "FOR BOTH", // Currently selected category
|
|
|
+ availableCategories: ["FOR BOTH", "CHANNELS", "CREATIVE"], // Available categories
|
|
|
+ curlCommand: "", // Generated curl command
|
|
|
+ checkInterval: 14, // Check interval in days
|
|
|
+
|
|
|
init() {
|
|
|
this.loadPlaylists();
|
|
|
this.loadHistory();
|
|
|
@@ -139,13 +146,17 @@ document.addEventListener("alpine:init", () => {
|
|
|
this.currentTab = tabs[0];
|
|
|
const url = new URL(this.currentTab.url);
|
|
|
this.isCurrentTabYoutube = url.hostname === "www.youtube.com";
|
|
|
+ this.isCurrentTabChannelPage = this.isCurrentTabYoutube && url.pathname.includes("/videos");
|
|
|
this.updateAddCurrentPageButtonText();
|
|
|
+ this.updateCurlCommand();
|
|
|
}
|
|
|
} catch (error) {
|
|
|
console.error("Error getting current tab:", error);
|
|
|
this.currentTab = null;
|
|
|
this.isCurrentTabYoutube = false;
|
|
|
+ this.isCurrentTabChannelPage = false;
|
|
|
this.updateAddCurrentPageButtonText();
|
|
|
+ this.updateCurlCommand();
|
|
|
}
|
|
|
},
|
|
|
|
|
|
@@ -159,6 +170,60 @@ document.addEventListener("alpine:init", () => {
|
|
|
}
|
|
|
},
|
|
|
|
|
|
+ updateCurlCommand() {
|
|
|
+ if (!this.currentTab || !this.isCurrentTabChannelPage) {
|
|
|
+ this.curlCommand = "This feature is only available on YouTube channel pages (/videos).";
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ const title = this.currentTab.title.replace(" - YouTube", "");
|
|
|
+ const url = this.currentTab.url;
|
|
|
+ const category = this.selectedCategory;
|
|
|
+ const interval = this.checkInterval;
|
|
|
+
|
|
|
+ this.curlCommand = `curl -X POST -H 'content-type: application/json' -d '{"query": "mutation add{ addChannel(details: {category: \\"${category}\\", checkInterval: ${interval}, name: \\"${title}\\", url: \\"${url}\\"}){name} } "}' localhost:8543/data | jq '.'`;
|
|
|
+ },
|
|
|
+
|
|
|
+ async copyCurlCommand() {
|
|
|
+ try {
|
|
|
+ await navigator.clipboard.writeText(this.curlCommand);
|
|
|
+ console.log("Curl command copied to clipboard");
|
|
|
+ // Could add visual feedback here
|
|
|
+ } catch (error) {
|
|
|
+ console.error("Failed to copy to clipboard:", error);
|
|
|
+ // Fallback for older browsers
|
|
|
+ try {
|
|
|
+ const textArea = document.createElement("textarea");
|
|
|
+ textArea.value = this.curlCommand;
|
|
|
+ document.body.appendChild(textArea);
|
|
|
+ textArea.focus();
|
|
|
+ textArea.select();
|
|
|
+ document.execCommand("copy");
|
|
|
+ document.body.removeChild(textArea);
|
|
|
+ console.log("Curl command copied to clipboard (fallback)");
|
|
|
+ } catch (fallbackError) {
|
|
|
+ console.error("Fallback copy failed:", fallbackError);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ selectCategory(category) {
|
|
|
+ this.selectedCategory = category;
|
|
|
+ this.updateCurlCommand();
|
|
|
+ },
|
|
|
+
|
|
|
+ updateCheckInterval(interval) {
|
|
|
+ // Ensure it's a positive integer, default to 14 if invalid
|
|
|
+ const parsedInterval = parseInt(interval);
|
|
|
+ this.checkInterval = parsedInterval > 0 ? parsedInterval : 14;
|
|
|
+ this.updateCurlCommand();
|
|
|
+ },
|
|
|
+
|
|
|
+ showSaveChannel() {
|
|
|
+ this.currentView = "saveChannel";
|
|
|
+ this.updateCurlCommand();
|
|
|
+ },
|
|
|
+
|
|
|
sortHistoryByRecentInteraction() {
|
|
|
// Convert history object to array with video ID and sort by most recent interaction
|
|
|
this.sortedHistory = Object.entries(this.history)
|
|
|
@@ -811,6 +876,12 @@ document.addEventListener("alpine:init", () => {
|
|
|
},
|
|
|
},
|
|
|
|
|
|
+ saveChannelButton: {
|
|
|
+ ["@click"]() {
|
|
|
+ this.showSaveChannel();
|
|
|
+ },
|
|
|
+ },
|
|
|
+
|
|
|
backButton: {
|
|
|
["@click"]() {
|
|
|
this.showPlaylists();
|
|
|
@@ -872,6 +943,12 @@ document.addEventListener("alpine:init", () => {
|
|
|
},
|
|
|
},
|
|
|
|
|
|
+ saveChannelHeader: {
|
|
|
+ ["x-show"]() {
|
|
|
+ return this.currentView === "saveChannel";
|
|
|
+ },
|
|
|
+ },
|
|
|
+
|
|
|
playlistsContainer: {
|
|
|
["x-show"]() {
|
|
|
return this.currentView === "playlists";
|
|
|
@@ -890,6 +967,12 @@ document.addEventListener("alpine:init", () => {
|
|
|
},
|
|
|
},
|
|
|
|
|
|
+ saveChannelContainer: {
|
|
|
+ ["x-show"]() {
|
|
|
+ return this.currentView === "saveChannel";
|
|
|
+ },
|
|
|
+ },
|
|
|
+
|
|
|
exportContainer: {
|
|
|
["x-show"]() {
|
|
|
return this.currentView === "playlists";
|
|
|
@@ -926,6 +1009,44 @@ document.addEventListener("alpine:init", () => {
|
|
|
},
|
|
|
},
|
|
|
|
|
|
+ // Save Channel specific bindings
|
|
|
+ copyCurlButton: {
|
|
|
+ ["@click"]() {
|
|
|
+ this.copyCurlCommand();
|
|
|
+ },
|
|
|
+ [":disabled"]() {
|
|
|
+ return !this.isCurrentTabChannelPage;
|
|
|
+ },
|
|
|
+ },
|
|
|
+
|
|
|
+ categoryButton: {
|
|
|
+ ["@click"]() {
|
|
|
+ const category = this.$el.dataset.category;
|
|
|
+ this.selectCategory(category);
|
|
|
+ },
|
|
|
+ [":class"]() {
|
|
|
+ const category = this.$el.dataset.category;
|
|
|
+ return {
|
|
|
+ active: this.selectedCategory === category,
|
|
|
+ };
|
|
|
+ },
|
|
|
+ },
|
|
|
+
|
|
|
+ saveChannelNotice: {
|
|
|
+ ["x-show"]() {
|
|
|
+ return !this.isCurrentTabChannelPage;
|
|
|
+ },
|
|
|
+ },
|
|
|
+
|
|
|
+ intervalInput: {
|
|
|
+ [":value"]() {
|
|
|
+ return this.checkInterval;
|
|
|
+ },
|
|
|
+ ["@input"]() {
|
|
|
+ this.updateCheckInterval(this.$el.value);
|
|
|
+ },
|
|
|
+ },
|
|
|
+
|
|
|
// Add current page button binding
|
|
|
addCurrentPageButton: {
|
|
|
["@click"]() {
|