Commit 0cd0e345 authored by Stefy Spora's avatar Stefy Spora

Add privacy level dropdown menu for flexible privacy settings

- Add dropdown menu to select between 'Friends Only' and 'All Fetlifers' privacy levels
- Update XHR payloads to use selected privacy level for both pictures and videos
- Pictures: 'only_friends' vs 'public' based on selection
- Videos: true vs false for only_friends based on selection
- Update popup.js to pass privacy level to content script functions
- Update background.js context menu functions to use privacy level
- Update content.js executePrivacyUpdate function to accept privacy level parameter
- Update README.md with privacy level selection instructions
- Add version 1.0.3 to CHANGELOG.md documenting the new feature
- Maintain backward compatibility with default 'friends_only' setting
parent 25b6b4cb
...@@ -5,6 +5,19 @@ All notable changes to the FetLife Privacy Helper extension will be documented i ...@@ -5,6 +5,19 @@ All notable changes to the FetLife Privacy Helper extension will be documented i
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [1.0.3] - 2025-08-31
### Added
- **Privacy Level Selection**: Added dropdown menu to choose between "Friends Only" and "All Fetlifers" privacy settings
- **Dynamic Privacy Settings**: Extension now respects user-selected privacy level for both pictures and videos
- **Flexible Privacy Control**: Users can set media to friends-only or make it visible to all FetLife users
### Enhanced
- **User Interface**: Added privacy level selector above the action buttons
- **Privacy Options**: Pictures can be set to "only_friends" or "public"
- **Video Privacy**: Videos can be set to friends-only (true) or all users (false)
- **Bulk Processing**: Privacy level selection applies to all bulk operations
## [1.0.2] - 2025-08-31 ## [1.0.2] - 2025-08-31
### Added ### Added
......
...@@ -10,10 +10,11 @@ A Chrome browser extension that automates privacy settings on FetLife.com. When ...@@ -10,10 +10,11 @@ A Chrome browser extension that automates privacy settings on FetLife.com. When
## Features ## Features
- **Privacy Level Selection**: Choose between "Friends Only" or "All Fetlifers" privacy settings
- **Single Update**: Click the "Privaxy" button in the extension popup - **Single Update**: Click the "Privaxy" button in the extension popup
- **Bulk Processing**: Click "Run on All Media" to process multiple pages automatically - **Bulk Processing**: Click "Run on All Media" to process multiple pages automatically
- **Context Menu**: Right-click on any FetLife page and select "Privaxy" or "Run on All Media" - **Context Menu**: Right-click on any FetLife page and select "Privaxy" or "Run on All Media"
- **Automatic Privacy Update**: Finds the Edit button, changes privacy to "only friends", and saves changes - **Automatic Privacy Update**: Uses XHR requests to update privacy settings directly
- **Pagination Support**: Automatically follows "next »" links to process multiple pages - **Pagination Support**: Automatically follows "next »" links to process multiple pages
- **Stop Control**: Stop bulk processing at any time with the Stop button - **Stop Control**: Stop bulk processing at any time with the Stop button
- **Progress Tracking**: Shows real-time progress during bulk operations - **Progress Tracking**: Shows real-time progress during bulk operations
...@@ -32,16 +33,18 @@ A Chrome browser extension that automates privacy settings on FetLife.com. When ...@@ -32,16 +33,18 @@ A Chrome browser extension that automates privacy settings on FetLife.com. When
### Method 1: Single Page Update (Extension Popup) ### Method 1: Single Page Update (Extension Popup)
1. Navigate to a FetLife picture or video page 1. Navigate to a FetLife picture or video page
2. Click the extension icon in your Chrome toolbar 2. Click the extension icon in your Chrome toolbar
3. Click the "Privaxy" button in the popup 3. Select your desired privacy level from the dropdown ("Friends Only" or "All Fetlifers")
4. Wait for the success message 4. Click the "Privaxy" button in the popup
5. Wait for the success message
### Method 2: Bulk Processing (Extension Popup) ### Method 2: Bulk Processing (Extension Popup)
1. Navigate to a FetLife gallery or list page with multiple media items 1. Navigate to a FetLife gallery or list page with multiple media items
2. Click the extension icon in your Chrome toolbar 2. Click the extension icon in your Chrome toolbar
3. Click the "Run on All Media" button in the popup 3. Select your desired privacy level from the dropdown ("Friends Only" or "All Fetlifers")
4. Watch the progress counter as it processes each page 4. Click the "Run on All Media" button in the popup
5. Click "Stop" at any time to halt the process 5. Watch the progress counter as it processes each page
6. Wait for the completion summary 6. Click "Stop" at any time to halt the process
7. Wait for the completion summary
### Method 3: Context Menu (Single Page) ### Method 3: Context Menu (Single Page)
1. Navigate to a FetLife picture or video page 1. Navigate to a FetLife picture or video page
......
...@@ -42,10 +42,11 @@ chrome.runtime.onInstalled.addListener(() => { ...@@ -42,10 +42,11 @@ chrome.runtime.onInstalled.addListener(() => {
chrome.contextMenus.onClicked.addListener(async (info, tab) => { chrome.contextMenus.onClicked.addListener(async (info, tab) => {
if (info.menuItemId === 'privaxy') { if (info.menuItemId === 'privaxy') {
try { try {
// Execute the privacy update function // Execute the privacy update function with default privacy level
const results = await chrome.scripting.executeScript({ const results = await chrome.scripting.executeScript({
target: { tabId: tab.id }, target: { tabId: tab.id },
function: executePrivacyUpdateFromContext function: (privacyLevel) => executePrivacyUpdateFromContext(privacyLevel),
args: ['friends_only']
}); });
const result = results[0].result; const result = results[0].result;
...@@ -96,7 +97,7 @@ chrome.contextMenus.onClicked.addListener(async (info, tab) => { ...@@ -96,7 +97,7 @@ chrome.contextMenus.onClicked.addListener(async (info, tab) => {
}); });
// Function to be injected for context menu execution - XHR-based approach // Function to be injected for context menu execution - XHR-based approach
function executePrivacyUpdateFromContext() { function executePrivacyUpdateFromContext(privacyLevel = 'friends_only') {
// Function to extract media ID and type from URL // Function to extract media ID and type from URL
function getMediaInfo() { function getMediaInfo() {
const url = window.location.href; const url = window.location.href;
...@@ -150,14 +151,14 @@ function executePrivacyUpdateFromContext() { ...@@ -150,14 +151,14 @@ function executePrivacyUpdateFromContext() {
throw new Error('Could not find CSRF token. Please refresh the page and try again.'); throw new Error('Could not find CSRF token. Please refresh the page and try again.');
} }
// Step 3: Prepare payload based on media type // Step 3: Prepare payload based on media type and privacy level
let payload; let payload;
if (mediaInfo.type === 'video') { if (mediaInfo.type === 'video') {
payload = { payload = {
video: { video: {
title: "", title: "",
description: "", description: "",
only_friends: true, only_friends: privacyLevel === 'friends_only' ? true : false,
tag_names: [], tag_names: [],
user_tag_ids: [] user_tag_ids: []
}, },
...@@ -167,7 +168,7 @@ function executePrivacyUpdateFromContext() { ...@@ -167,7 +168,7 @@ function executePrivacyUpdateFromContext() {
payload = { payload = {
picture: { picture: {
caption: "", caption: "",
content_privacy: "only_friends", content_privacy: privacyLevel === 'friends_only' ? "only_friends" : "public",
tag_names: [], tag_names: [],
user_tag_ids: [] user_tag_ids: []
}, },
...@@ -252,7 +253,7 @@ function executeBulkPrivacyUpdateFromContext() { ...@@ -252,7 +253,7 @@ function executeBulkPrivacyUpdateFromContext() {
return mediaIds; return mediaIds;
} }
async function updateMediaPrivacyById(mediaType, mediaId, csrfToken) { async function updateMediaPrivacyById(mediaType, mediaId, csrfToken, privacyLevel = 'friends_only') {
try { try {
let payload; let payload;
if (mediaType === 'video') { if (mediaType === 'video') {
...@@ -260,7 +261,7 @@ function executeBulkPrivacyUpdateFromContext() { ...@@ -260,7 +261,7 @@ function executeBulkPrivacyUpdateFromContext() {
video: { video: {
title: "", title: "",
description: "", description: "",
only_friends: true, only_friends: privacyLevel === 'friends_only' ? true : false,
tag_names: [], tag_names: [],
user_tag_ids: [] user_tag_ids: []
}, },
...@@ -270,7 +271,7 @@ function executeBulkPrivacyUpdateFromContext() { ...@@ -270,7 +271,7 @@ function executeBulkPrivacyUpdateFromContext() {
payload = { payload = {
picture: { picture: {
caption: "", caption: "",
content_privacy: "only_friends", content_privacy: privacyLevel === 'friends_only' ? "only_friends" : "public",
tag_names: [], tag_names: [],
user_tag_ids: [] user_tag_ids: []
}, },
...@@ -354,7 +355,7 @@ function executeBulkPrivacyUpdateFromContext() { ...@@ -354,7 +355,7 @@ function executeBulkPrivacyUpdateFromContext() {
// Process all media items on current page // Process all media items on current page
for (const item of mediaItems) { for (const item of mediaItems) {
try { try {
const result = await updateMediaPrivacyById(item.type, item.id, csrfToken); const result = await updateMediaPrivacyById(item.type, item.id, csrfToken, 'friends_only');
if (result.success) { if (result.success) {
successCount++; successCount++;
} else { } else {
......
...@@ -96,9 +96,9 @@ ...@@ -96,9 +96,9 @@
} }
// Main function to execute privacy update via XHR // Main function to execute privacy update via XHR
async function executePrivacyUpdate() { async function executePrivacyUpdate(privacyLevel = 'friends_only') {
try { try {
console.log('Starting XHR-based privacy update...'); console.log('Starting XHR-based privacy update with privacy level:', privacyLevel);
// Step 1: Detect media type and ID from URL // Step 1: Detect media type and ID from URL
const mediaInfo = getMediaInfo(); const mediaInfo = getMediaInfo();
...@@ -117,14 +117,14 @@ ...@@ -117,14 +117,14 @@
// Step 3: Get current media data to preserve existing values // Step 3: Get current media data to preserve existing values
const currentData = await getCurrentMediaData(mediaInfo.type, mediaInfo.id); const currentData = await getCurrentMediaData(mediaInfo.type, mediaInfo.id);
// Step 4: Prepare payload based on media type // Step 4: Prepare payload based on media type and privacy level
let payload; let payload;
if (mediaInfo.type === 'video') { if (mediaInfo.type === 'video') {
payload = { payload = {
video: { video: {
title: currentData.title, title: currentData.title,
description: currentData.description, description: currentData.description,
only_friends: true, only_friends: privacyLevel === 'friends_only' ? true : false,
tag_names: currentData.tag_names, tag_names: currentData.tag_names,
user_tag_ids: currentData.user_tag_ids user_tag_ids: currentData.user_tag_ids
}, },
...@@ -134,7 +134,7 @@ ...@@ -134,7 +134,7 @@
payload = { payload = {
picture: { picture: {
caption: currentData.caption, caption: currentData.caption,
content_privacy: "only_friends", content_privacy: privacyLevel === 'friends_only' ? "only_friends" : "public",
tag_names: currentData.tag_names, tag_names: currentData.tag_names,
user_tag_ids: currentData.user_tag_ids user_tag_ids: currentData.user_tag_ids
}, },
......
...@@ -84,6 +84,15 @@ ...@@ -84,6 +84,15 @@
</head> </head>
<body> <body>
<div class="header">FetLife Privacy Helper</div> <div class="header">FetLife Privacy Helper</div>
<div style="margin-bottom: 10px; text-align: center;">
<label for="privacy-select" style="font-size: 12px; color: #666; margin-right: 5px;">Privacy Level:</label>
<select id="privacy-select" style="padding: 3px 6px; border: 1px solid #ccc; border-radius: 3px; font-size: 12px; background-color: white;">
<option value="friends_only">👥 Friends Only</option>
<option value="all_fetlifers">🌐 All Fetlifers</option>
</select>
</div>
<button id="privaxy-btn" class="privaxy-btn">Privaxy</button> <button id="privaxy-btn" class="privaxy-btn">Privaxy</button>
<button id="run-all-btn" class="privaxy-btn" style="background-color: #2196F3; margin-top: 5px;">Run on All Media</button> <button id="run-all-btn" class="privaxy-btn" style="background-color: #2196F3; margin-top: 5px;">Run on All Media</button>
<button id="stop-btn" class="privaxy-btn" style="background-color: #f44336; margin-top: 5px; display: none;">Stop</button> <button id="stop-btn" class="privaxy-btn" style="background-color: #f44336; margin-top: 5px; display: none;">Stop</button>
......
...@@ -134,12 +134,17 @@ document.addEventListener('DOMContentLoaded', function() { ...@@ -134,12 +134,17 @@ document.addEventListener('DOMContentLoaded', function() {
return; return;
} }
// Get selected privacy level
const privacySelect = document.getElementById('privacy-select');
const privacyLevel = privacySelect.value;
showStatus('Executing privacy update...', 'info'); showStatus('Executing privacy update...', 'info');
// Execute the content script function // Execute the content script function with privacy level
const results = await chrome.scripting.executeScript({ const results = await chrome.scripting.executeScript({
target: { tabId: tab.id }, target: { tabId: tab.id },
function: executePrivacyUpdate function: (privacyLevel) => executePrivacyUpdate(privacyLevel),
args: [privacyLevel]
}); });
const result = results[0].result; const result = results[0].result;
...@@ -186,10 +191,15 @@ document.addEventListener('DOMContentLoaded', function() { ...@@ -186,10 +191,15 @@ document.addEventListener('DOMContentLoaded', function() {
showProgress(`Processing page ${pageCount}... (${successCount} success, ${errorCount} errors)`); showProgress(`Processing page ${pageCount}... (${successCount} success, ${errorCount} errors)`);
try { try {
// Execute privacy update on current page // Get selected privacy level
const privacySelect = document.getElementById('privacy-select');
const privacyLevel = privacySelect.value;
// Execute privacy update on current page with privacy level
const results = await chrome.scripting.executeScript({ const results = await chrome.scripting.executeScript({
target: { tabId: tab.id }, target: { tabId: tab.id },
function: executePrivacyUpdate function: (privacyLevel) => executePrivacyUpdate(privacyLevel),
args: [privacyLevel]
}); });
const result = results[0].result; const result = results[0].result;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment