Created
November 25, 2016 19:26
-
-
Save koteq/c311e60a38224c3863fc9d4dc3cf69d3 to your computer and use it in GitHub Desktop.
Parses friends of your friends and show you links profiles with people you may know. Usage: open your friends page, open dev tools, copypaste the script to console, press enter and wait. You may watch the downloading process on networks tab.
This file contains hidden or 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
const DEPTH = 2; // 1 is usless, 3 is insane | |
const PROFILE_RE = /profile\/(.*?)(?:\/|$)/; | |
const SELF_PROFILE_RE = /profile\/(.*?)\/friends/; | |
const PROFILE_URL = 'https://myanimelist.net/profile/{profile}'; | |
const FRIENDS_URL = 'https://myanimelist.net/profile/{profile}/friends'; | |
function promiseWhile(condition, action) { | |
return new Promise((resolve, reject) => { | |
function loop() { | |
if (!condition()) { | |
return resolve(); | |
} | |
action().then(loop).catch(reject); | |
} | |
setTimeout(loop, 0); | |
}); | |
} | |
const reduce = Function.bind.call(Function.call, Array.prototype.reduce); | |
const isEnumerable = Function.bind.call(Function.call, Object.prototype.propertyIsEnumerable); | |
const concat = Function.bind.call(Function.call, Array.prototype.concat); | |
const keys = Reflect.ownKeys; | |
if (!Object.values) { | |
Object.values = function values(O) { | |
return reduce(keys(O), (v, k) => concat(v, typeof k === 'string' && isEnumerable(O, k) ? [O[k]] : []), []); | |
}; | |
} | |
if (!Object.entries) { | |
Object.entries = function entries(O) { | |
return reduce(keys(O), (e, k) => concat(e, typeof k === 'string' && isEnumerable(O, k) ? [[k, O[k]]] : []), []); | |
}; | |
} | |
new(class { | |
constructor() { | |
const self = (window.location.toString().match(SELF_PROFILE_RE) || [null, null])[1]; | |
if (self === null) { | |
throw 'You have to run this script from friends page of someones profile.'; | |
} | |
this.skip = [self]; | |
this.myFriends = this.parseFriends(document); | |
this.friends = this.myFriends; | |
// this.friends = this.friends.slice(2, 4); // for debugging | |
this.friendsInCommon = {}; | |
let level = 0; | |
promiseWhile(() => level < DEPTH, () => { | |
const fetchPromises = []; | |
this.friends.forEach((friend) => { | |
if (this.skip.indexOf(friend) === -1) { | |
this.skip.push(friend); | |
const fetchPromise = fetch(FRIENDS_URL.replace('{profile}', friend)); | |
fetchPromises.push(Promise.all([fetchPromise.then(r => r.text()), friend])); | |
} | |
}); | |
return Promise.all(fetchPromises) | |
.then((data) => { | |
level += 1; | |
data.forEach(([responseText, friend]) => { | |
const parser = new DOMParser(); | |
const dom = parser.parseFromString(responseText, 'text/html'); | |
const friends = this.parseFriends(dom); | |
this.friends = this.friends.concat(friends); | |
this.friendsInCommon[friend] = this.getCommonFriendsCount(friends); | |
}); | |
}); | |
}).then(() => { | |
const sortedFriendsInCommon = Object.entries(this.friendsInCommon).sort((a, b) => a[1] - b[1]); | |
sortedFriendsInCommon.forEach(([friend, friendsInCommon]) => { | |
if (this.myFriends.indexOf(friend) === -1) { | |
const profileUrl = PROFILE_URL.replace('{profile}', friend); | |
console.log(`${friendsInCommon}\t${profileUrl}`); | |
} | |
}); | |
}); | |
} | |
parseFriends(dom) { | |
const friends = []; | |
dom.querySelectorAll('.friendHolder .friendBlock .friendIcon a[href*="profile/"]') | |
.forEach((el) => { | |
const friend = el.href.match(PROFILE_RE)[1]; | |
friends.push(friend); | |
}); | |
return friends; | |
} | |
getCommonFriendsCount(friends) { | |
let commonFriends = 0; | |
friends.forEach((friend) => { | |
if (this.myFriends.indexOf(friend) !== -1) { | |
commonFriends += 1; | |
} | |
}); | |
return commonFriends; | |
} | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment