Skip to content

Instantly share code, notes, and snippets.

@nakasyou
Created June 14, 2024 06:00
Show Gist options
  • Save nakasyou/2456b1a50dc99b2b8264ed25c18405e0 to your computer and use it in GitHub Desktop.
Save nakasyou/2456b1a50dc99b2b8264ed25c18405e0 to your computer and use it in GitHub Desktop.
var last_id = "8999999999999999999";
init = () => {
let path = location.pathname.split("/"),
pathlist = ["home", "explore", "search", "notifications", "messages", "i"];
if (path.length != 2 || pathlist.includes(path[1])) {
alert("ユーザーのページを開いてください");
return;
}
screen_name = path[1];
document.cookie.split("; ").forEach(a => {
let b = a.split('=');
if (b[0] == "ct0") window.ct0 = b[1]
});
last_id = "8999999999999999999";
show_log()
}
setxhr = (a) => {
let _ = (b, c) => a.setRequestHeader(b, c);
_('Authorization', 'Bearer AAAAAAAAAAAAAAAAAAAAAFQODgEAAAAAVHTp76lzh3rFzcHbmHVvQxYYpTw%3DckAlMINMjmCwxUcaXbAN4XqJVdgMJaHqNOFgPMK0zN1qLqLQCF');
_('x-csrf-token', ct0);
a.withCredentials = !0
};
formatDate = (d) => {
let date = new Date(d);
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
const hours = String(date.getHours()).padStart(2, '0');
const minutes = String(date.getMinutes()).padStart(2, '0');
return `${year}/${month}/${day} ${hours}:${minutes}`;
}
get_tweet = () => {
document.querySelectorAll('.button.ok')[0].disabled = true;
let a = new XMLHttpRequest();
a.open('GET', `https://api.x.com/1.1/favorites/list.json?count=40&screen_name=${screen_name}&max_id=${last_id}`);
setxhr(a);
a.onreadystatechange = () => {
if (a.readyState == 4) {
if (a.status == 200) {
let res = JSON.parse(a.responseText),
body = document.getElementById("body2");
for (let j = 0; j < res.length; j++) {
let str = `
<div class="tweet">
<div class="tweet-header">
<img src="${res[j].user.profile_image_url_https}" alt="プロフィール画像">
<div>
<span class="name">${res[j].user.name}</span>
<span class="handle">@${res[j].user.screen_name}</span>
</div>
</div>
<div class="tweet-content">
${res[j].text}
</div>
<div class="tweet-footer">
<div><i class="fa fa-retweet"></i> 🔁 ${res[j].retweet_count}</div>
<div><i class="fa fa-heart"></i> ♡ ${res[j].favorite_count}</div>
</div>
<div class="tweet-footer">
<div class="date">${formatDate(res[j].created_at)}</div>
<a href="https://x.com/X/status/${res[j].id_str}" class="link" target="_blank">ツイートを見る</a>
</div>
</div>`
body.innerHTML += str;
last_id = (BigInt(res[j].id_str) - BigInt(1)).toString();
}
document.querySelectorAll('.button.ok')[0].disabled = false;
} else {
document.querySelectorAll('.button.ok')[0].innerText = "API制限です";
}
}
};
a.send()
};
show_log = () => {
let styleTag = document.createElement('style');
styleTag.innerHTML = `
.dialog {
width: 95%;
height: 90vh;
max-height: 90%;
border: none;
border-radius: 4px;
box-shadow: 0 0 24px 4px rgba(0, 0, 0, 0.4);
padding: 0;
font-family: "Segoe UI",Meiryo,system-ui,-apple-system,BlinkMacSystemFont,sans-serif;
font-weight: bold;
color: black !important;
background-color: #fff;
}
.dialog::backdrop {
background-color: rgba(0, 0, 0, 0.4);
}
.inner {
height: 100%;
}
.body {
text-align: center;
}
.dialog .footer {
background-color: #fff;
text-align: center;
margin: 0;
padding: 1em;
position: sticky;
bottom: 0;
}
.dialog .button {
width: 8em;
height: 2.4em;
border: none;
border-radius: 4px;
font-size: smaller;
font-weight: bold;
color: black !important;
}
.dialog .button.cancel {
background-color: #e6eae6;
}
.dialog .button.ok {
background-color: #0075c2;
color: #fff !important;
}
.dialog .button:hover {
opacity: 0.8;
}
.dialog[open],
.dialog[open]::backdrop {
animation: fadeIn 200ms ease normal;
}
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
.dialog.hide,
.dialog.hide::backdrop {
animation: fadeOut 200ms ease normal;
}
@keyframes fadeOut {
to {
opacity: 0;
}
}
.tweet {
background-color: #fff;
border: 1px solid #e1e8ed;
border-radius: 8px;
padding: 16px;
margin: 16px;
text-align: left;
}
.tweet-header {
display: flex;
align-items: center;
}
.tweet-header img {
border-radius: 50%;
width: 48px;
height: 48px;
margin-right: 10px;
}
.tweet-header .name {
font-weight: bold;
}
.tweet-header .handle {
color: #657786;
margin-left: 8px;
}
.tweet-content {
margin: 20px 0;
}
.tweet-footer {
display: flex;
justify-content: space-around;
color: #657786;
}
.tweet-footer div {
display: flex;
align-items: center;
}
.tweet-footer div i {
margin-right: 5px;
}
.tweet-footer .date {
margin-left: auto;
}
.tweet-footer .link {
margin-left: 10px;
color: #1da1f2;
text-decoration: none;
}
.tweet-footer .link:hover {
text-decoration: underline;
}
`;
document.head.insertAdjacentElement('beforeend', styleTag);
let dialogs = document.createElement('div');
dialogs.id = "dialogs";
dialogs.innerHTML = `
<dialog id="dialogFade" class="dialog">
<div class="inner">
<div class="body">
<div id="body2">
</div>
<button class="button ok">さらに読み込む</button></p>
</div>
<div class="footer">
<p><button class="button cancel">閉じる</button></p>
</div>
</div>
</dialog>
`;
document.body.appendChild(dialogs);
dialogFade.showModal();
function remove(name, flag) {
let dia = document.querySelector('#' + name);
dia.classList.add('hide');
dia.addEventListener('animationend', function closeDialog() {
document.body.classList.remove('inactive');
this.classList.remove('hide');
this.close();
this.removeEventListener('animationend', closeDialog);
if (flag) document.getElementById("dialogs").remove()
});
}
document.querySelectorAll('.button.cancel')[0].addEventListener('click', () => {
remove("dialogFade", true)
});
document.querySelectorAll('.button.ok')[0].addEventListener('click', () => {
get_tweet();
});
get_tweet()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment