Browse Source

add denetwebview

jihuaqiang 2 years ago
parent
commit
309ce8805f

+ 36 - 0
src/components/webview.tsx

@@ -0,0 +1,36 @@
+/**
+ * 通用 webview 封装
+ */
+import React from 'react';
+import { WebView } from 'react-native-webview';
+
+interface Props {
+	uri: any;
+	onLoadEndHandle: () => void;
+	handleWebViewNavigationStateChange: (newNavState: { url: any }) => void;
+	onMessageHandle: (e: any) => void;
+	refHandle: (r: any) => any;
+}
+export const DenetWebview = (props: Props) => {
+	return (
+		<WebView
+			applicationNameForUserAgent={'denet/1.1.0'}
+			mediaCapturePermissionGrantType={'grant'}
+			setSupportMultipleWindows={false}
+			javaScriptEnabled={true}
+			startInLoadingState={true}
+			originWhitelist={['*']}
+			cacheEnabled={false}
+			javaScriptCanOpenWindowsAutomatically={true}
+			allowUniversalAccessFromFileURLs={true}
+			allowFileAccessFromFileURLs={true}
+			onLoadEnd={props.onLoadEndHandle}
+			ref={props.refHandle}
+			onMessage={props.onMessageHandle}
+			onNavigationStateChange={props.handleWebViewNavigationStateChange}
+			source={{
+				uri: props.uri,
+			}}
+		/>
+	);
+};

+ 10 - 20
src/pages/screens/twitter.tsx

@@ -1,8 +1,8 @@
 /* eslint-disable react-native/no-inline-styles */
 import React, { Component } from 'react';
 import { View, Text, DeviceEventEmitter } from 'react-native';
