diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e222a9d --- /dev/null +++ b/.gitignore @@ -0,0 +1,32 @@ +# Build artifacts +build/ +*.crx +*.pem +*.zip +!extension_store.crx +!extension_store.zip +!extension_installer.zip + +# IDE and editor files +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# OS generated files +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +ehthumbs.db +Thumbs.db + +# Logs +*.log +npm-debug.log* + +# Development +.aider* +.env diff --git a/README.md b/README.md index b753116..cb58aad 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,121 @@ -# myriad-importer-extension +# Myriad Importer Extension -This extension is LIVE at https://myriad.social/extension / https://chrome.google.com/webstore/detail/myriad-extension/caafifipbilmonkndcpppfehkhappcci +A browser extension that enables seamless content importing and cross-posting from various social media platforms to Myriad.social. + +## Official Links +This extension is LIVE at: +- https://myriad.social/extension +- https://chrome.google.com/webstore/detail/myriad-extension/caafifipbilmonkndcpppfehkhappcci + +## Technical Overview + +The extension provides several key functionalities: + +### Authentication +- Uses a magic link authentication system via email +- Authenticates through the Myriad.social API (`api.myriad.social/authentication`) +- Stores authentication tokens and username in local storage for persistent sessions +- Includes logout functionality with confirmation dialog + +### Content Import Support +1. **Twitter Posts** + - Automatically detects Twitter post URLs + - Imports posts directly to selected Myriad Experience + - Shows preview of imported posts in embedded iframe + +2. **Reddit Posts** + - Detects Reddit post URLs + - Direct importing to selected Myriad Experience + - Shows preview of imported posts in embedded iframe + +3. **YouTube Integration** + - Automatically converts YouTube URLs to embedded iframes + - Supports optional captions + - Full-width responsive video player integration + +4. **Twitch Integration** + - Converts Twitch channel URLs to embedded players + - Automatically configures proper parent domain settings + - Supports channel streaming embeds + +5. **Facebook Integration** + - Supports embedding of Facebook posts and videos + - Automatic conversion of mobile/web URLs to proper embed format + - Responsive iframe implementation + +### Experience Management +- Automatic creation of default Experience if none exists +- Experience selector with refresh capability +- Stores selected Experience as default in local storage +- Direct links to selected Experience page + +### UI Components +- Clean, responsive popup interface +- Purple gradient buttons with hover effects +- Loading spinner for async operations +- User feedback system with timed messages +- Conditional display of import/post options based on current URL +- Embedded post preview iframe for existing content +- Logout confirmation dialog + +## Technical Components + +- `background.js`: Manages Experience data and background tasks +- `contentScript.js`: Handles text grabbing from pages +- `popup.js`: Controls the extension's UI, authentication, and API interactions +- Custom styling with Mulish font family +- Secure API integration with Myriad.social endpoints + +## API Integration +- Base URL: `https://api.myriad.social` +- Key endpoints: + - `/authentication/otp/email` - Magic link generation + - `/authentication/login/otp` - Authentication + - `/user/posts/import` - Content importing + - `/user/experiences` - Experience management + - `/experiences/post` - Adding posts to experiences + +## Building and Packaging + +### Development Build +To test the extension locally: +1. Open Chrome and navigate to `chrome://extensions/` +2. Enable "Developer mode" (toggle in top right) +3. Click "Load unpacked" +4. Select your extension directory + +### Production Build +To package the extension for the Chrome Web Store: + +1. Clean the build directory: +```bash +rm -rf build/ +mkdir -p build +``` + +2. Create the distribution package: +```bash +zip -r build/extension_store.zip \ + manifest.json \ + popup.html \ + popup.js \ + background.js \ + contentScript.js \ + myriadlogo16.png \ + myriadlogo48.png \ + myriadlogo128.png +``` + +3. Create the Chrome extension package (optional): +- Open Chrome and go to `chrome://extensions/` +- Enable "Developer mode" +- Click "Pack extension" +- Select your extension directory +- Click "Pack Extension" +- Move the generated files: +```bash +mv extension.crx build/extension_store.crx +mv extension.pem build/extension.pem +``` + +The `build/extension_store.zip` file can be submitted to the Chrome Web Store for publication. diff --git a/background.js b/background.js index 07690fd..b770e39 100644 --- a/background.js +++ b/background.js @@ -1,32 +1,57 @@ -chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => { - if (!changeInfo.url) return; - - const url = changeInfo.url; - if (!url.includes("twitter.com") && !url.includes("reddit.com")) return; - - const match = url.includes("twitter.com") - ? url.match(/https:\/\/twitter\.com\/[^\/]+\/status\/(\d+)/) - : url.match(/https:\/\/www\.reddit\.com\/r\/[^\/]+\/comments\/(\w+)/); - - if (!match) return; - - const postId = match[1]; - const storageKey = `myriadUrl_${tabId}`; - - fetch('https://api.myriad.social/user/posts?pageLimit=200') - .then(response => response.json()) - .then(data => { - const post = data.data.find(post => post.originPostId === postId); - - if (!post) { - chrome.action.setBadgeText({text: '', tabId: tabId}); - return; - } - - const myriadUrl = `https://app.myriad.social/post/${post.id}`; - chrome.storage.local.set({[storageKey]: myriadUrl}); - chrome.action.setBadgeBackgroundColor({color: [255, 0, 0, 255]}); - chrome.action.setBadgeText({text: 'i', tabId: tabId}); - }) - .catch(error => console.error('Error:', error)); -}); + + + +function fetchAndStoreExperiences() { + // Retrieve access token from local storage + var base_url='https://api.myriad.social' + chrome.storage.local.get(['accessToken', 'username'], function(items) { + var accessToken = items.accessToken; + var username = items.username; + + var headers = { + 'accept': 'application/json', + 'Content-Type': 'application/json', + 'Authorization': 'Bearer ' + accessToken, + }; + + var url = base_url + "/user/experiences"; + var page = 1; + var pagelimit = 10; + var filter = '{"where":{"deletedAt":{"$exists":false}},"order":"createdAt DESC","include":["user",{"relation":"experience","scope":{"include":[{"relation":"user","scope":{"include":[{"relation":"accountSetting"}]}}]}}]}'; + var experiences = {}; // To store the Experience Names and IDs + + function fetchPage() { + var params = new URLSearchParams({ "pageNumber": page, "pageLimit": pagelimit, "filter": filter }); + fetch(url + "?" + params.toString(), { headers: headers }) + .then(response => response.json()) + .then(data => { + if (!data || !data.data) { + console.error('Unexpected data structure:', data); + return; // Exit early if data or data.data is undefined + } + var filtered_experiences = data.data.filter(exp => exp.experience.user.username === username); + filtered_experiences.forEach(exp => { + var experience_id = exp.experience.id; + var experience_name = exp.experience.name; + experiences[experience_name] = experience_id; + }); + + if (data.meta.additionalData.totalOwnedExperience > Object.keys(experiences).length) { + page += 1; + fetchPage(); // Fetch the next page if there are more experiences + } else { + // Store the experiences in local storage + chrome.storage.local.set({ "experiences": JSON.stringify(experiences) }, function() { + console.log("Experiences have been saved to local storage."); + //populateExperiences(experiences); // Populate the experiences in the optgroup + }); + } + }) + .catch(error => console.error('Error:', error)); + } + + fetchPage(); // Start fetching the first page + }); +} + + diff --git a/build/extension_store.crx b/build/extension_store.crx index 6cfd8d5..47e10ac 100644 Binary files a/build/extension_store.crx and b/build/extension_store.crx differ diff --git a/build/extension_store.zip b/build/extension_store.zip index a74ee07..03e61ef 100644 Binary files a/build/extension_store.zip and b/build/extension_store.zip differ diff --git a/build/readme.md b/build/readme.md index b33d36a..712ab20 100644 --- a/build/readme.md +++ b/build/readme.md @@ -1,8 +1,37 @@ -- Download everything here as a zip file by going to https://myriad.social/ext -- Unzip the file. You will see a *.zip* file and a *.crx* file -- Open Google Chrome / Microsoft Edge / Brave / Chromium. -- Go to chrome://extensions using the URL bar. -- Toggle "Developer Mode" (usually top right) to *on*. -- Drag the *.crx* file onto the page. If this fails, unzip the *.zip* file and press "Load Unpacked" button on the top left and choose the unzipped folder. -- Find the Myriad logo under the puzzle piece icon, and pin it. -- Use the extension by clicking on the Myriad logo and following the instructions to log in and start importing. +# Installation Guide for Myriad Extension + +## Quick Start +1. Download everything as a zip file from https://myriad.social/ext +2. Unzip the file. You will see a *.zip* file and a *.crx* file +3. Open Google Chrome / Microsoft Edge / Brave / Chromium +4. Go to chrome://extensions using the URL bar +5. Toggle "Developer Mode" (usually top right) to *on* +6. Drag the *.crx* file onto the page +7. Find the Myriad logo under the puzzle piece icon, and pin it +8. Click the Myriad logo and follow the login instructions to start importing + +## Detailed Installation Methods + +### Method 1: Direct Installation (Recommended) +1. Use the `.crx` file from the downloaded package +2. Navigate to `chrome://extensions` in your browser +3. Enable "Developer Mode" using the toggle in the top right +4. Drag and drop the `.crx` file onto the extensions page + +### Method 2: Manual Installation (If Method 1 fails) +1. Unzip the `.zip` file to a local directory +2. Navigate to `chrome://extensions` in your browser +3. Enable "Developer Mode" using the toggle in the top right +4. Click "Load Unpacked" button on the top left +5. Select the unzipped folder + +## Supported Browsers +- Google Chrome +- Microsoft Edge +- Brave +- Any Chromium-based browser + +## Troubleshooting +- If the `.crx` installation fails, try the manual installation method +- Ensure Developer Mode is enabled before installation +- Check that all files are properly extracted when using manual installation diff --git a/contentScript.js b/contentScript.js index ea448db..bf6d2fc 100644 --- a/contentScript.js +++ b/contentScript.js @@ -1,24 +1,6 @@ - -chrome.runtime.onMessage.addListener( - function(request, sender, sendResponse) { - if (request.message === "get_selected_text") { - var selectedText = window.getSelection().toString(); - - // Truncate it to the first 1000 characters - selectedText = selectedText.substr(0, 1000); - - // Break it into lines - var textBlocks = selectedText.split('\n').filter(function (txt) { - // Remove empty lines - return txt.trim().length > 0; - }); - - // Convert each line into a link - textBlocks = textBlocks.map(function (txt) { - return `

