-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathtools.js
143 lines (126 loc) · 3.72 KB
/
tools.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
// ==UserScript==
// @name Tools
// @namespace http://tampermonkey.net/
// @version 0.1
// @description Tools that I use to analyze sites
// @author cro
// @match *://*/*
// @grant GM_setValue
// @grant GM_getValue
// @require http://code.jquery.com/jquery-3.4.1.min.js
// @license MIT
// ==/UserScript==
'use strict';
let make_obj_prop_record = function(obj, prop, path)
{
let result = {};
result.path = Array.from(path);
result.parent = obj;
result.prop = prop;
result.value = obj[prop];
result.set = (new_val) => { result.value = obj[prop] = new_val; };
result.call = (...args) => obj[prop].apply(obj, args);
result.setcall = (new_val) => typeof obj[prop] == "function" ? result.call(new_val) : result.set(new_val)
return result;
};
let obj_search = function(root, matcher)
{
let visited = new WeakSet();
let found = [];
let path = [];
let search = function(obj)
{
let type = typeof obj;
if (!obj || type !== 'object') return;
if (visited.has(obj)) return;
visited.add(obj);
for (let prop in obj)
{
try
{
let val = obj[prop];
path.push(prop);
if (matcher(prop, val)) found.push(make_obj_prop_record(obj, prop, path));
search(val);
path.pop();
} catch(e) {}
}
};
let t = performance.now();
search(root);
console.log((performance.now() - t) / 1000);
return found;
};
let key_search = function(root, target, exact)
{
let expr = exact ? `^${target}` : target;
let regex = new RegExp(expr, "i");
return obj_search(root, (prop, val) => regex.test(prop));
};
let val_search = function(root, target)
{
return obj_search(root, (prop, val) => val == target);
};
let tw_key = "tw_followers";
let follower_collector = () =>
{
let get_instructions = obj => obj.data.user.result.timeline.timeline.instructions;
let get_entries = obj => get_instructions(obj).find(i => i.type == 'TimelineAddEntries').entries;
let get_legacy_data = entry => entry.content.itemContent.user_results.result.legacy;
let is_follower_item = item => item.content.entryType == "TimelineTimelineItem";
let make_minimal_record = (store, data) =>
{
if (data.followed_by)
{
store[data.screen_name] = [data.followers_count, data.following];
}
};
let store = GM_getValue(tw_key);
if (!store)
{
store = {};
}
let process_data = data =>
{
get_entries(data)
.filter(is_follower_item)
.map(get_legacy_data)
.forEach(data => make_minimal_record(store, data));
GM_setValue(tw_key, store);
};
const old_open = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function()
{
if (arguments[1].includes("/Followers"))
{
this.addEventListener('load', function()
{
try
{
process_data(JSON.parse(this.responseText));
}
catch (error)
{
console.error(error);
};
});
}
old_open.apply(this, arguments);
};
};
if (window.location.hostname == 'twitter.com')
{
follower_collector();
}
let get_store = function()
{
return GM_getValue(tw_key);
};
var lib =
{
obj_search : obj_search,
key_search : key_search,
val_search : val_search,
get_store : get_store,
};
unsafeWindow.crohelpers = lib;