diff --git a/index.user.js b/index.user.js index 3c9c75b..51a1f94 100644 --- a/index.user.js +++ b/index.user.js @@ -16,5 +16,5 @@ // @grant none // ==/UserScript== /*! For license information please see index.user.js.LICENSE.txt */ -(()=>{"use strict";let e,t,r,i,o,n,l,s,a,c,p,u,d;var f={},y={};function w(e){var t=y[e];if(void 0!==t)return t.exports;var r=y[e]={exports:{}};return f[e](r,r.exports,w),r.exports}w.rv=()=>"1.6.7",w.ruid="bundler=rspack@1.6.7";let h=(e=e=>"object"==typeof e.props&&null!==e.props&&t(e.props),t=e=>"object"==typeof e.retweetWithCommentLink&&null!==e.retweetWithCommentLink&&r(e.retweetWithCommentLink),r=e=>"object"==typeof e.state&&null!==e.state&&i(e.state),i=e=>"object"==typeof e.quotedStatus&&null!==e.quotedStatus&&o(e.quotedStatus),o=e=>(null===e.possibly_sensitive||void 0===e.possibly_sensitive||"boolean"==typeof e.possibly_sensitive)&&(null===e.possibly_sensitive_editable||void 0===e.possibly_sensitive_editable||"boolean"==typeof e.possibly_sensitive_editable)&&"string"==typeof e.permalink&&"object"==typeof e.user&&null!==e.user&&n(e.user),n=e=>(null===e.possibly_sensitive||void 0===e.possibly_sensitive||"boolean"==typeof e.possibly_sensitive)&&"string"==typeof e.screen_name&&(""===e.profile_interstitial_type||"sensitive_media"===e.profile_interstitial_type||"fake_account"===e.profile_interstitial_type||"offensive_profile_content"===e.profile_interstitial_type||"timeout"===e.profile_interstitial_type)&&Array.isArray(e.withheld_in_countries)&&e.withheld_in_countries.every(e=>"string"==typeof e),t=>"object"==typeof t&&null!==t&&Array.isArray(t.children)&&"object"==typeof t.children[1]&&null!==t.children[1]&&e(t.children[1])&&Array.isArray(t.children.slice(2))),m=(l=e=>"object"==typeof e.props&&null!==e.props&&s(e.props),s=e=>"boolean"==typeof e.isFocalTweet,e=>"object"==typeof e&&null!==e&&"object"==typeof e.children&&null!==e.children&&l(e.children)),_=(a=e=>"object"==typeof e.props&&null!==e.props&&c(e.props),c=e=>Array.isArray(e.children)&&2===e.children.length&&"object"==typeof e.children[1]&&null!==e.children[1]&&p(e.children[1]),p=e=>"object"==typeof e.props&&null!==e.props&&u(e.props),u=e=>"object"==typeof e.user&&null!==e.user&&d(e.user),d=e=>(null===e.possibly_sensitive||void 0===e.possibly_sensitive||"boolean"==typeof e.possibly_sensitive)&&"string"==typeof e.screen_name&&(""===e.profile_interstitial_type||"sensitive_media"===e.profile_interstitial_type||"fake_account"===e.profile_interstitial_type||"offensive_profile_content"===e.profile_interstitial_type||"timeout"===e.profile_interstitial_type)&&Array.isArray(e.withheld_in_countries)&&e.withheld_in_countries.every(e=>"string"==typeof e),e=>"object"==typeof e&&null!==e&&Array.isArray(e.children)&&2===e.children.length&&"object"==typeof e.children[0]&&null!==e.children[0]&&a(e.children[0])&&!0),b=e=>Array.isArray(e)&&e.length>0,v=e=>{let t=Object.getOwnPropertyNames(e).filter(e=>e.startsWith("__reactProps$"));return b(t)?e[t[0]]:null};class g{profileElement;constructor(e){this.profileElement=e}get props(){let e=v(this.profileElement);if(!_(e))throw Error("Failed to get React props of profile");return e.children[0].props.children[1].props.user}}let E=["pro.twitter.com","pro.x.com"],x=(e,t)=>new Promise(r=>{let i=e();if(i instanceof Element||i instanceof NodeList&&i.length)return void r(i);let o=null,n=new MutationObserver(()=>{let t=e();(t instanceof Element||t instanceof NodeList&&t.length)&&(n.disconnect(),o&&clearTimeout(o),r(t))});o=setTimeout(()=>{n.disconnect(),r(null)},t),n.observe(document.body,{attributes:!0,childList:!0,subtree:!0})}),A=async(e,t=document,r=500)=>await x(()=>t.querySelector(e),r),T=async(e,t=document,r=500)=>await x(()=>t.querySelectorAll(e),r)??document.createDocumentFragment().childNodes,k=e=>"TEXTAREA"===e.tagName?e:e.parentElement,S=async(e,t)=>{let r=E.includes(location.hostname),i=[...await T(r?"[role='dialog'] [data-text='true'], [role='dialog'] textarea[data-testid='tweetTextarea_0']":"[role='dialog'] [data-text='true'], textarea[data-testid='tweetTextarea_0']",document,t)];if(!b(i))throw Error("[twi-ext] Failed to get text box marker of tweet");for(let e=0;e{open(`https://x.com/intent/tweet?text=${encodeURIComponent(e)}`,"_blank")};class j{tweetElement;constructor(e){this.tweetElement=e}getMenuBar(){let e=this.tweetElement.querySelector("div[role='group'][id]");if(!e)throw Error("[twi-ext] Failed to get menu bar of tweet");return e}get element(){return this.tweetElement}get props(){let e=v(this.getMenuBar());if(!h(e))throw Error("[twi-ext] Failed to get React props of tweet");return e.children[1].props.retweetWithCommentLink.state.quotedStatus}get metadata(){let e=this.props.user.screen_name,t=this.getMenuBar().parentElement?.parentElement;if(!t)throw Error("[twi-ext] Failed to get grandparent of menu bar of tweet");let r=v(t);if(!m(r))throw Error("[twi-ext] Failed to determine whether it is in focal mode. There may have been a change in X's specifications.");let i=(()=>{let e,t,r,i=[...document.querySelectorAll("body > script:not([src])")].find(e=>e.textContent.trim().startsWith("window.__INITIAL_STATE__"));if(!i)throw Error("[twi-ext] Failed to find initial state.");let[o]=i.textContent.trim().replace(/^window\.__INITIAL_STATE__=/u,"").split(";window.__META_DATA__");if(!o)throw Error("[twi-ext] Failed to extract initial state.");let n=(e=e=>"object"==typeof e.remote&&null!==e.remote&&t(e.remote),t=e=>"object"==typeof e.settings&&null!==e.settings&&r(e.settings),r=e=>"string"==typeof e.screen_name,t=>{var r;return"object"==typeof(r=t=JSON.parse(t))&&null!==r&&"object"==typeof r.settings&&null!==r.settings&&e(r.settings)?t:null})(o);if(!n)throw Error("[twi-ext] Failed to parse initial state.");return n})().settings.remote.settings.screen_name;return{isFocalMode:r.children.props.isFocalTweet,isPostedByCurrentUser:e===i}}async clickRetweetButton(e){let t=await A("[data-testid='unretweet'], [data-testid='retweet']",this.tweetElement,e);if(!t)throw Error("[twi-ext] Failed to get retweet button of tweet");t.click()}static async clickQuoteButton(e){let t=await A("[data-testid='Dropdown'] [href='/compose/post'],[data-testid='sheetDialog'] [href='/compose/post']",document,e);if(!t)throw Error("[twi-ext] Failed to get quote button of tweet");t.click()}async quoteTweet(e,t=1e3,r=!1){let i=this.props.permalink,o=`${e} -https://x.com${i}`;if(r)return void N(o);try{await this.clickRetweetButton(t),await j.clickQuoteButton(t),await S(e,t)}catch{N(o)}}}var F=function(){var e=document.querySelectorAll("[role='group'] a[href$='analytics']"),t=!0,r=!1,i=void 0;try{for(var o,n,l,s=e[Symbol.iterator]();!(t=(l=s.next()).done);t=!0){var a=l.value;a.parentElement&&(a.href="",a.parentElement.style.display="none")}}catch(e){r=!0,i=e}finally{try{t||null==s.return||s.return()}finally{if(r)throw i}}var c=document.querySelector("a[aria-describedby] time");if(null==c||null==(n=c.parentElement)||null==(o=n.parentElement)?void 0:o.parentElement){var p=c.parentElement.parentElement.parentElement.querySelectorAll("div ~ *"),u=!0,d=!1,f=void 0;try{for(var y,w=p[Symbol.iterator]();!(u=(y=w.next()).done);u=!0)y.value.style.display="none"}catch(e){d=!0,f=e}finally{try{u||null==w.return||w.return()}finally{if(d)throw f}}}};new class{OBSERVER_OPTIONS={childList:!0,subtree:!0};onNewTweetCallback=null;onNewProfileCallback=null;constructor(e){const t=`data-twi-ext-checked-${crypto.randomUUID()}`,r={timeoutMs:1e4,...e},i=new MutationObserver(()=>{if(this.onNewTweetCallback)for(let e of document.querySelectorAll(`[data-testid="tweet"]:not([${t}])`))e.setAttribute(t,""),this.onNewTweetCallback(new j(e));if(this.onNewProfileCallback){let e=document.querySelector(`:not([data-testid="tweet"]) [data-testid="UserName"]:not([${t}])`);e&&(e.setAttribute(t,""),this.onNewProfileCallback(new g(e)))}});A("main",document,r.timeoutMs).then(e=>{if(!e)throw Error("[twi-ext] Failed to get main element");i.observe(e,this.OBSERVER_OPTIONS)}),A("#layers",document,r.timeoutMs).then(e=>{if(!e)throw Error("[twi-ext] Failed to get #layers element");i.observe(e,this.OBSERVER_OPTIONS)})}onNewTweet(e){this.onNewTweetCallback=e}onNewProfile(e){this.onNewProfileCallback=e}}().onNewTweet(function(){F()})})(); \ No newline at end of file +(()=>{"use strict";let e,t,r,i,o,n,l,s,a,c,p,u,d;var f={},h={};function m(e){var t=h[e];if(void 0!==t)return t.exports;var r=h[e]={exports:{}};return f[e](r,r.exports,m),r.exports}m.rv=()=>"1.6.8",m.ruid="bundler=rspack@1.6.8";let w=(e=e=>"object"==typeof e.props&&null!==e.props&&t(e.props),t=e=>"object"==typeof e.retweetWithCommentLink&&null!==e.retweetWithCommentLink&&r(e.retweetWithCommentLink),r=e=>"object"==typeof e.state&&null!==e.state&&i(e.state),i=e=>"object"==typeof e.quotedStatus&&null!==e.quotedStatus&&o(e.quotedStatus),o=e=>(null===e.possibly_sensitive||void 0===e.possibly_sensitive||"boolean"==typeof e.possibly_sensitive)&&(null===e.possibly_sensitive_editable||void 0===e.possibly_sensitive_editable||"boolean"==typeof e.possibly_sensitive_editable)&&"string"==typeof e.permalink&&"object"==typeof e.user&&null!==e.user&&n(e.user),n=e=>(null===e.possibly_sensitive||void 0===e.possibly_sensitive||"boolean"==typeof e.possibly_sensitive)&&"string"==typeof e.screen_name&&(""===e.profile_interstitial_type||"sensitive_media"===e.profile_interstitial_type||"fake_account"===e.profile_interstitial_type||"offensive_profile_content"===e.profile_interstitial_type||"timeout"===e.profile_interstitial_type)&&Array.isArray(e.withheld_in_countries)&&e.withheld_in_countries.every(e=>"string"==typeof e),t=>"object"==typeof t&&null!==t&&Array.isArray(t.children)&&"object"==typeof t.children[1]&&null!==t.children[1]&&e(t.children[1])&&Array.isArray(t.children.slice(2))),y=(l=e=>"object"==typeof e.props&&null!==e.props&&s(e.props),s=e=>"boolean"==typeof e.isFocalTweet,e=>"object"==typeof e&&null!==e&&"object"==typeof e.children&&null!==e.children&&l(e.children)),b=(a=e=>"object"==typeof e.props&&null!==e.props&&c(e.props),c=e=>Array.isArray(e.children)&&2===e.children.length&&"object"==typeof e.children[1]&&null!==e.children[1]&&p(e.children[1]),p=e=>"object"==typeof e.props&&null!==e.props&&u(e.props),u=e=>"object"==typeof e.user&&null!==e.user&&d(e.user),d=e=>(null===e.possibly_sensitive||void 0===e.possibly_sensitive||"boolean"==typeof e.possibly_sensitive)&&"string"==typeof e.screen_name&&(""===e.profile_interstitial_type||"sensitive_media"===e.profile_interstitial_type||"fake_account"===e.profile_interstitial_type||"offensive_profile_content"===e.profile_interstitial_type||"timeout"===e.profile_interstitial_type)&&Array.isArray(e.withheld_in_countries)&&e.withheld_in_countries.every(e=>"string"==typeof e),e=>"object"==typeof e&&null!==e&&Array.isArray(e.children)&&2===e.children.length&&"object"==typeof e.children[0]&&null!==e.children[0]&&a(e.children[0])&&!0),_=e=>{let t=Object.getOwnPropertyNames(e).find(e=>e.startsWith("__reactProps$"));return t?e[t]:null};class E{profileElement;constructor(e){this.profileElement=e}get props(){let e=(e=>{let t,r=(t=Object.getOwnPropertyNames(e).find(e=>e.startsWith("__reactFiber$")))?e[t]:null;if(!r)return null;let i=r.pendingProps??r.memoizedProps;return b(i)?i.children[0].props.children[1].props.user:null})(this.profileElement);if(e)return e;let t=_(this.profileElement);if(!b(t))throw Error("Failed to get React props of profile");return t.children[0].props.children[1].props.user}}let v=["pro.twitter.com","pro.x.com"],g=(e,t)=>new Promise(r=>{let i=e();if(i instanceof Element||i instanceof NodeList&&i.length)return void r(i);let o=null,n=new MutationObserver(()=>{let t=e();(t instanceof Element||t instanceof NodeList&&t.length)&&(n.disconnect(),o&&clearTimeout(o),r(t))});o=setTimeout(()=>{n.disconnect(),r(null)},t),n.observe(document.body,{attributes:!0,childList:!0,subtree:!0})}),N=async(e,t=document,r=500)=>await g(()=>t.querySelector(e),r),P=async(e,t=document,r=500)=>await g(()=>t.querySelectorAll(e),r)??document.createDocumentFragment().childNodes,A=e=>"TEXTAREA"===e.tagName?e:e.parentElement,x=async(e,t)=>{let r=v.includes(location.hostname),i=[...await P(r?"[role='dialog'] [data-text='true'], [role='dialog'] textarea[data-testid='tweetTextarea_0']":"[role='dialog'] [data-text='true'], textarea[data-testid='tweetTextarea_0']",document,t)];if(!(Array.isArray(i)&&i.length>0))throw Error("[twi-ext] Failed to get text box marker of tweet");for(let e=0;e{open(`https://x.com/intent/tweet?text=${encodeURIComponent(e)}`,"_blank")};class k{tweetElement;constructor(e){this.tweetElement=e}getMenuBar(){let e=this.tweetElement.querySelector("div[role='group'][id]");if(!e)throw Error("[twi-ext] Failed to get menu bar of tweet");return e}get element(){return this.tweetElement}get props(){let e=_(this.getMenuBar());if(!w(e))throw Error("[twi-ext] Failed to get React props of tweet");return e.children[1].props.retweetWithCommentLink.state.quotedStatus}get metadata(){let e=this.props.user.screen_name,t=this.getMenuBar().parentElement?.parentElement;if(!t)throw Error("[twi-ext] Failed to get grandparent of menu bar of tweet");let r=_(t);if(!y(r))throw Error("[twi-ext] Failed to determine whether it is in focal mode. There may have been a change in X's specifications.");let i=(()=>{let e,t,r,i=[...document.querySelectorAll("body > script:not([src])")].find(e=>e.textContent.trim().startsWith("window.__INITIAL_STATE__"));if(!i)throw Error("[twi-ext] Failed to find initial state.");let[o]=i.textContent.trim().replace(/^window\.__INITIAL_STATE__=/u,"").split(";window.__META_DATA__");if(!o)throw Error("[twi-ext] Failed to extract initial state.");let n=(e=e=>"object"==typeof e.remote&&null!==e.remote&&t(e.remote),t=e=>"object"==typeof e.settings&&null!==e.settings&&r(e.settings),r=e=>"string"==typeof e.screen_name,t=>{var r;return"object"==typeof(r=t=JSON.parse(t))&&null!==r&&"object"==typeof r.settings&&null!==r.settings&&e(r.settings)?t:null})(o);if(!n)throw Error("[twi-ext] Failed to parse initial state.");return n})().settings.remote.settings.screen_name;return{isFocalMode:r.children.props.isFocalTweet,isPostedByCurrentUser:e===i}}async clickRetweetButton(e){let t=await N("[data-testid='unretweet'], [data-testid='retweet']",this.tweetElement,e);if(!t)throw Error("[twi-ext] Failed to get retweet button of tweet");t.click()}static async clickQuoteButton(e){let t=await N("[data-testid='Dropdown'] [href='/compose/post'],[data-testid='sheetDialog'] [href='/compose/post']",document,e);if(!t)throw Error("[twi-ext] Failed to get quote button of tweet");t.click()}async quoteTweet(e,t=1e3,r=!1){let i=this.props.permalink,o=`${e} +https://x.com${i}`;if(r)return void T(o);try{await this.clickRetweetButton(t),await k.clickQuoteButton(t),await x(e,t)}catch{T(o)}}}class S{OBSERVER_OPTIONS={childList:!0,subtree:!0};static PROFILE_PROPS_MAX_ATTEMPTS=30;static PROFILE_SELECTOR=':not([data-testid="tweet"]) [data-testid="UserName"]';checkedDataAttribute;profileNameObservers=new WeakMap;onNewTweetCallback=null;onNewProfileCallback=null;constructor(e){this.checkedDataAttribute=`data-twi-ext-checked-${crypto.randomUUID()}`;const t={timeoutMs:1e4,...e},r=new MutationObserver(()=>{if(this.onNewTweetCallback)for(let e of document.querySelectorAll(`[data-testid="tweet"]:not([${this.checkedDataAttribute}])`))e.setAttribute(this.checkedDataAttribute,""),this.onNewTweetCallback(new k(e));if(this.onNewProfileCallback){let e=document.querySelector(`${S.PROFILE_SELECTOR}:not([${this.checkedDataAttribute}])`);e&&this.handleProfile(e)}});N("main",document,t.timeoutMs).then(e=>{if(!e)throw Error("[twi-ext] Failed to get main element");r.observe(e,this.OBSERVER_OPTIONS)}),N("#layers",document,t.timeoutMs).then(e=>{if(!e)throw Error("[twi-ext] Failed to get #layers element");r.observe(e,this.OBSERVER_OPTIONS)}),window.addEventListener("pageshow",()=>{if(!this.onNewProfileCallback)return;let e=document.querySelector(S.PROFILE_SELECTOR);e&&this.handleProfile(e,{forceRefresh:!0})})}onNewTweet(e){this.onNewTweetCallback=e}onNewProfile(e){this.onNewProfileCallback=e}observeProfileName(e){let t=S.getNameContainerFromProfile(e);if(!t||!this.onNewProfileCallback||this.profileNameObservers.has(t))return;let r=t.innerText.trim(),i=new MutationObserver(()=>{let e=t.innerText.trim(),r=this.profileNameObservers.get(t);if(r&&e!==r.lastName&&this.onNewProfileCallback){r.lastName=e;let i=S.normalizeScreenName(e);requestAnimationFrame(()=>{this.emitProfileWithFreshProps(t,i)})}});this.profileNameObservers.set(t,{lastName:r,observer:i}),i.observe(t,{characterData:!0,childList:!0,subtree:!0})}static normalizeScreenName(e){return e.trim().replace(/^@/u,"").toLowerCase()}static getNameContainerFromProfile(e){return e.querySelector(`${S.PROFILE_SELECTOR} [tabindex] [dir]`)??null}handleProfile(e,t){if(!this.onNewProfileCallback||!t?.forceRefresh&&e.hasAttribute(this.checkedDataAttribute))return;e.setAttribute(this.checkedDataAttribute,""),this.observeProfileName(e);let r=S.getNameContainerFromProfile(e);if(r){let e=this.profileNameObservers.get(r);e&&(e.lastName=r.innerText.trim())}let i=r?S.normalizeScreenName(r.innerText):null;this.emitProfileWithFreshProps(e,i)}emitProfileWithFreshProps(e,t,r=0){if(!this.onNewProfileCallback)return;let i=e.closest('[data-testid="UserName"]');if(!i)return;let o=new E(i),n=S.normalizeScreenName(o.props.screen_name),l=t??n;n!==l&&r{this.emitProfileWithFreshProps(e,l,r+1)}):this.onNewProfileCallback(o)}}var F=function(){var e=document.querySelectorAll("[role='group'] a[href$='analytics']"),t=!0,r=!1,i=void 0;try{for(var o,n,l,s=e[Symbol.iterator]();!(t=(l=s.next()).done);t=!0){var a=l.value;a.parentElement&&(a.href="",a.parentElement.style.display="none")}}catch(e){r=!0,i=e}finally{try{t||null==s.return||s.return()}finally{if(r)throw i}}var c=document.querySelector("a[aria-describedby] time");if(null==c||null==(n=c.parentElement)||null==(o=n.parentElement)?void 0:o.parentElement){var p=c.parentElement.parentElement.parentElement.querySelectorAll("div ~ *"),u=!0,d=!1,f=void 0;try{for(var h,m=p[Symbol.iterator]();!(u=(h=m.next()).done);u=!0)h.value.style.display="none"}catch(e){d=!0,f=e}finally{try{u||null==m.return||m.return()}finally{if(d)throw f}}}};new S().onNewTweet(function(){F()})})(); \ No newline at end of file