Skip to content

Instantly share code, notes, and snippets.

@koteq
Created November 25, 2016 19:26
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 koteq/c311e60a38224c3863fc9d4dc3cf69d3 to your computer and use it in GitHub Desktop.
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.
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