${txt}

`; - }); - - sendResponse({data: textBlocks}); - } - } -); +chrome.runtime.onMessage.addListener(function (message, sender, sendResponse) { + if (message.action === "grabText") { + const textContent = document.body.innerText; + chrome.runtime.sendMessage({ action: "textGrabbed", text: textContent }); + } +}); diff --git a/manifest.json b/manifest.json index 02ccd51..be1c3a6 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "manifest_version": 3, "name": "Myriad Extension", - "version": "1.0", + "version": "1.022", "description": "Import and Post to Myriad", "permissions": [ "activeTab", @@ -9,8 +9,10 @@ "*://*.twitter.com/*", "*://*.reddit.com/*", "*://*.twitch.tv/*", - "*://*.youtube.com/*" + "*://*.youtube.com/*", + "*://*.facebook.com/*" ], + "action": { "default_popup": "popup.html", "default_icon": { diff --git a/popup.html b/popup.html index 9245abc..bd3d161 100644 --- a/popup.html +++ b/popup.html @@ -5,14 +5,16 @@ - +
+ + +
+
+ +

Myriad Social

+ +
Log-in by inputing your e-mail address, and copy the link you will receive into the 'magic link' field. @@ -119,21 +225,41 @@

Myriad Social

_
-
- - -
+
+
+ + +
+
+ + + + + + - +
+ + + +
+
- +
@@ -141,6 +267,10 @@

Myriad Social

+ diff --git a/popup.js b/popup.js index 1e83e0b..4d7c5bb 100644 --- a/popup.js +++ b/popup.js @@ -4,6 +4,213 @@ var loginData = { }; + + +function checkSelectedExperience() { + // Get the select element by its ID + var selectElement = document.getElementById('experience_selector'); + + // Check if an option is selected + if (selectElement.selectedIndex !== -1) { + // Get the selected option's value (experience name) + var selectedExperienceName = selectElement.options[selectElement.selectedIndex].textContent; + + // Check if an experience is selected + if (selectedExperienceName) { + // Retrieve experiences from local storage + var experiences = localStorage.getItem("experiences"); + if (experiences) { + experiences = JSON.parse(experiences); + + // Get the corresponding experience ID + var experienceId = experiences[selectedExperienceName]; + + // Save the experience ID to local storage + localStorage.setItem("default_experience_id", experienceId); + + +// Create the hyperlink to the selected experience +var experienceLink = "https://app.myriad.social/?type=experience&id=" + experienceId; + +// Display the hyperlink using your function +displayUserFeedback('Click Here to go to the selected Experience.'); + + } + } + } +} + +function addToDefaultExperience(postId) { + var defaultExperienceId = localStorage.getItem("default_experience_id"); + var accessToken = localStorage.getItem("accessToken"); + + var apiUrl = "https://api.myriad.social/experiences/post"; + var headers = { + 'accept': 'application/json', + 'Content-Type': 'application/json', + 'Authorization': 'Bearer ' + accessToken, + }; + + var experienceData = { + "experienceIds": [defaultExperienceId], + "postId": postId + }; + + fetch(apiUrl, { + method: 'POST', + headers: headers, + body: JSON.stringify(experienceData) + }) + .then(response => { + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + return response.json(); + }) + .then(data => { + console.log(data); + displayUserFeedback('The post has been successfully added to the default Timeline.'); + }) + .catch((error) => { + console.error('Error:', error); + displayUserFeedback('There was an error adding the post to the default Timeline. Please try again.', false); + }); +} + + +// Function to populate experiences and show the experiences div +function populateExperiences(experiences, defaultExperienceId) { + var selectElement = document.getElementById('experience_selector'); + var optgroup = selectElement.querySelector('optgroup'); + + // Clear any existing options + optgroup.innerHTML = ''; + + // Add the experiences + for (var experience_name in experiences) { + var option = document.createElement('option'); + option.value = experiences[experience_name]; + option.textContent = experience_name; + optgroup.appendChild(option); + + // Select the default experience if it matches + if (experiences[experience_name] === defaultExperienceId) { + option.selected = true; + } + } + + // Show the experiences div + document.getElementById('experiences').style.display = 'block'; +} + +// Function to load experiences from local storage and populate the optgroup +function loadExperiencesFromLocalStorage() { + var experiences = localStorage.getItem("experiences"); + var defaultExperienceId = localStorage.getItem("default_experience_id"); + if (experiences) { + experiences = JSON.parse(experiences); + populateExperiences(experiences, defaultExperienceId); + } +} + + +function fetchAndStoreExperiences() { + var storedExperiences = localStorage.getItem("experiences"); + if (storedExperiences) { + return; // Exit early if experiences are already populated + } + // Show spinner and message + document.getElementById('spinner').style.display = 'block'; + displayUserFeedback("The extension is loading your Myriad data. Please do not close."); + + // Retrieve access token from local storage + var accessToken = localStorage.getItem("accessToken"); + var username = localStorage.getItem("username"); + var headers = { + 'accept': 'application/json', + 'Content-Type': 'application/json', + 'Authorization': 'Bearer ' + accessToken, + }; + + var url = base_url + "/user/experiences"; + var page = 1; + var pagelimit = 10; + var filter = '{"where":{"deletedAt":{"$exists":false}},"order":"createdAt DESC","include":["user",{"relation":"experience","scope":{"include":[{"relation":"user","scope":{"include":[{"relation":"accountSetting"}]}}]}}]}'; + var experiences = {}; // To store the Experience Names and IDs + + function fetchPage() { + var params = new URLSearchParams({ "pageNumber": page, "pageLimit": pagelimit, "filter": filter }); + fetch(url + "?" + params.toString(), { headers: headers }) + .then(response => response.json()) + .then(data => { + var filtered_experiences = data.data.filter(exp => exp.experience.user.username === username); + filtered_experiences.forEach(exp => { + var experience_id = exp.experience.id; + var experience_name = exp.experience.name; + experiences[experience_name] = experience_id; + }); + + if (data.meta.additionalData.totalOwnedExperience > Object.keys(experiences).length) { + page += 1; + fetchPage(); // Fetch the next page if there are more experiences + } else { + finalizeFetching(); + } + }) + .catch(error => console.error('Error:', error)); + } + + function finalizeFetching() { + // Check if there are no experiences + if (Object.keys(experiences).length === 0) { + createDefaultExperience(); // Create a new default experience + } + + // Store the experiences in local storage + localStorage.setItem("experiences", JSON.stringify(experiences)); + + // Set the default experience to be the first one if not already set + if (!localStorage.getItem("default_experience_id")) { + var firstExperienceId = Object.values(experiences)[0]; + localStorage.setItem("default_experience_id", firstExperienceId); + } + + displayUserFeedback("Myriad Timelines loaded."); + document.getElementById('spinner').style.display = 'none'; + populateExperiences(experiences); // Populate the experiences in the optgroup + } + + fetchPage(); // Start fetching the first page +} + +function createDefaultExperience() { + var accessToken = localStorage.getItem("accessToken"); + var headers = { + 'accept': 'application/json', + 'Content-Type': 'application/json', + 'Authorization': 'Bearer ' + accessToken, + }; + var url = base_url + "/user/experiences"; + + // We'll name the experience "Default" as you requested + var experience_name = "Default"; + var data = JSON.stringify({ "name": experience_name }); + + fetch(url, { + method: 'POST', // We'll use POST method to create the experience + headers: headers, + body: data + }) + .then(response => response.json()) + .then(responseData => { + // Here you can handle the response data if needed + console.log("Default experience created:", responseData); + }) + .catch(error => console.error('Error:', error)); +} + + + function dataURLToBlob(dataUrl) { const arr = dataUrl.split(','); const mime = arr[0].match(/:(.*?);/)[1]; @@ -16,7 +223,6 @@ function dataURLToBlob(dataUrl) { return new Blob([u8arr], { type: mime }); } - function displayUserFeedback(messageText, isSuccess = true) { // Create a new message element let messageElement = document.createElement('div'); @@ -24,8 +230,8 @@ function displayUserFeedback(messageText, isSuccess = true) { // Add classes to the message messageElement.className = 'message ' + (isSuccess ? 'success' : 'error'); - // Set the text content of the message - messageElement.textContent = messageText; + // Set the HTML content of the message + messageElement.innerHTML = messageText; // Use innerHTML instead of textContent // Append the message to the body document.body.appendChild(messageElement); @@ -33,12 +239,13 @@ function displayUserFeedback(messageText, isSuccess = true) { // After 6 seconds, remove the message setTimeout(() => { document.body.removeChild(messageElement); - }, 6000); + }, 5000); } + base_url='https://api.myriad.social'; function createMyriadPost(title, textBlocks, platform = 'myriad', visibility = 'public') { - + document.getElementById('spinner').style.display = 'block'; const apiEndpoint = `${base_url}/user/posts`; fetch(`${base_url}/users/${loginData.username}`, { @@ -61,11 +268,13 @@ function createMyriadPost(title, textBlocks, platform = 'myriad', visibility = ' let text = textBlocks.join('\n'); + var defaultExperienceId = localStorage.getItem("default_experience_id"); + let post_data = { "rawText": text, "text": text, "status": "published", - "selectedTimelineIds": [], + "selectedTimelineIds": [defaultExperienceId], "createdBy": createdBy, "createdAt": createdAt, "platform": platform, @@ -85,17 +294,92 @@ function createMyriadPost(title, textBlocks, platform = 'myriad', visibility = ' if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } + return response.json(); }) .then(data => { console.log('Post created successfully!'); displayUserFeedback('Post created successfully!', true); + + // Hide the spinner + document.getElementById('spinner').style.display = 'none'; }) .catch((error) => { console.error('Error:', error); + + // Hide the spinner + document.getElementById('spinner').style.display = 'none'; }); } + + + +function generateFacebookEmbed(url) { + // Remove subdomains like "m." or "web." if present + url = url.replace(/https:\/\/(m\.|web\.)?facebook\.com/, 'https://www.facebook.com'); + + let src; + if (url.includes('/videos/')) { + // It's a video + const videoId = url.split('/videos/')[1].split('/')[0]; + const pageName = url.split('facebook.com/')[1].split('/')[0]; + src = `https://www.facebook.com/plugins/video.php?height=476&href=https%3A%2F%2Fwww.facebook.com%2F${pageName}%2Fvideos%2F${videoId}%2F&show_text=false&width=100%&t=0`; + } else { + // It's a post + src = `https://www.facebook.com/plugins/post.php?href=${encodeURIComponent(url)}&show_text=true&width=100%`; + } + + return ``; +} + + + +function embedFacebookPost() { + // Get the current tab URL + chrome.tabs.query({ active: true, currentWindow: true }, function (tabs) { + const currentTabURL = tabs[0].url; + + // Check if the URL is a Facebook post or video + const facebookPattern = /^https:\/\/(www\.|m\.|web\.)?facebook\.com\/.+/; + if (!facebookPattern.test(currentTabURL)) { + //displayUserFeedback("Please go to a Facebook post or video."); + return; + } + + // Construct the embed HTML using the generateFacebookEmbed function + const embedHTML = generateFacebookEmbed(currentTabURL); + + // Title for the Myriad post (you can customize this) + const title = "Facebook Embed"; + + // Call the createMyriadPost function to post the embedded Facebook content + createMyriadPost(title, [embedHTML], 'myriad'); + }); +} + +// Listen for messages from the content script +chrome.runtime.onMessage.addListener(function (message, sender, sendResponse) { + if (message.action === "grabText") { + const originalText = message.text; + + // Construct the embed HTML using the generateFacebookEmbed function + const embedHTML = generateFacebookEmbed(sender.tab.url, originalText); + + // Title for the Myriad post + const title = "Facebook Embed"; + + // Call the createMyriadPost function to post the embedded Facebook content + createMyriadPost(title, [embedHTML], 'myriad'); + } +}); + +// ... Rest of the code as before ... + + + + + //Alex check below // When the popup is opened, get the active tab URL. chrome.tabs.query({active: true, lastFocusedWindow: true}, function(tabs) { @@ -158,8 +442,80 @@ chrome.tabs.query({active: true, lastFocusedWindow: true}, function(tabs) { } }); +// This function changes the visibility based on the last clicked button +function updateVisibility() { + var lastClicked = localStorage.getItem('lastClicked'); + + if(lastClicked === 'email_login') { + document.getElementById('selector').style.display = 'none'; + document.getElementById('emailfield').style.display = 'block'; + } else { + document.getElementById('selector').style.display = 'block'; + document.getElementById('emailfield').style.display = 'none'; + } +} + document.addEventListener('DOMContentLoaded', function () { + + +document.getElementById('refresh_button').addEventListener('click', function() { + // Remove the experiences data from local storage + localStorage.removeItem("experiences"); + + // Call fetchAndStoreExperiences to repopulate the data + fetchAndStoreExperiences(); + + +}); + +// Get the logout button and confirmation div +var logoutButton = document.getElementById('logout_button'); +var logoutConfirmation = document.getElementById('logout_confirmation'); + +// When the logout button is clicked +logoutButton.addEventListener('click', function() { + // Hide the logout button and show the confirmation div + logoutButton.style.display = 'none'; + logoutConfirmation.style.display = 'inline'; +}); + +// When the "yes" link is clicked +document.getElementById('logout_yes').addEventListener('click', function(e) { + e.preventDefault(); // Prevent the default link behavior + // Remove ALL data from local storage + localStorage.clear(); + + // Hide the confirmation div and show the logout button + logoutConfirmation.style.display = 'none'; + logoutButton.style.display = 'inline'; + + // You can add some user feedback here if you like + displayUserFeedback('Logged out successfully! See you next time!'); + checkLogin(); +}); + +// When the "no" link is clicked +document.getElementById('logout_no').addEventListener('click', function(e) { + e.preventDefault(); // Prevent the default link behavior + // Hide the confirmation div and show the logout button + logoutConfirmation.style.display = 'none'; + logoutButton.style.display = 'inline'; +}); + + +document.getElementById('logo').addEventListener('click', function () { + window.open('https://app.myriad.social', '_blank'); +}); + + document.getElementById('create_account').addEventListener('click', function () { + window.open('https://app.myriad.social/login?instance=https%3A%2F%2Fapi.myriad.social', '_blank'); +}); + +document.getElementById('connect_email').addEventListener('click', function () { + window.open('https://app.myriad.social/settings?section=email&instance=https%3A%2F%2Fapi.myriad.social', '_blank'); +}); + var buttons = document.getElementsByTagName('button'); for (var i = 0; i < buttons.length; i++) { buttons[i].addEventListener('click', function () { @@ -172,6 +528,7 @@ document.addEventListener('DOMContentLoaded', function () { var postContent = document.getElementById('post_content'); writePostButton.addEventListener('click', function () { + writePostButton.style.display='none'; postContent.style.display = 'block'; submitPostButton.style.display = 'inline-block'; }); @@ -184,24 +541,70 @@ document.addEventListener('DOMContentLoaded', function () { createMyriadPost(title, textBlocks); postContent.value = ''; + writePostButton.style.display='block'; postContent.style.display = 'none'; this.style.display = 'none'; } }); - document.getElementById('send_magic_link').addEventListener('click', function () { - var email = document.getElementById('email').value; - sendMagicLink(email); - }); +document.getElementById('send_magic_link').addEventListener('click', function () { + var email = document.getElementById('email').value; + localStorage.setItem('lastEmail', email); + sendMagicLink(email); + document.getElementById('magiclink').style.display = 'block'; // Show the magic link field + + // Check if email is Gmail or Yahoo, then provide link to email provider + var link = null; + if (email.endsWith("@gmail.com")) { + link = "https://mail.google.com"; + } else if (email.endsWith("@yahoo.com")) { + link = "https://mail.yahoo.com"; + } + + if (link) { + var emailProviderLink = document.getElementById('email_provider_link'); + if (emailProviderLink) { + emailProviderLink.href = link; // Update existing link if it already exists + } else { + // Create new link if it doesn't exist yet + emailProviderLink = document.createElement('a'); + emailProviderLink.id = 'email_provider_link'; + emailProviderLink.href = link; + emailProviderLink.target = "_blank"; + emailProviderLink.textContent = "Go to your email provider"; + + document.getElementById('emailfield').appendChild(emailProviderLink); // Append the link to the emailfield div + } + } +}); + - document.getElementById('submit_magic_link').addEventListener('click', function () { - var magicLink = document.getElementById('magic_link').value; - authenticate(magicLink); +document.getElementById('submit_magic_link').addEventListener('click', function () { + var magicLink = document.getElementById('magic_link').value; + authenticate(magicLink); +}); + +window.onload = function() { + var lastEmail = localStorage.getItem('lastEmail'); + if(lastEmail) { + document.getElementById('email').value = lastEmail; + document.getElementById('send_magic_link').textContent = 'Resend Magic Link'; + document.getElementById('magiclink').style.display = 'block'; // Show the magic link field if an email is stored + } + updateVisibility(); + + // This event listener is here + document.getElementById('email_login').addEventListener('click', function () { + localStorage.setItem('lastClicked', 'email_login'); + updateVisibility(); }); - +} + document.getElementById('import_post').addEventListener('click', function () { + var writePostButton = document.getElementById('write_post_button'); + writePostButton.style.display='block'; chrome.tabs.query({ active: true, currentWindow: true }, function (tabs) { var currentUrl = tabs[0].url; if (currentUrl.includes('twitter.com') || currentUrl.includes('reddit.com')) { @@ -239,11 +642,20 @@ document.getElementById('import_post').addEventListener('click', function () { postContent.value = ''; postContent.style.display = 'none'; this.style.display = 'none'; - } + } else if (currentUrl.includes('facebook.com/')) { + embedFacebookPost() + } }); }); +// Get the select element by its ID +var selectElement = document.getElementById('experience_selector'); + +// Add an event listener that listens for the "change" event +selectElement.addEventListener('change', checkSelectedExperience); + +checkSelectedExperience(); }); @@ -263,12 +675,17 @@ importbuttonElement.innerText = importbuttonElement.textContent = 'new text'; contextElement.innerText = "The current page is natively importable to Myriad! "; document.getElementById('write_post_button').style.display = 'none'; importbuttonElement.innerText = importbuttonElement.textContent = 'Import Post'; - } else if (currentUrl.includes('youtube.com') || currentUrl.includes('twitch.tv')) { + } else if (currentUrl.includes('youtube.com') || currentUrl.includes('twitch.tv') || currentUrl.includes('facebook.com')) { contextElement.innerText = "The current page can be embedded into a Myriad post! "; - writepostbuttonElement.innerText=writepostbuttonElement.textContent = 'Add Caption'; - importbuttonElement.innerText = importbuttonElement.textContent = 'Embed Video'; + // If the URL is not from Facebook, show the "Add Caption" button + if (!currentUrl.includes('facebook.com')) { + writepostbuttonElement.innerText = writepostbuttonElement.textContent = 'Add Caption'; } else { - contextElement.innerText = "Myriad supports imports from Twitter, Reddit, YouTube, and Twitch! You can still write a post below."; + writepostbuttonElement.style.display = 'none'; + } + importbuttonElement.innerText = importbuttonElement.textContent = 'Embed'; + } else { + contextElement.innerText = "Myriad supports inserting posts from Twitter, Reddit, YouTube, Twitch, and Facebook!\nYou can also write a Myriad text post below."; importbuttonElement.innerText = importbuttonElement.textContent = 'Archive Content'; document.getElementById('import_post').style.display = 'none'; } @@ -282,19 +699,23 @@ var username = localStorage.getItem("username"); if (accessToken && username) { loginData.accessToken = accessToken; loginData.username = username; - + fetchAndStoreExperiences(); + loadExperiencesFromLocalStorage(); var preloginElement = document.getElementById('prelogin'); if (preloginElement) { preloginElement.innerText = "Logged in as: " + username; } - + document.getElementById('logout_button').style.display = 'block'; document.getElementById('email').style.display = 'none'; document.getElementById('magic_link').style.display = 'none'; document.getElementById('send_magic_link').style.display = 'none'; document.getElementById('submit_magic_link').style.display = 'none'; - + document.getElementById('selector').style.display = 'none'; document.getElementById('write_post_button').style.display = 'inline-block'; document.getElementById('import_post').style.display = 'inline-block'; + + document.getElementById('contextof').style.display = 'block'; + } else { document.getElementById('email').style.display = 'block'; document.getElementById('magic_link').style.display = 'block'; @@ -302,6 +723,9 @@ if (accessToken && username) { document.getElementById('submit_magic_link').style.display = 'block'; document.getElementById('prelogin').style.display = 'block'; + document.getElementById('contextof').style.display = 'none'; + + document.getElementById('write_post_button').style.display = 'none'; document.getElementById('import_post').style.display = 'none'; } @@ -311,6 +735,7 @@ if (accessToken && username) { function sendMagicLink(email) { + document.getElementById('spinner').style.display = 'block'; var apiUrl = "https://api.myriad.social/authentication/otp/email"; fetch(apiUrl, { @@ -337,10 +762,13 @@ function sendMagicLink(email) { console.error('Error:', error); displayUserFeedback('There was an error sending the magic link. Please try again.', false); }); + document.getElementById('spinner').style.display = 'none'; } function authenticate(magicLink) { + // Show the spinner + document.getElementById('spinner').style.display = 'block'; var callbackUrl = "https://app.myriad.social/login"; var token = magicLink.replace(callbackUrl+"?token=", ""); @@ -354,70 +782,86 @@ function authenticate(magicLink) { body: JSON.stringify({ "token": token }) - }).then(response => response.json()) - .then(data => { - var accessToken = data.token.accessToken; - var username = data.user.username; - - // store accessToken and username in local storage - localStorage.setItem("accessToken", accessToken); - localStorage.setItem("username", username); - displayUserFeedback('Access Token and Username are set in local storage'); - checkLogin(); - document.getElementById('import_post').style.visibility = 'visible'; - var preloginElement = document.getElementById('prelogin'); - if (preloginElement) { - preloginElement.innerText = "Logged in as: " + username; - } - }) - .catch((error) => { - console.error('Error:', error); - displayUserFeedback('There was an error during authentication. Please try again.', false); - }); + }) + .then(response => response.json()) + .then(data => { + var accessToken = data.token.accessToken; + var username = data.user.username; + + // store accessToken and username in local storage + localStorage.setItem("accessToken", accessToken); + localStorage.setItem("username", username); + displayUserFeedback("You're authenticated!"); + checkLogin(); + document.getElementById('import_post').style.visibility = 'visible'; + var preloginElement = document.getElementById('prelogin'); + if (preloginElement) { + preloginElement.innerText = "Logged in as: " + username; + } + + // Fetch and store experiences after successful authentication + + //chrome.runtime.sendMessage({ action: 'fetchAndStoreExperiences' }); + }) + .catch((error) => { + console.error('Error:', error); + displayUserFeedback('There was an error during authentication. Please try again.', false); + }); + document.getElementById('spinner').style.display = 'none'; } -function importTwitterPost(twitterUrl, selectedTimelineIds = []) { +function importTwitterPost(twitterUrl) { + // Show the spinner + document.getElementById('spinner').style.display = 'block'; + // retrieve access token and username from local storage var at = localStorage.getItem("accessToken"); -var un = localStorage.getItem("username"); + var un = localStorage.getItem("username"); + var defaultExperienceId = localStorage.getItem("default_experience_id"); + + var apiUrl = "https://api.myriad.social/user/posts/import"; + var headers = { + 'accept': 'application/json', + 'Content-Type': 'application/json', + 'Authorization': 'Bearer ' + at, + }; - - var apiUrl = "https://api.myriad.social/user/posts/import"; - var headers = { - 'accept': 'application/json', - 'Content-Type': 'application/json', - 'Authorization': 'Bearer ' + at, - }; + var data = { + "url": twitterUrl, + "importer": un, + "selectedTimelineIds": defaultExperienceId , + }; - var data = { - "url": twitterUrl, - "importer": un, - "selectedTimelineIds": selectedTimelineIds, - }; + fetch(apiUrl, { + method: 'POST', + headers: headers, + body: JSON.stringify(data) + }) + .then(response => { + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + return response.json(); + }) + .then(data => { -fetch(apiUrl, { - method: 'POST', - headers: headers, - body: JSON.stringify(data) -}) -.then(response => { - if (!response.ok) { - throw new Error(`HTTP error! status: ${response.status}`); - } - return response.json(); -}) -.then(data => { - console.log(data); - displayUserFeedback('The post has been successfully imported.'); -}) -.catch((error) => { - console.error('Error:', error); - displayUserFeedback('There was an error during the import. Please try again.', false); -}); + console.log(data); + displayUserFeedback('The post has been successfully imported.'); + + // Hide the spinner + document.getElementById('spinner').style.display = 'none'; + }) + .catch((error) => { + console.error('Error:', error); + displayUserFeedback('There was an error during the import. Please try again.', false); + + // Hide the spinner + document.getElementById('spinner').style.display = 'none'; + }); +}; - }; document.addEventListener('DOMContentLoaded', checkLogin); diff --git a/popup.old b/popup.old index 364e182..0713c0f 100644 --- a/popup.old +++ b/popup.old @@ -1,22 +1,118 @@ + + -

Myriad Social Importer

- - - - + +

Myriad Social Extension

+
+
+ Log-in by inputing your e-mail address, and copy the link you will receive into the 'magic link' field. + Don't forget to check your spam box! +
+
+ _ +
+
+ + +
+ +
+ +
+ + + +
- +
+ +
-