Skip to content

Instantly share code, notes, and snippets.

@pocesar
Last active August 11, 2018 12:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pocesar/4f51298da5698886e0c58997c4b101fe to your computer and use it in GitHub Desktop.
Save pocesar/4f51298da5698886e0c58997c4b101fe to your computer and use it in GitHub Desktop.
Javascript: delete all facebook posts from activity log
// go to https://www.facebook.com/your_page_or_profile_name/allactivity?privacy_source=activity_log&log_filter=all
// load the maximum number of items you can before
// then open up the console and execute this code
// will take care of errors, successes and timeouts. it looks like a really proficient human clicking stuff
// it's messy and might break at any time, made for English version, but it's working as of august 2018
(async function f() {
'use strict'
// simple exponential backoff reusable helper
const backoff = () => {
let count = 0
return () => (Math.pow(2, count++))
}
const clickAll = (set) => set.forEach((s) => s['click']())
const race = (promises) => (new Promise((resolve) => promises.forEach((promise) => promise.then(resolve))))
// wait some miliseconds
const waiter = (time) => (new Promise((resolve) => (setTimeout(resolve, time))))
// common wrapper for tasks that should expire after some tries
const backoffPromise = (predicate, label = 'timeout', times = 10) => (new Promise((resolve, reject) => {
const b = backoff()
setTimeout(function retry() {
if (!times--) {
return reject(new Error(label))
}
const result = predicate()
if (result) {
return resolve(result)
}
setTimeout(retry, b())
}, 0)
}))
// wait for element to disappear (usually on modal). throws if times out, returns true
const waitForClose = (selector) => (backoffPromise(() => {
const element = document.querySelectorAll(selector)
return element && element.length > 0
}, selector, 5))
// wait for element (usually on modal). throws if times out, returns elements found
const waitForAvailability = (selector, text, times = 12, label = selector) => (backoffPromise(() => {
const elements = document.querySelectorAll(selector)
if (!elements || elements.length === 0) return false
let out = []
for (let element of elements) {
if (element) {
if (text === null || element['innerText'] === text) {
out.push(element)
}
}
}
return out
}, label, times))
const delBtn = '.layerConfirm.uiOverlayButton' // Delete button
const closeModal = 'form .layerCancel.uiOverlayButton' // Cancel / Delete modal
const cancelBtn = '._1yv .layerCancel' // error / failed modal
const menuBtn = 'a._42ft._42fu._4-s1._2agf._4o_4._p._42gx'
const actionsBtns = 'a._54nc'
const dialog = '._1yv[role="dialog"]'
let lastCount = 0
console.log('triggering menus')
for (let menu of document.querySelectorAll(menuBtn)) {
if (!menu.querySelector('.sp_In7zzQ3ECOk.sx_042959')) { // hidden from timeline class
menu['click']()
await backoffPromise(() => {
const last = document.querySelectorAll(actionsBtns).length
if (last > lastCount) { return true }
lastCount = last
return false
})
}
}
console.log('done triggering menus, will try to act')
const actions = document.querySelectorAll(actionsBtns) // actions
for (let action of actions) {
if (action['innerText'] === 'Hidden from Page' || action['innerText'] === 'Remove Reaction') {
action['click']()
try {
if ((await waitForAvailability(dialog, null)).length) {
const close = await race([
waitForAvailability(cancelBtn, 'Close', 3),
waitForAvailability(closeModal, 'Close', 3),
waitForAvailability(closeModal, 'Cancel', 3),
waitForAvailability(cancelBtn, 'Cancel', 3)
])
clickAll(close)
await waitForClose(dialog)
}
} catch (e) { }
}
if (action['innerText'] === 'Delete') {
action['click']()
try {
const del = await waitForAvailability(delBtn, 'Delete')
// modal is opened
clickAll(del)
// wait for result
try {
const close = await waitForAvailability(cancelBtn, 'Close', 5)
// seems an error happened, close the modal
clickAll(close)
const cancel = await waitForAvailability(closeModal, 'Cancel', 2)
// close current modal that errored out
clickAll(cancel)
} catch (e) {
if (e.message !== closeModal) {
const cancel = await waitForAvailability(closeModal, 'Cancel', 2)
clickAll(cancel)
}
// no error happened, let's wait for the modal to close
await race([
waitForClose(dialog),
waitForClose(closeModal),
])
}
} catch (e) {
// modal didn't close, last brute force try
try {
const close = await race([
waitForAvailability(cancelBtn, 'Close', 5),
waitForAvailability(closeModal, 'Close', 5),
waitForAvailability(closeModal, 'Cancel', 5),
waitForAvailability(cancelBtn, 'Cancel', 5)
])
clickAll(close)
await waitForClose(dialog)
} catch (e) {
console.log(e)
}
}
}
await waiter(500) // throttle requests, Facebook doesn't like too much, too fast
}
alert('done?')
})()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment