Created
December 24, 2017 13:42
-
-
Save gaeulbyul/2f28100c7286a471b17986a5445a83d8 to your computer and use it in GitHub Desktop.
체인블락
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* globals location, fetch, URLSearchParams $ */ | |
// some code taken from: | |
// https://github.com/satsukitv/twitter-block-chain | |
function sendBlockRequest (userId) { | |
const authenticityToken = $('#authenticity_token').val() | |
const requestBody = new URLSearchParams() | |
requestBody.append('authenticity_token', authenticityToken) | |
requestBody.append('challenges_passed', 'false') | |
requestBody.append('handles_challenges', '1') | |
requestBody.append('impression_id', '') | |
requestBody.append('user_id', userId) | |
// [1]: referrer | |
// Chrome에선 referrer속성 없이도 정상적으로 작동하지만 | |
// Firefox에서 그러면 referer 없이 요청을 보내서 403에러가 난다. | |
// 따라서 직접 명시하도록 했음. | |
const fetchOptions = { | |
method: 'POST', | |
mode: 'cors', | |
credentials: 'include', | |
referrer: location.href, // [1] | |
body: requestBody | |
} | |
return fetch('https://twitter.com/i/user/block', fetchOptions).then(response => { | |
if (response.ok) { | |
return response | |
} else { | |
console.dir(response) | |
throw new Error(response) | |
} | |
}) | |
} | |
function chainBlock (callbacks) { | |
/* | |
if (!window.confirm('[Mirror of Block]: Are you sure to chain-block?')) { | |
return | |
} | |
*/ | |
const targets = [] | |
const skipped = [] | |
let currentList = '' | |
if (/\/followers$/.test(location.pathname)) { | |
currentList = 'followers' | |
} else if (/\/followings$/.test(location.pathname)) { | |
currentList = 'followings' | |
} else { | |
throw new Error('unsupported page') | |
} | |
function scanner (data, callbacks) { | |
const {progressCallback, finalCallback} = callbacks | |
const cards = $(data.items_html).find('.ProfileCard') | |
Array.from(cards).forEach(card_ => { | |
const $card = $(card_) | |
const blocksYou = $card.find('.blocks-you').length > 0 | |
const actions = $($card.find('.user-actions')) | |
const userId = actions.data('user-id') | |
const userName = actions.data('screen-name') | |
const userNickName = $card.find('.fullname').text().trim() | |
const alreadyBlocked = $card.find('.blocked').length > 0 | |
const muted = $card.find('.muting').length > 0 | |
if (!blocksYou) { | |
return | |
} | |
if (alreadyBlocked) { | |
skipped.push({ | |
userId, | |
userName, | |
userNickName, | |
reason: 'already-blocked' | |
}) | |
} else if (muted) { | |
skipped.push({ | |
userId, | |
userName, | |
userNickName, | |
reason: 'muted' | |
}) | |
} else { | |
targets.push({userId, userName, userNickName}) | |
} | |
}) | |
if (data.has_more_items) { | |
const profileUsername = $('.ProfileHeaderCard .username b').text() | |
const moreUsersUrl = `https://twitter.com/${profileUsername}/${currentList}/users?include_available_features=1&include_entities=1&reset_error_state=false&max_position=${data.min_position}` | |
const fetchOptions = { | |
method: 'GET', | |
credentials: 'include', | |
referrer: location.href | |
} | |
fetch(moreUsersUrl, fetchOptions).then(async response => { | |
const json = await response.json() | |
progressCallback({targets, skipped}) | |
scanner(json, callbacks) | |
}) | |
} else if (typeof finalCallback === 'function') { | |
finalCallback({targets, skipped}) | |
} | |
} | |
const grid = $('.GridTimeline-items') | |
scanner({ | |
items_html: grid.html(), | |
min_position: grid.data('min-position'), | |
has_more_items: true | |
}, callbacks) | |
} | |
function doChainBlock () { | |
chainBlock({ | |
progressCallback ({targets, skipped}) { | |
console.group('체인블락 중간 보고:') | |
console.log('타겟 %d명, 스킵 %d명', targets.length, skipped.length) | |
console.groupEnd() | |
}, | |
finalCallback ({targets, skipped}) { | |
console.group('체인블락 결과 보고:') | |
console.log('타겟 %d명, 스킵 %d명', targets.length, skipped.length) | |
console.dir({targets, skipped}) | |
console.groupEnd() | |
for (const user of targets) { | |
const {userId} = user | |
sendBlockRequest(userId) | |
} | |
} | |
}) | |
} | |
doChainBlock() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment