Skip to content

Instantly share code, notes, and snippets.

@gerwld
Last active January 7, 2025 10:41
Show Gist options
  • Save gerwld/3151df0117b8450566257e3191c44f5c to your computer and use it in GitHub Desktop.
Save gerwld/3151df0117b8450566257e3191c44f5c to your computer and use it in GitHub Desktop.
/**
* This script automates the process of unblocking your own blocked Instagram users list.
* It unblocks users one-by-one to avoid hitting rate limits or breaking the page.
*
* WARNING: This function directly manipulates the DOM and depends on the current HTML
* structure of Instagram's website to work. If Instagram implements changes to the
* activity page layout, structure, or functionality, this script may break or cause
* unexpected behavior. Use at your own risk and always review code before running it.
**/
(async function () {
const DELETION_BATCH_SIZE = 100;
const DELAY_BETWEEN_ACTIONS_MS = 1100;
const DELAY_BETWEEN_CHECKBOX_CLICKS_MS = 890;
const CONFIRMATION_TIMEOUT_MS = 5000;
const DOM_UPDATE_TIMEOUT_MS = 10000;
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
const waitForElement = async (selector, timeout = 30000) => {
const startTime = Date.now();
while (Date.now() - startTime < timeout) {
const element = document.querySelector(selector);
if (element) return element;
await delay(100);
}
throw new Error(`Element with selector "${selector}" not found within ${timeout}ms`);
};
const clickElement = async (element) => {
if (!element) throw new Error('Element not found');
element.click();
};
const waitForUpdatedCheckboxes = async (selector, timeout = DOM_UPDATE_TIMEOUT_MS) => {
const startTime = Date.now();
while (Date.now() - startTime < timeout) {
const checkboxes = document.querySelectorAll(selector);
if (checkboxes.length > 0) return checkboxes;
console.log('Waiting for checkboxes to update...');
await delay(500);
}
throw new Error('Checkboxes did not update in time.');
};
const deleteActivity = async () => {
try {
while (true) {
console.log("Looking for 'Unblock' checkboxes...");
let checkboxes = await waitForUpdatedCheckboxes('[aria-label="Unblock"]');
if (checkboxes.length === 0) {
console.log('No more items to unblock.');
break;
}
for (let i = 0; i < Math.min(DELETION_BATCH_SIZE, checkboxes.length); i++) {
try {
// Gets all checkboxes one more time, as Instagram fetches all of them & updates the DOM on each operation.
checkboxes = document.querySelectorAll('[aria-label="Unblock"]');
const checkbox = checkboxes[i];
if (!checkbox) {
console.log(`Checkbox ${i + 1} disappeared, refreshing the list...`);
continue; // Skipping operation if checkbox dissapear
}
console.log(`Clicking checkbox ${i + 1} of ${checkboxes.length}...`);
await clickElement(checkbox);
await delay(DELAY_BETWEEN_CHECKBOX_CLICKS_MS);
console.log('Waiting for confirmation button...');
const confirmButton = await waitForElement('._a9--._ap36._a9_1', CONFIRMATION_TIMEOUT_MS);
console.log('Clicking confirm button...');
await clickElement(confirmButton);
await delay(DELAY_BETWEEN_ACTIONS_MS);
console.log('Successfully unblocked.');
} catch (error) {
console.error(`Error processing checkbox ${i + 1}:`, error.message);
}
}
console.log('Waiting for DOM update after batch operation...');
checkboxes = await waitForUpdatedCheckboxes('[aria-label="Unblock"]', DOM_UPDATE_TIMEOUT_MS);
if (checkboxes.length === 0) {
console.log('No more items to unblock.');
break;
}
}
} catch (error) {
console.error('Error in deleteActivity:', error.message);
}
};
try {
console.log('Starting unblock process...');
await deleteActivity();
console.log('Unblock process completed.');
} catch (error) {
console.error('Fatal error:', error.message);
}
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment