-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcontent.js
More file actions
178 lines (155 loc) · 7.98 KB
/
content.js
File metadata and controls
178 lines (155 loc) · 7.98 KB
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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
if (request.action === 'exportFollowers') {
exportData('followers', sendResponse);
return true; // 非同期処理のためにtrueを返す
} else if (request.action === 'exportFollowing') {
exportData('following', sendResponse);
return true; // 非同期処理のためにtrueを返す
}
// もしどっちのアクションでもなかったら…
console.log('あれ?どっちのアクションでもないみたい…🤔', request.action);
sendResponse({ status: 'error', message: 'Unknown action.' }); // 一応レスポンス返しとく
return false; // 非同期処理じゃない場合はfalse
});
async function exportData(type, sendResponse) {
let data = [];
let listElement;
if (type === 'followers') {
// フォロワーリストのモーダルを開くトリガーをクリック
const followersLink = document.querySelector('a[href$="/followers/"]');
if (followersLink) {
followersLink.click();
await sleep(2000); // モーダルが開くのを待つ
} else {
console.error('フォロワーリンクが見つからないんだけど…😭');
sendResponse({ status: 'error', message: 'Could not find followers link. Please navigate to your profile page.' });
return;
}
// モーダル内のフォロワーリストの親要素を探す
// クラス名が変更される可能性が高いので、開発者ツールで要確認
const userListWrapper = document.querySelector('div[role="dialog"] div[style*="overflow: hidden auto"]');
if (userListWrapper && userListWrapper.parentElement) {
listElement = userListWrapper.parentElement;
const styles = window.getComputedStyle(listElement);
} else {
console.error('ユーザーリストのラッパーか、その親要素が見つかんないんだけど…😱 セレクタ再確認プリーズ!');
sendResponse({ status: 'error', message: 'Could not find the scrollable list element. Check selectors.' });
return;
}
} else if (type === 'following') {
// フォローリストのモーダルを開くトリガーをクリック
const followingLink = document.querySelector('a[href$="/following/"]');
if (followingLink) {
followingLink.click();
await sleep(2000); // モーダルが開くのを待つ
} else {
console.error('フォロー中リンクが見つからないんだけど…😭'); // ★デバッグログ
sendResponse({ status: 'error', message: 'Could not find following link. Please navigate to your profile page.' });
return;
}
// モーダル内のフォロー中リストの親要素を探す
// クラス名が変更される可能性が高いので、開発者ツールで要確認
const userListWrapper = document.querySelector('div[role="dialog"] div[style*="overflow: hidden auto"]');
if (userListWrapper && userListWrapper.parentElement) {
listElement = userListWrapper.parentElement;
const styles = window.getComputedStyle(listElement);
} else {
console.error('ユーザーリストのラッパーか、その親要素が見つかんないんだけど…😱 セレクタ再確認プリーズ!');
sendResponse({ status: 'error', message: 'Could not find the scrollable list element. Check selectors.' });
return;
}
}
// listElementがちゃんと取れてるかチェック!
if (!listElement) {
console.error('結局listElementが取れてないじゃん!😭 exportDataを中断するね…');
return;
}
// 無限スクロール処理
let previousHeight = 0;
let currentHeight = listElement.scrollHeight;
let scrollAttempts = 0; // スクロール試行回数をカウントする変数
const MAX_SCROLL_ATTEMPTS = 3; // スクロールしても高さが変わらない場合の最大試行回数
while (true) { // 基本的に無限ループにして、脱出条件を明確にする
previousHeight = listElement.scrollHeight; // スクロール前の高さを記憶
listElement.scrollTop = listElement.scrollHeight; // リストの一番下までスクロール
await sleep(2000); // 新しいコンテンツが読み込まれるのをしっかり待つ
currentHeight = listElement.scrollHeight; // スクロール後の高さを取得
if (currentHeight === previousHeight) {
scrollAttempts++; // 高さが変わらなかったら試行回数を増やす
console.log(`高さ変わんない…試行回数: ${scrollAttempts}`); // ★デバッグログ
if (scrollAttempts >= MAX_SCROLL_ATTEMPTS) {
console.log('最大試行回数に達したから、スクロール終わりにするね!🏁'); // ★デバッグログ
break; // もう読み込むものがなさそうなのでループを抜ける
}
// 念のため、さらに少し待ってから再度高さを確認する
await sleep(2000);
currentHeight = listElement.scrollHeight;
if (currentHeight === previousHeight) {
} else {
scrollAttempts = 0; // 高さが変わったらリセット
}
} else {
scrollAttempts = 0; // 高さが変わったらリセット
}
}
const userElements = listElement.querySelectorAll('div.x1dm5mii.x16mil14.xiojian.x1yutycm.x1lliihq.x193iq5w.xh8yej3');
userElements.forEach(element => {
let displayName = '';
let userId = '';
// ユーザーID (プロフィールID) を取得する
const userIdSpanElement = element.querySelector('a span._ap3a._aaco._aacw._aacx._aad7._aade');
if (userIdSpanElement) {
userId = userIdSpanElement.textContent.trim();
console.log('ユーザーID (プロフィールID) を見つけたよ!:', userId, userIdSpanElement);
} else {
console.warn('あれれ、ユーザーID (プロフィールID) が見つからなかった…😢', element);
}
const displayNameSpan = element.querySelector('span.x1lliihq.x193iq5w.x6ikm8r.x10wlt62.xlyipyv.xuxw1ft');
if (displayNameSpan && displayNameSpan.textContent.trim()) {
displayName = displayNameSpan.textContent.trim();
console.log('表示名を見つけたよ!:', displayName, displayNameSpan);
} else {
console.warn('うーん、指定したクラス名のspanが見つからないか、中身が空っぽだった…🤔', element);
}
if (displayName || userId) {
data.push({ username: displayName, userId: userId });
} else {
console.warn('結局、表示名もIDも見つからなかった…しょぼん(´・ω・`)', element);
}
});
if (data.length > 0) {
console.log('データあった!CSVダウンロードするね!😉', data); // ★デバッグログ
downloadCSV(data, `${type}_list.csv`);
sendResponse({ status: 'success' });
} else {
console.warn('あれ、データが空っぽだ…🤔'); // ★デバッグログ
sendResponse({ status: 'error', message: 'No data found.' });
}
}
// ヘルパー関数: 指定ミリ秒待機
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
// CSVダウンロード関数
function downloadCSV(data, filename) {
const csvRows = [];
const headers = Object.keys(data[0]); // ヘッダーとしてオブジェクトのキーを使用
csvRows.push(headers.join(',')); // ヘッダー行を追加
for (const row of data) {
const values = headers.map(header => {
const escaped = ('' + row[header]).replace(/"/g, '""'); // ダブルクォートをエスケープ
return `"${escaped}"`; // ダブルクォートで囲む
});
csvRows.push(values.join(','));
}
const csvString = csvRows.join('\n');
const blob = new Blob([csvString], { type: 'text/csv;charset=utf-8;' });
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.setAttribute('href', url);
link.setAttribute('download', filename);
link.style.visibility = 'hidden';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}