Twitter Detail Page Save to Notion

Extract images, tweets from Twitter detail page

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey, Greasemonkey или Violentmonkey.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey или Violentmonkey.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey или Violentmonkey.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey или Userscripts.

Чтобы установить этот скрипт, сначала вы должны установить расширение браузера, например Tampermonkey.

Чтобы установить этот скрипт, вы должны установить расширение — менеджер скриптов.

(у меня уже есть менеджер скриптов, дайте мне установить скрипт!)

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

(у меня уже есть менеджер стилей, дайте мне установить скрипт!)

// ==UserScript==
// @name         Twitter Detail Page Save to Notion
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  Extract images, tweets from Twitter detail page
// @author       CherryLover
// @match        https://twitter.com/*
// @grant        GM_xmlhttpRequest
// @grant        GM_setValue
// @grant        GM_getValue
// @license MIT
// ==/UserScript==

(function() {
	'use strict';

	function extractImages() {
		// const className = "css-175oi2r r-1pi2tsx r-13qz1uu r-eqz5dr";
		const className = 'css-175oi2r r-9aw3ui r-1s2bzr4';
		let images = [];
		let elements = document.getElementsByClassName(className);
		if (elements.length <= 0) {
			return images;
		}

		for (let i = 0; i < elements.length; i++) {
			const target = elements[i];
			// 查找所有属性:data-testid 为 "tweetPhoto" 的 div 元素
			let divElements = target.querySelectorAll('div[data-testid=\'tweetPhoto\']');
			console.log('find ' + divElements.length + ' divs');

			for (let j = 0; j < divElements.length; j++) {
				const innerDiv = divElements[j];
				let imgElements = innerDiv.querySelectorAll('img');
				console.log('find ' + imgElements.length + ' imgs');
				imgElements.forEach((img) => {
					let imgData = {
						src: img.src,
						alt: img.alt
					};
					let imgExist = images.find(element => element.src === imgData.src);
					if (!imgExist) {
						images.push(imgData);
					}
				});
			}

		}
		return images;
	}

	function getTwitterContent() {
		const className = 'css-175oi2r r-1s2bzr4';
		// 获取所有指定类的div元素
		let elements = document.getElementsByClassName(className);
		let text = '';

		// 遍历所有获取到的元素
		if (elements.length <= 0) {
			return text;
		}
		console.log('all element size ', elements.length);
		for (let i = 0; i < elements.length; i++) {
			// console.log("element ", i, " ", elements[i].innerText);
			let children = elements[i].childNodes;

			for (let j = 0; j < children.length; j++) {
				const attrDataTestId = children[j].getAttribute('data-testid');
				if (attrDataTestId === 'tweetText') {
					const tweetText = parseUrlAndText(children[j].childNodes);
					// const tweetText = children[j].innerText;
					console.log('tweet text', tweetText);
					text += tweetText;
				}
			}
		}
		return text;
	}

	function parseUrlAndText(elements) {
		let text = '';
		for (let i = 0; i < elements.length; i++) {
			const element = elements[i];
			if (element.nodeName === 'A') {
				text += element.href + '\n';
			} else {
				text += element.textContent;
			}
		}
		return text;
	}

	function showResults(token, databaseId) {
		let currentUrl = window.location.href;
		console.log('当前页面的URL是: ' + currentUrl);
		// 使用方法
		let allText = '';
		allText = getTwitterContent();
		const imgs = extractImages();

		const header = {
			'Content-Type': 'application/json',
			'Authorization': `Bearer ${token}`,
			'Notion-Version': '2022-02-22'
		};
		let finalText = allText + '\n\n';
		// for (var i = 0; i < imgs.length; i++) {
		// 	finalText += 'img: ' + imgs[i].src + '\n';
		// }
		console.log('token: ', token);
		console.log('databaseId: ', databaseId);

		// alert("Data has been sent to server");

		// title 为 finalText 的前 10 个字符
		let title = '';
		if (finalText.length > 10) {
			title = finalText.substring(0, 10);
		} else {
			title = finalText.replaceAll('\n', '');
			if (title.length === 0) {
				title = 'No title';
			}
		}

		const requestUrl = `https://api.notion.com/v1/pages/`;
		const body = {
			'parent': {
				'database_id': databaseId
			},
			'properties': {
				'Name': {
					'title': [
						{
							'text': {
								'content': title
							}
						}
					]
				},
				'original': {
					'url': currentUrl
				}
			},
			'children': [
				{
					'object': 'block',
					'type': 'paragraph',
					'paragraph': {
						'rich_text': [
							{
								'type': 'text',
								'text': {
									'content': finalText
								}
							}
						]
					}
				}
			]
		};

		imgs.forEach((img) => {
			// 向正文中添加图片 及 alt
			// body.properties.Content.text.push({
			// 	'image': {
			// 		'type': 'external',
			// 		'external': {
			// 			'url': img.src
			// 		}
			// 	}
			// });
			body.children.push({
				'object': 'block',
				'type': 'embed',
				'embed': {
					'caption': [
						{
							'type': 'text',
							'text': {
								'content': img.alt
							}
						}
					],
					'url': img.src
				}
			});
		});

		console.log('request body ' + JSON.stringify(body));
		GM_xmlhttpRequest({
			method: 'POST',
			url: requestUrl,
			headers: header,
			data: JSON.stringify(body),
			onload: function(response) {
				console.log('Response: ', response);
				alert('Data has been sent to server');
			},
			onerror: function(response) {
				console.log('Error: ', response);
				alert('Error: ' + response);
			}
		});

		// GM_xmlhttpRequest({
		//     method: "POST",
		//     url: `https://${domain}/api/v1/memo`,
		//     headers: header,
		//     data: JSON.stringify({
		//         content: finalText,
		//     }),
		//     onload: function(response) {
		//         console.log("Response: ", response);
		//         alert("Data has been sent to server");
		//     },
		//     onerror: function(response) {
		//         console.log("Error: ", response);
		//         alert("Error: " + response);
		//     }
		// });
	}

	// Create input for domain
	let databaseIdInput = document.createElement('input');
	databaseIdInput.placeholder = 'Database Id';
	databaseIdInput.style.position = 'fixed';
	databaseIdInput.style.bottom = '50px';
	databaseIdInput.style.left = '10px';
	databaseIdInput.style.zIndex = '9999';

// Create input for accessToken
	let tokenInput = document.createElement('input');
	tokenInput.placeholder = 'Integrations Secret';
	tokenInput.style.position = 'fixed';
	tokenInput.style.bottom = '30px';
	tokenInput.style.left = '10px';
	tokenInput.style.zIndex = '9999';

// Append inputs to body
	document.body.appendChild(databaseIdInput);
	document.body.appendChild(tokenInput);

	// Create button
	let button = document.createElement('button');
	button.textContent = '保存到 Notion';
	button.style.position = 'fixed';
	button.style.bottom = '10px';
	button.style.left = '10px';
	button.style.zIndex = '9999';
	button.onclick = function() {
		const currentUrl = window.location.href;
		// 判断当前页面是否是推特详情页
		if (!currentUrl.includes('status')) {
			alert('请进入具体推文详情页面后再点击');
			return;
		}
		let dbId = '';
		let token = '';
		if (databaseIdInput.style.display === 'block') {
			dbId = databaseIdInput.value;
		} else {
			dbId = GM_getValue('databaseId', '');
		}
		if (tokenInput.style.display === 'block') {
			token = tokenInput.value;
		} else {
			token = GM_getValue('accessToken', '');
		}
		if (!dbId || !token) {
			alert('请配置 Notion 数据库 ID 和 Integrations Secret');
			databaseIdInput.style.display = 'block';
			tokenInput.style.display = 'block';
			return;
		}
		GM_setValue('databaseId', dbId);
		GM_setValue('accessToken', token);
		databaseIdInput.style.display = 'none';
		tokenInput.style.display = 'none';
		showResults(token, dbId);
	};

	// Append button to body
	document.body.appendChild(button);

// Initially hide the inputs
	databaseIdInput.style.display = 'none';
	tokenInput.style.display = 'none';
	var settingShow = false;

	function toggleSettings() {
		settingShow = !settingShow;
		if (settingShow) {
			databaseIdInput.style.display = 'block';
			tokenInput.style.display = 'block';
			const cDatabaseId = GM_getValue('databaseId', '');
			const cToken = GM_getValue('accessToken', '');

			databaseIdInput.value = cDatabaseId;
			tokenInput.value = cToken;
			databaseIdInput.focus();
		} else {
			GM_setValue('databaseId', databaseIdInput.value);
			GM_setValue('accessToken', tokenInput.value);
			databaseIdInput.style.display = 'none';
			tokenInput.style.display = 'none';
		}
	}

	window.addEventListener('keydown', function(event) {
		if (event.key === 'F9') {
			toggleSettings();
		}
	});

})();