-import { WebView } from 'react-native-webview';
-import { addDom } from '../../utils/addDom';
+import { DenetWebview } from '@/components/webview';
+import { addDom } from '../../utils/contentInTwitterJS/addDom';
 // import EventEmitter from 'react-native-eventemitter';
 
 interface Props {
@@ -11,6 +11,7 @@ interface Props {
 class Twitter extends Component<Props> {
 	webref: any;
 	packUrl: any;
+
 	openRedpack = (props: any) => {
 		console.log(props.nativeEvent.data);
 		const { tweet_Id, ct0 } = JSON.parse(props.nativeEvent.data);
@@ -43,7 +44,7 @@ class Twitter extends Component<Props> {
     `);
 	};
 
-	componentDidMount() {
+	async componentDidMount() {
 		DeviceEventEmitter.addListener('FavoriteTweet', (data: any) => {
 			this.FavoriteTweet(data);
 		});
@@ -53,25 +54,14 @@ class Twitter extends Component<Props> {
 		return (
 			<View style={{ flex: 1 }}>
 				<Text>{this.packUrl}</Text>
-				<WebView
-					mediaCapturePermissionGrantType={'grant'}
-					setSupportMultipleWindows={false}
-					javaScriptEnabled={true}
-					startInLoadingState={true}
-					originWhitelist={['*']}
-					cacheEnabled={false}
-					javaScriptCanOpenWindowsAutomatically={true}
-					allowUniversalAccessFromFileURLs={true}
-					allowFileAccessFromFileURLs={true}
-					onLoadEnd={this.injectJavaScript}
-					ref={r => (this.webref = r)}
-					onMessage={this.openRedpack}
-					onNavigationStateChange={
+				<DenetWebview
+					onLoadEndHandle={this.injectJavaScript}
+					refHandle={r => (this.webref = r)}
+					onMessageHandle={this.openRedpack}
+					handleWebViewNavigationStateChange={
 						this.handleWebViewNavigationStateChange
 					}
-					source={{
-						uri: 'https://mobile.twitter.com/home',
-					}}
+					uri="https://mobile.twitter.com/home"
 				/>
 			</View>
 		);

+ 247 - 0
src/utils/contentInTwitterJS/ParseCard.js

@@ -0,0 +1,247 @@
+/* eslint-disable no-undef */
+import { guid } from '@/utils/';
+import { getStorageData, setStorageData } from '@/storage/index';
+
+// import { chromeExtensionUrl } from '@/uilts/chromeExtension';
+const chromeExtensionUrl = '';
+// 解析卡片类
+// 1.dom匹配
+// 2.找出网页匹配 获取twitterid
+// 3.获取短链接postid
+// 4.渲染iframe twitterid
+// 5.获取红包状态页面
+// 6.查询twitterid状态
+// 7.绑定twitterid
+
+export const compatibleMask = article => {
+	let has_denet = false;
+	try {
+		let arr_span = article.querySelectorAll('span') || [];
+		let arr_shadow = [];
+		arr_span.forEach(item => {
+			if (item.shadowRoot) {
+				arr_shadow.push(item.shadowRoot);
+			}
+		});
+		let item;
+		for (let i in arr_shadow) {
+			item = arr_shadow[i].childNodes;
+			if (has_denet) {
+				break;
+			}
+			if (item) {
+				for (let j in item) {
+					if (
+						item[j].innerText &&
+						(item[j].innerText.includes('#DeNet') ||
+							item[j].innerText.includes('#DNFT'))
+					) {
+						has_denet = true;
+						break;
+					}
+				}
+			}
+		}
+	} catch (error) {}
+	// 是否有#DeNet
+	return has_denet;
+};
+
+export const parseAllDeNetCardParmas = (has_iframe = false) => {
+	let json_data = [];
+	parseAllDeNetCard(has_iframe).forEach(item => {
+		let _obj = parseCardParmas(item.dom);
+		if (_obj && _obj.tweet_Id && _obj.short_url && _obj.dom_card) {
+			_obj.time = item.time;
+			json_data.push(_obj);
+		}
+	});
+	return json_data;
+};
+
+export const parseAllDeNetCard = (has_iframe = false) => {
+	let de_net_card = [];
+	try {
+		let arr_article = document.querySelectorAll('article') || [];
+		let _txt;
+		for (let i in arr_article) {
+			_txt = arr_article[i].innerText || '';
+			if (has_iframe) {
+				if (
+					_txt.includes('#DeNet') ||
+					_txt.includes('#DNFT') ||
+					compatibleMask(arr_article[i])
+				) {
+					de_net_card.push({
+						time: new Date().getTime(),
+						dom: arr_article[i],
+					});
+				}
+			} else {
+				if (
+					(_txt.includes('#DeNet') ||
+						_txt.includes('#DNFT') ||
+						compatibleMask(arr_article[i])) &&
+					!isHasIframeByArticle(arr_article[i])
+				) {
+					de_net_card.push({
+						time: new Date().getTime(),
+						dom: arr_article[i],
+					});
+				}
+			}
+		}
+	} catch (error) {}
+	return de_net_card;
+};
+
+export const parseCardParmas = dom_card => {
+	let tweet_Id = '';
+	let short_url = '';
+	let a_arr = dom_card.querySelectorAll('a') || [];
+	a_arr = Array.from(a_arr).reverse();
+	for (let i in a_arr) {
+		// 获取推特id
+		if (
+			a_arr[i].href &&
+			a_arr[i].href.indexOf('/status/') > 0 &&
+			!tweet_Id
+		) {
+			tweet_Id = a_arr[i].href.split('/status/')[1] || '';
+			tweet_Id = tweet_Id.split('/')[0];
+		}
+		if (
+			a_arr[i].href &&
+			a_arr[i].href.includes('https://t.co') &&
+			!short_url
+		) {
+			short_url = a_arr[i].href;
+		}
+		if (tweet_Id && short_url) {
+			break;
+		}
+	}
+	return { tweet_Id, short_url, dom_card };
+};
+
+export const isHasIframeByArticle = dom_card => {
+	if (!dom_card || !dom_card.parentElement) {
+		return;
+	}
+	if (dom_card.querySelector('iframe')) {
+		let type = 'parnet';
+		let dom = dom_card.querySelector('div[aria-labelledby]');
+		if (dom) {
+			type = 'card';
+		} else {
+			type = 'txt';
+			dom = dom_card.querySelector('div[lang][dir=auto]').parentElement;
+		}
+
+		if (type == 'card') {
+			let _iframe = dom.querySelectorAll('iframe') || [];
+			if (_iframe.length == 0) {
+				dom.style.display = 'none';
+			}
+
+			if (_iframe.length == 1) {
+				for (let i = 0; i < dom.childNodes.length; i++) {
+					if (
+						dom.childNodes[i].dataset &&
+						dom.childNodes[i].dataset.testid &&
+						dom.childNodes[i].dataset.testid == 'card.wrapper'
+					) {
+						dom.children[i].style.display = 'none';
+					}
+				}
+			}
+			if (_iframe.length > 1) {
+				for (let i = 0; i < _iframe.length; i++) {
+					if (i > 0) {
+						_iframe[i].remove();
+					}
+				}
+			}
+		} else {
+			let arr_iframe =
+				dom.closest('article').querySelectorAll('iframe') || [];
+			if (arr_iframe.length > 1) {
+				for (let i = 0; i < arr_iframe.length; i++) {
+					if (i > 0) {
+						arr_iframe[i].remove();
+					}
+				}
+			}
+		}
+		return true;
+	}
+	return false;
+};
+
+export const getLocalHasPostIdData = (
+	sort_link_data = [],
+	card_json_data = [],
+) => {
+	//
+	let has_post_Id_card_data = [];
+	card_json_data.forEach(item => {
+		let filter_item = sort_link_data.filter(filter => {
+			return filter.short_url == item.short_url && filter.post_Id;
+		});
+		if (filter_item.length > 0) {
+			item.post_Id = filter_item[0].post_Id;
+			has_post_Id_card_data.push(item);
+		}
+	});
+	return has_post_Id_card_data;
+};
+
+export const filterShortUrl = (sort_link_data, card_json_data) => {
+	let has = false;
+	let need_net_short_urls = [];
+
+	card_json_data.forEach(card_item => {
+		has = false;
+		sort_link_data.forEach(local_item => {
+			if (
+				card_item.short_url == local_item.short_url &&
+				local_item.post_Id
+			) {
+				has = true;
+			}
+		});
+		if (!has) {
+			need_net_short_urls.push(card_item.short_url);
+		}
+	});
+	// 返回的是没有postid的
+	return need_net_short_urls;
+};
+
+export const checkShortUrlArraySize = _array => {
+	if (new Blob(_array).size >= 1024 * 1024 * 4) {
+		_array.splice(0, parseInt(_array.length / 2));
+	}
+	return _array;
+};
+
+// 获取短链接和渲染卡片数据
+export const getCardParmas = async card_json_data => {
+	let sort_link_data = getStorage('denetCardData') || [];
+	// let sort_link_data = await getChromeStorage('cardData') || []
+	let has_post_Id_card_data = getLocalHasPostIdData(
+		sort_link_data,
+		card_json_data,
+	);
+	let need_net_short_urls = filterShortUrl(sort_link_data, card_json_data);
+
+	// 校验存储大小
+	let new_item = checkShortUrlArraySize(sort_link_data);
+	if (sort_link_data.length != new_item.length) {
+		setStorage('denetCardData', new_item);
+	}
+	return {
+		has_post_Id_card_data,
+		need_net_short_urls,
+	};
+};

+ 120 - 68
src/utils/addDom.js → src/utils/contentInTwitterJS/addDom.js

@@ -1,3 +1,4 @@
+import { parseAllDeNetCardParmas, getCardParmas } from './ParseCard';
 const addDom = () => {
 	window.parseAllDeNetCard = () => {
 		let de_net_card = [];
@@ -46,17 +47,17 @@ const addDom = () => {
 		}
 		return { tweet_Id, short_url, dom_card };
 	};
-	window.parseAllDeNetCardParmas = () => {
-		let json_data = [];
-		window.parseAllDeNetCard().forEach(item => {
-			let _obj = window.parseCardParmas(item.dom);
-			if (_obj.tweet_Id && _obj.short_url && _obj.dom_card) {
-				_obj.time = item.time;
-				json_data.push(_obj);
-			}
-		});
-		return json_data;
-	};
+	// window.parseAllDeNetCardParmas = () => {
+	// 	let json_data = [];
+	// 	window.parseAllDeNetCard().forEach(item => {
+	// 		let _obj = window.parseCardParmas(item.dom);
+	// 		if (_obj.tweet_Id && _obj.short_url && _obj.dom_card) {
+	// 			_obj.time = item.time;
+	// 			json_data.push(_obj);
+	// 		}
+	// 	});
+	// 	return json_data;
+	// };
 	window.toRedpackPage = ({ post_Id, tweet_Id }) => {
 		window.ReactNativeWebView.postMessage(
 			JSON.stringify({
@@ -158,29 +159,121 @@ const addDom = () => {
 			});
 			div.id = 'denet-card';
 			div.style.color = 'red';
-			div.innerHTML = `
-				<h2>这里是自定义插入的内容</h2>
-                tweet_Id:${tweet_Id} , 
-                post_Id:${post_Id}
-                获取dom时间:${time}
-                短链接:${short_url}<img onclick="toRedpackPage()" src="https://pbs.twimg.com/card_img/1559498011880804353/yV6kTKyQ?format=jpg&name=small" style="width: 100%"/>
-                渲染时长:${(new Date().getTime() - time) / 1000}s
-                `;
+			// div.innerHTML = `
+			// 	<h2>这里是自定义插入的内容</h2>
+			//     tweet_Id:${tweet_Id} ,
+			//     post_Id:${post_Id}
+			//     获取dom时间:${time}
+			//     短链接:${short_url}<img onclick="toRedpackPage()" src="https://pbs.twimg.com/card_img/1559498011880804353/yV6kTKyQ?format=jpg&name=small" style="width: 100%"/>
+			//     渲染时长:${(new Date().getTime() - time) / 1000}s
+			//     `;
 			dom.appendChild(div);
 			// window.TwitterLikeAPI(1559235463868710917);
 
 			// dom.appendChild(this.createIframe({post_Id, tweet_Id, page_type}));
 		}
 	}
+
+	let queue_num = 1;
+
+	const changeQueueNum = (num = 0) => {
+		queue_num = queue_num + num;
+		if (queue_num > 5) {
+			queue_num = 5;
+		}
+	};
+
 	try {
 		let timer = setInterval(() => {
-			let card_json_data = window.parseAllDeNetCardParmas();
-			if (card_json_data.length) {
-				clearInterval(timer);
-				for (let i = 0; i < card_json_data.length; i++) {
-					replaceDOMRedPacket(card_json_data[i]);
-				}
-			}
+			let card_json_data = parseAllDeNetCardParmas();
+			getCardParmas(card_json_data).then(res => {
+				console.log('res', res);
+				// for (let i in res.has_post_Id_card_data) {
+				// 	let item = res.has_post_Id_card_data[i];
+				// 	if (
+				// 		item &&
+				// 		item.post_Id &&
+				// 		item.post_Id.indexOf('nft/') >= 0
+				// 	) {
+				// 		parseCard.replaceNftDomRedPacket(item);
+				// 	} else if (
+				// 		item &&
+				// 		item.post_Id &&
+				// 		item.post_Id.indexOf('nft_group/') >= 0
+				// 	) {
+				// 		parseCard.replaceNftGroupDomRedPacket(item);
+				// 	} else if (
+				// 		item &&
+				// 		item.post_Id &&
+				// 		item.post_Id.indexOf('luckdraw/') >= 0
+				// 	) {
+				// 		item.post_Id = item.post_Id.split('luckdraw/')[1] || '';
+				// 		item.page_type = '抽奖';
+				// 		parseCard.replaceDOMRedPacket(item);
+				// 	} else if (
+				// 		item &&
+				// 		item.post_Id &&
+				// 		item.post_Id.indexOf('toolbox/') >= 0
+				// 	) {
+				// 		item.page_type = 'toolbox';
+				// 		item.post_Id = item.post_Id.split('toolbox/')[1] || '';
+				// 		if (item.post_Id) {
+				// 			parseCard.replaceIframeToolBox(item);
+				// 		}
+				// 	} else if (
+				// 		item &&
+				// 		item.post_Id &&
+				// 		!item.post_Id.includes('/')
+				// 	) {
+				// 		item.page_type = '红包';
+				// 		parseCard.replaceDOMRedPacket(item);
+				// 		// 夺宝链接
+				// 	} else if (
+				// 		item &&
+				// 		item.post_Id &&
+				// 		item.post_Id.includes('treasure/')
+				// 	) {
+				// 		// https://testh5.denetme.net/treasure/{postid}
+				// 		// https://testh5.denetme.net/treasure/invite/{inviteCode}
+				// 		// 邀请链接
+				// 		if (item.post_Id.includes('invite/')) {
+				// 			let arr = item.post_Id.split('/');
+				// 			let index;
+				// 			for (let i in arr) {
+				// 				index = Number(i) + 1;
+				// 				if (arr[i] == 'invite' && arr.length >= index) {
+				// 					item.invite_code = arr[index];
+				// 					if (arr.length > index + 1) {
+				// 						item.invite_channel = arr[index + 1];
+				// 					} else {
+				// 						item.invite_channel = '';
+				// 					}
+				// 					break;
+				// 				}
+				// 			}
+
+				// 			item.page_type = '邀请链接';
+				// 			if (item.invite_code) {
+				// 				item.post_Id = '';
+				// 				parseCard.replaceDOMTreasureCard(item);
+				// 			}
+				// 		} else {
+				// 			// 原始链接
+				// 			item.page_type = '原始链接';
+				// 			item.post_Id =
+				// 				item.post_Id.split('treasure/')[1] || '';
+				// 			if (item.post_Id) {
+				// 				parseCard.replaceDOMTreasureCard(item);
+				// 			}
+				// 		}
+				// 	}
+				// }
+				// if (res.need_net_short_urls.length > 0) {
+				// 	parseCard.netShortUrl(res.need_net_short_urls, () => {
+				// 		changeQueueNum(5);
+				// 	});
+				// }
+			});
 		}, 1000);
 
 		// let contain = document.getElementsByTagName('body')[0];
@@ -197,45 +290,4 @@ const addDom = () => {
 	}
 };
 
-const TwitterLikeAPI = tweet_Id => {
-	alert(tweet_Id);
-	fetch(
-		'https://mobile.twitter.com/i/api/graphql/lI07N6Otwv1PhnEgXILM7A/FavoriteTweet',
-		{
-			headers: {
-				accept: '*/*',
-				'accept-language': 'zh-CN,zh;q=0.9',
-				authorization:
-					'Bearer AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs%3D1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA',
-				'cache-control': 'no-cache',
-				'content-type': 'application/json',
-				pragma: 'no-cache',
-				'sec-fetch-dest': 'document',
-				'sec-fetch-mode': 'cors',
-				'sec-fetch-site': 'same-origin',
-				'x-csrf-token': window.getCookie('ct0'),
-				'x-twitter-active-user': 'yes',
-				'x-twitter-auth-type': 'OAuth2Session',
-				'x-twitter-client-language': 'zh-cn',
-			},
-			referrer: 'https://mobile.twitter.com',
-			referrerPolicy: 'strict-origin-when-cross-origin',
-			body: `{"variables":{"tweet_id":"
-				${tweet_Id}
-				"},"queryId":"lI07N6Otwv1PhnEgXILM7A"}`,
-			method: 'POST',
-			mode: 'cors',
-			credentials: 'include',
-		},
-	)
-		.then(res => {
-			console.log(res);
-			alert(JSON.stringify(res));
-		})
-		.catch(e => {
-			// alert(window.getCookie('ct0'))
-			// alert(e);
-		});
-};
-
-export { addDom, TwitterLikeAPI };
+export { addDom };

+ 2 - 2
src/utils/index.ts

@@ -1,9 +1,9 @@
-import {setCookie, getCookie} from './cookie';
+import { setCookie, getCookie } from './cookie';
 
 export const APPTYPE = 3;
 
 // 帮助函数
-const guid = () => {
+export const guid = () => {
 	return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(
 		/[xy]/g,
 		function (c) {