diff --git a/README-en.md b/README-en.md index 80b58a83..f4975c91 100644 --- a/README-en.md +++ b/README-en.md @@ -29,11 +29,12 @@ An extension includes a lot of small extensions. Make your life easier. Current Versions: -- **v1.68**: big facebook update (01/07/2024) +- **v1.69**: small update (14/07/2024)
Old versions +- v1.68: big facebook update (01/07/2024) - v1.67 - huge update (29/05/2024) - v1.66 - big update (27/04/2024) - v1.65-hotfix (08/04/2024) diff --git a/README.md b/README.md index eb9dc982..07526738 100644 --- a/README.md +++ b/README.md @@ -29,11 +29,12 @@ Xem [Lịch sử cập nhật](/md/CHANGELOGS.md) Phiên bản hiện tại: -- **v1.68**: bản cập nhật facebook lớn (01/07/2024) +- **v1.69**: small update (14/07/2024)
Xem phiên bản cũ hơn +- v1.68: bản cập nhật facebook lớn (01/07/2024) - v1.67 - bản cập nhật siêu lớn (29/05/2024) - v1.66 - bản cập nhật lớn (27/04/2024) - v1.65-hotfix (08/04/2024) diff --git a/manifest.json b/manifest.json index d03cd309..e698f238 100644 --- a/manifest.json +++ b/manifest.json @@ -4,7 +4,7 @@ "name": "Useful Scripts", "description": "Scripts that can make your life faster and better", "homepage_url": "https://github.com/HoangTran0410/useful-script", - "version": "1.68", + "version": "1.69", "icons": { "16": "./assets/icon16.png", "32": "./assets/icon32.png", @@ -66,7 +66,10 @@ "https://hoangtran0410.github.io/*", "https://useful-scripts-extension.github.io/*", "https://facebook-all-in-one.com/*", - "http://localhost:5173/*" + "http://localhost:5173/*", + "http://127.0.0.1:5173/*", + "http://localhost:5500/*", + "http://127.0.0.1:5500/*" ] } } diff --git a/md/CHANGELOGS.md b/md/CHANGELOGS.md index 3484ad4c..b39999ae 100644 --- a/md/CHANGELOGS.md +++ b/md/CHANGELOGS.md @@ -1,5 +1,31 @@ ## Change logs +
+ v1.69 - 14/07/2024 + +- Facebook + - Auto like for facebook [source](/scripts/fb_autoLike.js) + - Fix download watching video [source](/scripts/fb_downloadWatchingVideo.js) + - Fix download story [source](/scripts/fb_storySaver.js) + +- Youtube: + - change country [source](/scripts/youtube_changeCountry.js) + - download thumbnail [source](/scripts/youtube_getVideoThumbnail.js) + - show/download captions [source](/scripts/youtube_getVideoCaption.js) + +- Smooth scroll: + - click to disable/enable for current website [source](/scripts/smoothScroll.js) + +- Merge request + - [fix: 🐛 fix fireship_vip script](https://github.com/HoangTran0410/useful-script/pull/28) + - [feat: youglish search + ](https://github.com/HoangTran0410/useful-script/pull/30) + - [feat: youtube download video UI](https://github.com/HoangTran0410/useful-script/pull/31) + - [style: 🪄 beautify ui for viewScriptSource](https://github.com/HoangTran0410/useful-script/pull/32) +- More shortcuts: google trend, time.is, aiforthat, cobalt, nirsoft + +
+
v1.68 - 01/07/2024 - cập nhật facebook lớn diff --git a/md/LIST_SCRIPTS_EN.md b/md/LIST_SCRIPTS_EN.md index 3df950f5..bbab297b 100644 --- a/md/LIST_SCRIPTS_EN.md +++ b/md/LIST_SCRIPTS_EN.md @@ -1,7 +1,31 @@ ### Search
- 1. Find alternative web + 1. There's an AI for that + + [View source](/scripts/recommend_theresanaiforthat.js) + + Collection of thousand of AI tools. Easy to search by category + +
+
+ 2. Time.is - Check your time + + [View source](/scripts/recommend_timeis.js) + + Exact time for any time zone. + +
+
+ 3. Google trending - See what trending now + + [View source](/scripts/recommend_googleTrending.js) + + See what people are searching on Google. Top treding every day, realtime. + +
+
+ 4. Find alternative web [View source](/scripts/similarWeb.js) @@ -9,7 +33,7 @@
- 2. Bypass limit in SimilarWeb + 5. Bypass limit in SimilarWeb [View source](/scripts/similarWeb_bypassLimit.js) @@ -19,7 +43,7 @@
- 3. Find shared login + 6. Find shared login [View source](/scripts/search_sharedAccount.js) @@ -27,7 +51,7 @@
- 4. Internet archive - Free library + 7. Internet archive - Free library [View source](/scripts/recommend_archive.js) @@ -37,7 +61,7 @@
- 5. Wappalyzer - view website stacks + 8. Wappalyzer - view website stacks [View source](/scripts/recommend_wappalyzer.js) @@ -45,7 +69,7 @@
- 6. Who.is + 9. Who.is [View source](/scripts/whois.js) @@ -53,7 +77,7 @@
- 7. See web meta info (SEO) + 10. See web meta info (SEO) [View source](/scripts/viewWebMetaInfo.js) @@ -61,7 +85,7 @@
- 8. Top global treding music? + 11. Top global treding music? [View source](/scripts/recommend_search_musicTreding.js) @@ -69,7 +93,7 @@
- 9. Where to find papers/books/pdf/... + 12. Where to find papers/books/pdf/... [View source](/scripts/search_paperWhere.js) @@ -77,7 +101,7 @@
- 10. Search guitar chords + 13. Search guitar chords [View source](/scripts/search_hopamchuan.js) @@ -85,7 +109,7 @@
- 11. Dowfor - Check web die + 14. Dowfor - Check web die [View source](/scripts/checkWebDie.js) @@ -93,7 +117,7 @@
- 12. DownDetector - View report web crash + 15. DownDetector - View report web crash [View source](/scripts/downDetector.js) @@ -101,7 +125,7 @@
- 13. Open wayback url + 16. Open wayback url [View source](/scripts/openWaybackUrl.js) @@ -109,7 +133,7 @@
- 14. Archive the current Page online + 17. Archive the current Page online [View source](/scripts/archiveToday.js) @@ -117,7 +141,7 @@
- 15. Search Userscripts + 18. Search Userscripts [View source](/scripts/recommend_search_userscript.js) @@ -129,7 +153,15 @@ --- All in one ---
- 16. Save All Video + 19. Cobalt - Media downloader + + [View source](/scripts/recommend_cobalt.js) + + Support youtube, tiktok, instagram, twitter/x, bilibili, twitch, vimeo, soundcloud, dailymotion, pinterest, reddit, tumblr, ... + +
+
+ 20. Save All Video [View source](/scripts/saveAllVideo.js) @@ -137,7 +169,7 @@
- 17. Vuiz - Get link audio/video/album + 21. Vuiz - Get link audio/video/album [View source](/scripts/vuiz_getLink.js) @@ -145,7 +177,7 @@
- 18. SaveVideo - Download video + 22. SaveVideo - Download video [View source](/scripts/savevideo_me.js) @@ -153,7 +185,7 @@
- 19. Get audio/video (luanxt) + 23. Get audio/video (luanxt) [View source](/scripts/getLinkLuanxt_newtab.js) @@ -163,7 +195,7 @@ --- Photos ---
- 20. Twitter X - Add download button + 24. Twitter X - Add download button [View source](/scripts/twitter_downloadButton.js) @@ -173,7 +205,7 @@
- 21. Download favicon from website + 25. Download favicon from website [View source](/scripts/getFavicon.js) @@ -181,7 +213,7 @@
- 22. Picviewer CE+ download images + 26. Picviewer CE+ download images [View source](/scripts/recommend_picviewer_ce+.js) @@ -191,7 +223,7 @@
- 23. File-converter.io - change image type + 27. File-converter.io - change image type [View source](/scripts/recommend_file_converter.js) @@ -201,7 +233,7 @@
- 24. Squoosh.app - compress images + 28. Squoosh.app - compress images [View source](/scripts/recommend_squoosh_app.js) @@ -211,7 +243,7 @@ --- Music ---
- 25. Spotify - Add download button + 29. Spotify - Add download button [View source](/scripts/spotify_downloadButton.js) @@ -221,7 +253,7 @@
- 26. Soundcloud - Add download button + 30. Soundcloud - Add download button [View source](/scripts/soundcloud_downloadMusic.js) @@ -231,7 +263,7 @@
- 27. Nhaccuatui music/lyric downloader + 31. Nhaccuatui music/lyric downloader [View source](/scripts/nhaccuatui_downloader.js) @@ -239,7 +271,7 @@
- 28. Zingmp3 music dowloader (API) + 32. Zingmp3 music dowloader (API) [View source](/scripts/zingmp3_downloadMusic.js) @@ -247,7 +279,7 @@
- 29. Show all audio in website + 33. Show all audio in website [View source](/scripts/showTheAudios.js) @@ -257,7 +289,7 @@ --- Videos ---
- 30. Download watching video + 34. Download watching video [View source](/scripts/download_watchingVideo.js) @@ -265,7 +297,7 @@
- 31. Vimeo - video downloader + 35. Vimeo - video downloader [View source](/scripts/vimeo_downloader.js) @@ -273,7 +305,7 @@
- 32. Show all videos in website + 36. Show all videos in website [View source](/scripts/showTheVideos.js) @@ -283,7 +315,7 @@ --- Document ---
- 33. Studocu - Download documents + 37. Studocu - Download documents [View source](/scripts/studocu_downs.js) @@ -291,7 +323,7 @@
- 34. Scribd - Download documents + 38. Scribd - Download documents [View source](/scripts/scribd_downloadDocuments.js) @@ -299,7 +331,7 @@
- 35. Download free from tailieu.vn + 39. Download free from tailieu.vn [View source](/scripts/tailieu_vn.js) @@ -307,7 +339,7 @@
- 36. DocDownloader - Download document + 40. DocDownloader - Download document [View source](/scripts/recommend_docsdownloader.js) @@ -315,7 +347,7 @@
- 37. Export bookmarks to file + 41. Export bookmarks to file [View source](/scripts/bookmark_exporter.js) @@ -323,7 +355,7 @@
- 38. Bookmark Sidebar + 42. Bookmark Sidebar [View source](/scripts/recommend_BookmarkSidebar.js) @@ -335,7 +367,7 @@ --- Download ---
- 39. Google drive - generate direct link + 43. Google drive - generate direct link [View source](/scripts/ggdrive_generateDirectLink.js) @@ -343,7 +375,7 @@
- 40. GG Drive - Download PDF + 44. GG Drive - Download PDF [View source](/scripts/ggdrive_downloadPdf.js) @@ -351,7 +383,7 @@
- 41. GG Drive - Download PowerPoint (Slides/Presentation) + 45. GG Drive - Download PowerPoint (Slides/Presentation) [View source](/scripts/ggdrive_downloadPresentation.js) @@ -359,7 +391,7 @@
- 42. GG Drive - Download Document (to PDF) + 46. GG Drive - Download Document (to PDF) [View source](/scripts/ggdrive_downloadDoc.js) @@ -367,7 +399,7 @@
- 43. GG Drive - Download Sheet (copy Text) + 47. GG Drive - Download Sheet (copy Text) [View source](/scripts/ggdrive_copySheetText.js) @@ -375,7 +407,7 @@
- 44. GG Drive - Download video + 48. GG Drive - Download video [View source](/scripts/ggdrive_downloadVideo.js) @@ -383,7 +415,7 @@
- 45. Google - Download all your data + 49. Google - Download all your data [View source](/scripts/google_downloadAllYourData.js) @@ -393,7 +425,7 @@ --- Bulk Download ---
- 46. GGDrive - Download all videos in folder + 50. GGDrive - Download all videos in folder [View source](/scripts/ggDrive_downloadAllVideosInFolder.js) @@ -403,7 +435,7 @@ --- More ---
- 47. Google search advanced + 51. Google search advanced [View source](/scripts/recommend_googleAdvanced.js) @@ -411,7 +443,7 @@
- 48. Check total indexed pages + 52. Check total indexed pages [View source](/scripts/search_totalIndexedPages.js) @@ -419,7 +451,7 @@
- 49. Google site search + 53. Google site search [View source](/scripts/search_googleSite.js) @@ -427,7 +459,7 @@
- 50. Google shortcuts + 54. Google shortcuts [View source](/scripts/googleShortcuts.js) @@ -435,7 +467,7 @@
- 51. View Google cache of website + 55. View Google cache of website [View source](/scripts/googleCache.js) @@ -443,7 +475,7 @@
- 52. Google mirror - I'm elgooG + 56. Google mirror - I'm elgooG [View source](/scripts/google_mirror.js) @@ -455,7 +487,7 @@ --- All in one ---
- 53. Facebook - All In One + 57. Facebook - All In One [View source](/scripts/fb_allInOne.js) @@ -465,7 +497,7 @@ --- Download ---
- 54. Download watching fb video + 58. Download watching fb video [View source](/scripts/fb_downloadWatchingVideo.js) @@ -473,7 +505,7 @@
- 55. Download watching fb Story/Comment + 59. Download watching fb Story/Comment [View source](/scripts/fb_storySaver.js) @@ -481,7 +513,7 @@
- 56. Download fb video/reel/watch from url + 60. Download fb video/reel/watch from url [View source](/scripts/fb_videoDownloader.js) @@ -489,7 +521,7 @@
- 57. Get avatar from fb user id + 61. Get avatar from fb user id [View source](/scripts/fb_getAvatarFromUid.js) @@ -497,7 +529,7 @@
- 58. Export saved facebook items + 62. Export saved facebook items [View source](/scripts/fb_exportSaved.js) @@ -507,7 +539,20 @@ --- Hot ---
- 59. Facebook - Reveal deleted messages + 63. Auto like post on Facebook + + [View source](/scripts/fb_autoLike.js) + + Auto like post on Facebook. +
    +
  • Support all post types (page, group, user, feed, ...)
  • +
  • Support bulk remove/add reactions
  • +
  • Support all reaction types
  • +
+ +
+
+ 64. Facebook - Reveal deleted messages [View source](/scripts/fb_revealDeletedMessages.js) @@ -515,7 +560,7 @@
- 60. Facebook Story - More reactions + 65. Facebook Story - More reactions [View source](/scripts/fb_moreReactionStory.js) @@ -525,7 +570,7 @@
- 61. Turn off light facebook newfeed + 66. Turn off light facebook newfeed [View source](/scripts/fb_toggleLight.js) @@ -533,7 +578,7 @@
- 62. Hide facebook new feed + 67. Hide facebook new feed [View source](/scripts/fb_toggleNewFeed.js) @@ -541,7 +586,7 @@
- 63. Stop new feed facebook + 68. Stop new feed facebook [View source](/scripts/fb_stopNewFeed.js) @@ -552,7 +597,7 @@
- 64. 👀 Block seen story facebook + 69. 👀 Block seen story facebook [View source](/scripts/fb_blockSeenStory.js) @@ -560,7 +605,7 @@
- 65. Show facebook post reaction count + 70. Show facebook post reaction count [View source](/scripts/fb_getPostReactionCount.js) @@ -570,7 +615,7 @@
- 66. Facebook - Who is typing to you? + 71. Facebook - Who is typing to you? [View source](/scripts/fb_whoIsTyping.js) @@ -580,7 +625,7 @@ --- Statistic ---
- 67. Facebook - View your friends's joined groups + 72. Facebook - View your friends's joined groups [View source](/scripts/fb_searchGroupForOther.js) @@ -588,7 +633,7 @@
- 68. Facebook - View your friend's liked pages + 73. Facebook - View your friend's liked pages [View source](/scripts/fb_searchPageForOther.js) @@ -596,7 +641,7 @@
- 69. Facebook - Find all posts of your friends + 74. Facebook - Find all posts of your friends [View source](/scripts/fb_searchPostsForOther.js) @@ -606,7 +651,7 @@ --- Access Token ---
- 70. Check fb access token + 75. Check fb access token [View source](/scripts/fb_checkToken.js) @@ -614,7 +659,7 @@
- 71. Get fb token EAAB (instagram) + 76. Get fb token EAAB (instagram) [View source](/scripts/fb_getTokenFacebook.js) @@ -622,7 +667,7 @@
- 72. Get fb token EAADo1 (messenger) + 77. Get fb token EAADo1 (messenger) [View source](/scripts/fb_getTokenMessage.js) @@ -630,7 +675,7 @@
- 73. Get fb token EAAG (business_locations) + 78. Get fb token EAAG (business_locations) [View source](/scripts/fb_getTokenBussinessLocation.js) @@ -638,7 +683,7 @@
- 74. Get fb token EAAB (campaigns) + 79. Get fb token EAAB (campaigns) [View source](/scripts/fb_getTokenCampaigns.js) @@ -646,7 +691,7 @@
- 75. Get fb token from cookie (ffb.vn) + 80. Get fb token from cookie (ffb.vn) [View source](/scripts/fb_getTokenFfb.js) @@ -656,7 +701,7 @@ --- Get ID ---
- 76. Get fb User ID + 81. Get fb User ID [View source](/scripts/fb_getUid.js) @@ -664,7 +709,7 @@
- 77. Get fb Page ID + 82. Get fb Page ID [View source](/scripts/fb_getPageId.js) @@ -672,7 +717,7 @@
- 78. Get fb Group ID + 83. Get fb Group ID [View source](/scripts/fb_getGroupId.js) @@ -680,7 +725,7 @@
- 79. Get fb Album ID + 84. Get fb Album ID [View source](/scripts/fb_getAlbumId.js) @@ -688,7 +733,7 @@
- 80. Get all fb Album ID from current page + 85. Get all fb Album ID from current page [View source](/scripts/fb_getAllAlbumIdFromCurrentWebsite.js) @@ -696,7 +741,7 @@
- 81. Get fb User ID from url + 86. Get fb User ID from url [View source](/scripts/fb_getUidFromUrl.js) @@ -704,7 +749,7 @@
- 82. Get all fb User ID from search page + 87. Get all fb User ID from search page [View source](/scripts/fb_getAllUidFromFbSearch.js) @@ -712,7 +757,7 @@
- 83. Get all fb User ID from group + 88. Get all fb User ID from group [View source](/scripts/fb_getAllUidOfGroupMembers.js) @@ -722,7 +767,7 @@ --- Shortcut ---
- 84. View your facebook saved + 89. View your facebook saved [View source](/scripts/fb_openSaved.js) @@ -730,7 +775,7 @@
- 85. View your memories on facebook + 90. View your memories on facebook [View source](/scripts/fb_openMemories.js) @@ -738,7 +783,7 @@
- 86. View your ads activities + 91. View your ads activities [View source](/scripts/fb_openAdsActivities.js) @@ -746,7 +791,7 @@
- 87. Check your activities on Facebook + 92. Check your activities on Facebook [View source](/scripts/fb_openAllActivities.js) @@ -754,7 +799,7 @@
- 88. Video you watched on facebook + 93. Video you watched on facebook [View source](/scripts/fb_openVideoActivities.js) @@ -762,7 +807,7 @@
- 89. Events joined on facebook + 94. Events joined on facebook [View source](/scripts/fb_openPassEvents.js) @@ -770,7 +815,7 @@
- 90. Facebook friend's birthdays + 95. Facebook friend's birthdays [View source](/scripts/fb_openBirthdays.js) @@ -778,7 +823,7 @@
- 91. Change language facebook + 96. Change language facebook [View source](/scripts/fb_openChangeLanguage.js) @@ -786,7 +831,7 @@
- 92. Recover facebook account + 97. Recover facebook account [View source](/scripts/fb_openAccountHacked.js) @@ -797,7 +842,7 @@ ### Instagram
- 93. Get insta user info (uid, avatar, ...) + 98. Get insta user info (uid, avatar, ...) [View source](/scripts/insta_getUserInfo.js) @@ -805,7 +850,7 @@
- 94. Add Instagram download button + 99. Add Instagram download button [View source](/scripts/insta_injectDownloadBtn.js) @@ -815,7 +860,7 @@
- 95. Insta - Anonymous story viewer + 100. Insta - Anonymous story viewer [View source](/scripts/insta_anonymousStoryViewer.js) @@ -825,7 +870,7 @@ --- Bulk Download ---
- 96. Get all media of insta user (API) + 101. Get all media of insta user (API) [View source](/scripts/insta_getAllUserMedia.js) @@ -833,7 +878,7 @@
- 97. Insta - Export all following/followers + 102. Insta - Export all following/followers [View source](/scripts/insta_getFollowForOther.js) @@ -844,65 +889,97 @@ ### Youtube
- 98. Download youtube video/audio + 103. Picture in Picture + + [View source](/scripts/pictureInPicture.js) + + Watch videos in a floating window + +
+
+ 104. Download youtube video/audio [View source](/scripts/youtube_downloadVideo.js) - Bypass age restriction, without login + Bypass age restriction, without login +
    +
  • Click once to download current video
  • +
  • Enable autorun to render download button
  • +
+ + ![](/scripts/youtube_downloadVideo.png)
- 99. Toggle light youtube + 105. Get Youtube video's captions - [View source](/scripts/youtube_toggleLight.js) + [View source](/scripts/youtube_getVideoCaption.js) - Toggle light on/off to focus to youtube video + - Click to get all captions of playing youtube video
- Enable autorun to show realtime captions (transcript)
+ + ![](/scripts/youtube_getVideoCaption.png)
- 100. Picture in Picture + 106. Return youtube dislike - [View source](/scripts/pictureInPicture.js) + [View source](/scripts/youtube_viewDislikes.js) - Watch videos in a floating window + Returns ability to see dislikes of youtube video/short
- 101. PIP full website + 107. Youtube nonstop - [View source](/scripts/pip_fullWebsite.js) + [View source](/scripts/youtube_nonstop.js) - Picture in picture mode for full website + Kiss the annoying "Video paused. Continue watching?" confirmation goodbye! + + ![](/scripts/youtube_nonstop.png)
- 102. PIP for canvas + 108. Youtube change country - [View source](/scripts/pip_canvas.js) + [View source](/scripts/youtube_changeCountry.js) - Picture in picture mode for canvas + Change youtube country to view content in other country
- 103. Return youtube dislike + 109. Get Youtube video's thumbnail - [View source](/scripts/youtube_viewDislikes.js) + [View source](/scripts/youtube_getVideoThumbnail.js) - Returns ability to see dislikes of youtube video/short + Get largest thumbnail of playing youtube video
- 104. Youtube nonstop + 110. Toggle light youtube - [View source](/scripts/youtube_nonstop.js) + [View source](/scripts/youtube_toggleLight.js) - Kiss the annoying "Video paused. Continue watching?" confirmation goodbye! + Toggle light on/off to focus to youtube video - ![](/scripts/youtube_nonstop.png) +
+
+ 111. PIP full website + + [View source](/scripts/pip_fullWebsite.js) + + Picture in picture mode for full website
- 105. Improve YouTube - 85+ features + 112. PIP for canvas + + [View source](/scripts/pip_canvas.js) + + Picture in picture mode for canvas + +
+
+ 113. Improve YouTube - 85+ features [View source](/scripts/recommend_improve_youtube.js) @@ -914,7 +991,7 @@ --- Tiktok ---
- 106. Tiktok - Download watching video + 114. Tiktok - Download watching video [View source](/scripts/tiktok_downloadWatchingVideo.js) @@ -922,7 +999,7 @@
- 107. Tiktok - Download video from URL + 115. Tiktok - Download video from URL [View source](/scripts/tiktok_downloadVideo.js) @@ -930,7 +1007,7 @@
- 108. Tiktok - Batch download + 116. Tiktok - Batch download [View source](/scripts/tiktok_batchDownload.js) @@ -942,7 +1019,7 @@ --- Douyin ---
- 109. Douyin - Download watching video + 117. Douyin - Download watching video [View source](/scripts/douyin_downloadWachingVideo.js) @@ -950,7 +1027,7 @@
- 110. Douyin - Download all user videos + 118. Douyin - Download all user videos [View source](/scripts/douyin_downloadAllVideoUser.js) @@ -962,7 +1039,7 @@ --- Utility ---
- 111. Web timer + 119. Web timer [View source](/scripts/web_timer.js) @@ -973,7 +1050,7 @@
- 112. Auto lock websites + 120. Auto lock websites [View source](/scripts/auto_lockWebsite.js) @@ -985,17 +1062,20 @@
- 113. Super smooth scroll + 121. Super smooth scroll [View source](/scripts/smoothScroll.js) Scroll smoothly on all websites with your mouse and keyboard.
- Smooth like when you scroll this extension.

- Support middle click to scroll.
+
    +
  • Suggested if you use mouse (turn off if use touchpad)
  • +
  • Click to Disable/Enable for current website
  • +
  • Support middle click to scroll
  • +

- 114. Magnify any Image + 122. Magnify any Image [View source](/scripts/magnify_image.js) @@ -1018,7 +1098,7 @@
- 115. Auto - view largest image + 123. Auto - view largest image [View source](/scripts/auto_redirectLargestImageSrc.js) @@ -1032,7 +1112,7 @@
- 116. Show image on hover link + 124. Show image on hover link [View source](/scripts/showImageOnHoverLink.js) @@ -1040,7 +1120,7 @@
- 117. Prevent tracking url + 125. Prevent tracking url [View source](/scripts/remove_tracking_in_url.js) @@ -1053,7 +1133,7 @@
- 118. Don't close browser with last tab + 126. Don't close browser with last tab [View source](/scripts/prevent_closeBrowser_lastTab.js) @@ -1062,7 +1142,7 @@
- 119. Block trackers, spy and malware + 127. Block trackers, spy and malware [View source](/scripts/chongLuaDao.js) @@ -1074,7 +1154,7 @@
- 120. Shorten URL + 128. Shorten URL [View source](/scripts/shortenURL.js) @@ -1082,7 +1162,7 @@
- 121. Unshorten link + 129. Unshorten link [View source](/scripts/unshorten.js) @@ -1090,7 +1170,7 @@
- 122. Create invisible message + 130. Create invisible message [View source](/scripts/createInvisibleText.js) @@ -1100,7 +1180,7 @@ --- Automation ---
- 123. Web to PDF + 131. Web to PDF [View source](/scripts/webToPDF.js) @@ -1108,7 +1188,7 @@
- 124. Screenshot full webpage + 132. Screenshot full webpage [View source](/scripts/screenshotFullPage.js) @@ -1116,7 +1196,7 @@
- 125. Screenshot webpage + 133. Screenshot webpage [View source](/scripts/screenshotVisiblePage.js) @@ -1124,7 +1204,7 @@
- 126. Scroll to very end + 134. Scroll to very end [View source](/scripts/scrollToVeryEnd.js) @@ -1132,7 +1212,7 @@
- 127. Extract all Emails from website + 135. Extract all Emails from website [View source](/scripts/getAllEmailsInWeb.js) @@ -1140,7 +1220,7 @@
- 128. Enable/Disable Hack T-Rex Dino Game + 136. Enable/Disable Hack T-Rex Dino Game [View source](/scripts/dino_hack.js) @@ -1148,7 +1228,7 @@
- 129. Password generator + 137. Password generator [View source](/scripts/passwordGenerator.js) @@ -1158,7 +1238,7 @@ --- Tools ---
- 130. Text to QRCode + 138. Text to QRCode [View source](/scripts/textToQrCode.js) @@ -1166,7 +1246,7 @@
- 131. Text to Speech (j2team) + 139. Text to Speech (j2team) [View source](/scripts/textToSpeech.js) @@ -1174,7 +1254,7 @@
- 132. Audio output switcher + 140. Audio output switcher [View source](/scripts/changeAudioOutput.js) @@ -1182,7 +1262,7 @@
- 133. Send - Share file faster + 141. Send - Share file faster [View source](/scripts/send_shareFiles.js) @@ -1190,7 +1270,7 @@
- 134. Vuiz - create logo WAP online + 142. Vuiz - create logo WAP online [View source](/scripts/vuiz_createLogo.js) @@ -1198,7 +1278,7 @@
- 135. Performance Analyzer + 143. Performance Analyzer [View source](/scripts/performanceAnalyzer.js) @@ -1206,7 +1286,7 @@
- 136. IT Tools - All for Developers + 144. IT Tools - All for Developers [View source](/scripts/recommend_ItTools.js) @@ -1214,7 +1294,7 @@
- 137. CopyIcon - FREE emoji, icon, generator + 145. CopyIcon - FREE emoji, icon, generator [View source](/scripts/recommend_copyicon.js) @@ -1222,7 +1302,7 @@
- 138. Beautify Tools + 146. Beautify Tools [View source](/scripts/recommend_beautifytools.js) @@ -1243,7 +1323,7 @@ --- Github ---
- 139. Github - Go to any commit + 147. Github - Go to any commit [View source](/scripts/github_goToAnyCommit.js) @@ -1251,7 +1331,7 @@
- 140. Github - HTML preview + 148. Github - HTML preview [View source](/scripts/github_HTMLPreview.js) @@ -1259,7 +1339,7 @@
- 141. Github - Open repo pages + 149. Github - Open repo pages [View source](/scripts/github_openRepoPages.js) @@ -1269,7 +1349,7 @@
- 142. Github - Open repo in github.dev + 150. Github - Open repo in github.dev [View source](/scripts/githubdev.js) @@ -1277,7 +1357,7 @@
- 143. Github - Open repo in github1s.com + 151. Github - Open repo in github1s.com [View source](/scripts/github1s.js) @@ -1285,7 +1365,7 @@
- 144. Cloc - count line of code + 152. Cloc - count line of code [View source](/scripts/recommend_cloc.js) @@ -1295,7 +1375,7 @@
- 145. Refined GitHub + 153. Refined GitHub [View source](/scripts/recommend_refined_github.js) @@ -1305,7 +1385,7 @@ --- Shopping ---
- 146. Shopee - Top variation + 154. Shopee - Top variation [View source](/scripts/shopee_topVariation.js) @@ -1315,7 +1395,7 @@
- 147. Shopee - Total spend money + 155. Shopee - Total spend money [View source](/scripts/shopee_totalSpendMoney.js) @@ -1323,7 +1403,7 @@
- 148. Shopee - Export order history (Excel) + 156. Shopee - Export order history (Excel) [View source](/scripts/shopee_totalSpendMoney_excel.js) @@ -1331,7 +1411,7 @@
- 149. Tiki - Total spend money? + 157. Tiki - Total spend money? [View source](/scripts/tiki_totalSpendMoney.js) @@ -1339,7 +1419,7 @@
- 150. Beecost + 158. Beecost [View source](/scripts/recommend_Beecost.js) @@ -1349,7 +1429,7 @@ --- PDF ---
- 151. FastDoc - Convert PDF/Photo to Word/Excel + 159. FastDoc - Convert PDF/Photo to Word/Excel [View source](/scripts/recommend_fastDoc.js) @@ -1357,7 +1437,7 @@
- 152. SmartPDF - Tools for PDF + 160. SmartPDF - Tools for PDF [View source](/scripts/recommend_smartPDF.js) @@ -1365,7 +1445,7 @@
- 153. PDF Stuffs - Tools for PDF + 161. PDF Stuffs - Tools for PDF [View source](/scripts/recommend_pdfstuffs.js) @@ -1377,7 +1457,7 @@ --- Unlock web ---
- 154. Hack Duck race + 162. Hack Duck race [View source](/scripts/duckRace_cheat.js) @@ -1387,7 +1467,7 @@
- 155. Hack Wheel of Names + 163. Hack Wheel of Names [View source](/scripts/wheelOfNames_hack.js) @@ -1395,7 +1475,7 @@
- 156. Read full medium article + 164. Read full medium article [View source](/scripts/medium_readFullArticle.js) @@ -1403,7 +1483,7 @@
- 157. Medium - Fix vietnamese font + 165. Medium - Fix vietnamese font [View source](/scripts/medium_fixVietnameseFont.js) @@ -1415,7 +1495,7 @@
- 158. Fireship - PRO unlocked + 166. Fireship - PRO unlocked [View source](/scripts/fireship_vip.js) @@ -1423,7 +1503,7 @@
- 159. Studocu - Bypass preview + 167. Studocu - Bypass preview [View source](/scripts/studocu_bypassPreview.js) @@ -1431,7 +1511,7 @@
- 160. Scribd - bypass preview + 168. Scribd - bypass preview [View source](/scripts/scribd_bypassPreview.js) @@ -1439,17 +1519,27 @@
- 161. Studyphim - Watch free movies + 169. Studyphim - Watch free movies [View source](/scripts/studyphim_unlimited.js) Watch movies on Studyphim for free without login +
+
+ 170. Mở khoá Learn Anything + + [View source](/scripts/bypass_learnAnything.js) + + View learn-anything.xyz content without become a member + + ![](/scripts/bypass_LearnAnything.png) +
--- Unlock function ---
- 162. Enable/Disable allow copy + 171. Enable/Disable allow copy [View source](/scripts/simpleAllowCopy.js) @@ -1463,7 +1553,7 @@
- 163. Detect Zero-Width Characters + 172. Detect Zero-Width Characters [View source](/scripts/detect_zeroWidthCharacters.js) @@ -1471,7 +1561,7 @@
- 164. Inject script to website + 173. Inject script to website [View source](/scripts/injectScriptToWebsite.js) @@ -1479,7 +1569,7 @@
- 165. Show hidden fields + 174. Show hidden fields [View source](/scripts/showHiddenFields.js) @@ -1487,7 +1577,7 @@
- 166. View cookies + 175. View cookies [View source](/scripts/viewCookies.js) @@ -1495,7 +1585,7 @@
- 167. Remove cookies + 176. Remove cookies [View source](/scripts/removeCookies.js) @@ -1505,7 +1595,7 @@ --- Other ---
- 168. Make browser super fast + 177. Make browser super fast [View source](/scripts/recommend_chromeFlags.js) @@ -1513,7 +1603,7 @@
- 169. View saved wifi passwords + 178. View saved wifi passwords [View source](/scripts/recommend_viewSavedWifiPass.js) @@ -1521,7 +1611,7 @@
- 170. Leak check - your password has been leaked? + 179. Leak check - your password has been leaked? [View source](/scripts/recommend_leakCheck.js) @@ -1533,7 +1623,7 @@ --- Hot ---
- 171. Darkmode for pdf + 180. Darkmode for pdf [View source](/scripts/darkModePDF.js) @@ -1541,7 +1631,7 @@
- 172. Toggle edit page + 181. Toggle edit page [View source](/scripts/toggleEditPage.js) @@ -1549,7 +1639,7 @@
- 173. Show FPS + 182. Show FPS [View source](/scripts/showFPS.js) @@ -1557,7 +1647,7 @@
- 174. Show FPS - ver 2 + 183. Show FPS - ver 2 [View source](/scripts/showFps_v2.js) @@ -1565,7 +1655,7 @@
- 175. Hide/Show password field + 184. Hide/Show password field [View source](/scripts/toggle_passwordField.js) @@ -1573,7 +1663,7 @@
- 176. Dark reader + 185. Dark reader [View source](/scripts/recommend_DarkReader.js) @@ -1581,7 +1671,7 @@
- 177. CSS Portal - Empowered your CSS skills + 186. CSS Portal - Empowered your CSS skills [View source](/scripts/recommend_cssportal.js) @@ -1589,7 +1679,7 @@
- 178. CSS Loaders - 600+ css loader + 187. CSS Loaders - 600+ css loader [View source](/scripts/recommend_cssloaders.js) @@ -1597,7 +1687,7 @@
- 179. UIverse - Open-Source UI elements + 188. UIverse - Open-Source UI elements [View source](/scripts/recommend_uiverse.js) @@ -1607,7 +1697,7 @@ --- View ---
- 180. Font Rendering - better font display + 189. Font Rendering - better font display [View source](/scripts/recommend_fontRendering.js) @@ -1615,7 +1705,7 @@
- 181. What font + 190. What font [View source](/scripts/whatFont.js) @@ -1623,7 +1713,7 @@
- 182. Show all javascript events + 191. Show all javascript events [View source](/scripts/visualEvent.js) @@ -1631,7 +1721,7 @@
- 183. View all images in web + 192. View all images in web [View source](/scripts/listAllImagesInWeb.js) @@ -1639,7 +1729,7 @@
- 184. View all links + 193. View all links [View source](/scripts/viewAllLinks.js) @@ -1647,7 +1737,7 @@
- 185. View scripts used + 194. View scripts used [View source](/scripts/viewScriptsUsed.js) @@ -1655,7 +1745,7 @@
- 186. View stylesheet used + 195. View stylesheet used [View source](/scripts/viewStylesUsed.js) @@ -1663,7 +1753,7 @@
- 187. CSS selector viewer + 196. CSS selector viewer [View source](/scripts/cssSelectorViewer.js) @@ -1673,7 +1763,7 @@ --- Remove ---
- 188. Remove all colors in web + 197. Remove all colors in web [View source](/scripts/removeColours.js) @@ -1681,7 +1771,7 @@
- 189. Remove stylesheet + 198. Remove stylesheet [View source](/scripts/removeStylesheet.js) @@ -1689,7 +1779,7 @@
- 190. Remove images + 199. Remove images [View source](/scripts/removeImages.js) @@ -1697,7 +1787,7 @@
- 191. Remove bloat (iframe, embed) + 200. Remove bloat (iframe, embed) [View source](/scripts/removeBloat.js) @@ -1707,7 +1797,7 @@ --- Table ---
- 192. Add sort to table + 201. Add sort to table [View source](/scripts/table_addSortTable.js) @@ -1715,7 +1805,7 @@
- 193. Add number columns + 202. Add number columns [View source](/scripts/table_addNumberColumn.js) @@ -1723,7 +1813,7 @@
- 194. Swap rows and columns + 203. Swap rows and columns [View source](/scripts/table_swapRowAndColumn.js) @@ -1733,7 +1823,7 @@ --- More ---
- 195. Highlight internal/external link + 204. Highlight internal/external link [View source](/scripts/internalOrExternalLink.js) @@ -1743,7 +1833,7 @@
- 196. Get window size + 205. Get window size [View source](/scripts/getWindowSize.js) @@ -1751,7 +1841,7 @@
- 197. Let it snow + 206. Let it snow [View source](/scripts/letItSnow.js) diff --git a/md/LIST_SCRIPTS_VI.md b/md/LIST_SCRIPTS_VI.md index 59b988b2..34a456eb 100644 --- a/md/LIST_SCRIPTS_VI.md +++ b/md/LIST_SCRIPTS_VI.md @@ -1,7 +1,31 @@ ### Tìm kiếm
- 1. Tìm trang web tương tự + 1. There's an AI for that - Tìm AI + + [Xem mã nguồn](/scripts/recommend_theresanaiforthat.js) + + Tổng hợp hàng ngàn công cụ AI hiện có. Dễ dàng tìm kiếm theo chủ đề + +
+
+ 2. Time.is - Kiểm tra thời gian + + [Xem mã nguồn](/scripts/recommend_timeis.js) + + Đồng hồ chính xác nhất. Kiểm tra đồng hồ trên máy của bạn nhanh hay chậm. + +
+
+ 3. Google trending - Nội dung nổi bật + + [Xem mã nguồn](/scripts/recommend_googleTrending.js) + + Xem mọi người đang tìm gì trên google. Thống kê từng ngày, thời gian thực. + +
+
+ 4. Tìm trang web tương tự [Xem mã nguồn](/scripts/similarWeb.js) @@ -9,7 +33,7 @@
- 2. SimilarWeb - không bị giới hạn + 5. SimilarWeb - không bị giới hạn [Xem mã nguồn](/scripts/similarWeb_bypassLimit.js) @@ -19,7 +43,7 @@
- 3. Tìm tài khoản miễn phí + 6. Tìm tài khoản miễn phí [Xem mã nguồn](/scripts/search_sharedAccount.js) @@ -27,7 +51,7 @@
- 4. Internet archive - Thư viện miễn phí + 7. Internet archive - Thư viện miễn phí [Xem mã nguồn](/scripts/recommend_archive.js) @@ -37,7 +61,7 @@
- 5. Wappalyzer - Web dùng công nghệ gì? + 8. Wappalyzer - Web dùng công nghệ gì? [Xem mã nguồn](/scripts/recommend_wappalyzer.js) @@ -45,7 +69,7 @@
- 6. Who.is + 9. Who.is [Xem mã nguồn](/scripts/whois.js) @@ -53,7 +77,7 @@
- 7. Xem thông tin meta của web (SEO) + 10. Xem thông tin meta của web (SEO) [Xem mã nguồn](/scripts/viewWebMetaInfo.js) @@ -61,7 +85,7 @@
- 8. Bài nhạc top treding toàn cầu? + 11. Bài nhạc top treding toàn cầu? [Xem mã nguồn](/scripts/recommend_search_musicTreding.js) @@ -69,7 +93,7 @@
- 9. Tìm bài báo/sách/pdf/...ở đâu? + 12. Tìm bài báo/sách/pdf/...ở đâu? [Xem mã nguồn](/scripts/search_paperWhere.js) @@ -77,7 +101,7 @@
- 10. Tìm hợp âm guitar + 13. Tìm hợp âm guitar [Xem mã nguồn](/scripts/search_hopamchuan.js) @@ -85,7 +109,7 @@
- 11. Dowfor - Kiểm tra web die + 14. Dowfor - Kiểm tra web die [Xem mã nguồn](/scripts/checkWebDie.js) @@ -93,7 +117,7 @@
- 12. DownDetector - Thống kê sự cố web + 15. DownDetector - Thống kê sự cố web [Xem mã nguồn](/scripts/downDetector.js) @@ -101,7 +125,7 @@
- 13. Xem wayback url của website + 16. Xem wayback url của website [Xem mã nguồn](/scripts/openWaybackUrl.js) @@ -109,7 +133,7 @@
- 14. Lưu trữ online trang hiện tại + 17. Lưu trữ online trang hiện tại [Xem mã nguồn](/scripts/archiveToday.js) @@ -117,7 +141,7 @@
- 15. Tìm Userscripts + 18. Tìm Userscripts [Xem mã nguồn](/scripts/recommend_search_userscript.js) @@ -129,7 +153,15 @@ --- Tổng hợp ---
- 16. Save All Video + 19. Cobalt - Tải video/nhạc + + [Xem mã nguồn](/scripts/recommend_cobalt.js) + + Hỗ trợ youtube, tiktok, instagram, twitter/x, bilibili, twitch, vimeo, soundcloud, dailymotion, pinterest, reddit, tumblr, ... + +
+
+ 20. Save All Video [Xem mã nguồn](/scripts/saveAllVideo.js) @@ -137,7 +169,7 @@
- 17. Vuiz - Get link nhạc/video/album + 21. Vuiz - Get link nhạc/video/album [Xem mã nguồn](/scripts/vuiz_getLink.js) @@ -145,7 +177,7 @@
- 18. SaveVideo - Tải video + 22. SaveVideo - Tải video [Xem mã nguồn](/scripts/savevideo_me.js) @@ -153,7 +185,7 @@
- 19. Tải nhạc/video (luanxt) + 23. Tải nhạc/video (luanxt) [Xem mã nguồn](/scripts/getLinkLuanxt_newtab.js) @@ -163,7 +195,7 @@ --- Ảnh ---
- 20. Twitter X - Thêm nút tải video/ảnh + 24. Twitter X - Thêm nút tải video/ảnh [Xem mã nguồn](/scripts/twitter_downloadButton.js) @@ -173,7 +205,7 @@
- 21. Tải favicon của trang web + 25. Tải favicon của trang web [Xem mã nguồn](/scripts/getFavicon.js) @@ -181,7 +213,7 @@
- 22. Picviewer CE+ tải ảnh + 26. Picviewer CE+ tải ảnh [Xem mã nguồn](/scripts/recommend_picviewer_ce+.js) @@ -191,7 +223,7 @@
- 23. File-converter.io - chuyển đổi ảnh + 27. File-converter.io - chuyển đổi ảnh [Xem mã nguồn](/scripts/recommend_file_converter.js) @@ -201,7 +233,7 @@
- 24. Squoosh.app - nén ảnh + 28. Squoosh.app - nén ảnh [Xem mã nguồn](/scripts/recommend_squoosh_app.js) @@ -211,7 +243,7 @@ --- Nhạc ---
- 25. Spotify - Thêm nút tải nhạc + 29. Spotify - Thêm nút tải nhạc [Xem mã nguồn](/scripts/spotify_downloadButton.js) @@ -221,7 +253,7 @@
- 26. Soundcloud - Thêm nút tải nhạc + 30. Soundcloud - Thêm nút tải nhạc [Xem mã nguồn](/scripts/soundcloud_downloadMusic.js) @@ -231,7 +263,7 @@
- 27. Nhaccuatui tải nhạc/lời + 31. Nhaccuatui tải nhạc/lời [Xem mã nguồn](/scripts/nhaccuatui_downloader.js) @@ -239,7 +271,7 @@
- 28. Zingmp3 tải nhạc (API) + 32. Zingmp3 tải nhạc (API) [Xem mã nguồn](/scripts/zingmp3_downloadMusic.js) @@ -247,7 +279,7 @@
- 29. Hiển thị mọi audio trong trang web + 33. Hiển thị mọi audio trong trang web [Xem mã nguồn](/scripts/showTheAudios.js) @@ -257,7 +289,7 @@ --- Video ---
- 30. Tải video đang xem + 34. Tải video đang xem [Xem mã nguồn](/scripts/download_watchingVideo.js) @@ -265,7 +297,7 @@
- 31. Vimeo - tải video + 35. Vimeo - tải video [Xem mã nguồn](/scripts/vimeo_downloader.js) @@ -273,7 +305,7 @@
- 32. Hiển thị mọi video có trong web + 36. Hiển thị mọi video có trong web [Xem mã nguồn](/scripts/showTheVideos.js) @@ -283,7 +315,7 @@ --- Tài liệu ---
- 33. Studocu - Tải documents + 37. Studocu - Tải documents [Xem mã nguồn](/scripts/studocu_downs.js) @@ -291,7 +323,7 @@
- 34. Scribd - Tải documents + 38. Scribd - Tải documents [Xem mã nguồn](/scripts/scribd_downloadDocuments.js) @@ -299,7 +331,7 @@
- 35. Tải miễn phí từ tailieu.vn + 39. Tải miễn phí từ tailieu.vn [Xem mã nguồn](/scripts/tailieu_vn.js) @@ -307,7 +339,7 @@
- 36. DocDownloader - Tải document + 40. DocDownloader - Tải document [Xem mã nguồn](/scripts/recommend_docsdownloader.js) @@ -315,7 +347,7 @@
- 37. Xuất bookmarks ra file + 41. Xuất bookmarks ra file [Xem mã nguồn](/scripts/bookmark_exporter.js) @@ -323,7 +355,7 @@
- 38. Bookmark Sidebar + 42. Bookmark Sidebar [Xem mã nguồn](/scripts/recommend_BookmarkSidebar.js) @@ -335,7 +367,7 @@ --- Tải xuống ---
- 39. Google drive - tạo link tải ngay + 43. Google drive - tạo link tải ngay [Xem mã nguồn](/scripts/ggdrive_generateDirectLink.js) @@ -343,7 +375,7 @@
- 40. GG Drive - Tải PDF + 44. GG Drive - Tải PDF [Xem mã nguồn](/scripts/ggdrive_downloadPdf.js) @@ -351,7 +383,7 @@
- 41. GG Drive - Tải PowerPoint (Slides) + 45. GG Drive - Tải PowerPoint (Slides) [Xem mã nguồn](/scripts/ggdrive_downloadPresentation.js) @@ -359,7 +391,7 @@
- 42. GG Drive - Tải Document (sang PDF) + 46. GG Drive - Tải Document (sang PDF) [Xem mã nguồn](/scripts/ggdrive_downloadDoc.js) @@ -367,7 +399,7 @@
- 43. GG Drive - Tải Sheet (copy nội dung) + 47. GG Drive - Tải Sheet (copy nội dung) [Xem mã nguồn](/scripts/ggdrive_copySheetText.js) @@ -375,7 +407,7 @@
- 44. GG Drive - Tải video + 48. GG Drive - Tải video [Xem mã nguồn](/scripts/ggdrive_downloadVideo.js) @@ -383,7 +415,7 @@
- 45. Google - Tải xuống dữ liệu của bạn + 49. Google - Tải xuống dữ liệu của bạn [Xem mã nguồn](/scripts/google_downloadAllYourData.js) @@ -393,7 +425,7 @@ --- Tải hàng loạt ---
- 46. GGDrive - Tải mọi video trong folder + 50. GGDrive - Tải mọi video trong folder [Xem mã nguồn](/scripts/ggDrive_downloadAllVideosInFolder.js) @@ -403,7 +435,7 @@ --- Khác ---
- 47. Google tìm kiếm nâng cao + 51. Google tìm kiếm nâng cao [Xem mã nguồn](/scripts/recommend_googleAdvanced.js) @@ -411,7 +443,7 @@
- 48. Xem các pages được google quét + 52. Xem các pages được google quét [Xem mã nguồn](/scripts/search_totalIndexedPages.js) @@ -419,7 +451,7 @@
- 49. Tìm kiếm trên trang web này + 53. Tìm kiếm trên trang web này [Xem mã nguồn](/scripts/search_googleSite.js) @@ -427,7 +459,7 @@
- 50. Google phím tắt + 54. Google phím tắt [Xem mã nguồn](/scripts/googleShortcuts.js) @@ -435,7 +467,7 @@
- 51. Xem Google cache của trang web + 55. Xem Google cache của trang web [Xem mã nguồn](/scripts/googleCache.js) @@ -443,7 +475,7 @@
- 52. Google mirror - I'm elgooG + 56. Google mirror - I'm elgooG [Xem mã nguồn](/scripts/google_mirror.js) @@ -455,7 +487,7 @@ --- Tất cả trong một ---
- 53. Facebook - All In One + 57. Facebook - All In One [Xem mã nguồn](/scripts/fb_allInOne.js) @@ -465,7 +497,7 @@ --- Tải xuống ---
- 54. Tải video fb đang xem + 58. Tải video fb đang xem [Xem mã nguồn](/scripts/fb_downloadWatchingVideo.js) @@ -473,7 +505,7 @@
- 55. Tải Story/Comment fb đang xem + 59. Tải Story/Comment fb đang xem [Xem mã nguồn](/scripts/fb_storySaver.js) @@ -481,7 +513,7 @@
- 56. Tải video/reel/watch fb từ url + 60. Tải video/reel/watch fb từ url [Xem mã nguồn](/scripts/fb_videoDownloader.js) @@ -489,7 +521,7 @@
- 57. Tải avatar từ fb user id + 61. Tải avatar từ fb user id [Xem mã nguồn](/scripts/fb_getAvatarFromUid.js) @@ -497,7 +529,7 @@
- 58. Xuất mục đã lưu trên facebook + 62. Xuất mục đã lưu trên facebook [Xem mã nguồn](/scripts/fb_exportSaved.js) @@ -507,7 +539,20 @@ --- Nổi bật ---
- 59. Facebook - Xem tin nhắn bị gỡ + 63. Tự động thích bài đăng Facebook + + [Xem mã nguồn](/scripts/fb_autoLike.js) + + Tự động thả cảm xúc cho bài đăng trên Facebook. +
    +
  • Hỗ trợ mọi loại bài đăng (trang, nhóm, người dùng, new feed, ...)
  • +
  • Hỗ trợ gỡ/thêm cảm xúc hàng loạt
  • +
  • Hỗ trợ mọi loại cảm xúc
  • +
+ +
+
+ 64. Facebook - Xem tin nhắn bị gỡ [Xem mã nguồn](/scripts/fb_revealDeletedMessages.js) @@ -515,7 +560,7 @@
- 60. Facebook Story - Thêm cảm xúc + 65. Facebook Story - Thêm cảm xúc [Xem mã nguồn](/scripts/fb_moreReactionStory.js) @@ -525,7 +570,7 @@
- 61. Tắt đèn newfeed facebook + 66. Tắt đèn newfeed facebook [Xem mã nguồn](/scripts/fb_toggleLight.js) @@ -533,7 +578,7 @@
- 62. Ẩn dòng thời gian facebook + 67. Ẩn dòng thời gian facebook [Xem mã nguồn](/scripts/fb_toggleNewFeed.js) @@ -541,7 +586,7 @@
- 63. Dừng dòng thời gian facebook + 68. Dừng dòng thời gian facebook [Xem mã nguồn](/scripts/fb_stopNewFeed.js) @@ -552,7 +597,7 @@
- 64. 👀 Chặn "Đã xem" story facebook + 69. 👀 Chặn "Đã xem" story facebook [Xem mã nguồn](/scripts/fb_blockSeenStory.js) @@ -560,7 +605,7 @@
- 65. Hiện tổng lượt thích bài viết facebook + 70. Hiện tổng lượt thích bài viết facebook [Xem mã nguồn](/scripts/fb_getPostReactionCount.js) @@ -570,7 +615,7 @@
- 66. Facebook - Ai đang nhắn cho bạn? + 71. Facebook - Ai đang nhắn cho bạn? [Xem mã nguồn](/scripts/fb_whoIsTyping.js) @@ -580,7 +625,7 @@ --- Thống kê ---
- 67. Facebook - Xem các nhóm bạn bè tham gia + 72. Facebook - Xem các nhóm bạn bè tham gia [Xem mã nguồn](/scripts/fb_searchGroupForOther.js) @@ -588,7 +633,7 @@
- 68. Facebook - Xem các trang bạn bè thích + 73. Facebook - Xem các trang bạn bè thích [Xem mã nguồn](/scripts/fb_searchPageForOther.js) @@ -596,7 +641,7 @@
- 69. Facebook - Tìm mọi bài viết của bạn bè + 74. Facebook - Tìm mọi bài viết của bạn bè [Xem mã nguồn](/scripts/fb_searchPostsForOther.js) @@ -606,7 +651,7 @@ --- Access Token ---
- 70. Kiểm tra fb access token + 75. Kiểm tra fb access token [Xem mã nguồn](/scripts/fb_checkToken.js) @@ -614,7 +659,7 @@
- 71. Lấy fb token EAAB (instagram) + 76. Lấy fb token EAAB (instagram) [Xem mã nguồn](/scripts/fb_getTokenFacebook.js) @@ -622,7 +667,7 @@
- 72. Lấy fb token EAADo1 (messenger) + 77. Lấy fb token EAADo1 (messenger) [Xem mã nguồn](/scripts/fb_getTokenMessage.js) @@ -630,7 +675,7 @@
- 73. Lấy fb token EAAG (business_locations) + 78. Lấy fb token EAAG (business_locations) [Xem mã nguồn](/scripts/fb_getTokenBussinessLocation.js) @@ -638,7 +683,7 @@
- 74. Lấy fb token EAAB (campaigns) + 79. Lấy fb token EAAB (campaigns) [Xem mã nguồn](/scripts/fb_getTokenCampaigns.js) @@ -646,7 +691,7 @@
- 75. Lấy fb token từ cookie (ffb.vn) + 80. Lấy fb token từ cookie (ffb.vn) [Xem mã nguồn](/scripts/fb_getTokenFfb.js) @@ -656,7 +701,7 @@ --- Lấy ID ---
- 76. Lấy fb User ID + 81. Lấy fb User ID [Xem mã nguồn](/scripts/fb_getUid.js) @@ -664,7 +709,7 @@
- 77. Lấy fb Page ID + 82. Lấy fb Page ID [Xem mã nguồn](/scripts/fb_getPageId.js) @@ -672,7 +717,7 @@
- 78. Lấy fb Group ID + 83. Lấy fb Group ID [Xem mã nguồn](/scripts/fb_getGroupId.js) @@ -680,7 +725,7 @@
- 79. Lấy fb Album ID + 84. Lấy fb Album ID [Xem mã nguồn](/scripts/fb_getAlbumId.js) @@ -688,7 +733,7 @@
- 80. Lấy tất cả fb album id từ trang hiện tại + 85. Lấy tất cả fb album id từ trang hiện tại [Xem mã nguồn](/scripts/fb_getAllAlbumIdFromCurrentWebsite.js) @@ -696,7 +741,7 @@
- 81. Lấy fb User ID từ URL + 86. Lấy fb User ID từ URL [Xem mã nguồn](/scripts/fb_getUidFromUrl.js) @@ -704,7 +749,7 @@
- 82. Lấy tất cả fb user ID từ trang tìm kiếm + 87. Lấy tất cả fb user ID từ trang tìm kiếm [Xem mã nguồn](/scripts/fb_getAllUidFromFbSearch.js) @@ -712,7 +757,7 @@
- 83. Lấy tất cả fb user ID từ group + 88. Lấy tất cả fb user ID từ group [Xem mã nguồn](/scripts/fb_getAllUidOfGroupMembers.js) @@ -722,7 +767,7 @@ --- Phím tắt ---
- 84. Xem mục đã lưu trên facebook + 89. Xem mục đã lưu trên facebook [Xem mã nguồn](/scripts/fb_openSaved.js) @@ -730,7 +775,7 @@
- 85. Xem kỷ niệm của bạn trên facebook + 90. Xem kỷ niệm của bạn trên facebook [Xem mã nguồn](/scripts/fb_openMemories.js) @@ -738,7 +783,7 @@
- 86. Xem các quảng cáo fb bạn đã xem + 91. Xem các quảng cáo fb bạn đã xem [Xem mã nguồn](/scripts/fb_openAdsActivities.js) @@ -746,7 +791,7 @@
- 87. Xem nhật ký hoạt động trên facebook + 92. Xem nhật ký hoạt động trên facebook [Xem mã nguồn](/scripts/fb_openAllActivities.js) @@ -754,7 +799,7 @@
- 88. Video bạn vừa xem trên facebook + 93. Video bạn vừa xem trên facebook [Xem mã nguồn](/scripts/fb_openVideoActivities.js) @@ -762,7 +807,7 @@
- 89. Sự kiện đã tham gia trên facebook + 94. Sự kiện đã tham gia trên facebook [Xem mã nguồn](/scripts/fb_openPassEvents.js) @@ -770,7 +815,7 @@
- 90. Sinh nhật bạn bè facebook + 95. Sinh nhật bạn bè facebook [Xem mã nguồn](/scripts/fb_openBirthdays.js) @@ -778,7 +823,7 @@
- 91. Đổi ngôn ngữ facebook + 96. Đổi ngôn ngữ facebook [Xem mã nguồn](/scripts/fb_openChangeLanguage.js) @@ -786,7 +831,7 @@
- 92. Khôi phục tài khoản facebook + 97. Khôi phục tài khoản facebook [Xem mã nguồn](/scripts/fb_openAccountHacked.js) @@ -797,7 +842,7 @@ ### Instagram
- 93. Lấy insta thông tin user (uid, avatar, ...) + 98. Lấy insta thông tin user (uid, avatar, ...) [Xem mã nguồn](/scripts/insta_getUserInfo.js) @@ -805,7 +850,7 @@
- 94. Thêm nút tải cho Instagram + 99. Thêm nút tải cho Instagram [Xem mã nguồn](/scripts/insta_injectDownloadBtn.js) @@ -815,7 +860,7 @@
- 95. Insta - Xem story ẩn danh + 100. Insta - Xem story ẩn danh [Xem mã nguồn](/scripts/insta_anonymousStoryViewer.js) @@ -825,7 +870,7 @@ --- Tải hàng loạt ---
- 96. Tải về tất cả media của insta user (API) + 101. Tải về tất cả media của insta user (API) [Xem mã nguồn](/scripts/insta_getAllUserMedia.js) @@ -833,7 +878,7 @@
- 97. Insta - Tải tất cả following/follower + 102. Insta - Tải tất cả following/follower [Xem mã nguồn](/scripts/insta_getFollowForOther.js) @@ -844,65 +889,97 @@ ### Youtube
- 98. Tải video/audio youtube + 103. Picture in Picture + + [Xem mã nguồn](/scripts/pictureInPicture.js) + + Xem video trong cửa sổ nổi + +
+
+ 104. Tải video/audio youtube [Xem mã nguồn](/scripts/youtube_downloadVideo.js) - Tải cả video giới hạn độ tuổi, không cần đăng nhập + Tải cả video giới hạn độ tuổi, không cần đăng nhập +
    +
  • Bấm 1 lần để tải video hiện tại
  • +
  • Bật tự chạy để hiển thị nút tải
  • +
+ + ![](/scripts/youtube_downloadVideo.png)
- 99. Tắt/Mở đèn youtube + 105. Lấy phụ đề video trên Youtube - [Xem mã nguồn](/scripts/youtube_toggleLight.js) + [Xem mã nguồn](/scripts/youtube_getVideoCaption.js) - Tắt/Mở đèn để tập trung xem video youtube + - Bấm để tải về tất cả phụ đề của video youtube đang xem
- Bật tự chạy để hiển thị phụ đề thời gian thực
+ + ![](/scripts/youtube_getVideoCaption.png)
- 100. Picture in Picture + 106. Hiện lượt không thích youtube - [Xem mã nguồn](/scripts/pictureInPicture.js) + [Xem mã nguồn](/scripts/youtube_viewDislikes.js) - Xem video trong cửa sổ nổi + Hiển thị số lượt không thích của video/short youtube
- 101. PIP toàn website + 107. Youtube nonstop - [Xem mã nguồn](/scripts/pip_fullWebsite.js) + [Xem mã nguồn](/scripts/youtube_nonstop.js) - Picture in picture: Xem toàn bộ website (thay vì chỉ video) trong của sổ nổi + Phát youtube không còn bị làm phiền bởi popup 'Video đã tạm dừng. Bạn có muốn xem tiếp?' của youtube. + + ![](/scripts/youtube_nonstop.png)
- 102. PIP cho canvas + 108. Đổi quốc gia Youtube - [Xem mã nguồn](/scripts/pip_canvas.js) + [Xem mã nguồn](/scripts/youtube_changeCountry.js) - Picture in picture: Xem canvas trong của sổ nổi + Đổi quốc gia youtube để xem nội dung youtube bên các nước khác
- 103. Hiện lượt không thích youtube + 109. Lấy thumbnail video trên Youtube - [Xem mã nguồn](/scripts/youtube_viewDislikes.js) + [Xem mã nguồn](/scripts/youtube_getVideoThumbnail.js) - Hiển thị số lượt không thích của video/short youtube + Tải về hình thumbnail độ phân giải lớn nhất của video youtube đang xem
- 104. Youtube nonstop + 110. Tắt/Mở đèn youtube - [Xem mã nguồn](/scripts/youtube_nonstop.js) + [Xem mã nguồn](/scripts/youtube_toggleLight.js) - Phát youtube không còn bị làm phiền bởi popup 'Video đã tạm dừng. Bạn có muốn xem tiếp?' của youtube. + Tắt/Mở đèn để tập trung xem video youtube - ![](/scripts/youtube_nonstop.png) +
+
+ 111. PIP toàn website + + [Xem mã nguồn](/scripts/pip_fullWebsite.js) + + Picture in picture: Xem toàn bộ website (thay vì chỉ video) trong của sổ nổi
- 105. Improve YouTube - 85+ chức năng + 112. PIP cho canvas + + [Xem mã nguồn](/scripts/pip_canvas.js) + + Picture in picture: Xem canvas trong của sổ nổi + +
+
+ 113. Improve YouTube - 85+ chức năng [Xem mã nguồn](/scripts/recommend_improve_youtube.js) @@ -914,7 +991,7 @@ --- Tiktok ---
- 106. Tiktok - Tải video đang xem + 114. Tiktok - Tải video đang xem [Xem mã nguồn](/scripts/tiktok_downloadWatchingVideo.js) @@ -922,7 +999,7 @@
- 107. Tiktok - Tải video từ URL + 115. Tiktok - Tải video từ URL [Xem mã nguồn](/scripts/tiktok_downloadVideo.js) @@ -930,7 +1007,7 @@
- 108. Tiktok - Tải hàng loạt + 116. Tiktok - Tải hàng loạt [Xem mã nguồn](/scripts/tiktok_batchDownload.js) @@ -942,7 +1019,7 @@ --- Douyin ---
- 109. Douyin - Tải video đang xem + 117. Douyin - Tải video đang xem [Xem mã nguồn](/scripts/douyin_downloadWachingVideo.js) @@ -950,7 +1027,7 @@
- 110. Douyin - Tải tất cả video người dùng + 118. Douyin - Tải tất cả video người dùng [Xem mã nguồn](/scripts/douyin_downloadAllVideoUser.js) @@ -962,7 +1039,7 @@ --- Tiện ích ---
- 111. Thời gian lướt web + 119. Thời gian lướt web [Xem mã nguồn](/scripts/web_timer.js) @@ -973,7 +1050,7 @@
- 112. Tự động khoá trang web + 120. Tự động khoá trang web [Xem mã nguồn](/scripts/auto_lockWebsite.js) @@ -985,17 +1062,20 @@
- 113. Cuộn chuột siêu mượt + 121. Cuộn chuột siêu mượt [Xem mã nguồn](/scripts/smoothScroll.js) Cuộn chuột siêu mượt cho mọi trang web.
- Mượt như khi cuộn chuột trong extension này vậy.

- Hỗ trợ scroll khi bấm chuột giữa.
+
    +
  • Khuyên dùng với chuột (tắt nếu dùng touchpad)
  • +
  • Bấm để Tắt/Mở cho trang web hiện tại
  • +
  • Hỗ trợ bấm chuột giữa để cuộn trang
  • +

- 114. Phóng to mọi hình ảnh + 122. Phóng to mọi hình ảnh [Xem mã nguồn](/scripts/magnify_image.js) @@ -1017,7 +1097,7 @@
- 115. Tự động - xem ảnh lớn nhất + 123. Tự động - xem ảnh lớn nhất [Xem mã nguồn](/scripts/auto_redirectLargestImageSrc.js) @@ -1031,7 +1111,7 @@
- 116. Hiện ảnh khi di chuột qua link + 124. Hiện ảnh khi di chuột qua link [Xem mã nguồn](/scripts/showImageOnHoverLink.js) @@ -1039,7 +1119,7 @@
- 117. Xoá theo dõi trong url + 125. Xoá theo dõi trong url [Xem mã nguồn](/scripts/remove_tracking_in_url.js) @@ -1052,7 +1132,7 @@
- 118. Không tắt trình duyệt khi tắt tab cuối + 126. Không tắt trình duyệt khi tắt tab cuối [Xem mã nguồn](/scripts/prevent_closeBrowser_lastTab.js) @@ -1061,7 +1141,7 @@
- 119. Chống lừa đảo + 127. Chống lừa đảo [Xem mã nguồn](/scripts/chongLuaDao.js) @@ -1073,7 +1153,7 @@
- 120. Rút gọn link + 128. Rút gọn link [Xem mã nguồn](/scripts/shortenURL.js) @@ -1081,7 +1161,7 @@
- 121. Giải mã link rút gọn + 129. Giải mã link rút gọn [Xem mã nguồn](/scripts/unshorten.js) @@ -1089,7 +1169,7 @@
- 122. Tạo tin nhắn tàng hình + 130. Tạo tin nhắn tàng hình [Xem mã nguồn](/scripts/createInvisibleText.js) @@ -1099,7 +1179,7 @@ --- Tự động ---
- 123. In web ra PDF + 131. In web ra PDF [Xem mã nguồn](/scripts/webToPDF.js) @@ -1107,7 +1187,7 @@
- 124. Chụp ảnh toàn bộ web + 132. Chụp ảnh toàn bộ web [Xem mã nguồn](/scripts/screenshotFullPage.js) @@ -1115,7 +1195,7 @@
- 125. Chụp ảnh web + 133. Chụp ảnh web [Xem mã nguồn](/scripts/screenshotVisiblePage.js) @@ -1123,7 +1203,7 @@
- 126. Cuộn trang xuống cuối cùng + 134. Cuộn trang xuống cuối cùng [Xem mã nguồn](/scripts/scrollToVeryEnd.js) @@ -1131,7 +1211,7 @@
- 127. Trích xuất mọi emails từ trang web + 135. Trích xuất mọi emails từ trang web [Xem mã nguồn](/scripts/getAllEmailsInWeb.js) @@ -1139,7 +1219,7 @@
- 128. Bật/Tắt Hack game T-Rex Dino + 136. Bật/Tắt Hack game T-Rex Dino [Xem mã nguồn](/scripts/dino_hack.js) @@ -1147,7 +1227,7 @@
- 129. Tạo mật khẩu cho trang web + 137. Tạo mật khẩu cho trang web [Xem mã nguồn](/scripts/passwordGenerator.js) @@ -1157,7 +1237,7 @@ --- Công cụ ---
- 130. Chữ sang QRCode + 138. Chữ sang QRCode [Xem mã nguồn](/scripts/textToQrCode.js) @@ -1165,7 +1245,7 @@
- 131. Văn bản thành Giọng nói (j2team) + 139. Văn bản thành Giọng nói (j2team) [Xem mã nguồn](/scripts/textToSpeech.js) @@ -1173,7 +1253,7 @@
- 132. Thay đổi đầu ra âm thanh + 140. Thay đổi đầu ra âm thanh [Xem mã nguồn](/scripts/changeAudioOutput.js) @@ -1181,7 +1261,7 @@
- 133. Send - Chia sẻ file nhanh + 141. Send - Chia sẻ file nhanh [Xem mã nguồn](/scripts/send_shareFiles.js) @@ -1189,7 +1269,7 @@
- 134. Vuiz - Tạo logo WAP online + 142. Vuiz - Tạo logo WAP online [Xem mã nguồn](/scripts/vuiz_createLogo.js) @@ -1197,7 +1277,7 @@
- 135. Phân tích hiệu suất + 143. Phân tích hiệu suất [Xem mã nguồn](/scripts/performanceAnalyzer.js) @@ -1205,7 +1285,7 @@
- 136. IT Tools - Vì tương lai Developer + 144. IT Tools - Vì tương lai Developer [Xem mã nguồn](/scripts/recommend_ItTools.js) @@ -1213,7 +1293,7 @@
- 137. CopyIcon - emoji, icon, svg miễn phí + 145. CopyIcon - emoji, icon, svg miễn phí [Xem mã nguồn](/scripts/recommend_copyicon.js) @@ -1221,7 +1301,7 @@
- 138. Beautify Tools + 146. Beautify Tools [Xem mã nguồn](/scripts/recommend_beautifytools.js) @@ -1242,7 +1322,7 @@ --- Github ---
- 139. Github - Đi tới commit bất kỳ + 147. Github - Đi tới commit bất kỳ [Xem mã nguồn](/scripts/github_goToAnyCommit.js) @@ -1250,7 +1330,7 @@
- 140. Github - xem trước file HTML + 148. Github - xem trước file HTML [Xem mã nguồn](/scripts/github_HTMLPreview.js) @@ -1258,7 +1338,7 @@
- 141. Github - Mở repo pages + 149. Github - Mở repo pages [Xem mã nguồn](/scripts/github_openRepoPages.js) @@ -1268,7 +1348,7 @@
- 142. Github - Mở repo trong github.dev + 150. Github - Mở repo trong github.dev [Xem mã nguồn](/scripts/githubdev.js) @@ -1276,7 +1356,7 @@
- 143. Github - Mở repo trong github1s.com + 151. Github - Mở repo trong github1s.com [Xem mã nguồn](/scripts/github1s.js) @@ -1284,7 +1364,7 @@
- 144. Cloc - đếm số dòng code + 152. Cloc - đếm số dòng code [Xem mã nguồn](/scripts/recommend_cloc.js) @@ -1294,7 +1374,7 @@
- 145. Refined GitHub + 153. Refined GitHub [Xem mã nguồn](/scripts/recommend_refined_github.js) @@ -1304,7 +1384,7 @@ --- Mua sắm ---
- 146. Shopee - Loại hàng mua nhiều nhất + 154. Shopee - Loại hàng mua nhiều nhất [Xem mã nguồn](/scripts/shopee_topVariation.js) @@ -1314,7 +1394,7 @@
- 147. Shopee - Thống kê chi tiêu + 155. Shopee - Thống kê chi tiêu [Xem mã nguồn](/scripts/shopee_totalSpendMoney.js) @@ -1322,7 +1402,7 @@
- 148. Shopee - Xuất lịch sử đơn hàng (Excel) + 156. Shopee - Xuất lịch sử đơn hàng (Excel) [Xem mã nguồn](/scripts/shopee_totalSpendMoney_excel.js) @@ -1330,7 +1410,7 @@
- 149. Tiki - Đã mua bao nhiêu tiền? + 157. Tiki - Đã mua bao nhiêu tiền? [Xem mã nguồn](/scripts/tiki_totalSpendMoney.js) @@ -1338,7 +1418,7 @@
- 150. Beecost + 158. Beecost [Xem mã nguồn](/scripts/recommend_Beecost.js) @@ -1348,7 +1428,7 @@ --- PDF ---
- 151. FastDoc - Chuyển PDF/Ảnh sang Word/Excel + 159. FastDoc - Chuyển PDF/Ảnh sang Word/Excel [Xem mã nguồn](/scripts/recommend_fastDoc.js) @@ -1356,7 +1436,7 @@
- 152. SmartPDF - Công cụ cho PDF + 160. SmartPDF - Công cụ cho PDF [Xem mã nguồn](/scripts/recommend_smartPDF.js) @@ -1364,7 +1444,7 @@
- 153. PDF Stuffs - Công cụ PDF + 161. PDF Stuffs - Công cụ PDF [Xem mã nguồn](/scripts/recommend_pdfstuffs.js) @@ -1376,7 +1456,7 @@ --- Mở khoá web ---
- 154. Hack Duck race + 162. Hack Duck race [Xem mã nguồn](/scripts/duckRace_cheat.js) @@ -1386,7 +1466,7 @@
- 155. Hack Wheel of Names + 163. Hack Wheel of Names [Xem mã nguồn](/scripts/wheelOfNames_hack.js) @@ -1394,7 +1474,7 @@
- 156. Đọc bài viết medium full + 164. Đọc bài viết medium full [Xem mã nguồn](/scripts/medium_readFullArticle.js) @@ -1402,7 +1482,7 @@
- 157. Medium - Fix font Tiếng Việt + 165. Medium - Fix font Tiếng Việt [Xem mã nguồn](/scripts/medium_fixVietnameseFont.js) @@ -1414,7 +1494,7 @@
- 158. Fireship - Mở khoá PRO + 166. Fireship - Mở khoá PRO [Xem mã nguồn](/scripts/fireship_vip.js) @@ -1422,7 +1502,7 @@
- 159. Studocu - Xem miễn phí VIP + 167. Studocu - Xem miễn phí VIP [Xem mã nguồn](/scripts/studocu_bypassPreview.js) @@ -1430,7 +1510,7 @@
- 160. Scribd - Xem miễn phí VIP + 168. Scribd - Xem miễn phí VIP [Xem mã nguồn](/scripts/scribd_bypassPreview.js) @@ -1438,17 +1518,27 @@
- 161. Studyphim - Xem miễn phí + 169. Studyphim - Xem miễn phí [Xem mã nguồn](/scripts/studyphim_unlimited.js) Xem phim miễn phí trên Studyphim không cần đăng nhập +
+
+ 170. Bypass Learn Anything + + [Xem mã nguồn](/scripts/bypass_learnAnything.js) + + Xem nội dung web learn-anything.xyz không cần đăng ký member + + ![](/scripts/bypass_LearnAnything.png) +
--- Mở khoá chức năng ---
- 162. Bật/Tắt cho phép sao chép + 171. Bật/Tắt cho phép sao chép [Xem mã nguồn](/scripts/simpleAllowCopy.js) @@ -1462,7 +1552,7 @@
- 163. Phát hiện ký tự ẩn (Zero-Width) + 172. Phát hiện ký tự ẩn (Zero-Width) [Xem mã nguồn](/scripts/detect_zeroWidthCharacters.js) @@ -1470,7 +1560,7 @@
- 164. Nhúng script vào trang web + 173. Nhúng script vào trang web [Xem mã nguồn](/scripts/injectScriptToWebsite.js) @@ -1478,7 +1568,7 @@
- 165. Hiện các thành phần web bị ẩn + 174. Hiện các thành phần web bị ẩn [Xem mã nguồn](/scripts/showHiddenFields.js) @@ -1486,7 +1576,7 @@
- 166. Xem cookies + 175. Xem cookies [Xem mã nguồn](/scripts/viewCookies.js) @@ -1494,7 +1584,7 @@
- 167. Xoá Cookies + 176. Xoá Cookies [Xem mã nguồn](/scripts/removeCookies.js) @@ -1504,7 +1594,7 @@ --- Khác ---
- 168. Tăng tốc tối đa trình duyệt + 177. Tăng tốc tối đa trình duyệt [Xem mã nguồn](/scripts/recommend_chromeFlags.js) @@ -1512,7 +1602,7 @@
- 169. Xem mật khẩu wifi đã lưu + 178. Xem mật khẩu wifi đã lưu [Xem mã nguồn](/scripts/recommend_viewSavedWifiPass.js) @@ -1520,7 +1610,7 @@
- 170. Leak check - lộ mật khẩu email? + 179. Leak check - lộ mật khẩu email? [Xem mã nguồn](/scripts/recommend_leakCheck.js) @@ -1532,7 +1622,7 @@ --- Nổi bật ---
- 171. Chế độ tối cho PDF + 180. Chế độ tối cho PDF [Xem mã nguồn](/scripts/darkModePDF.js) @@ -1540,7 +1630,7 @@
- 172. Bật/tắt chế độ chỉnh sửa website + 181. Bật/tắt chế độ chỉnh sửa website [Xem mã nguồn](/scripts/toggleEditPage.js) @@ -1548,7 +1638,7 @@
- 173. Hiện thị FPS + 182. Hiện thị FPS [Xem mã nguồn](/scripts/showFPS.js) @@ -1556,7 +1646,7 @@
- 174. Hiện thị FPS - ver 2 + 183. Hiện thị FPS - ver 2 [Xem mã nguồn](/scripts/showFps_v2.js) @@ -1564,7 +1654,7 @@
- 175. Ẩn/Hiện ô nhập mật khẩu + 184. Ẩn/Hiện ô nhập mật khẩu [Xem mã nguồn](/scripts/toggle_passwordField.js) @@ -1572,7 +1662,7 @@
- 176. Dark reader + 185. Dark reader [Xem mã nguồn](/scripts/recommend_DarkReader.js) @@ -1580,7 +1670,7 @@
- 177. CSS Portal - Nâng trình CSS + 186. CSS Portal - Nâng trình CSS [Xem mã nguồn](/scripts/recommend_cssportal.js) @@ -1588,7 +1678,7 @@
- 178. CSS Loaders - 600+ css loading + 187. CSS Loaders - 600+ css loading [Xem mã nguồn](/scripts/recommend_cssloaders.js) @@ -1596,7 +1686,7 @@
- 179. UIverse - Tổng hợp code UI xịn + 188. UIverse - Tổng hợp code UI xịn [Xem mã nguồn](/scripts/recommend_uiverse.js) @@ -1606,7 +1696,7 @@ --- Xem ---
- 180. Font Rendering - font chữ dễ nhìn + 189. Font Rendering - font chữ dễ nhìn [Xem mã nguồn](/scripts/recommend_fontRendering.js) @@ -1614,7 +1704,7 @@
- 181. Kiểm tra font chữ + 190. Kiểm tra font chữ [Xem mã nguồn](/scripts/whatFont.js) @@ -1622,7 +1712,7 @@
- 182. Xem tất cả tất cả javascript events + 191. Xem tất cả tất cả javascript events [Xem mã nguồn](/scripts/visualEvent.js) @@ -1630,7 +1720,7 @@
- 183. Xem mọi hình ảnh có trong website + 192. Xem mọi hình ảnh có trong website [Xem mã nguồn](/scripts/listAllImagesInWeb.js) @@ -1638,7 +1728,7 @@
- 184. Xem tất cả link + 193. Xem tất cả link [Xem mã nguồn](/scripts/viewAllLinks.js) @@ -1646,7 +1736,7 @@
- 185. Xem tất cả scripts + 194. Xem tất cả scripts [Xem mã nguồn](/scripts/viewScriptsUsed.js) @@ -1654,7 +1744,7 @@
- 186. Xem tất cả stylesheet + 195. Xem tất cả stylesheet [Xem mã nguồn](/scripts/viewStylesUsed.js) @@ -1662,7 +1752,7 @@
- 187. Trình kiểm tra css cục bộ + 196. Trình kiểm tra css cục bộ [Xem mã nguồn](/scripts/cssSelectorViewer.js) @@ -1672,7 +1762,7 @@ --- Xoá ---
- 188. Xoá màu website + 197. Xoá màu website [Xem mã nguồn](/scripts/removeColours.js) @@ -1680,7 +1770,7 @@
- 189. Xoá stylesheet + 198. Xoá stylesheet [Xem mã nguồn](/scripts/removeStylesheet.js) @@ -1688,7 +1778,7 @@
- 190. Xoá mọi hình ảnh + 199. Xoá mọi hình ảnh [Xem mã nguồn](/scripts/removeImages.js) @@ -1696,7 +1786,7 @@
- 191. Xoá mọi iframe/embed + 200. Xoá mọi iframe/embed [Xem mã nguồn](/scripts/removeBloat.js) @@ -1706,7 +1796,7 @@ --- Bảng ---
- 192. Thêm sắp xếp cho bảng + 201. Thêm sắp xếp cho bảng [Xem mã nguồn](/scripts/table_addSortTable.js) @@ -1714,7 +1804,7 @@
- 193. Thêm cột số thứ tự + 202. Thêm cột số thứ tự [Xem mã nguồn](/scripts/table_addNumberColumn.js) @@ -1722,7 +1812,7 @@
- 194. Đổi chỗ hàng và cột + 203. Đổi chỗ hàng và cột [Xem mã nguồn](/scripts/table_swapRowAndColumn.js) @@ -1732,7 +1822,7 @@ --- Khác ---
- 195. Tô màu cho link + 204. Tô màu cho link [Xem mã nguồn](/scripts/internalOrExternalLink.js) @@ -1742,7 +1832,7 @@
- 196. Lấy kích thước trang web + 205. Lấy kích thước trang web [Xem mã nguồn](/scripts/getWindowSize.js) @@ -1750,7 +1840,7 @@
- 197. Hiệu ứng tuyết rơi + 206. Hiệu ứng tuyết rơi [Xem mã nguồn](/scripts/letItSnow.js) diff --git a/pages/viewScriptSource/fonts/JetBrainsMono-Bold.woff2 b/pages/viewScriptSource/fonts/JetBrainsMono-Bold.woff2 new file mode 100644 index 00000000..4917f434 Binary files /dev/null and b/pages/viewScriptSource/fonts/JetBrainsMono-Bold.woff2 differ diff --git a/pages/viewScriptSource/fonts/JetBrainsMono-Regular.woff2 b/pages/viewScriptSource/fonts/JetBrainsMono-Regular.woff2 new file mode 100644 index 00000000..40da4276 Binary files /dev/null and b/pages/viewScriptSource/fonts/JetBrainsMono-Regular.woff2 differ diff --git a/pages/viewScriptSource/style.css b/pages/viewScriptSource/style.css index 61e6d256..3f1b9126 100644 --- a/pages/viewScriptSource/style.css +++ b/pages/viewScriptSource/style.css @@ -1,37 +1,72 @@ +@font-face { + font-family: JetBrainsMono; + src: url(fonts/JetBrainsMono-Regular.woff2); +} + +@font-face { + font-family: JetBrainsMono; + src: url(fonts/JetBrainsMono-Bold.woff2); + font-weight: bold; +} + +* { + font-family: JetBrainsMono, 'Courier New', Courier, monospace; +} + +*::-webkit-scrollbar { + height: 10px; + width: 10px; +} + +*::-webkit-scrollbar-track, +*::-webkit-scrollbar-track-piece { + background-color: #23241f; +} + +*::-webkit-scrollbar-thumb { + background-color: #828282; + border-radius: 10px; +} + body, pre, code { - margin: 0; - padding: 0; + margin: 0; + padding: 0; } body { - overflow: auto; - width: 100vw; - height: 100vh; + overflow: auto; + width: 100vw; + height: 100vh; +} + +pre { + background-color: #23241f; + width: max-content; + height: max-content; } code { - font-family: 'Courier New', Courier, monospace; - font-size: 14px; - font-style: normal; - font-variant: normal; - font-weight: 400; - line-height: 20px; - margin-top: 30px; + font-size: 14px; + font-style: normal; + font-variant: normal; + font-weight: 400; + line-height: 20px; } button { - position: fixed; - top: 0px; - left: 0px; - padding: 5px 10px; - border: none; - cursor: pointer; - color: #eee; - background-color: #555; + position: fixed; + top: 0px; + left: 0px; + padding: 5px 10px; + border: none; + cursor: pointer; + color: #eee; + background-color: #555; + transition: background-color ease-in-out 0.2s; } button:hover { - background-color: #999; + background-color: #828282; } diff --git a/popup/index.js b/popup/index.js index 366af5b6..cf436134 100644 --- a/popup/index.js +++ b/popup/index.js @@ -39,7 +39,7 @@ import { viewScriptSource, } from "./helpers/utils.js"; import { checkPass } from "../scripts/auto_lockWebsite.js"; -import _ from "../md/exportScriptsToMd.js"; +// import _ from "../md/exportScriptsToMd.js"; const settingsBtn = document.querySelector(".settings"); const openInNewTabBtn = document.querySelector(".open-in-newtab"); @@ -669,7 +669,7 @@ function initSettings() { })}" data-flow="bottom" >${t({ - vi: "Cuôn chuột siêu mượt", + vi: "Cuộn chuột siêu mượt", en: "Super smooth scroll", })}
diff --git a/popup/tabs.js b/popup/tabs.js index bc56c510..9dc1a71a 100644 --- a/popup/tabs.js +++ b/popup/tabs.js @@ -38,6 +38,51 @@ const tabs = [ scripts: [ // s._test, // s._ufs_statistic, + { + id: "recommend_theresanaiforthat", + icon: "https://theresanaiforthat.com/favicon.ico", + name: { + en: "There's an AI for that", + vi: "There's an AI for that - Tìm AI", + }, + description: { + en: "Collection of thousand of AI tools. Easy to search by category", + vi: "Tổng hợp hàng ngàn công cụ AI hiện có. Dễ dàng tìm kiếm theo chủ đề", + }, + popupScript: { + onClick: () => window.open("https://theresanaiforthat.com/"), + }, + }, + { + id: "recommend_timeis", + icon: "https://time.is/favicon.ico", + name: { + en: "Time.is - Check your time", + vi: "Time.is - Kiểm tra thời gian", + }, + description: { + en: "Exact time for any time zone.", + vi: "Đồng hồ chính xác nhất. Kiểm tra đồng hồ trên máy của bạn nhanh hay chậm.", + }, + popupScript: { + onClick: () => window.open("https://time.is/"), + }, + }, + { + id: "recommend_googleTrending", + icon: "https://www.gstatic.com/trends/favicon.ico", + name: { + en: "Google trending - See what trending now", + vi: "Google trending - Nội dung nổi bật", + }, + description: { + en: "See what people are searching on Google. Top treding every day, realtime.", + vi: "Xem mọi người đang tìm gì trên google. Thống kê từng ngày, thời gian thực.", + }, + popupScript: { + onClick: () => window.open("https://trends.google.com/"), + }, + }, s.similarWeb, s.similarWeb_bypassLimit, s.search_sharedAccount, @@ -120,6 +165,32 @@ const tabs = [ ...CATEGORY.download, scripts: [ createTitle("--- All in one ---", "--- Tổng hợp ---"), + { + id: "recommend_cobalt", + icon: "https://cobalt.tools/favicon.ico", + name: { + en: "Cobalt - Media downloader", + vi: "Cobalt - Tải video/nhạc", + }, + description: { + en: "Support youtube, tiktok, instagram, twitter/x, bilibili, twitch, vimeo, soundcloud, dailymotion, pinterest, reddit, tumblr, ...", + vi: "Hỗ trợ youtube, tiktok, instagram, twitter/x, bilibili, twitch, vimeo, soundcloud, dailymotion, pinterest, reddit, tumblr, ...", + }, + badges: [BADGES.recommend, BADGES.new], + buttons: [ + { + icon: '', + name: { + vi: "Github", + en: "Github", + }, + onClick: () => window.open("https://github.com/imputnet/cobalt"), + }, + ], + popupScript: { + onClick: () => window.open("https://cobalt.tools/"), + }, + }, s.saveAllVideo, s.vuiz_getLink, s.savevideo_me, @@ -211,7 +282,6 @@ const tabs = [ s.studocu_downs, s.scribd_downloadDocuments, s.tailieu_vn, - { id: "recommend_docsdownloader", icon: "https://docsdownloader.com/assets/img/android-icon-192x192.png", @@ -306,6 +376,7 @@ const tabs = [ // s.fb_downloadWallMediaFromPosts, // s.fb_getAllAlbumInformation, createTitle("--- Hot ---", "--- Nổi bật ---"), + s.fb_autoLike, s.fb_revealDeletedMessages, s.fb_moreReactionStory, s.fb_toggleLight, @@ -498,14 +569,16 @@ const tabs = [ { ...CATEGORY.youtube, scripts: [ - // s.youtube_localDownloader, + s.pictureInPicture, s.youtube_downloadVideo, + s.youtube_getVideoCaption, + s.youtube_viewDislikes, + s.youtube_nonstop, + s.youtube_changeCountry, + s.youtube_getVideoThumbnail, s.youtube_toggleLight, - s.pictureInPicture, s.pip_fullWebsite, s.pip_canvas, - s.youtube_viewDislikes, - s.youtube_nonstop, { id: "recommend_improve_youtube", icon: "https://lh3.googleusercontent.com/WDytHNO8o0Ev6sWp_yLbya_SSS9kXZWGJIc-WJ3goInHJalzD02Aq5wVhExFlbzrzNsOxo-V1O_TgF-JLJNyTkvB=s0", @@ -1009,6 +1082,20 @@ const recommendTab = { window.open("https://github.com/HoangTran0410/FBMediaDownloader"), }, }, + // https://www.nirsoft.net/ + { name: { en: "--- Tools ---", vi: "--- Công cụ hay ---" } }, + { + id: "recommend_nirsoft", + icon: "https://www.nirsoft.net/favicon.ico", + name: { en: "Nirsoft", vi: "Nirsoft" }, + description: { + en: "A unique collection of small and useful freeware utilities", + vi: "Tổng hợp bộ công cụ nhanh, nhẹ, miễn phí dành cho windows", + }, + popupScript: { + onClick: () => window.open("https://www.nirsoft.net/"), + }, + }, { name: { en: "--- Extensions ---", vi: "--- Extensions hay ---" } }, { id: "recommend_CRXViewer", diff --git a/scripts/_index.js b/scripts/_index.js index 03de5a6d..492beea0 100644 --- a/scripts/_index.js +++ b/scripts/_index.js @@ -131,7 +131,6 @@ export { default as vuiz_createLogo } from "./vuiz_createLogo.js"; export { default as vuiz_getLink } from "./vuiz_getLink.js"; export { default as ggdrive_downloadPdf } from "./ggdrive_downloadPdf.js"; export { default as ggdrive_downloadPresentation } from "./ggdrive_downloadPresentation.js"; -export { default as youtube_localDownloader } from "./youtube_localDownloader.js"; export { default as twitter_downloadButton } from "./twitter_downloadButton.js"; export { default as spotify_downloadButton } from "./spotify_downloadButton.js"; export { default as ggdrive_downloadDoc } from "./ggdrive_downloadDoc.js"; @@ -168,3 +167,8 @@ export { default as showImageOnHoverLink } from "./showImageOnHoverLink.js"; export { default as fb_allInOne } from "./fb_allInOne.js"; export { default as fb_getPostReactionCount } from "./fb_getPostReactionCount.js"; export { default as bypass_learnAnything } from "./bypass_learnAnything.js"; +export { default as youglish_search } from "./youglish_search.js"; +export { default as youtube_getVideoThumbnail } from "./youtube_getVideoThumbnail.js"; +export { default as youtube_getVideoCaption } from "./youtube_getVideoCaption.js"; +export { default as youtube_changeCountry } from "./youtube_changeCountry.js"; +export { default as fb_autoLike } from "./fb_autoLike.js"; diff --git a/scripts/_test.js b/scripts/_test.js index 140501e6..986166a3 100644 --- a/scripts/_test.js +++ b/scripts/_test.js @@ -1,4 +1,5 @@ import { UfsGlobal } from "./content-scripts/ufs_global.js"; +import { fetchGraphQl, getFbdtsg } from "./fb_GLOBAL.js"; export default { icon: "", @@ -12,6 +13,79 @@ export default { }, popupScript: { + onClick: async () => { + function getAverageRGB(img) { + var blockSize = 5, // only visit every 5 pixels + defaultRGB = { r: 0, g: 0, b: 0 }, // for non-supporting envs + canvas = document.createElement("canvas"), + context = canvas.getContext && canvas.getContext("2d"), + data, + width, + height, + i = -4, + length, + rgb = { r: 0, g: 0, b: 0 }, + count = 0; + + if (!context) { + return defaultRGB; + } + + height = canvas.height = + img.naturalHeight || img.offsetHeight || img.height; + width = canvas.width = img.naturalWidth || img.offsetWidth || img.width; + + context.drawImage(img, 0, 0); + + try { + data = context.getImageData(0, 0, width, height); + } catch (e) { + /* security error, img on diff domain */ + return defaultRGB; + } + + length = data.data.length; + + while ((i += blockSize * 4) < length) { + ++count; + rgb.r += data.data[i]; + rgb.g += data.data[i + 1]; + rgb.b += data.data[i + 2]; + } + + // ~~ used to floor values + rgb.r = ~~(rgb.r / count); + rgb.g = ~~(rgb.g / count); + rgb.b = ~~(rgb.b / count); + + return rgb; + } + + function getAverageRGBFromUrl(url) { + return new Promise((resolve, reject) => { + let img = new Image(); + img.src = url; + img.onload = () => { + let rgb = getAverageRGB(img); + resolve(rgb); + }; + img.onerror = (error) => { + alert("Error: " + JSON.stringify(error)); + console.log(error); + reject(); + }; + }); + } + + getAverageRGBFromUrl( + "https://scontent.fsgn2-7.fna.fbcdn.net/v/t39.30808-1/352545274_2285354618338828_3224207586206963955_n.jpg?stp=dst-jpg_p480x480&ccb=1-7&_nc_sid=0ecb9b&_nc_ohc=7D3Usqt8u2UQ7kNvgEeWxht&_nc_ht=scontent.fsgn2-7.fna&oh=00_AYAeunf-6BuCakj2L59wVi8mNA5QuGlLuVQ6eROL5UKC8A&oe=668D93B9" + ).then(console.log); + + getAverageRGBFromUrl( + "https://www.facebook.com/profile/pic.php?cuid=AYjse6TURBs86Oy-7iO2UdCZFqYOhyemrWC2KV8yPo6ABGAHCWi87GNGtXwITHZJRPIOPLMTbuZetu6t3T9WQllYE5xhBm4t5rAZVKC1IGjSqGbJiwr9z4g-bDx6bHAPuqqXgfCaH4Yml-_UAAJgEGdftXSGc4uCKUer8j3oCtpLakjxWAOTYeNAzt-rWWp0fNtY03PE0XzLzPqKEI8leoS_08eYd_V9L4O_P1lwGxHyMA&square_px=64" + ).then(console.log); + }, + // selenium automation get album's images _onClick: async () => { const { openWebAndRunScript } = await import("./helpers/utils.js"); diff --git a/scripts/_ufs_statistic.css b/scripts/_ufs_statistic.css index 68ff0c30..281ad85f 100644 --- a/scripts/_ufs_statistic.css +++ b/scripts/_ufs_statistic.css @@ -9,6 +9,10 @@ canvas { max-height: 500px; } +li { + position: relative; +} + li:hover { background: #555; color: white; @@ -16,14 +20,13 @@ li:hover { li a { display: inline-block; - position: relative; } li a img { width: 30px; transition: all 0.2s ease; position: absolute; - left: 0; + right: 0; top: 0; } diff --git a/scripts/backup/auto-like-fb.js b/scripts/backup/auto-like-fb.js new file mode 100644 index 00000000..e1277934 --- /dev/null +++ b/scripts/backup/auto-like-fb.js @@ -0,0 +1,59 @@ +javascript: (async function () { + function sleep(ms) { + return new Promise((resolve) => setTimeout(resolve, ms)); + } + function focusTo(element) { + element.dispatchEvent( + new MouseEvent("pointerover", { + view: window, + bubbles: true, + cancelable: true, + }) + ); + } + + function scrollToBottom() { + window.scrollTo(0, document.body.scrollHeight, { + // behavior: "smooth", + }); + } + + const doneKey = "auto-like-done"; + const btns = []; + while (true) { + if (!btns.length) { + let curBtns = Array.from( + document.querySelectorAll("[aria-label='Bày tỏ cảm xúc']:not(li *)") + ); + let added = 0; + for (let btn of curBtns) { + if (btn.getAttribute(doneKey) === null) { + btns.push(btn); + btn.setAttribute(doneKey, true); + added++; + } + } + if (added === 0) break; + } + + for (let btn of btns) { + btn.scrollIntoView({ + block: "center", + // behavior: "smooth", + }); + btn.click(); + await sleep(500); + let loveBtn = document.querySelector("[aria-label='Yêu thích']"); + if (loveBtn) { + focusTo(loveBtn); + await sleep(500); + loveBtn.click(); + await sleep(500); + } + btns.splice(btns.indexOf(btn), 1); + } + scrollToBottom(); + await sleep(3000); + } + alert("xong"); +})(); diff --git a/scripts/backup/fb-proxy.js b/scripts/backup/fb-proxy.js index bb388a6c..f4b95028 100644 --- a/scripts/backup/fb-proxy.js +++ b/scripts/backup/fb-proxy.js @@ -1,41 +1,38 @@ +function make_uuid() { + let h = new Date().getTime(); + return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (i) { + let F = (h + 16 * Math.random()) % 16 | 0; + h = Math.floor(h / 16); + return (i == "x" ? F : (3 & F) | 8).toString(16); + }); +} + (function () { "use strict"; (function () { - function n(r) { - return r + function decodeModuleName(encoded) { + return encoded; + return encoded .split("") .reverse() .map((f) => String.fromCharCode(f.charCodeAt(0) - 1)) .join(""); } - function l(r) { - const [f, u = "default"] = n(r).split("|"); - return [f, u]; + function getModuleName(encoded) { + const [moduleName, extensionId = "default"] = + decodeModuleName(encoded).split("|"); + return [moduleName, extensionId]; } function cacheFunction(code) { const fnBody = (function (code) { return code.slice(code.indexOf("{") + 1, code.lastIndexOf("}")) || ""; })(code), fnParams = (function (code) { - let i = code.replace(b, ""), + let i = code.replace(commentRegex, ""), F = i.slice(i.indexOf("(") + 1, i.indexOf(")")).match(s); return F === null && (F = []), F; })(code), - uuid = - "id_" + - (function () { - let h = new Date().getTime(); - return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace( - /[xy]/g, - function (i) { - var F = (h + 16 * Math.random()) % 16 | 0; - return ( - (h = Math.floor(h / 16)), - (i == "x" ? F : (3 & F) | 8).toString(16) - ); - } - ); - })(); + uuid = "id_" + make_uuid(); let y = `window['__fnCache']["${uuid}"]= function(${fnParams}){${fnBody}}`, c = document.createElement("script"); try { @@ -48,7 +45,7 @@ return v.appendChild(c), v.removeChild(c), window.__fnCache[`${uuid}`]; } window.__fnCache = window.__fnCache || {}; - let b = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/gm, + let commentRegex = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/gm, s = /([^\s,]+)/g; function m(r, f, u = !1) { const w = f.split(/\.|\[(\d+)\]/).filter(Boolean); @@ -58,174 +55,188 @@ if (((y = c), (c = c[w[v]]), c === void 0)) return u ? y : void 0; return u ? y : c; } - ((r) => { + (() => { if (window.GZUAwCFuFf) return; window.GZUAwCFuFf = !0; - const f = {}, + const moduleCached = {}, u = {}, w = {}, - y = {}, + isModuleLoaded = {}, c = {}; - let v = window.__d; + let modified__d = window.__d; window.__d && - (~v.toString().indexOf("__d_stub") + (~modified__d.toString().indexOf("__d_stub") ? delete window.__d - : (v = new Proxy(window.__d, { - apply: (e, t, d) => ((d = i(d)), e.apply(t, d)), + : (modified__d = new Proxy(window.__d, { + apply: (target, thisArg, argumentsList) => ( + (argumentsList = i(argumentsList)), + target.apply(thisArg, argumentsList) + ), }))), Object.defineProperty(window, "__d", { get: function () { - return v; + return modified__d; }, set: function (e) { - v = new Proxy(e, { - apply: (t, d, p) => ((p = i(p)), t.apply(d, p)), + modified__d = new Proxy(e, { + apply: (target, thisArg, argumentsList) => ( + (argumentsList = i(argumentsList)), + target.apply(thisArg, argumentsList) + ), }); }, }); - const h = []; + const moduleNames = []; function i(e) { - let [t, d, p] = e; - return ( - typeof t != "string" || - h.includes(t) || - (h.push(t), - (e[2] = (function (_, S) { - if (!w[S]) return _; - const k = w[S]; - k.sort((a, A) => a.options.order - A.options.order); - const E = k.find((a) => a.options.skipOthers); - return cacheFunction( - E - ? E.replacement(_.toString()) - : k.reduce((a, A) => (a = A.replacement(a)), _.toString()) - ); - })(e[2], t)), - (e[2] = (function (_, S) { - return u[S] - ? new Proxy(_, { - apply(k, E, a) { - if (a[5] && a[5].dependencies) - for (let x = 0; x < a[5].dependencies.length; x++) - a.push(a[5].dependencies[x].exports); - const A = k.apply(E, a); - return ( - u[S].map((x) => { - x(a); - }), - A - ); - }, - }) - : _; - })(e[2], t)), - (e[2] = (function (_, S) { - if (!f[S] || f[S].length === 0) return _; - const k = f[S]; - k.sort((a, A) => a.options.order - A.options.order); - const E = k.reduce((a, A) => { - const x = A.options.definerPath; - return (a[x] = a[x] || []), a[x].push(A), a; - }, {}); - return new Proxy(_, { - apply(a, A, x) { - const L = a.apply(A, x); - if (x[5] && x[5].dependencies) - for (let j = 0; j < x[5].dependencies.length; j++) - x.push(x[5].dependencies[j].exports); - const q = x[3], - Q = (0, x[2])("CometErrorBoundary.react"), - B = (j) => (console.error(j), "Error"); - for (let j in E) { - const U = m(x, j, !0), - G = j.split(".").pop(), - K = m(x, j); - U[G] = function (...D) { - const Y = K.apply(K, D), - R = D[0], - { - useState: M, - useEffect: W, - jsx: T, - Fragment: O, - } = q("react"), - [Z, X] = M(0), - V = () => { - if (!E[j]) return I(Y); - const g = E[j].find((z) => z.options.skipOthers); - if (g && g.component) - return T(g.fallback ? Q : O, { - fallback: g.fallback, - children: T(g.component, { - payload: R, - SourceCmp: Y, - lastCmp: I(Y), - definedArgs: x, - callingArgs: D, - extraPayloadFromDefiner: g.options.extraPayload, - proxyCount: 0, + let [moduleName, dependencies, callback] = e; + + if (typeof moduleName != "string" || moduleNames.includes(moduleName)) + return; + + moduleNames.push(moduleName); + e[2] = (function (orig, _moduleName) { + if (!w[_moduleName]) return orig; + const k = w[_moduleName]; + k.sort((a, A) => a.options.order - A.options.order); + const E = k.find((a) => a.options.skipOthers); + return cacheFunction( + E + ? E.replacement(orig.toString()) + : k.reduce((a, A) => (a = A.replacement(a)), orig.toString()) + ); + })(e[2], moduleName); + + e[2] = (function (orig, _moduleName) { + return u[_moduleName] + ? new Proxy(orig, { + apply(target, thisArg, argsList) { + if (argsList[5] && argsList[5].dependencies) + for (let i = 0; i < argsList[5].dependencies.length; i++) + argsList.push(argsList[5].dependencies[i].exports); + const res = target.apply(thisArg, argsList); + return ( + u[_moduleName].map((x) => { + x(argsList); + }), + res + ); + }, + }) + : orig; + })(e[2], moduleName); + + e[2] = (function (orig, _moduleName) { + if ( + !moduleCached[_moduleName] || + moduleCached[_moduleName].length === 0 + ) + return orig; + const k = moduleCached[_moduleName]; + k.sort((a, A) => a.options.order - A.options.order); + const E = k.reduce((a, A) => { + const x = A.options.definerPath; + return (a[x] = a[x] || []), a[x].push(A), a; + }, {}); + return new Proxy(orig, { + apply(target, thisArg, argsList) { + const L = target.apply(thisArg, argsList); + if (argsList[5] && argsList[5].dependencies) + for (let j = 0; j < argsList[5].dependencies.length; j++) + argsList.push(argsList[5].dependencies[j].exports); + const _import = argsList[3], + Q = (0, argsList[2])("CometErrorBoundary.react"), + B = (j) => (console.error(j), "Error"); + for (let j in E) { + const U = m(argsList, j, !0), + G = j.split(".").pop(), + K = m(argsList, j); + U[G] = function (...callingArgs) { + const sourceCmp = K.apply(K, callingArgs), + payload = callingArgs[0], + { + useState: M, + useEffect: W, + jsx: T, + Fragment: O, + } = _import("react"), + [Z, X] = M(0), + V = () => { + if (!E[j]) return I(sourceCmp); + const g = E[j].find((z) => z.options.skipOthers); + if (g && g.component) + return T(g.fallback ? Q : O, { + fallback: g.fallback, + children: T(g.component, { + payload: payload, + SourceCmp: sourceCmp, + lastCmp: I(sourceCmp), + definedArgs: argsList, + callingArgs: callingArgs, + extraPayloadFromDefiner: g.options.extraPayload, + proxyCount: 0, + removeThisModuleProxy() { + const z = E[j].indexOf(g); + ~z && E[j].splice(z, 1); + }, + }), + }); + let $ = 0; + return E[j].reduce( + (lastCmp, P) => ( + P.component && + ((lastCmp = T(P.fallback ? Q : O, { + fallback: P.fallback, + children: T(P.component, { + payload: payload, + SourceCmp: sourceCmp, + lastCmp: lastCmp, + extraPayloadFromDefiner: P.options.extraPayload, + proxyCount: $, + definedArgs: argsList, + callingArgs: callingArgs, removeThisModuleProxy() { - const z = E[j].indexOf(g); - ~z && E[j].splice(z, 1); + const N = E[j].indexOf(P); + if (~N) { + const J = k.indexOf(P); + E[j].splice(N, 1), + k.splice(J, 1), + C(_moduleName); + } }, }), - }); - let $ = 0; - return E[j].reduce( - (z, P) => ( - P.component && - ((z = T(P.fallback ? Q : O, { - fallback: P.fallback, - children: T(P.component, { - payload: R, - SourceCmp: Y, - lastCmp: z, - extraPayloadFromDefiner: - P.options.extraPayload, - proxyCount: $, - definedArgs: x, - callingArgs: D, - removeThisModuleProxy() { - const N = E[j].indexOf(P); - if (~N) { - const J = k.indexOf(P); - E[j].splice(N, 1), k.splice(J, 1), C(S); - } - }, - }), - })), - $++), - z - ), - I(Y) - ); - }; - function I(g) { - return g && g.$1 && typeof g.$1 == "function" - ? T(g, g.props) - : g; - } - return ( - W(() => { - const g = F(S, () => { - X(Math.random()); - }); - return () => g(); - }, []), - T(Q, { - fallback: B, - children: V(), - }) + })), + $++), + lastCmp + ), + I(sourceCmp) ); }; + function I(g) { + return g && g.$1 && typeof g.$1 == "function" + ? T(g, g.props) + : g; } - return L; - }, - }); - })(e[2], t)), - y[t] && console.log(t, e)), - e - ); + return ( + W(() => { + const g = F(_moduleName, () => { + X(Math.random()); + }); + return () => g(); + }, []), + T(Q, { + fallback: B, + children: V(), + }) + ); + }; + } + return L; + }, + }); + })(e[2], moduleName); + + isModuleLoaded[moduleName] && console.log(moduleName, e); + return e; } function F(e, t) { return ( @@ -240,260 +251,290 @@ function C(e) { if (c[e]) for (let t of c[e]) t(); } - (r.zKjQYvgSmF = function (e) { - return window.require(n(e)); - }), - (r.zKjQYvcSmF = (e, t, d) => { - const [p, _] = l(e); - f[p] || console.error(`Undefined module ${p} from ${_} #1`); - const S = f[p].find((E) => E.extensionId === _); - if (!S) return console.error(`Undefined module ${p} from ${_} #2`); - const { fallback: k } = d || {}; - (S.component = t), (S.fallback = k), C(p); - }), - (r.zKjQYVcSmF = (e, t) => { - const d = Object.assign( - { - order: 10, - skipOthers: !1, - beforeInject: () => !0, - afterInject: () => {}, - extraPayload: void 0, - definerPath: "[6].default", - }, - t - ), - [p, _] = l(e); - (f[p] = f[p] || []), - f[p].push({ - extensionId: _, - moduleName: p, - options: d, - component: void 0, - fallback: void 0, - }); - }), - (r.zKjQYwcSmF = (e) => { - y[n(e)] = !0; - }), - (r.zKjQYvcSfF = (e, t, d) => { - const p = Object.assign( - { - order: 10, - skipOthers: !1, - }, - d - ), - [_, S] = l(e); - (w[_] = w[_] || []), - w[_].push({ - moduleName: _, - options: p, - replacement: t, - }); - }), - (r.zKGQYvcSmF = (e, t) => { - (e = n(e)), (u[e] = u[e] || []), u[e].push(t); - }), - r.zKjQYvcSfF("umvbgfe}spssf.cg", (e) => - e.replace( - 'debugjs.")', - 'debugjs.");console.error(b.stackFrames.slice(0,10).map(e=>e.text).join("\\n"))' - ) - ), - r.zKjQYvcSfF("umvbgfe}djttbmd/epsq.NPEudbfS", (e) => - e.replace(/Error\(\w\(418\)\)/g, "void 0") - ), - r.zKjQYvcSfF("umvbgfe}fvfvRitjmcvQzbmfS0fsput0fnjuovs.zbmfs", (e) => + window._require = function (e) { + return window.require(decodeModuleName(e)); + }; + window.zKjQYvcSmF = (e, t, d) => { + const [moduleName, extensionId] = getModuleName(e); + moduleCached[moduleName] || + console.error( + `Undefined module ${moduleName} from ${extensionId} #1` + ); + const S = moduleCached[moduleName].find( + (E) => E.extensionId === extensionId + ); + if (!S) + return console.error( + `Undefined module ${moduleName} from ${extensionId} #2` + ); + const { fallback } = d || {}; + S.component = t; + S.fallback = fallback; + C(moduleName); + }; + window.zKjQYVcSmF = (e, t) => { + const d = Object.assign( + { + order: 10, + skipOthers: !1, + beforeInject: () => !0, + afterInject: () => {}, + extraPayload: void 0, + definerPath: "[6].default", + }, + t + ); + const [p, extensionId] = getModuleName(e); + moduleCached[p] = moduleCached[p] || []; + moduleCached[p].push({ + extensionId: extensionId, + moduleName: p, + options: d, + component: void 0, + fallback: void 0, + }); + }; + window.zKjQYwcSmF = (e) => { + isModuleLoaded[decodeModuleName(e)] = !0; + }; + window.cheatFbModule_replaceCode = (e, replacement, d) => { + const options = Object.assign( + { + order: 10, + skipOthers: !1, + }, + d + ); + const [moduleName, S] = getModuleName(e); + w[moduleName] = w[moduleName] || []; + w[moduleName].push({ + moduleName: moduleName, + options: options, + replacement: replacement, + }); + }; + window.cheatFbModule_overrideCode = (encodedModuleName, t) => { + encodedModuleName = decodeModuleName(encodedModuleName); + u[encodedModuleName] = u[encodedModuleName] || []; + u[encodedModuleName].push(t); + }; + + window.cheatFbModule_replaceCode("b-error|default", (e) => + e.replace( + 'debugjs.")', + 'debugjs.");console.error(b.stackFrames.slice(0,10).map(e=>e.text).join("\\n"))' + ) + ); + + window.cheatFbModule_replaceCode("ReactDOM-prod.classic|default", (e) => + e.replace(/Error\(\w\(418\)\)/g, "void 0") + ); + + window.cheatFbModule_replaceCode( + "relay-runtime/store/RelayPublishQueue|default", + (e) => e.replace( /,(\w)=new\(b\("relay-runtime\/mutations\/RelayRecordSourceProxy"/, ',$1=window["RlbiULLGWt"]=new(b("relay-runtime/mutations/RelayRecordSourceProxy"' ) - ), - r.zKjQYvcSfF( - "umvbgfe}fvfvRitjmcvQzbmfS0fsput0fnjuovs.zbmfs", - (e) => - (e = e.replace( - /;(\w)\.commitPayload=function\(([\w,]+)\){/, - ";$1.commitPayload=function($2){try{if(arguments[0]){if(arguments[0]?.request?.variables?.__relay_internal__pv__CometUFIReactionEnableShortNamerelayprovider === true) return;};}catch(e){console.log('relayStoreCommitPayload',e)};" - )) - ); - })(window), - ((r) => { - r.vTUNhjwVvX || - ((r.vTUNhjwVvX = !0), - (r.zKjqYvcSmF = (f, u, w) => { - const y = r.RlbiULLGWt, - c = typeof f == "string" ? y.get(f) : f; - if (c === void 0) return c; - let v = ((h = u.replace(/\[(\d+)\]/g, ".$1")), - h.replace(/\((.*?)\.(.*?)\)/g, "($1_*_*_*_*_$2)")).split("."); - var h; - v = v.map((e) => - (function (t) { - return t.replaceAll("_*_*_*_*_", "."); - })(e) - ); - let i = c; - for (let e = 0; e < v.length; e++) { - const t = v[e]; - if (t === "*") return i; - if (t.indexOf("^^") === 0) { - const [d, p] = F(t.substring(2)); - if (((i = i.getLinkedRecords(d, p)), i === void 0)) - return C(t), i; - } else if (t.indexOf("^") === 0) { - const [d, p] = F(t.substring(1)); - if (((i = i.getLinkedRecord(d, p)), i == null)) return C(t), i; - } else if (t.match(/^\d+$/)) { - if (((i = i[parseInt(t)]), i == null)) return C(t), i; - } else { - const [d, p] = F(t); - if (((i = i.getValue(d, p)), i == null)) return C(t), i; - } - } - return i; - function F(e) { - const [t, d] = e.split("{"); - if (!d) return [t, {}]; - if (!w) throw new Error("args undefined"); - return [t, w[d.substring(0, d.length - 1)] || {}]; - } - function C(e) { - ~r.location.search.indexOf("debug") && - console.warn("undefined value", { - id: f, - path: u, - args: w, - currentPath: e, - }); + ); + + window.cheatFbModule_replaceCode( + "relay-runtime/store/RelayPublishQueue|default", + (e) => + (e = e.replace( + /;(\w)\.commitPayload=function\(([\w,]+)\){/, + ";$1.commitPayload=function($2){try{if(arguments[0]){if(arguments[0]?.request?.variables?.__relay_internal__pv__CometUFIReactionEnableShortNamerelayprovider === true) return;};}catch(e){console.log('relayStoreCommitPayload',e)};" + )) + ); + })(); + (() => { + window.vTUNhjwVvX || + ((window.vTUNhjwVvX = !0), + (window.zKjqYvcSmF = (f, u, w) => { + const y = window.RlbiULLGWt, + c = typeof f == "string" ? y.get(f) : f; + if (c === void 0) return c; + let v = ((h = u.replace(/\[(\d+)\]/g, ".$1")), + h.replace(/\((.*?)\.(.*?)\)/g, "($1_*_*_*_*_$2)")).split("."); + var h; + v = v.map((e) => + (function (t) { + return t.replaceAll("_*_*_*_*_", "."); + })(e) + ); + let i = c; + for (let e = 0; e < v.length; e++) { + const t = v[e]; + if (t === "*") return i; + if (t.indexOf("^^") === 0) { + const [d, p] = F(t.substring(2)); + if (((i = i.getLinkedRecords(d, p)), i === void 0)) + return C(t), i; + } else if (t.indexOf("^") === 0) { + const [d, p] = F(t.substring(1)); + if (((i = i.getLinkedRecord(d, p)), i == null)) return C(t), i; + } else if (t.match(/^\d+$/)) { + if (((i = i[parseInt(t)]), i == null)) return C(t), i; + } else { + const [d, p] = F(t); + if (((i = i.getValue(d, p)), i == null)) return C(t), i; } - })); - })(window), - ((r) => { - if (window.xmxlgxMDjA) return; - window.xmxlgxMDjA = !0; - let f = {}; - r.zKGQYvcSmF("sf{jmbjsfTbubEfmqnjTsiy", (u) => { - const w = u[4].exports.default; - u[4].exports.default = function (...y) { - const c = y[0].fb_api_req_friendly_name; - return ( - c && f[c] && (y[0] = f[c].reduce((v, h) => (v = h(v)), y[0])), - w.apply(w, y) - ); - }; - }), - (r.zkjQYvcSmF = (u, w) => { - (u = n(u)), (f[u] = f[u] || []), f[u].push(w); - }); - })(window); - })(), - window.zKjQYvcSfF( - "lppcfdbg.spg.offtov}topjujojgfEcpKXBN", - (n) => ( - (n = n.replace( - /markThreadAsRead:function.*?{/, - "markThreadAsRead:function(){return;" - )), - n - ) - ), - window.zKjQYvcSfF( - "lppcfdbg.spg.offtov}fubuThojqzUfsvdfTXBN", - (n) => ((n = n.replaceAll("sendChatStateFromComposer", "none")), n) - ), - window.zKGQYvcSmF("spubdjeoJhojqzUeofTTM", (n) => { - if (n[4].exports) - if (n[4].exports.default) { - const l = n[4].exports.default; - n[4].exports.default = function (...o) { - var b, s; - return ( - (o[2] = !( - (s = - (b = window == null ? void 0 : window.unseen_for_facebook) == - null - ? void 0 - : b.DISABLE_TYPING) != null && s.enable - )), - l.apply(l, o) - ); - }; - } else { - const l = n[4].exports; - n[4].exports = function (...o) { - var b, s; - return ( - (o[2] = !( - (s = - (b = window == null ? void 0 : window.unseen_for_facebook) == - null - ? void 0 - : b.DISABLE_TYPING) != null && s.enable - )), - l.apply(l, o) - ); - }; - } - }), - window.zKGQYvcSmF("3WebfSebfsiUlsbNdjutjnjuqPTM", (n) => { - if (n[4].exports) - if (n[4].exports.default) { - const l = n[4].exports.default; - n[4].exports.default = function (...o) { - var s, m; - let b = o[o.length - 1]; - return (m = - (s = window == null ? void 0 : window.unseen_for_facebook) == null - ? void 0 - : s.DISABLE_READ) != null && m.enable - ? b.resolve([]) - : l.apply(l, o); - }; - } else { - const l = n[4].exports; - n[4].exports = function (...o) { - var s, m; - let b = o[o.length - 1]; - return (m = - (s = window == null ? void 0 : window.unseen_for_facebook) == null - ? void 0 - : s.DISABLE_READ) != null && m.enable - ? b.resolve([]) - : l.apply(l, o); - }; - } - }), - window.zKGQYvcSmF("mqnJ3WebfSebfsiUlsbNdjutjnjuqPTM", (n) => { - if (n[4].exports) - if (n[4].exports.default) { - const l = n[4].exports.default; - n[4].exports.default = function (...o) { - var s, m; - let b = o[o.length - 1]; - return (m = - (s = window == null ? void 0 : window.unseen_for_facebook) == null - ? void 0 - : s.DISABLE_READ) != null && m.enable - ? b.resolve([]) - : l.apply(l, o); - }; - } else { - const l = n[4].exports; - n[4].exports = function (...o) { - var s, m; - let b = o[o.length - 1]; - return (m = - (s = window == null ? void 0 : window.unseen_for_facebook) == null - ? void 0 - : s.DISABLE_READ) != null && m.enable - ? b.resolve([]) - : l.apply(l, o); - }; - } - }), - window.zKGQYvcSmF("cfXmqnJ3WebfSebfsiUlsbNdjutjnjuqPTM", (n) => { + } + return i; + function F(e) { + const [t, d] = e.split("{"); + if (!d) return [t, {}]; + if (!w) throw new Error("args undefined"); + return [t, w[d.substring(0, d.length - 1)] || {}]; + } + function C(e) { + ~window.location.search.indexOf("debug") && + console.warn("undefined value", { + id: f, + path: u, + args: w, + currentPath: e, + }); + } + })); + })(); + (() => { + if (window.xmxlgxMDjA) return; + window.xmxlgxMDjA = !0; + let cache = {}; + window.cheatFbModule_overrideCode("xhrSimpleDataSerializer", (u) => { + const orig = u[4].exports.default; + u[4].exports.default = function (...args) { + const name = args[0].fb_api_req_friendly_name; + return ( + name && + cache[name] && + (args[0] = cache[name].reduce((v, h) => (v = h(v)), args[0])), + orig.apply(orig, args) + ); + }; + }); + window.zkjQYvcSmF = (u, w) => { + u = decodeModuleName(u); + cache[u] = cache[u] || []; + cache[u].push(w); + }; + })(); + })(); + + window.cheatFbModule_replaceCode( + "MAWJobDefinitions|unseen-for-facebook", + (n) => ( + (n = n.replace( + /markThreadAsRead:function.*?{/, + "markThreadAsRead:function(){return;" + )), + n + ) + ); + + window.cheatFbModule_replaceCode( + "MAWSecureTypingState|unseen-for-facebook", + (n) => ((n = n.replaceAll("sendChatStateFromComposer", "none")), n) + ); + + window.cheatFbModule_overrideCode("LSSendTypingIndicator", (n) => { + if (n[4].exports) + if (n[4].exports.default) { + const l = n[4].exports.default; + n[4].exports.default = function (...o) { + var b, s; + return ( + (o[2] = !( + (s = + (b = window == null ? void 0 : window.unseen_for_facebook) == + null + ? void 0 + : b.DISABLE_TYPING) != null && s.enable + )), + l.apply(l, o) + ); + }; + } else { + const l = n[4].exports; + n[4].exports = function (...o) { + var b, s; + return ( + (o[2] = !( + (s = + (b = window == null ? void 0 : window.unseen_for_facebook) == + null + ? void 0 + : b.DISABLE_TYPING) != null && s.enable + )), + l.apply(l, o) + ); + }; + } + }); + + window.cheatFbModule_overrideCode("LSOptimisticMarkThreadReadV2", (n) => { + if (n[4].exports) + if (n[4].exports.default) { + const l = n[4].exports.default; + n[4].exports.default = function (...o) { + var s, m; + let b = o[o.length - 1]; + return (m = + (s = window == null ? void 0 : window.unseen_for_facebook) == null + ? void 0 + : s.DISABLE_READ) != null && m.enable + ? b.resolve([]) + : l.apply(l, o); + }; + } else { + const l = n[4].exports; + n[4].exports = function (...o) { + var s, m; + let b = o[o.length - 1]; + return (m = + (s = window == null ? void 0 : window.unseen_for_facebook) == null + ? void 0 + : s.DISABLE_READ) != null && m.enable + ? b.resolve([]) + : l.apply(l, o); + }; + } + }); + + window.cheatFbModule_overrideCode("LSOptimisticMarkThreadReadV2Impl", (n) => { + if (n[4].exports) + if (n[4].exports.default) { + const l = n[4].exports.default; + n[4].exports.default = function (...o) { + var s, m; + let b = o[o.length - 1]; + return (m = + (s = window == null ? void 0 : window.unseen_for_facebook) == null + ? void 0 + : s.DISABLE_READ) != null && m.enable + ? b.resolve([]) + : l.apply(l, o); + }; + } else { + const l = n[4].exports; + n[4].exports = function (...o) { + var s, m; + let b = o[o.length - 1]; + return (m = + (s = window == null ? void 0 : window.unseen_for_facebook) == null + ? void 0 + : s.DISABLE_READ) != null && m.enable + ? b.resolve([]) + : l.apply(l, o); + }; + } + }); + + window.cheatFbModule_overrideCode( + "LSOptimisticMarkThreadReadV2ImplWeb", + (n) => { if (n[4].exports) if (n[4].exports.default) { const l = n[4].exports.default; @@ -520,15 +561,17 @@ : l.apply(l, o); }; } - }), - window.zKjQYvcSfF( - "lppcfdbg.spg.offtov}udbfs/sfojbuopDufldvCftofqtvTtfjspuT", - (n) => ( - (n = n.replace( - /,onCardSeen:(\w),/g, - ",onCardSeen:window?.unseen_for_facebook?.DISABLE_STORIES_SEEN?.enable ? ()=>{} : $1," - )), - n - ) - ); + } + ); + + window.cheatFbModule_replaceCode( + "StoriesSuspenseBucketContainer.react|unseen-for-facebook", + (n) => ( + (n = n.replace( + /,onCardSeen:(\w),/g, + ",onCardSeen:window?.unseen_for_facebook?.DISABLE_STORIES_SEEN?.enable ? ()=>{} : $1," + )), + n + ) + ); })(); diff --git a/scripts/backup/m38u_detector.js b/scripts/backup/m38u_detector.js new file mode 100644 index 00000000..e0066ae8 --- /dev/null +++ b/scripts/backup/m38u_detector.js @@ -0,0 +1,820 @@ +// ==UserScript== +// @name m3u8视频侦测下载器【自动嗅探】 +// @name:zh-CN m3u8视频侦测下载器【自动嗅探】 +// @name:zh-TW m3u8視頻偵測下載器【自動嗅探】 +// @name:en M3U8 Video Detector and Downloader +// @version 1.4.1 +// @description 自动检测页面m3u8视频并进行完整下载。检测到m3u8链接后会自动出现在页面右上角位置,点击下载即可跳转到m3u8下载器。 +// @description:zh-CN 自动检测页面m3u8视频并进行完整下载。检测到m3u8链接后会自动出现在页面右上角位置,点击下载即可跳转到m3u8下载器。 +// @description:zh-TW 自動檢測頁面m3u8視頻並進行完整下載。檢測到m3u8鏈接後會自動出現在頁面右上角位置,點擊下載即可跳轉到m3u8下載器。 +// @description:en Automatically detect the m3u8 video of the page and download it completely. Once detected the m3u8 link, it will appear in the upper right corner of the page. Click download to jump to the m3u8 downloader. +// @icon https://tools.thatwind.com/favicon.png +// @author allFull +// @namespace https://tools.thatwind.com/ +// @homepage https://tools.thatwind.com/tool/m3u8downloader +// @match *://*/* +// @exclude *://www.diancigaoshou.com/* +// @require https://cdn.jsdelivr.net/npm/m3u8-parser@4.7.1/dist/m3u8-parser.min.js +// @connect * +// @grant unsafeWindow +// @grant GM_openInTab +// @grant GM.openInTab +// @grant GM_getValue +// @grant GM.getValue +// @grant GM_setValue +// @grant GM.setValue +// @grant GM_deleteValue +// @grant GM.deleteValue +// @grant GM_xmlhttpRequest +// @grant GM.xmlHttpRequest +// @grant GM_download +// @run-at document-start +// ==/UserScript== + +(function () { + "use strict"; + + const mgmapi = { + addStyle(s) { + let style = document.createElement("style"); + style.innerHTML = s; + document.documentElement.appendChild(style); + }, + async getValue(name, defaultVal) { + return await (typeof GM_getValue === "function" + ? GM_getValue + : GM.getValue)(name, defaultVal); + }, + async setValue(name, value) { + return await (typeof GM_setValue === "function" + ? GM_setValue + : GM.setValue)(name, value); + }, + async deleteValue(name) { + return await (typeof GM_deleteValue === "function" + ? GM_deleteValue + : GM.deleteValue)(name); + }, + openInTab(url, open_in_background = false) { + return (typeof GM_openInTab === "function" ? GM_openInTab : GM.openInTab)( + url, + open_in_background + ); + }, + xmlHttpRequest(details) { + return ( + typeof GM_xmlhttpRequest === "function" + ? GM_xmlhttpRequest + : GM.xmlHttpRequest + )(details); + }, + download(details) { + return this.openInTab(details.url); + + if (typeof GM_download === "function") { + this.message( + "下载中,请留意浏览器下载弹窗\nDownloading, pay attention to the browser's download pop-up.", + 3000 + ); + return GM_download(details); + } else { + this.openInTab(details.url); + } + }, + copyText(text) { + copyTextToClipboard(text); + function copyTextToClipboard(text) { + // 复制文本 + var copyFrom = document.createElement("textarea"); + copyFrom.textContent = text; + document.body.appendChild(copyFrom); + copyFrom.select(); + document.execCommand("copy"); + copyFrom.blur(); + document.body.removeChild(copyFrom); + } + }, + message(text, disappearTime = 5000) { + const id = "f8243rd238-gm-message-panel"; + let p = document.querySelector(`#${id}`); + if (!p) { + p = document.createElement("div"); + p.id = id; + p.style = ` + position: fixed; + bottom: 20px; + right: 20px; + display: flex; + flex-direction: column; + align-items: end; + z-index: 999999999999999; + `; + (document.body || document.documentElement).appendChild(p); + } + let mdiv = document.createElement("div"); + mdiv.innerText = text; + mdiv.style = ` + padding: 3px 8px; + border-radius: 5px; + background: black; + box-shadow: #000 1px 2px 5px; + margin-top: 10px; + font-size: small; + color: #fff; + text-align: right; + `; + p.appendChild(mdiv); + setTimeout(() => { + p.removeChild(mdiv); + }, disappearTime); + }, + }; + + if ( + location.host === "tools.thatwind.com" || + location.host === "localhost:3000" + ) { + mgmapi.addStyle("#userscript-tip{display:none !important;}"); + + // 对请求做代理 + const _fetch = unsafeWindow.fetch; + unsafeWindow.fetch = async function (...args) { + try { + let response = await _fetch(...args); + if (response.status !== 200) throw new Error(response.status); + return response; + } catch (e) { + // 失败请求使用代理 + if (args.length == 1) { + console.log(`请求代理:${args[0]}`); + return await new Promise((resolve, reject) => { + let referer = new URLSearchParams(location.hash.slice(1)).get( + "referer" + ); + let headers = {}; + if (referer) { + referer = new URL(referer); + headers = { + origin: referer.origin, + referer: referer.href, + }; + } + mgmapi.xmlHttpRequest({ + method: "GET", + url: args[0], + responseType: "arraybuffer", + headers, + onload(r) { + resolve({ + status: r.status, + headers: new Headers( + r.responseHeaders + .split("\n") + .filter((n) => n) + .map((s) => s.split(/:\s*/)) + .reduce((all, [a, b]) => { + all[a] = b; + return all; + }, {}) + ), + async text() { + return r.responseText; + }, + async arrayBuffer() { + return r.response; + }, + }); + }, + onerror() { + reject(new Error()); + }, + }); + }); + } else { + throw e; + } + } + }; + + return; + } + + // iframe 信息交流 + // 目前只用于获取顶部标题 + window.addEventListener("message", async (e) => { + if (e.data === "3j4t9uj349-gm-get-title") { + let name = `top-title-${Date.now()}`; + await mgmapi.setValue(name, document.title); + e.source.postMessage(`3j4t9uj349-gm-top-title-name:${name}`, "*"); + } + }); + + function getTopTitle() { + return new Promise((resolve) => { + window.addEventListener("message", async function l(e) { + if (typeof e.data === "string") { + if (e.data.startsWith("3j4t9uj349-gm-top-title-name:")) { + let name = e.data.slice("3j4t9uj349-gm-top-title-name:".length); + await new Promise((r) => setTimeout(r, 5)); // 等5毫秒 确定 setValue 已经写入 + resolve(await mgmapi.getValue(name)); + mgmapi.deleteValue(name); + window.removeEventListener("message", l); + } + } + }); + window.top.postMessage("3j4t9uj349-gm-get-title", "*"); + }); + } + + { + // 请求检测 + // const _fetch = unsafeWindow.fetch; + // unsafeWindow.fetch = function (...args) { + // if (checkUrl(args[0])) doM3U({ url: args[0] }); + // return _fetch(...args); + // } + + const _r_text = unsafeWindow.Response.prototype.text; + unsafeWindow.Response.prototype.text = function () { + return new Promise((resolve, reject) => { + _r_text + .call(this) + .then((text) => { + resolve(text); + if (checkContent(text)) doM3U({ url: this.url, content: text }); + }) + .catch(reject); + }); + }; + + const _open = unsafeWindow.XMLHttpRequest.prototype.open; + unsafeWindow.XMLHttpRequest.prototype.open = function (...args) { + this.addEventListener("load", () => { + try { + let content = this.responseText; + if (checkContent(content)) doM3U({ url: args[1], content }); + } catch {} + }); + // checkUrl(args[1]); + return _open.apply(this, args); + }; + + function checkUrl(url) { + url = new URL(url, location.href); + if (url.pathname.endsWith(".m3u8") || url.pathname.endsWith(".m3u")) { + // 发现 + return true; + } + } + + function checkContent(content) { + if (content.trim().startsWith("#EXTM3U")) { + return true; + } + } + + // 检查纯视频 + setInterval(doVideos, 1000); + } + + const rootDiv = document.createElement("div"); + rootDiv.style = ` + position: fixed; + z-index: 9999999999999999; + opacity: 0.9; + `; + rootDiv.style.display = "none"; + document.documentElement.appendChild(rootDiv); + + const shadowDOM = rootDiv.attachShadow({ mode: "open" }); + const wrapper = document.createElement("div"); + shadowDOM.appendChild(wrapper); + + // 指示器 + const bar = document.createElement("div"); + bar.style = ` + text-align: right; + `; + bar.innerHTML = ` + + + + + + + + `; + + wrapper.appendChild(bar); + + // 样式 + const style = document.createElement("style"); + + style.innerHTML = ` + .number-indicator{ + position:relative; + } + + .number-indicator::after{ + content: attr(data-number); + position: absolute; + bottom: 0; + right: 0; + color: #40a9ff; + font-size: 14px; + font-weight: bold; + background: #000; + border-radius: 10px; + padding: 3px 5px; + } + + .copy-link:active{ + color: #ccc; + } + + .download-btn:hover{ + text-decoration: underline; + } + .download-btn:active{ + opacity: 0.9; + } + + .m3u8-item{ + color: white; + margin-bottom: 5px; + display: flex; + flex-direction: row; + background: black; + padding: 3px 10px; + border-radius: 3px; + font-size: 14px; + user-select: none; + } + + [data-shown="false"] { + opacity: 0.8; + zoom: 0.8; + } + + [data-shown="false"]:hover{ + opacity: 1; + } + + [data-shown="false"] .m3u8-item{ + display: none; + } + + `; + + wrapper.appendChild(style); + + const barBtn = bar.querySelector(".number-indicator"); + + // 关于显隐和移动 + + (async function () { + let shown = await GM_getValue("shown", true); + wrapper.setAttribute("data-shown", shown); + + let x = await GM_getValue("x", 10); + let y = await GM_getValue("y", 10); + + x = Math.min(innerWidth - 50, x); + y = Math.min(innerHeight - 50, y); + + if (x < 0) x = 0; + if (y < 0) y = 0; + + rootDiv.style.top = `${y}px`; + rootDiv.style.right = `${x}px`; + + barBtn.addEventListener("mousedown", (e) => { + let startX = e.pageX; + let startY = e.pageY; + + let moved = false; + + let mousemove = (e) => { + let offsetX = e.pageX - startX; + let offsetY = e.pageY - startY; + if (moved || Math.abs(offsetX) + Math.abs(offsetY) > 5) { + moved = true; + rootDiv.style.top = `${y + offsetY}px`; + rootDiv.style.right = `${x - offsetX}px`; + } + }; + let mouseup = (e) => { + let offsetX = e.pageX - startX; + let offsetY = e.pageY - startY; + + if (moved) { + x -= offsetX; + y += offsetY; + mgmapi.setValue("x", x); + mgmapi.setValue("y", y); + } else { + shown = !shown; + mgmapi.setValue("shown", shown); + wrapper.setAttribute("data-shown", shown); + } + + removeEventListener("mousemove", mousemove); + removeEventListener("mouseup", mouseup); + }; + addEventListener("mousemove", mousemove); + addEventListener("mouseup", mouseup); + }); + })(); + + let count = 0; + let shownUrls = []; + + function doVideos() { + for (let v of Array.from(document.querySelectorAll("video"))) { + if ( + v.duration && + v.src && + v.src.startsWith("http") && + !shownUrls.includes(v.src) + ) { + const src = v.src; + + shownUrls.push(src); + showVideo({ + type: "video", + url: new URL(src), + duration: `${Math.ceil((v.duration * 10) / 60) / 10} mins`, + download() { + const details = { + url: src, + name: (() => { + let name = new URL(src).pathname.split("/").slice(-1)[0]; + if (!/\.\w+$/.test(name)) { + if (name.match(/^\s*$/)) name = Date.now(); + name = name + ".mp4"; + } + return name; + })(), + headers: { + // referer: location.origin, // 不允许该头 + origin: location.origin, + }, + onerror(e) { + mgmapi.openInTab(src); + }, + }; + mgmapi.download(details); + }, + }); + } + } + } + + async function doM3U({ url, content }) { + url = new URL(url); + + if (shownUrls.includes(url.href)) return; + + // 解析 m3u + content = content || (await (await fetch(url)).text()); + + const parser = new m3u8Parser.Parser(); + parser.push(content); + parser.end(); + const manifest = parser.manifest; + + if (manifest.segments) { + let duration = 0; + manifest.segments.forEach((segment) => { + duration += segment.duration; + }); + manifest.duration = duration; + } + + showVideo({ + type: "m3u8", + url, + duration: manifest.duration + ? `${Math.ceil((manifest.duration * 10) / 60) / 10} mins` + : manifest.playlists + ? `多(Multi)(${manifest.playlists.length})` + : "未知(unknown)", + async download() { + mgmapi.openInTab( + `https://tools.thatwind.com/tool/m3u8downloader#${new URLSearchParams( + { + m3u8: url.href, + referer: location.href, + filename: (await getTopTitle()) || "", + } + )}` + ); + }, + }); + } + + async function showVideo({ type, url, duration, download }) { + let div = document.createElement("div"); + div.className = "m3u8-item"; + div.innerHTML = ` + ${type} + ${url.pathname} + ${duration} + 下载(Download) + `; + + div.querySelector(".copy-link").addEventListener("click", () => { + // 复制链接 + mgmapi.copyText(url.href); + mgmapi.message("已复制链接 (link copied)", 2000); + }); + + div.querySelector(".download-btn").addEventListener("click", download); + + rootDiv.style.display = "block"; + + count++; + + shownUrls.push(url.href); + + bar.querySelector(".number-indicator").setAttribute("data-number", count); + + wrapper.appendChild(div); + } +})(); + +(function () { + "use strict"; + + const reg = /magnet:\?xt=urn:btih:\w{10,}([-a-zA-Z0-9()@:%_\+.~#?&//=]*)/; + + let l = navigator.language || "en"; + if (l.startsWith("en-")) l = "en"; + else if (l.startsWith("zh-")) l = "zh-CN"; + else l = "en"; + + const T = { + en: { + play: "Play", + }, + "zh-CN": { + play: "播放", + }, + }[l]; + + whenDOMReady(() => { + addStyle(` + button[data-wtmzjk-mag-url]{ + all: initial; + border: none; + outline: none; + background: none; + background: #f7d308; + background: #08a6f7; + margin: 2px 8px; + border-radius: 3px; + color: white; + cursor: pointer; + display: inline-flex; + height: 1.6em; + padding: 0 .8em; + align-items: center; + justify-content: center; + transition: background .15s; + text-decoration: none; + border-radius: 0.8em; + font-size: small; + } + button[data-wtmzjk-mag-url]>svg{ + height: 60%; + fill: white; + pointer-events: none; + } + button[data-wtmzjk-mag-url]:hover{ + background: #fae157; + background: #39b9f9; + } + button[data-wtmzjk-mag-url]:active{ + background: #dfbe07; + background: #0797df; + } + button[data-wtmzjk-mag-url]>span{ + pointer-events: none; + font-size: small;margin-right: .5em;font-weight:bold;color:white !important; + } + `); + window.addEventListener("click", onEvents, true); + window.addEventListener("mousedown", onEvents, true); + window.addEventListener("mouseup", onEvents, true); + + watchBodyChange(work); + }); + + function onEvents(e) { + if (e.target.hasAttribute("data-wtmzjk-mag-url")) { + e.preventDefault(); + e.stopPropagation(); + if (e.type == "click") { + let a = document.createElement("a"); + a.href = + "https://www.diancigaoshou.com/#" + + new URLSearchParams({ + url: e.target.getAttribute("data-wtmzjk-mag-url"), + }); + a.target = "_blank"; + a.click(); + } + } + } + + function createWatchButton(url, isForPlain = false) { + let button = document.createElement("button"); + button.setAttribute("data-wtmzjk-mag-url", url); + if (isForPlain) button.setAttribute("data-wtmzjk-button-for-plain", ""); + button.innerHTML = `${T.play}`; + return button; + } + + function hasPlainMagUrlThatNotHandled() { + let m = document.body.textContent.match(new RegExp(reg, "g")); + return ( + document.querySelectorAll(`[data-wtmzjk-button-for-plain]`).length != + (m ? m.length : 0) + ); + } + + function work() { + if (!document.body) return; + if (hasPlainMagUrlThatNotHandled()) { + for (let node of getAllTextNodes(document.body)) { + if ( + node.nextSibling && + node.nextSibling.hasAttribute && + node.nextSibling.hasAttribute("data-wtmzjk-mag-url") + ) + continue; + let text = node.nodeValue; + if (!reg.test(text)) continue; + let match = text.match(reg); + if (match) { + let url = match[0]; + let p = node.parentNode; + p.insertBefore( + document.createTextNode(text.slice(0, match.index + url.length)), + node + ); + p.insertBefore(createWatchButton(url, true), node); + p.insertBefore( + document.createTextNode(text.slice(match.index + url.length)), + node + ); + p.removeChild(node); + } + } + } + for (let a of Array.from( + document.querySelectorAll( + [ + "href", + "value", + "data-clipboard-text", + "data-value", + "title", + "alt", + "data-url", + "data-magnet", + "data-copy", + ] + .map((n) => `[${n}*="magnet:?xt=urn:btih:"]`) + .join(",") + ) + )) { + if ( + a.nextSibling && + a.nextSibling.hasAttribute && + a.nextSibling.hasAttribute("data-wtmzjk-mag-url") + ) + continue; // 已经添加 + if (reg.test(a.textContent)) continue; + for (let attr of a.getAttributeNames()) { + let val = a.getAttribute(attr); + if (!reg.test(val)) continue; + let url = val.match(reg)[0]; + a.parentNode.insertBefore(createWatchButton(url), a.nextSibling); + } + } + } + + function watchBodyChange(onchange) { + let timeout; + let observer = new MutationObserver(() => { + if (!timeout) { + timeout = setTimeout(() => { + timeout = null; + onchange(); + }, 200); + } + }); + observer.observe(document.documentElement, { + childList: true, + subtree: true, + attributes: true, + characterData: true, + }); + } + + function getAllTextNodes(parent) { + var re = []; + if ( + [ + "STYLE", + "SCRIPT", + "BASE", + "COMMAND", + "LINK", + "META", + "TITLE", + "XTRANS-TXT", + "XTRANS-TXT-GROUP", + "XTRANS-POPUP", + ].includes(parent.tagName) + ) + return re; + for (let node of parent.childNodes) { + if (node.childNodes.length) re = re.concat(getAllTextNodes(node)); + else if ( + Text.prototype.isPrototypeOf(node) && + !node.nodeValue.match(/^\s*$/) + ) + re.push(node); + } + return re; + } + + function whenDOMReady(f) { + if (document.body) f(); + else window.addEventListener("DOMContentLoaded", f); + } + + function addStyle(s) { + let style = document.createElement("style"); + style.innerHTML = s; + document.documentElement.appendChild(style); + } +})(); diff --git a/scripts/content-scripts/ufs_global.js b/scripts/content-scripts/ufs_global.js index e63a90b2..463e518e 100644 --- a/scripts/content-scripts/ufs_global.js +++ b/scripts/content-scripts/ufs_global.js @@ -143,6 +143,12 @@ function runInContentScript(fnPath, params) { }); } function runInBackground(fnPath, params) { + if (typeof chrome?.runtime?.sendMessage == "function") { + return chrome.runtime.sendMessage({ + action: "ufs-runInBackground", + data: { fnPath, params }, + }); + } return sendToContentScript("ufs-runInBackground", { fnPath, params, @@ -150,8 +156,8 @@ function runInBackground(fnPath, params) { } async function fetchByPassOrigin(url, options = {}) { try { - let _url = url; - let urlObject = new URL(url); + let _url = makeUrlValid(url); + let urlObject = new URL(_url); // https://stackoverflow.com/a/9375786/23648002 if (location.hostname == urlObject?.hostname) { _url = urlObject.pathname; @@ -165,15 +171,31 @@ async function fetchByPassOrigin(url, options = {}) { function getURL(filePath) { return runInContentScript("chrome.runtime.getURL", [filePath]); } -function download(options) { - return runInBackground("chrome.downloads.download", [options]); -} function trackEvent(scriptId) { return runInBackground("trackEvent", [scriptId]); } function waitForTabToLoad(tabId) { return runInBackground("utils.waitForTabToLoad", [tabId]); } + +// https://developer.chrome.com/docs/extensions/reference/api/downloads#type-DownloadOptions +/** + * A function to trigger a download using chrome.downloads API. + * + * @param {Object} options - The options for the download operation. + * @param {string} options.url - The URL to download. + * @param {string} [options.body] - Post body. + * @param {{name: string, value: string}[]} [options.headers] - Extra HTTP headers to send with the request if the URL uses the HTTP[s] protocol. Each header is represented as a dictionary containing the keys name and either value or binaryValue, restricted to those allowed by XMLHttpRequest. + * @param {'GET'|'POST'} [options.method] - The HTTP method to use for the download. + * @param {string} [options.filename] - A file path relative to the Downloads directory to contain the downloaded file, possibly containing subdirectories. + * @param {string} [options.saveAs] - Use a file-chooser to allow the user to select a filename regardless of whether filename is set or already exists. + * @param {'uniquify'|'overwrite'|'prompt'} [options.conflictAction] - The action to take if filename already exists. + * @return {Promise} - A promise that resolves to the ID of the created download. + */ +function download(options) { + return runInBackground("chrome.downloads.download", [options]); +} + // #endregion // #region DOM @@ -561,9 +583,10 @@ function notify({ } return false; }, - setText(text) { + setText(text, duration) { if (div) { div.innerHTML = createTrustedHtml(text); + if (duration) closeAfter(duration); return true; } return false; @@ -902,6 +925,9 @@ function makeUrlValid(url) { if (url.startsWith("//")) { url = "https:" + url; } + if (url.startsWith("/")) { + url = location.origin + url; + } return url; } function getWatchingVideoSrc() { @@ -1276,6 +1302,7 @@ async function getLargestImageSrc(imgSrc, webUrl) { } // bypass redirect + imgSrc = makeUrlValid(imgSrc); let redirectedUrl = await getRedirectedUrl(imgSrc); if (redirectedUrl) { imgSrc = redirectedUrl; @@ -1833,9 +1860,7 @@ function downloadBlob(blob, filename) { a.href = blobUrl; a.download = filename; a.style.display = "none"; - document.body.appendChild(a); a.click(); - document.body.removeChild(a); URL.revokeObjectURL(blobUrl); } // https://stackoverflow.com/a/15832662/11898496 @@ -1845,9 +1870,7 @@ function downloadURL(url, name) { link.target = "_blank"; link.download = name; link.href = url; - document.body.appendChild(link); link.click(); - document.body.removeChild(link); } function downloadData(data, filename, type = "text/plain") { let file = new Blob([data], { type: type }); diff --git a/scripts/douyin_downloadWachingVideo.js b/scripts/douyin_downloadWachingVideo.js index 2e3fdee0..0b67b56d 100644 --- a/scripts/douyin_downloadWachingVideo.js +++ b/scripts/douyin_downloadWachingVideo.js @@ -1,3 +1,5 @@ +import { UfsGlobal } from "./content-scripts/ufs_global.js"; + export default { icon: "https://www.douyin.com/favicon.ico", name: { @@ -12,18 +14,10 @@ export default { popupScript: { onClick: async function () { - const { UfsGlobal } = await import("./content-scripts/ufs_global.js"); const { runScriptInCurrentTab, showLoading } = await import( "./helpers/utils.js" ); - // const { - // downloadURL, - // downloadBlob, - // getBlobFromUrlWithProgress, - // formatSize, - // } = UfsGlobal.Utils; - const { closeLoading, setLoadingText } = showLoading( "Đang tìm video url..." ); @@ -36,21 +30,7 @@ export default { alert("Không tìm thấy video nào."); } else { setLoadingText("Đang tải video..."); - // downloadURL(src, "douyin_video.mp4"); window.open(src); - // const blob = await getBlobFromUrlWithProgress( - // src, - // ({ loaded, total, speed }) => { - // const percent = ((loaded / total) * 100) | 0; - // setLoadingText( - // `Đang tải video...
` + - // `Vui lòng không tắt popup
` + - // `${formatSize(loaded)}/${formatSize(total)} (${percent}%)` + - // ` - ${formatSize(speed)}/s` - // ); - // } - // ); - // await downloadBlob(blob, "douyin_video.mp4"); } closeLoading(); }, diff --git a/scripts/fb_GLOBAL.js b/scripts/fb_GLOBAL.js index 6e05e8f2..d1ce0c11 100644 --- a/scripts/fb_GLOBAL.js +++ b/scripts/fb_GLOBAL.js @@ -119,6 +119,45 @@ export async function getUidFromUrl(url) { } return null; } +export async function searchUser(keyword, exact_match = true) { + const res = await fetchGraphQl( + { + doc_id: 7561210460668291, + variables: { + count: 5, + allow_streaming: false, + args: { + callsite: "COMET_GLOBAL_SEARCH", + config: { + exact_match: exact_match, + high_confidence_config: null, + intercept_config: null, + sts_disambiguation: null, + watch_config: null, + }, + experience: { + client_defined_experiences: [], + encoded_server_defined_params: null, + fbid: null, + type: "PEOPLE_TAB", + }, + filters: [], + text: keyword, + }, + cursor: null, + feedbackSource: 23, + fetch_filters: true, + renderLocation: "search_results_page", + scale: 2, + stream_initial_count: 0, + useDefaultActor: false, + }, + }, + await getFbdtsg() + ); + const json = JSON.parse(res); + console.log(json); +} // ============================================================================= // =================================== Friend ================================== @@ -238,6 +277,68 @@ export async function fetchAllAddedFriendsSince( return allFriends; } +//https://web.facebook.com/ajax/typeahead/first_degree.php?viewer=100075867577015&rsp=search&max_results=13&q=s&session_id=0.7324328179909558&fb_dtsg_ag=AQwWeyg6g3SN6ZcrmAy6uVrA3HAMBgbFAse89jki-JZ8t9iK:24:1672755996&jazoest=24821&__dyn=1KQEGiFo525Ujwh8-t0BBBgS5UqxKcwRwAxu3-Uco6q3q327Hw9e5orx60lW4o3Bw4Ewk9EdEnw65xO2O1Vwro7ifw5Zx62K2G0g26E52229wcq0C9EdE2IzU2Xwp82vwAwmE2ewnE2Lx-220jG3qazo11E2ZwrU6C2-0z836w&__csr=&__req=b&__a=AYltv4PwLKfRaPOm3vXywmuQ7w-cOgesCW15eyelU6wut5KA1ngiReAq53QySzrSQ2h7opM7jRkZK9XgPIIB-ek2Vx9Z70y5FAKyLiR-ISfqpA&__user=100075867577015 +//https://www.facebook.com/ajax/typeahead/first_degree.php?viewer=100075867577015&token=v7&filter[0]=user&options[0]=friends_only&options[1]=nm&fb_dtsg_ag=NAcM4Va03WgxUC9_454ocvAxZhjX-dlrZVyWsjooAcffVe-I9YvzAVw:24:1672755996&__user=100075867577015&__a=1&__req=d&__rev=1686870533469 +//https://web.facebook.com/ajax/typeahead/first_degree.php?viewer=100075867577015&token=v7&filter[0]=user&options[0]=friends_only&options[1]=nm&fb_dtsg_ag=AQwWeyg6g3SN6ZcrmAy6uVrA3HAMBgbFAse89jki-JZ8t9iK:24:1672755996&__a=1&__user=100075867577015 +export async function getFriendsAsync(uid, fbs) { + var urll = "https://www.facebook.com/ajax/typeahead/first_degree.php?"; + (urll += "viewer=" + uid), + (urll += + "&token=v7&filter[0]=user&options[0]=friends_only&options[1]=nm&fb_dtsg_ag=" + + fbs + + "&__user=" + + uid), + (urll += "&__a=1&__req=d&__rev=" + new Date().getTime()); + var d = await fetch(urll); + if ( + (!d.statusText && d.status && 200 != d.status) || + (!d.status && d.statusText && "OK" != d.statusText) + ) + return console.log("Fail here"); + var t = await d.text(); + var e = t.replace("for (;;);", ""); + var e = JSON.parse(e); + if (e.error) { + return new Error("err"); + } + if (e.redirect) { + d = await fetch(urll.replace("www", "web")); + if ( + (!d.statusText && d.status && 200 != d.status) || + (!d.status && d.statusText && "OK" != d.statusText) + ) + return console.log("Fail here"); + var t = await d.text(); + var e = t.replace("for (;;);", ""); + e = JSON.parse(e); + if (e.error) { + return new Error("err"); + } + } + var res = {}; + var f = {}; + var name = ""; + let photo = ""; + for (var g in e.payload.entries) { + var h = e.payload.entries[g]; + if (h.uid != uid) { + f[h.uid] = { + uid: h.uid, + name: h.names[0], + photo: h.photo, + }; + } + if (h.uid == uid) { + name = h.names[0]; + photo = h.photo; + } + } + res.f = f; + res.name = name; + res.photo = photo; + return res; +} + // ============================================================================= // ================================= Messages ================================== // ============================================================================= @@ -557,6 +658,41 @@ export async function getFbdtsg() { return null; } +export async function getFbDtsgAg() { + return new Promise(function (resolve, reject) { + fetch("https://www.facebook.com/settings?tab=account§ion=name&view") + .then(function (response) { + if (response.status !== 200) { + console.log( + "Looks like there was a problem. Status Code: " + response.status + ); + reject(response.status); + } + response.text().then((r) => { + const regex = /name="fb_dtsg" value="\s*(.*?)\s*"/g; + const html = r; + var newReg = new RegExp( + /DTSGInitData(?:.*?):"(.*?)",(?:.*?):"(.*?)"/ + ); + var newReg1 = new RegExp(/\"fb_dtsg\",\"value\"\:\"(.+?)\"}/); + var reg = new RegExp( + regex.source + "|" + newReg.source + "|" + newReg1.source + ); + var dtsgMatches = html.match(reg); + if (!dtsgMatches || !dtsgMatches.hasOwnProperty(1)) { + resolve(""); + } + resolve(dtsgMatches[3]); + //resolve(dtsgMatches[1] || dtsgMatches[2] || dtsgMatches[3]); + }); + }) + .catch(function (err) { + console.log("Fetch Error :-S", err); + reject(err); + }); + }); +} + // ============================================================================= // =================================== Story =================================== // ============================================================================= diff --git a/scripts/fb_autoLike.js b/scripts/fb_autoLike.js new file mode 100644 index 00000000..8194dc1a --- /dev/null +++ b/scripts/fb_autoLike.js @@ -0,0 +1,220 @@ +import { UfsGlobal } from "./content-scripts/ufs_global.js"; +import { BADGES } from "./helpers/badge.js"; + +export default { + icon: '', + name: { + en: "Auto like post on Facebook", + vi: "Tự động thích bài đăng Facebook", + }, + description: { + en: `Auto like post on Facebook. +
    +
  • Support all post types (page, group, user, feed, ...)
  • +
  • Support bulk remove/add reactions
  • +
  • Support all reaction types
  • +
`, + vi: `Tự động thả cảm xúc cho bài đăng trên Facebook. +
    +
  • Hỗ trợ mọi loại bài đăng (trang, nhóm, người dùng, new feed, ...)
  • +
  • Hỗ trợ gỡ/thêm cảm xúc hàng loạt
  • +
  • Hỗ trợ mọi loại cảm xúc
  • +
`, + }, + badges: [BADGES.new], + changeLogs: { + "2024-07-08": "init", + }, + + whiteList: ["https://*.facebook.com/*"], + + pageScript: { + onClick: () => { + const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); + + function focusTo(element) { + element.dispatchEvent( + new MouseEvent("pointerover", { + view: window, + bubbles: true, + cancelable: true, + }) + ); + } + + function scrollToBottom() { + window.scrollTo(0, document.body.scrollHeight, { behavior: "smooth" }); + } + + function rand(min, max) { + return Math.floor(Math.random() * (max - min + 1) + min); + } + + function isRunning(value) { + if (!(typeof value === "boolean")) + return window.ufs_fb_autoLike_running; + else window.ufs_fb_autoLike_running = value; + } + + const Reactions = { + like: { vi: "Thích", en: "Like", emoji: "👍" }, + love: { vi: "Yêu thích", en: "Love", emoji: "❤️" }, + care: { vi: "Thương thương", en: "Care", emoji: "🤗" }, + haha: { vi: "Haha", en: "Haha", emoji: "😂" }, + wow: { vi: "Wow", en: "Wow", emoji: "😮" }, + sad: { vi: "Buồn", en: "Sad", emoji: "😢" }, + angry: { vi: "Phẫn nộ", en: "Angry", emoji: "😠" }, + }; + + const Types = { + addReact: { + vi: "Bày tỏ cảm xúc", + en: "React", + name: "Thả cảm xúc - Add reaction", + }, + removeReact: { + vi: "Gỡ ", + en: "Remove ", + name: "Gỡ cảm xúc - Remove reaction", + }, + }; + + async function startAutoLike( + type = Types.addReact, + reaction = Reactions.love, + maxPosts = Infinity + ) { + isRunning(true); + + const notify = UfsGlobal.DOM.notify({ + msg: "Đang chuẩn bị ...", + duration: 999999, + }); + + let count = 0; + + const btns = []; + const unobserver = UfsGlobal.DOM.onElementsAdded( + ["en", "vi"] + .map((l) => + type === Types.removeReact + ? Object.values(Reactions).map( + (r) => + `[aria-label='${type[l]}${r[l]}']:not(li *):not([hidden] *)` + ) + : `[aria-label='${type[l]}']:not(li *)` + ) + .flat() + .join(", "), + (nodes) => { + btns.push(...nodes); + } + ); + + let scrollTried = 0; + while (true) { + if (!isRunning()) { + alert("Stopped Auto react !\n\nĐã dừng tự động thích!"); + break; + } + if (!btns.length) { + scrollTried++; + if (scrollTried > 50) break; + notify.setText("Scrolling to bottom... " + scrollTried, 99999); + scrollToBottom(); + await sleep(2000); + continue; + } + scrollTried = 0; + + const btn = btns.shift(); + btn.scrollIntoView({ + block: "center", + behavior: "smooth", + }); + + let waitFor = rand(1000, 4000); + count++; + if (count >= maxPosts) break; + notify.setText( + type.name + + ": " + + count + + "/" + + (count + btns.length) + + " - waiting: " + + (waitFor / 1000).toFixed(1) + + "s", + 99999 + ); + + await sleep(waitFor); + + btn.click(); + + if (type === Types.addReact) { + await sleep(500); + + let reactBtn = document.querySelector( + [reaction.en, reaction.vi] + .map((_) => `[aria-label='${_}']`) + .join(", ") + ); + if (reactBtn) { + focusTo(reactBtn); + await sleep(100); + reactBtn.click(); + await sleep(100); + } + } + } + + unobserver?.(); + let text = type.name + ": " + count + " posts"; + notify.setText(text, 5000); + isRunning(false); + alert(text); + } + + if (isRunning()) { + return isRunning(false); + } + + const typeIndex = prompt( + "Bạn muốn?\n" + + Object.entries(Types) + .map(([key, value], i) => i + ": " + value.name) + .join("\n"), + 0 + ); + let selectedType = Types[Object.keys(Types)[typeIndex]]; + let selectedReact; + if (typeIndex === null || !selectedType) return; + + if (typeIndex == 0) { + let reactIndex = prompt( + "Chọn reaction:\n" + + Object.entries(Reactions) + .map( + ([key, value], i) => + i + ": " + value.emoji + " " + value.en + " - " + value.vi + ) + .join("\n"), + 1 + ); + selectedReact = Reactions[Object.keys(Reactions)[reactIndex]]; + if (reactIndex == null || !selectedReact) return; + } + + let max = prompt( + "Thả bao nhiêu bài post? - Max post?: (0 = tất cả/all) ", + 0 + ); + if (max == null) return; + if (max == 0) max = Infinity; + else max = parseInt(max); + + startAutoLike(selectedType, selectedReact, max); + }, + }, +}; diff --git a/scripts/fb_downloadWatchingVideo.js b/scripts/fb_downloadWatchingVideo.js index 9c78dc6a..35b0577e 100644 --- a/scripts/fb_downloadWatchingVideo.js +++ b/scripts/fb_downloadWatchingVideo.js @@ -29,20 +29,25 @@ export default { ); try { let listVideoId = await shared.getListVideoIdInWebsite(); - if (!listVideoId?.length > 0) throw Error("Không tìm thấy video"); + if (!listVideoId?.length > 0) throw Error("Không tìm thấy video nào"); - for (let videoId of listVideoId) { - if (!videoId) continue; - - setLoadingText("Đang lấy token dtsg..."); - let dtsg = await fb_videoDownloader.getDtsg(); + setLoadingText("Đang lấy token dtsg..."); + let dtsg = await fb_videoDownloader.getDtsg(); + let downloaded = 0; + for (let videoId of listVideoId) { setLoadingText("Đang tìm video url..."); let videoUrl = await fb_videoDownloader.getLinkFbVideo(videoId, dtsg); - - if (!videoUrl) continue; - - UfsGlobal.Utils.downloadURL(videoUrl, "fb_video.mp4"); + if (videoUrl) { + downloaded++; + UfsGlobal.Extension.download({ + url: videoUrl, + filename: "fb_video.mp4", + }); + } + } + if (downloaded === 0) { + alert("Không tìm thấy link video"); } } catch (e) { alert("ERROR: " + e); diff --git a/scripts/fb_revealDeletedMessages.js b/scripts/fb_revealDeletedMessages.js index 5ccb8043..31b0513a 100644 --- a/scripts/fb_revealDeletedMessages.js +++ b/scripts/fb_revealDeletedMessages.js @@ -200,7 +200,7 @@ export default { ) { const have_msg_id = /(?=mid\.\$)(.*?)(?=\\")/.exec(utf8_str); if (have_msg_id) { - console.log("reveal deleted ", utf8_str); + // console.log("reveal deleted ", utf8_str); let dataStr = utf8_str.slice(utf8_str.indexOf("{")); let data = JSON.parse(dataStr); let payload = JSON.parse(data?.["payload"]); @@ -262,10 +262,10 @@ export default { else if ( confirm( `Bạn có chắc muốn xóa tất cả ${len} tin nhắn` + - ` đã được lưu bởi chức năng này?\n\n` + - `+ Chỉ nên xóa khi thấy đã lưu quá nhiều tin nhắn.\n` + - `+ Sau khi xóa, nếu có người thu hồi tin nhắn, mà tin đó chưa được lưu\n` + - ` thì bạn sẽ ko biết được nội dung tin nhắn.` + ` đã được lưu bởi chức năng này?\n\n` + + `+ Chỉ nên xóa khi thấy đã lưu quá nhiều tin nhắn.\n` + + `+ Sau khi xóa, nếu có người thu hồi tin nhắn, mà tin đó chưa được lưu\n` + + ` thì bạn sẽ ko biết được nội dung tin nhắn.` ) ) { window.ufs_rvdfm_all_msgs = {}; diff --git a/scripts/fb_storySaver.js b/scripts/fb_storySaver.js index 3d95be19..6c15778c 100644 --- a/scripts/fb_storySaver.js +++ b/scripts/fb_storySaver.js @@ -11,7 +11,7 @@ export default { vi: "Tải facebook story / video bình luận bạn đang xem", }, - contentScript: { + pageScript: { onClick: function () { // Source code extracted from: https://chrome.google.com/webstore/detail/story-saver/mafcolokinicfdmlidhaebadidhdehpk @@ -22,45 +22,55 @@ export default { if (videos[i].offsetHeight === 0) continue; let reactKey = ""; let keys = Object.keys(videos[i]); - for (let key of keys) { - if (key.indexOf("__reactFiber") != -1) { - reactKey = key.split("__reactFiber")[1]; + for (let j = 0; j < keys.length; j++) { + if (keys[j].indexOf("__reactFiber") != -1) { + reactKey = keys[j].split("__reactFiber")[1]; break; } } let storyUrl; try { - //prettier-ignore - storyUrl = videos[i].parentElement.parentElement.parentElement.parentElement['__reactProps' + reactKey].children[0].props.children.props.implementations[1].data.hdSrc; + storyUrl = + videos[i].parentElement.parentElement.parentElement.parentElement[ + "__reactProps" + reactKey + ].children[0].props.children.props.implementations[1].data.hdSrc; } catch (e) {} if (storyUrl == null) { try { - //prettier-ignore - storyUrl = videos[i].parentElement.parentElement.parentElement.parentElement['__reactProps' + reactKey].children[0].props.children.props.implementations[1].data.sdSrc; + storyUrl = + videos[i].parentElement.parentElement.parentElement.parentElement[ + "__reactProps" + reactKey + ].children[0].props.children.props.implementations[1].data.sdSrc; } catch (e) {} } if (storyUrl == null) { try { - //prettier-ignore - storyUrl = videos[i].parentElement.parentElement.parentElement.parentElement['__reactProps' + reactKey].children.props.children.props.implementations[1].data.hdSrc; + storyUrl = + videos[i].parentElement.parentElement.parentElement.parentElement[ + "__reactProps" + reactKey + ].children.props.children.props.implementations[1].data.hdSrc; } catch (e) {} } if (storyUrl == null) { try { - //prettier-ignore - storyUrl = videos[i].parentElement.parentElement.parentElement.parentElement['__reactProps' + reactKey].children.props.children.props.implementations[1].data.sdSrc; + storyUrl = + videos[i].parentElement.parentElement.parentElement.parentElement[ + "__reactProps" + reactKey + ].children.props.children.props.implementations[1].data.sdSrc; } catch (e) {} } if (storyUrl == null) { try { - //prettier-ignore - storyUrl = videos[i]['__reactFiber' + reactKey].return.stateNode.props.videoData.$1.hd_src; + storyUrl = + videos[i]["__reactFiber" + reactKey].return.stateNode.props + .videoData.$1.hd_src; } catch (e) {} } if (storyUrl == null) { try { - //prettier-ignore - storyUrl = videos[i]['__reactFiber' + reactKey].return.stateNode.props.videoData.$1.sd_src; + storyUrl = + videos[i]["__reactFiber" + reactKey].return.stateNode.props + .videoData.$1.sd_src; } catch (e) {} } if (storyUrl != null) { @@ -69,16 +79,24 @@ export default { } let storyImgUrl = Array.from( - document.querySelectorAll('div[data-id] img[draggable="false"]') + document.querySelectorAll('img[draggable="false"]') ).find((_) => _.alt)?.src; if (storyImgUrl) { listUrls.push({ url: storyImgUrl, type: "img" }); } + let profile_pic = document.querySelector( + "a[role=link][tabindex='0'][href*='https://www.facebook']>img" + ); + let username = profile_pic?.alt || "fb_story"; + if (!listUrls.length) { alert("Không tìm thấy facebook story nào trong trang web."); } else if (listUrls.length === 1) { - UfsGlobal.Utils.downloadURL(listUrls[0].url, "fb_story_video.mp4"); + UfsGlobal.Extension.download({ + url: listUrls[0].url, + filename: username + (listUrls[0].type === "img" ? ".jpg" : ".mp4"), + }); } else { let w = window.open("", "", "width=500,height=700"); w.document.write( diff --git a/scripts/fireship_vip.js b/scripts/fireship_vip.js index b2fa36ab..384535f1 100644 --- a/scripts/fireship_vip.js +++ b/scripts/fireship_vip.js @@ -1,23 +1,23 @@ export default { - icon: "https://fireship.io/img/favicon.png", + icon: 'https://fireship.io/img/favicon.png', name: { - en: "Fireship - PRO unlocked", - vi: "Fireship - Mở khoá PRO", + en: 'Fireship - PRO unlocked', + vi: 'Fireship - Mở khoá PRO', }, description: { - en: "Unlock all Fireship PRO courses/lessons (saved $399 USD)", - vi: "Mở khoá tất cả khoá học/bài giảng PRO trên Fireship (tiết kiệm $399 USD)", + en: 'Unlock all Fireship PRO courses/lessons (saved $399 USD)', + vi: 'Mở khoá tất cả khoá học/bài giảng PRO trên Fireship (tiết kiệm $399 USD)', }, - infoLink: "https://fireship.io/", + infoLink: 'https://fireship.io/', - whiteList: ["https://fireship.io/*"], + whiteList: ['https://fireship.io/*'], - contentScript: { + pageScript: { onDocumentIdle: () => { // ==UserScript== // @name Freeship // @namespace lemons - // @version 1.7 + // @version 1.8 // @description Unlock all Fireship PRO courses/lessons. // @author lemons // @match https://fireship.io/* @@ -27,31 +27,54 @@ export default { // @updateURL https://update.greasyfork.org/scripts/455330/Freeship.meta.js // ==/UserScript== - // prettier-ignore - setInterval(async () => { - document.querySelectorAll("[free=\"\"]").forEach(el => el.setAttribute("free", true)) // set all elements with the attribute free set to "" to true + console.log('use fireship_vip.js'); - if (document.querySelector("if-access [slot=\"granted\"]")) { // replace HOW TO ENROLL to YOU HAVE ACCESS - document.querySelector("if-access [slot=\"denied\"]").remove() - document.querySelector("if-access [slot=\"granted\"]").setAttribute("slot", "denied") + const unlock = async () => { + // set all elements with the attribute free set to "" to true + document.querySelectorAll('[free=""]').forEach((el) => el.setAttribute('free', true)); + + if (document.querySelector('if-access [slot="granted"]')) { + // replace HOW TO ENROLL to YOU HAVE ACCESS + document.querySelector('if-access [slot="denied"]').remove(); + document.querySelector('if-access [slot="granted"]').setAttribute('slot', 'denied'); } - if (document.querySelector("video-player")?.shadowRoot?.querySelector(".vid")?.innerHTML) return; // return if no video player - const vimeoId = Number(atob(document.querySelector("global-data").vimeo)); // get id for vimeo video - const youtubeId = atob(document.querySelector("global-data").youtube); // get id for vimeo video + // return if no video player + if (document.querySelector('video-player')?.shadowRoot?.querySelector('.vid')?.innerHTML) return; + + // get id for vimeo video + const vimeoId = Number(atob(document.querySelector('global-data').vimeo || btoa(''))); - if (youtubeId) { // if there is an id, - document.querySelector("video-player").setAttribute("free", true) // set free to true - document.querySelector("video-player").shadowRoot.querySelector(".vid").innerHTML = `` // set video - return; + // get id for vimeo video + const youtubeId = atob(document.querySelector('global-data').youtube || btoa('')); + + if (youtubeId) { + // if there is an id, + document.querySelector('video-player').setAttribute('free', true); // set free to true + document + .querySelector('video-player') + .shadowRoot.querySelector( + '.vid' + ).innerHTML = ``; // set video + return; } - if (vimeoId) { // if there is an id, - document.querySelector("video-player").setAttribute("free", true) // set free to true - const html = (await fetch(`https://vimeo.com/api/oembed.json?url=https%3A%2F%2Fvimeo.com%2F${vimeoId}&id=${vimeoId}`).then(r=>r.json())).html - document.querySelector("video-player").shadowRoot.querySelector(".vid").innerHTML = html // set video - return; + if (vimeoId) { + // if there is an id, + document.querySelector('video-player').setAttribute('free', true); // set free to true + const html = ( + await fetch( + `https://vimeo.com/api/oembed.json?url=https%3A%2F%2Fvimeo.com%2F${vimeoId}&id=${vimeoId}` + ).then((r) => r.json()) + ).html; + document.querySelector('video-player').shadowRoot.querySelector('.vid').innerHTML = html; // set video + return; } - }, 500) + }; + + window.onload = unlock(); + window.addEventListener('flamethrower:router:end', unlock); }, }, }; diff --git a/scripts/libs/utils/xmlParser.js b/scripts/libs/utils/xmlParser.js index fbea7fd5..4859fb10 100644 --- a/scripts/libs/utils/xmlParser.js +++ b/scripts/libs/utils/xmlParser.js @@ -1,5 +1,4 @@ -// https://stackoverflow.com/a/1773571 - +// https://stackoverflow.com/a/1773571/11898496 export function parseXml(xml) { var dom = null; if (window.DOMParser) { @@ -23,196 +22,4 @@ export function parseXml(xml) { return dom; } -export function xml2json(xml, tab) { - var X = { - toObj: function (xml) { - var o = {}; - if (xml.nodeType == 1) { - // element node .. - if (xml.attributes.length) - // element with attributes .. - for (var i = 0; i < xml.attributes.length; i++) - o["@" + xml.attributes[i].nodeName] = ( - xml.attributes[i].nodeValue || "" - ).toString(); - if (xml.firstChild) { - // element has child nodes .. - var textChild = 0, - cdataChild = 0, - hasElementChild = false; - for (var n = xml.firstChild; n; n = n.nextSibling) { - if (n.nodeType == 1) hasElementChild = true; - else if (n.nodeType == 3 && n.nodeValue.match(/[^ \f\n\r\t\v]/)) - textChild++; // non-whitespace text - else if (n.nodeType == 4) cdataChild++; // cdata section node - } - if (hasElementChild) { - if (textChild < 2 && cdataChild < 2) { - // structured element with evtl. a single text or/and cdata node .. - X.removeWhite(xml); - for (var n = xml.firstChild; n; n = n.nextSibling) { - if (n.nodeType == 3) - // text node - o["#text"] = X.escape(n.nodeValue); - else if (n.nodeType == 4) - // cdata node - o["#cdata"] = X.escape(n.nodeValue); - else if (o[n.nodeName]) { - // multiple occurence of element .. - if (o[n.nodeName] instanceof Array) - o[n.nodeName][o[n.nodeName].length] = X.toObj(n); - else o[n.nodeName] = [o[n.nodeName], X.toObj(n)]; - } // first occurence of element.. - else o[n.nodeName] = X.toObj(n); - } - } else { - // mixed content - if (!xml.attributes.length) o = X.escape(X.innerXml(xml)); - else o["#text"] = X.escape(X.innerXml(xml)); - } - } else if (textChild) { - // pure text - if (!xml.attributes.length) o = X.escape(X.innerXml(xml)); - else o["#text"] = X.escape(X.innerXml(xml)); - } else if (cdataChild) { - // cdata - if (cdataChild > 1) o = X.escape(X.innerXml(xml)); - else - for (var n = xml.firstChild; n; n = n.nextSibling) - o["#cdata"] = X.escape(n.nodeValue); - } - } - if (!xml.attributes.length && !xml.firstChild) o = null; - } else if (xml.nodeType == 9) { - // document.node - o = X.toObj(xml.documentElement); - } else alert("unhandled node type: " + xml.nodeType); - return o; - }, - toJson: function (o, name, ind) { - var json = name ? '"' + name + '"' : ""; - if (o instanceof Array) { - for (var i = 0, n = o.length; i < n; i++) - o[i] = X.toJson(o[i], "", ind + "\t"); - json += - (name ? ":[" : "[") + - (o.length > 1 - ? "\n" + ind + "\t" + o.join(",\n" + ind + "\t") + "\n" + ind - : o.join("")) + - "]"; - } else if (o == null) json += (name && ":") + "null"; - else if (typeof o == "object") { - var arr = []; - for (var m in o) arr[arr.length] = X.toJson(o[m], m, ind + "\t"); - json += - (name ? ":{" : "{") + - (arr.length > 1 - ? "\n" + ind + "\t" + arr.join(",\n" + ind + "\t") + "\n" + ind - : arr.join("")) + - "}"; - } else if (typeof o == "string") - json += (name && ":") + '"' + o.toString() + '"'; - else json += (name && ":") + o.toString(); - return json; - }, - innerXml: function (node) { - var s = ""; - if ("innerHTML" in node) s = node.innerHTML; - else { - var asXml = function (n) { - var s = ""; - if (n.nodeType == 1) { - s += "<" + n.nodeName; - for (var i = 0; i < n.attributes.length; i++) - s += - " " + - n.attributes[i].nodeName + - '="' + - (n.attributes[i].nodeValue || "").toString() + - '"'; - if (n.firstChild) { - s += ">"; - for (var c = n.firstChild; c; c = c.nextSibling) s += asXml(c); - s += ""; - } else s += "/>"; - } else if (n.nodeType == 3) s += n.nodeValue; - else if (n.nodeType == 4) s += ""; - return s; - }; - for (var c = node.firstChild; c; c = c.nextSibling) s += asXml(c); - } - return s; - }, - escape: function (txt) { - return txt - .replace(/[\\]/g, "\\\\") - .replace(/[\"]/g, '\\"') - .replace(/[\n]/g, "\\n") - .replace(/[\r]/g, "\\r"); - }, - removeWhite: function (e) { - e.normalize(); - for (var n = e.firstChild; n; ) { - if (n.nodeType == 3) { - // text node - if (!n.nodeValue.match(/[^ \f\n\r\t\v]/)) { - // pure whitespace text node - var nxt = n.nextSibling; - e.removeChild(n); - n = nxt; - } else n = n.nextSibling; - } else if (n.nodeType == 1) { - // element node - X.removeWhite(n); - n = n.nextSibling; - } // any other node - else n = n.nextSibling; - } - return e; - }, - }; - if (xml.nodeType == 9) - // document node - xml = xml.documentElement; - var json = X.toJson(X.toObj(X.removeWhite(xml)), xml.nodeName, "\t"); - return ( - "{\n" + - tab + - (tab ? json.replace(/\t/g, tab) : json.replace(/\t|\n/g, "")) + - "\n}" - ); -} - -export function json2xml(o, tab) { - var toXml = function (v, name, ind) { - var xml = ""; - if (v instanceof Array) { - for (var i = 0, n = v.length; i < n; i++) - xml += ind + toXml(v[i], name, ind + "\t") + "\n"; - } else if (typeof v == "object") { - var hasChild = false; - xml += ind + "<" + name; - for (var m in v) { - if (m.charAt(0) == "@") - xml += " " + m.substr(1) + '="' + v[m].toString() + '"'; - else hasChild = true; - } - xml += hasChild ? ">" : "/>"; - if (hasChild) { - for (var m in v) { - if (m == "#text") xml += v[m]; - else if (m == "#cdata") xml += ""; - else if (m.charAt(0) != "@") xml += toXml(v[m], m, ind + "\t"); - } - xml += - (xml.charAt(xml.length - 1) == "\n" ? ind : "") + ""; - } - } else { - xml += ind + "<" + name + ">" + v.toString() + ""; - } - return xml; - }, - xml = ""; - for (var m in o) xml += toXml(o[m], m, ""); - return tab ? xml.replace(/\t/g, tab) : xml.replace(/\t|\n/g, ""); -} +// https://stackoverflow.com/a/20861541/11898496 diff --git a/scripts/magnify_image.css b/scripts/magnify_image.css index 62c38be6..12c79e4e 100644 --- a/scripts/magnify_image.css +++ b/scripts/magnify_image.css @@ -220,6 +220,11 @@ opacity: 1; } +#ufs-magnify-image-hover-div.hide { + opacity: 0; + display: block !important; +} + #ufs-magnify-image-hover-div.hide:not(:hover) { opacity: 0; transition: all 0.2s 2s ease; diff --git a/scripts/passwordGenerator.js b/scripts/passwordGenerator.js index 27e99918..c1cf4aae 100644 --- a/scripts/passwordGenerator.js +++ b/scripts/passwordGenerator.js @@ -8,6 +8,9 @@ export default { en: "You only have to remember 1 password", vi: "Bạn chỉ còn cần phải nhớ 1 mật khẩu", }, + changeLogs: { + "2024-07-11": "hotfix", + }, contentScript: { onClick: function () { @@ -125,6 +128,7 @@ export default { " + Tự động điền vào trang web khi nhập đúng Mật_khẩu_Chính\n" + "\nNhập Mật_khẩu_Chính của bạn:" ); + let host, sld, domain, D; if (master != "" && master != null) { host = document.location.href.match(/http(s*):\/\/([^/]+)/)[2]; if ( diff --git a/scripts/pictureInPicture.js b/scripts/pictureInPicture.js index 1a108629..cb6e8599 100644 --- a/scripts/pictureInPicture.js +++ b/scripts/pictureInPicture.js @@ -1,7 +1,7 @@ import { BADGES } from "./helpers/badge.js"; export default { - icon: "https://lh3.googleusercontent.com/cvfpnTKw3B67DtM1ZpJG2PNAIjP6hVMOyYy403X4FMkOuStgG1y4cjCn21vmTnnsip1dTZSVsWBA9IxutGuA3dVDWhg=w128-h128-e365-rj-sc0x00ffffff", + icon: '', name: { en: "Picture in Picture", vi: "Picture in Picture", diff --git a/scripts/pip_canvas.js b/scripts/pip_canvas.js index 353e741d..9001c04d 100644 --- a/scripts/pip_canvas.js +++ b/scripts/pip_canvas.js @@ -1,7 +1,7 @@ import { UfsGlobal } from "./content-scripts/ufs_global.js"; export default { - icon: "https://lh3.googleusercontent.com/cvfpnTKw3B67DtM1ZpJG2PNAIjP6hVMOyYy403X4FMkOuStgG1y4cjCn21vmTnnsip1dTZSVsWBA9IxutGuA3dVDWhg=w128-h128-e365-rj-sc0x00ffffff", + icon: '', name: { en: "PIP for canvas", vi: "PIP cho canvas", diff --git a/scripts/pip_fullWebsite.js b/scripts/pip_fullWebsite.js index 47ec6ed2..c62d0f47 100644 --- a/scripts/pip_fullWebsite.js +++ b/scripts/pip_fullWebsite.js @@ -1,7 +1,7 @@ import { UfsGlobal } from "./content-scripts/ufs_global.js"; export default { - icon: "https://lh3.googleusercontent.com/cvfpnTKw3B67DtM1ZpJG2PNAIjP6hVMOyYy403X4FMkOuStgG1y4cjCn21vmTnnsip1dTZSVsWBA9IxutGuA3dVDWhg=w128-h128-e365-rj-sc0x00ffffff", + icon: '', name: { en: "PIP full website", vi: "PIP toàn website", diff --git a/scripts/screenshotFullPage.js b/scripts/screenshotFullPage.js index e9ac24fd..8b1d7323 100644 --- a/scripts/screenshotFullPage.js +++ b/scripts/screenshotFullPage.js @@ -45,10 +45,10 @@ export default { console.log(img); setLoadingText("Đang lưu ảnh..."); - UfsGlobal.Utils.downloadURL( - "data:image/png;base64," + img.data, - "fullpage.png" - ); + UfsGlobal.Extension.download({ + url: "data:image/png;base64," + img.data, + filename: "fullpage.png", + }); } await detachDebugger(tab); } catch (e) { diff --git a/scripts/screenshotVisiblePage.js b/scripts/screenshotVisiblePage.js index 1639104c..55788a42 100644 --- a/scripts/screenshotVisiblePage.js +++ b/scripts/screenshotVisiblePage.js @@ -72,10 +72,10 @@ export default { console.log(img); setLoadingText("Đang lưu ảnh..."); - UfsGlobal.Utils.downloadURL( - "data:image/png;base64," + img.data, - "webpage.png" - ); + UfsGlobal.Extension.download({ + url: "data:image/png;base64," + img.data, + filename: "webpage.png", + }); await detachDebugger(tab); } catch (e) { diff --git a/scripts/smoothScroll.js b/scripts/smoothScroll.js index 096323b0..8583f78f 100644 --- a/scripts/smoothScroll.js +++ b/scripts/smoothScroll.js @@ -8,11 +8,17 @@ export default { }, description: { en: `Scroll smoothly on all websites with your mouse and keyboard.
- Smooth like when you scroll this extension.

- Support middle click to scroll.`, +
    +
  • Suggested if you use mouse (turn off if use touchpad)
  • +
  • Click to Disable/Enable for current website
  • +
  • Support middle click to scroll
  • +

`, vi: `Cuộn chuột siêu mượt cho mọi trang web.
- Mượt như khi cuộn chuột trong extension này vậy.

- Hỗ trợ scroll khi bấm chuột giữa.`, +
    +
  • Khuyên dùng với chuột (tắt nếu dùng touchpad)
  • +
  • Bấm để Tắt/Mở cho trang web hiện tại
  • +
  • Hỗ trợ bấm chuột giữa để cuộn trang
  • +

`, video: "https://www.smoothscroll.net/mac/img/vid/Demo-Mac-720p.mp4", }, badges: [BADGES.hot], @@ -28,107 +34,90 @@ export default { ], changeLogs: { + "2024-07-11": "click to disable/enable for current site", "2024-05-26": "init", }, popupScript: { - onEnable: async () => { - const { t } = await import("../popup/helpers/lang.js"); - const { runScriptInTab, getAllTabs: getAllAvailableTabs } = await import( - "./helpers/utils.js" - ); - const tabs = await getAllAvailableTabs(); - let count = 0; - for (let tab of tabs) { - try { - runScriptInTab({ - target: { - tabId: tab.id, - allFrames: true, - }, - func: enableSmoothScroll, - world: "ISOLATED", - }); - count++; - } catch (e) { - console.error(e); - } - } - if (count) - Swal.fire({ - icon: "success", - title: t({ - vi: "Đã bật Cuộn chuột Siêu mượt", - en: "Super smooth scroll enabled", - }), - html: t({ - vi: - `Đã tự BẬT cho ${count} tab đang mở

` + - "Bạn có thể dùng ngay không cần tải lại trang.", - en: - `Enabled smooth scroll for ${count} opening tabs

` + - "Dont need to reload websites.", - }), - }); - }, - onDisable: async () => { - const { t } = await import("../popup/helpers/lang.js"); - const { runScriptInTab, getAllTabs: getAllAvailableTabs } = await import( - "./helpers/utils.js" - ); - const tabs = await getAllAvailableTabs(); - let count = 0; - for (let tab of tabs) { - try { - runScriptInTab({ - target: { - tabId: tab.id, - allFrames: true, - }, - func: () => { - window.ufs_smoothScroll_disable?.(); - }, - world: "ISOLATED", - }); - count++; - } catch (e) { - console.error(e); - } - } - if (count) - Swal.fire({ - icon: "success", - title: t({ - vi: "Đã tắt Cuộn chuột Siêu mượt", - en: "Super smooth scroll disabled", - }), - html: t({ - vi: - `Đã tự TẮT cho ${count} tab đang mở

` + - "Không cần tải lại trang.", - en: - `Disabled smooth scroll for ${count} opening tabs

` + - "Dont need to reload websites.", - }), - }); - }, + onEnable: () => setEnableForAllTab(true), + onDisable: () => setEnableForAllTab(false), }, contentScript: { - onDocumentStart_: (details) => { - enableSmoothScroll(); + onDocumentStart_: enableSmoothScroll, + onClick_: () => { + if (typeof window.ufs_smoothScroll_disable === "function") { + window.ufs_smoothScroll_disable(); + localStorage.setItem("ufs_smoothScroll_disable", 1); + if (window === window.top) + alert("DISABLED smooth scroll for this site: " + location.hostname); + } else { + localStorage.setItem("ufs_smoothScroll_disable", 0); + enableSmoothScroll(); + if (window === window.top) + alert("ENABLED smooth scroll for this site: " + location.hostname); + } }, }, }; +async function setEnableForAllTab(enable) { + const { t } = await import("../popup/helpers/lang.js"); + const { runScriptInTab, getAllTabs: getAllAvailableTabs } = await import( + "./helpers/utils.js" + ); + const tabs = await getAllAvailableTabs(); + let count = 0; + for (let tab of tabs) { + try { + runScriptInTab({ + target: { + tabId: tab.id, + allFrames: true, + }, + func: enable + ? enableSmoothScroll + : () => { + window.ufs_smoothScroll_disable?.(); + }, + world: "ISOLATED", + }); + count++; + } catch (e) { + console.error(e); + } + } + let text = enable + ? { vi: "Bật", en: "Enabled" } + : { vi: "Tắt", en: "Disabled" }; + + if (count) + Swal.fire({ + icon: "success", + title: t({ + vi: "Đã " + text.vi + " Cuộn chuột Siêu mượt", + en: "Super smooth scroll " + text.en, + }), + html: t({ + vi: + `Đã tự ${text.vi} cho ${count} tab đang mở

` + + "Bạn có thể dùng ngay không cần tải lại trang.", + en: + `${text.en} smooth scroll for ${count} opening tabs

` + + "Dont need to reload websites.", + }), + }); +} + // TODO: -// + setting page -// + horizontal scroll -// + fix window.scrollTo with behavior: "smooth" -// + check excluded +// [ ] setting page +// [ ] horizontal scroll +// [x] fix window.scrollTo with behavior: "smooth" +// [x] check excluded // https://chromewebstore.google.com/detail/smoothscroll/nbokbjkabcmbfdlbddjidfmibcpneigj export function enableSmoothScroll() { + if (localStorage.getItem("ufs_smoothScroll_disable") == 1) return; // ======================================================================= // ============================ sscr.js ================================== // ======================================================================= @@ -979,6 +968,7 @@ export function enableSmoothScroll() { window.ufs_smoothScroll_disable = () => { cleanup(); cleanupMiddlemouse(); + window.ufs_smoothScroll_disable = null; }; return window.ufs_smoothScroll_disable; diff --git a/scripts/tiktok_downloadWatchingVideo.js b/scripts/tiktok_downloadWatchingVideo.js index 9fb790a2..5d804a9c 100644 --- a/scripts/tiktok_downloadWatchingVideo.js +++ b/scripts/tiktok_downloadWatchingVideo.js @@ -84,8 +84,15 @@ export default { setLoadingText( t({ vi: `Đang tải video ${title}...`, en: `Downloading ${title}...` }) ); - const { formatSize, downloadBlob } = UfsGlobal.Utils; - const blob = await UfsGlobal.Utils.getBlobFromUrlWithProgress( + + // UfsGlobal.Extension.download({ + // url: link, + // filename: title + ".mp4", + // }); + + const { formatSize, downloadBlob, getBlobFromUrlWithProgress } = + UfsGlobal.Utils; + const blob = await getBlobFromUrlWithProgress( link, ({ loaded, total, speed }) => { let desc = diff --git a/scripts/webToPDF.js b/scripts/webToPDF.js index aea283df..6acd42d6 100644 --- a/scripts/webToPDF.js +++ b/scripts/webToPDF.js @@ -33,11 +33,10 @@ export default { }); await detachDebugger(tab); - // https://stackoverflow.com/a/59352848/11898496 - UfsGlobal.Utils.downloadURL( - "data:application/pdf;base64," + res.data, - "web.pdf" - ); + UfsGlobal.Extension.download({ + url: "data:application/pdf;base64," + res.data, + filename: "web.pdf", + }); } catch (e) { if ( confirm( diff --git a/scripts/youglish_search.js b/scripts/youglish_search.js new file mode 100644 index 00000000..36d6e7da --- /dev/null +++ b/scripts/youglish_search.js @@ -0,0 +1,47 @@ +import { BADGES } from './helpers/badge.js'; + +const contextMenuId = 'youglish-search'; + +export default { + icon: '', + name: { + en: 'YouGlish search', + vi: 'Tìm kiếm trên YouGlish', + }, + description: { + en: "Master English pronunciation naturally! Learn how to pronounce tricky sounds like a native with YouGlish's real-world clips. No more dictionary confusion, just real English in context. (from 'youglish.com')", + vi: 'Làm chủ phát âm tiếng Anh một cách tự nhiên! Học cách phát âm những âm thanh khó khăn như người bản xứ với các đoạn video thực tế từ YouGlish. Không còn bối rối với từ điển, chỉ có tiếng Anh thực sự trong ngữ cảnh. (từ "youglish.com")', + }, + badges: [BADGES.new], + changeLogs: { + '2024-07-06': 'init', + }, + + popupScript: { + onClick: () => window.close(), + }, + + backgroundScript: { + runtime: { + onInstalled: () => { + chrome.contextMenus.create({ + title: 'YouGlish Search', + contexts: ['selection'], + id: contextMenuId, + parentId: 'root', + }); + }, + }, + contextMenus: { + onClicked: ({ info }, context) => { + if (info.menuItemId == contextMenuId) { + const content = (info.selectionText || '').trim().toLowerCase(); + if (!content.length) return; + + const link = `https://youglish.com/pronounce/${content}/english`; + chrome.tabs.create({ url: link }); + } + }, + }, + }, +}; diff --git a/scripts/youtube_changeCountry.js b/scripts/youtube_changeCountry.js new file mode 100644 index 00000000..a1cdfdf5 --- /dev/null +++ b/scripts/youtube_changeCountry.js @@ -0,0 +1,243 @@ +import { BADGES } from "./helpers/badge.js"; + +export default { + icon: '', + name: { + en: "Youtube change country", + vi: "Đổi quốc gia Youtube", + }, + description: { + en: "Change youtube country to view content in other country", + vi: "Đổi quốc gia youtube để xem nội dung youtube bên các nước khác", + }, + badges: [BADGES.new], + changeLogs: { + "2024-07-07": "init", + }, + + whiteList: ["https://*.youtube.com/*"], + + pageScript: { + onClick: () => { + const id = "ufs_youtube_changeCountry"; + const exist = document.getElementById(id); + if (exist) exist.remove(); + + const popup = document.createElement("div"); + popup.id = id; + popup.innerHTML = ` + +
+

Useful-Scripts

+

Change youtube contry

+
+ + +
+ + +
+ `; + + document.body.appendChild(popup); + + const select = popup.querySelector("#ufs_country"); + const saveBtn = popup.querySelector("#ufs_btnApply"); + const rememberCheckbox = popup.querySelector("#ufs_checkbox"); + + for (const contry of countries) { + const { name, name_en, code } = contry; + select.innerHTML += ``; + } + let current = getCurrentCountry(); + select.value = countries.find((c) => c.code == current) + ? current + : "default"; + saveBtn.onclick = () => { + changeCountry(select.value, rememberCheckbox.checked); + }; + + popup.onclick = (e) => { + if (e.target === popup) popup.remove(); + }; + }, + }, +}; + +function changeCountry(value, persist) { + if (value) { + let href = "https://www.youtube.com/feed/trending"; + if (persist) { + if (value !== "default") { + var date = new Date(); + date.setTime(date.getTime() + 3.154e10); + + document.cookie = + "s_gl=" + + value + + "; path=/; domain=.youtube.com; expires=" + + date.toGMTString(); + } else { + document.cookie = + "s_gl=0; path=/; domain=.youtube.com; expires=Thu, 01 Jan 1970 00:00:01 GMT"; + } + + window.location.href = href; + } else { + href += `?persist_gl=0&gl=${value}`; + window.location.href = href; + } + } +} + +function getCurrentCountry() { + const code = + window?.ytInitialData?.topbar?.desktopTopbarRenderer?.countryCode || + window.yt?.config_?.GL || + // regex in cookie + document.cookie.match(/s_gl=([^;]+)/)?.[1]; + return code || "default"; +} + +const countries = [ + { name: "Ả-Rập Xê-út", code: "SA", name_en: "Saudi Arabia" }, + { name: "Ai Cập", code: "EG", name_en: "Egypt" }, + { name: "Algeria", code: "DZ", name_en: "Algeria" }, + { name: "Áo", code: "AT", name_en: "Austria" }, + { name: "Argentina", code: "AR", name_en: "Argentina" }, + { name: "Azerbaijan", code: "AZ", name_en: "Azerbaijan" }, + { name: "Ấn Độ", code: "IN", name_en: "India" }, + { name: "Ba Lan", code: "PL", name_en: "Poland" }, + { name: "Bahrain", code: "BH", name_en: "Bahrain" }, + { name: "Bangladesh", code: "BD", name_en: "Bangladesh" }, + { name: "Bắc Macedonia", code: "MK", name_en: "North Macedonia" }, + { name: "Belarus", code: "BY", name_en: "Belarus" }, + { name: "Bỉ", code: "BE", name_en: "Belgium" }, + { name: "Bolivia", code: "BO", name_en: "Bolivia" }, + { + name: "Bosnia và Herzegovina", + code: "BA", + name_en: "Bosnia and Herzegovina", + }, + { name: "Bồ Đào Nha", code: "PT", name_en: "Portugal" }, + { name: "Brazil", code: "BR", name_en: "Brazil" }, + { name: "Bungary", code: "BG", name_en: "Bulgaria" }, + { + name: "Các Tiểu Vương quốc Ả Rập Thống nhất", + code: "AE", + name_en: "United Arab Emirates", + }, + { name: "Campuchia", code: "KH", name_en: "Cambodia" }, + { name: "Canada", code: "CA", name_en: "Canada" }, + { name: "Chile", code: "CL", name_en: "Chile" }, + { name: "Colombia", code: "CO", name_en: "Colombia" }, + { name: "Costa Rica", code: "CR", name_en: "Costa Rica" }, + { name: "Cộng hoà Dominica", code: "DO", name_en: "Dominican Republic" }, + { name: "Croatia", code: "HR", name_en: "Croatia" }, + { name: "Đài Loan", code: "TW", name_en: "Taiwan" }, + { name: "Đan Mạch", code: "DK", name_en: "Denmark" }, + { name: "Đảo Síp", code: "CY", name_en: "Cyprus" }, + { name: "Đức", code: "DE", name_en: "Germany" }, + { name: "Ecuador", code: "EC", name_en: "Ecuador" }, + { name: "El Salvador", code: "SV", name_en: "El Salvador" }, + { name: "Estonia", code: "EE", name_en: "Estonia" }, + { name: "Georgia", code: "GE", name_en: "Georgia" }, + { name: "Ghana", code: "GH", name_en: "Ghana" }, + { name: "Guatemala", code: "GT", name_en: "Guatemala" }, + { name: "Hà Lan", code: "NL", name_en: "Netherlands" }, + { name: "Hàn Quốc", code: "KR", name_en: "South Korea" }, + { name: "Hoa Kỳ", code: "US", name_en: "United States" }, + { name: "Honduras", code: "HN", name_en: "Honduras" }, + { name: "Hồng Kông", code: "HK", name_en: "Hong Kong" }, + { name: "Hungary", code: "HU", name_en: "Hungary" }, + { name: "Hy Lạp", code: "GR", name_en: "Greece" }, + { name: "Iceland", code: "IS", name_en: "Iceland" }, + { name: "Indonesia", code: "ID", name_en: "Indonesia" }, + { name: "Iraq", code: "IQ", name_en: "Iraq" }, + { name: "Ireland", code: "IE", name_en: "Ireland" }, + { name: "Israel", code: "IL", name_en: "Israel" }, + { name: "Jamaica", code: "JM", name_en: "Jamaica" }, + { name: "Jordan", code: "JO", name_en: "Jordan" }, + { name: "Kazakhstan", code: "KZ", name_en: "Kazakhstan" }, + { name: "Kenya", code: "KE", name_en: "Kenya" }, + { name: "Kuwait", code: "KW", name_en: "Kuwait" }, + { name: "Lào", code: "LA", name_en: "Laos" }, + { name: "Latvia", code: "LV", name_en: "Latvia" }, + { name: "Lebanon", code: "LB", name_en: "Lebanon" }, + { name: "Libya", code: "LY", name_en: "Libya" }, + { name: "Liechtenstein", code: "LI", name_en: "Liechtenstein" }, + { name: "Lithuania", code: "LT", name_en: "Lithuania" }, + { name: "Luxembourg", code: "LU", name_en: "Luxembourg" }, + { name: "Ma-rốc", code: "MA", name_en: "Morocco" }, + { name: "Malaysia", code: "MY", name_en: "Malaysia" }, + { name: "Malta", code: "MT", name_en: "Malta" }, + { name: "Mexico", code: "MX", name_en: "Mexico" }, + { name: "Moldova", code: "MD", name_en: "Moldova" }, + { name: "Montenegro", code: "ME", name_en: "Montenegro" }, + { name: "Na Uy", code: "NO", name_en: "Norway" }, + { name: "Nam Phi", code: "ZA", name_en: "South Africa" }, + { name: "Nepal", code: "NP", name_en: "Nepal" }, + { name: "New Zealand", code: "NZ", name_en: "New Zealand" }, + { name: "Nga", code: "RU", name_en: "Russia" }, + { name: "Nhật Bản", code: "JP", name_en: "Japan" }, + { name: "Nicaragua", code: "NI", name_en: "Nicaragua" }, + { name: "Nigeria", code: "NG", name_en: "Nigeria" }, + { name: "Oman", code: "OM", name_en: "Oman" }, + { name: "Pakistan", code: "PK", name_en: "Pakistan" }, + { name: "Panama", code: "PA", name_en: "Panama" }, + { name: "Papua New Guinea", code: "PG", name_en: "Papua New Guinea" }, + { name: "Paraguay", code: "PY", name_en: "Paraguay" }, + { name: "Peru", code: "PE", name_en: "Peru" }, + { name: "Pháp", code: "FR", name_en: "France" }, + { name: "Phần Lan", code: "FI", name_en: "Finland" }, + { name: "Philipin", code: "PH", name_en: "Philippines" }, + { name: "Puerto Rico", code: "PR", name_en: "Puerto Rico" }, + { name: "Qatar", code: "QA", name_en: "Qatar" }, + { name: "Rumani", code: "RO", name_en: "Romania" }, + { name: "Séc", code: "CZ", name_en: "Czech Republic" }, + { name: "Senegal", code: "SN", name_en: "Senegal" }, + { name: "Serbia", code: "RS", name_en: "Serbia" }, + { name: "Singapore", code: "SG", name_en: "Singapore" }, + { name: "Slovakia", code: "SK", name_en: "Slovakia" }, + { name: "Slovenia", code: "SI", name_en: "Slovenia" }, + { name: "Sri Lanka", code: "LK", name_en: "Sri Lanka" }, + { name: "Tanzania", code: "TZ", name_en: "Tanzania" }, + { name: "Tây Ban Nha", code: "ES", name_en: "Spain" }, + { name: "Thái Lan", code: "TH", name_en: "Thailand" }, + { name: "Thổ Nhĩ Kỳ", code: "TR", name_en: "Turkey" }, + { name: "Thuỵ Điển", code: "SE", name_en: "Sweden" }, + { name: "Thuỵ Sĩ", code: "CH", name_en: "Switzerland" }, + { name: "Tunisia", code: "TN", name_en: "Tunisia" }, + { name: "Úc", code: "AU", name_en: "Australia" }, + { name: "Uganda", code: "UG", name_en: "Uganda" }, + { name: "Ukraina", code: "UA", name_en: "Ukraine" }, + { name: "Uruguay", code: "UY", name_en: "Uruguay" }, + { name: "Venezuela", code: "VE", name_en: "Venezuela" }, + { name: "Việt Nam", code: "VN", name_en: "Vietnam" }, + { name: "Vương quốc Anh", code: "GB", name_en: "United Kingdom" }, + { name: "Ý", code: "IT", name_en: "Italy" }, + { name: "Yemen", code: "YE", name_en: "Yemen" }, + { name: "Zimbabwe", code: "ZW", name_en: "Zimbabwe" }, +]; diff --git a/scripts/youtube_downloadVideo.css b/scripts/youtube_downloadVideo.css new file mode 100644 index 00000000..3ae13c73 --- /dev/null +++ b/scripts/youtube_downloadVideo.css @@ -0,0 +1,35 @@ +.ufs-ytDownloadVideo__btn { + color: #f1f1f1; + display: inline-block; + padding: 2px 12px; + border-radius: 6px; + text-decoration: none; + font-weight: bold; + width: 100%; + text-align: left; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); + -webkit-tap-highlight-color: transparent; +} + +.ufs-ytDownloadVideo__btn:hover { + background-color: #333; +} + +.ufs-ytDownloadVideo__dropdown { + background-color: #272727; + z-index: 999; + position: absolute; + top: 45px; + left: 0; + + display: none; + flex-flow: column; + justify-content: start; + align-items: start; + + overflow: hidden auto; + width: max-content; + max-height: 250px; + padding: 8px; + border-radius: 12px; +} diff --git a/scripts/youtube_downloadVideo.js b/scripts/youtube_downloadVideo.js index bbda9be4..3ee23217 100644 --- a/scripts/youtube_downloadVideo.js +++ b/scripts/youtube_downloadVideo.js @@ -1,3 +1,4 @@ +import { UfsGlobal } from "./content-scripts/ufs_global.js"; import { BADGES } from "./helpers/badge.js"; export default { @@ -7,68 +8,35 @@ export default { vi: "Tải video/audio youtube", }, description: { - en: "Bypass age restriction, without login", - vi: "Tải cả video giới hạn độ tuổi, không cần đăng nhập", + en: `Bypass age restriction, without login +
    +
  • Click once to download current video
  • +
  • Enable autorun to render download button
  • +
`, + vi: `Tải cả video giới hạn độ tuổi, không cần đăng nhập +
    +
  • Bấm 1 lần để tải video hiện tại
  • +
  • Bật tự chạy để hiển thị nút tải
  • +
`, + img: "/scripts/youtube_downloadVideo.png", }, - badges: [BADGES.hot], + badges: [BADGES.new], + + whiteList: ["https://*.youtube.com/*"], contentScript: { onClick: function () { - // https://stackoverflow.com/a/8260383/11898496 - function getIdFromYoutubeURL(url) { - let regExp = - /.*(?:youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=)([^#\&\?]*).*/; - let match = url.match(regExp); - return match && match[1].length == 11 ? match[1] : false; - } - - let options = [ - { - name: "y2mate.com", - func: (url) => url.replace("youtube.com", "youtubepp.com"), - }, - { - name: "yt1s.com", - func: (url) => "https://yt1s.com/vi/youtube-to-mp4?q=" + url, - }, - { - name: "yt5s.com", - func: (url) => url.replace("youtube.com", "youtube5s.com"), - }, - { - name: "tubemp3.to", - func: (url) => "https://tubemp3.to/" + url, - }, - { - name: "10downloader.com", - func: (url) => "https://10downloader.com/download?v=" + url, - }, - { - name: "9xbuddy.com", - func: (url) => "https://9xbuddy.com/process?url=" + url, - }, - { - name: "getlinks.vip", - func: (url) => - "https://getlinks.vip/vi/youtube/" + getIdFromYoutubeURL(url), - }, - { - name: "ymp4.com", - func: (url) => "https://ymp4.download/en50/?url=" + url, - }, - ]; - let choose = prompt( "Tải video youtube: \n\n" + - options.map((_, i) => `${i}: ${_.name}`).join("\n") + + providers.map((_, i) => `${i}: ${_.name}`).join("\n") + "\n\nNhập lựa chọn:", 0 ); - if (choose != null && choose >= 0 && choose < options.length) { + if (choose != null && choose >= 0 && choose < providers.length) { let url = prompt("Nhập link youtube:", location.href); if (url) { - url = options[choose].func(url); + url = providers[choose].func(url); let myWin = window.open( url, "Download Youtube Video", @@ -77,5 +45,140 @@ export default { } } }, + + onDocumentIdle: () => { + const downloadIcon = ` + + + `; + + injectCss(); + + let intervalId = setInterval(function () { + const container = document.querySelector("#above-the-fold #title > h1"); + if (!container) return; + + clearInterval(intervalId); + + document.addEventListener("click", (e) => { + const el = document.querySelector("#ufs-ytDownloadBtn__dropdown"); + if (e.target !== el || (el && el.style.display === "flex")) + el.style.display = "none"; + }); + + const links = providers.map( + (provider) => /* html */ ` + + ${provider.name} + ` + ); + + const div = document.createElement("div"); + div.id = "ufs-ytDownloadBtn__container"; + div.innerHTML = /* html */ ` + `; + + const button = div.querySelector("button"); + button.addEventListener("click", (e) => { + e.stopPropagation(); + const el = document.querySelector("#ufs-ytDownloadBtn__dropdown"); + if (!el) return; + el.style.display = el.style.display == "flex" ? "none" : "flex"; + }); + + const options = div.querySelectorAll("a"); + options.forEach((option) => { + option.addEventListener("click", (e) => { + e.stopPropagation(); + const providerName = option.getAttribute("data-provider"); + const provider = providers.find((p) => p.name === providerName); + if (!provider) return; + const url = provider.func(window.location.href); + window.open(url, "_blank"); + }); + }); + + container.insertAdjacentElement("afterend", div); + }, 500); + }, }, }; + +// https://stackoverflow.com/a/8260383/11898496 +export function getIdFromYoutubeURL(url) { + const regExp = /.*(?:youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=)([^#\&\?]*).*/; + const match = url.match(regExp); + return match && match[1].length == 11 ? match[1] : false; +} + +const providers = [ + { + name: "y2mate.com", + func: (url) => url.replace("youtube", "youtubepp"), + }, + { + name: "yt5s.com", + func: (url) => url.replace("youtube", "youtube5s"), + }, + { + name: "yt1s.com", + func: (url) => "https://yt1s.com/vi/youtube-to-mp4?q=" + url, + }, + { + name: "tubemp3.to", + func: (url) => "https://tubemp3.to/" + url, + }, + { + name: "10downloader.com", + func: (url) => "https://10downloader.com/download?v=" + url, + }, + { + name: "9xbuddy.com", + func: (url) => "https://9xbuddy.com/process?url=" + url, + }, + { + name: "ymp4.com", + func: (url) => "https://ymp4.download/?url=" + url, + }, + { + name: "savefrom.net", + func: (url) => url.replace("youtube", "ssyoutube"), + }, + { + name: "10downloader.com", + func: (url) => url.replace("youtube", "000tube"), + }, + { + name: "getlinks.vip", + func: (url) => + "https://getlinks.vip/vi/youtube/" + getIdFromYoutubeURL(url), + }, +]; + +function injectCss( + path = "/scripts/youtube_downloadVideo.css", + id = "ufs-yt_downloadVideo-css" +) { + if (!document.querySelector("#" + id)) { + UfsGlobal.Extension.getURL(path).then((url) => { + UfsGlobal.DOM.injectCssFile(url, id); + }); + } +} diff --git a/scripts/youtube_downloadVideo.png b/scripts/youtube_downloadVideo.png new file mode 100644 index 00000000..b8d34a8e Binary files /dev/null and b/scripts/youtube_downloadVideo.png differ diff --git a/scripts/youtube_getVideoCaption.js b/scripts/youtube_getVideoCaption.js new file mode 100644 index 00000000..cac5d971 --- /dev/null +++ b/scripts/youtube_getVideoCaption.js @@ -0,0 +1,225 @@ +import { UfsGlobal } from "./content-scripts/ufs_global.js"; +import { runScriptInCurrentTab } from "./helpers/utils.js"; +import { BADGES } from "./helpers/badge.js"; + +export default { + icon: '', + name: { + en: "Get Youtube video's captions", + vi: "Lấy phụ đề video trên Youtube", + }, + description: { + en: "- Click to get all captions of playing youtube video
- Enable autorun to show realtime captions (transcript)", + vi: "- Bấm để tải về tất cả phụ đề của video youtube đang xem
- Bật tự chạy để hiển thị phụ đề thời gian thực", + img: "/scripts/youtube_getVideoCaption.png", + }, + badges: [BADGES.new], + changeLogs: { + "2024-07-04": "init", + }, + + whiteList: ["https://*.youtube.com/*"], + + popupScript: { + onEnable: () => { + runScriptInCurrentTab(showTranscript, [true]); + }, + onDisable: () => { + runScriptInCurrentTab(showTranscript, [false]); + }, + }, + + pageScript: { + onDocumentEnd: () => { + setInterval(() => { + showTranscript(true); + }, 1000); + }, + onClick: async () => { + const { parseXml } = await import("./libs/utils/xmlParser.js"); + + function renderCaptions(captions, title) { + const id = "ufs_youtube_getVideoCaption"; + const exist = document.getElementById(id); + if (exist) exist.remove(); + + const div = document.createElement("div"); + div.id = id; + div.innerHTML = /*html*/ ` + +
+

Useful-scripts: Youtube captions


+

${title}


+
    + ${captions + .map( + (caption) => `
  • + ${caption.name.simpleText} (${caption.languageCode}) + srt + txt + xml +
  • ` + ) + .join("")} +
+
+ Auto translate +
+ `; + div.onclick = async (e) => { + if (e.target == div) div.remove(); + if (e.target.tagName == "A") { + const type = e.target.getAttribute("data-type"); + if (type) { + e.preventDefault(); + downloadCaption(e.target.getAttribute("href"), type, title); + } + } + }; + document.documentElement.appendChild(div); + } + + async function downloadCaption(url, type, title) { + try { + const res = await fetch(url, { + headers: { + contentType: "text/xml", + }, + }); + const text = await res.text(); + const xml = parseXml(text); + + const transcript = xml.getElementsByTagName("transcript")[0]; + const texts = Array.from(transcript.getElementsByTagName("text")); + + if (type === "txt") { + const data = texts + .map((t) => decodeHtmlEntities(t.textContent)) + .join("\n"); + UfsGlobal.Utils.downloadData(data, title + ".txt"); + } else if (type === "srt") { + const data = texts + .map((t, i) => { + // 1 + // 00:00:00,120 --> 00:00:01,880 + // mùa tuyển sinh sắp đến rồi nên là hôm + let index = i + 1; + let start = Number(t.getAttribute("start")); + let dur = Number(t.getAttribute("dur")); + let end = start + dur; + return ( + index + + "\n" + + formatTimeToSRT(start) + + " --> " + + formatTimeToSRT(end) + + "\n" + + decodeHtmlEntities(t.textContent) + ); + }) + .join("\n\n"); + UfsGlobal.Utils.downloadData(data, title + ".srt"); + } + } catch (e) { + alert(e); + console.error(e); + } + } + + const pad = (num, len = 2) => num.toString().padStart(len, "0"); + + // 6.120 -> 00:00:06,120 + function formatTimeToSRT(seconds) { + // Get hours, minutes, and seconds + const hours = Math.floor(seconds / 3600); + const minutes = Math.floor((seconds % 3600) / 60); + const secs = Math.floor(seconds % 60); + const milliseconds = Math.floor((seconds % 1) * 1000); + // Format the time string + return `${pad(hours)}:${pad(minutes)}:${pad(secs)},${pad( + milliseconds, + 3 + )}`; + } + + var textArea = document.createElement("textarea"); + function decodeHtmlEntities(text) { + textArea.innerHTML = text; + return textArea.innerHTML; + } + + const methods = [ + () => document.getElementsByTagName("ytd-app")[0].data.playerResponse, + () => ytplayer.config.args.raw_player_response, + ]; + + for (let f of methods) { + try { + let p = f(); + let captions = + p.captions.playerCaptionsTracklistRenderer.captionTracks; + let title = p.videoDetails?.title || document.title; + + if (captions) { + renderCaptions(captions, title); + return; + } + } catch (e) { + console.error(e); + } + } + + alert("No captions found"); + }, + }, +}; + +function showTranscript(show) { + if (show) { + document + .querySelector("*[target-id*=transcript]") + ?.removeAttribute("visibility"); + } else { + document + .querySelector("*[target-id*=transcript] #visibility-button button") + ?.click(); + } +} diff --git a/scripts/youtube_getVideoCaption.png b/scripts/youtube_getVideoCaption.png new file mode 100644 index 00000000..6b0c840c Binary files /dev/null and b/scripts/youtube_getVideoCaption.png differ diff --git a/scripts/youtube_getVideoThumbnail.js b/scripts/youtube_getVideoThumbnail.js new file mode 100644 index 00000000..65b63df6 --- /dev/null +++ b/scripts/youtube_getVideoThumbnail.js @@ -0,0 +1,53 @@ +import { BADGES } from "./helpers/badge.js"; +import { getIdFromYoutubeURL } from "./youtube_downloadVideo.js"; + +export default { + icon: '', + name: { + en: "Get Youtube video's thumbnail", + vi: "Lấy thumbnail video trên Youtube", + }, + description: { + en: "Get largest thumbnail of playing youtube video", + vi: "Tải về hình thumbnail độ phân giải lớn nhất của video youtube đang xem", + }, + badges: [BADGES.new], + changeLogs: { + "2024-07-04": "init", + }, + + whiteList: ["https://*.youtube.com/*"], + + pageScript: { + onClick: () => { + const methods = [ + () => + document + .getElementsByTagName("ytd-app")[0] + .data.playerResponse.videoDetails.thumbnail.thumbnails.sort( + (a, b) => b.width * b.height - a.width * a.height + )[0].url, + () => + ytplayer.config.args.raw_player_response.videoDetails.thumbnail.thumbnails.sort( + (a, b) => b.width * b.height - a.width * a.height + )[0].url, + () => + `https://i.ytimg.com/vi/${getIdFromYoutubeURL( + location.href + )}/maxresdefault.jpg`, + ]; + + for (let f of methods) { + try { + let url = f(); + if (url) { + window.open(url, "_blank"); + return; + } + } catch (e) { + console.error(e); + } + } + }, + }, +}; diff --git a/scripts/youtube_localDownloader.html b/scripts/youtube_localDownloader.html deleted file mode 100644 index 01691e77..00000000 --- a/scripts/youtube_localDownloader.html +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - Useful Script - YouTube Local Downloader - - - - - - - - - diff --git a/scripts/youtube_localDownloader.js b/scripts/youtube_localDownloader.js deleted file mode 100644 index eeef4ab3..00000000 --- a/scripts/youtube_localDownloader.js +++ /dev/null @@ -1,35 +0,0 @@ -export default { - icon: "https://www.youtube.com/s/desktop/accca349/img/favicon_48x48.png", - name: { - en: "Youtube local downloader", - vi: "Youtube tải video local", - }, - description: { - en: "", - vi: "", - }, - - whiteList: ["https://*youtube.com/*"], - - popupScript: { - onClick: async () => { - const { runScriptInCurrentTab } = await import("./helpers/utils.js"); - - const yt_data = await runScriptInCurrentTab(() => { - return document.getElementsByTagName("ytd-app")[0].data.playerResponse; - }); - - if (!yt_data) { - alert("Không tìm thấy video data"); - return; - } - - localStorage.setItem( - "ufs_youtube_localDownloader", - JSON.stringify(yt_data) - ); - - window.open("/scripts/youtube_localDownloader.html"); - }, - }, -}; diff --git a/scripts/youtube_localDownloader_main.js b/scripts/youtube_localDownloader_main.js deleted file mode 100644 index a00337d8..00000000 --- a/scripts/youtube_localDownloader_main.js +++ /dev/null @@ -1,132 +0,0 @@ -import { UfsGlobal } from "./content-scripts/ufs_global.js"; - -const { formatSize, promiseAllStepN } = UfsGlobal.Utils; -const { injectScriptSrc } = UfsGlobal.DOM; - -const xhrDownloadUint8Array = async ({ url, contentLength }, progressCb) => { - if (typeof contentLength === "string") - contentLength = parseInt(contentLength); - progressCb({ - loaded: 0, - total: contentLength, - speed: 0, - }); - const chunkSize = 65536; - const getBuffer = (start, end) => - fetch(url + `&range=${start}-${end ? end - 1 : ""}`).then((r) => - r.arrayBuffer() - ); - const data = new Uint8Array(contentLength); - let downloaded = 0; - const tasks = []; - const startTime = Date.now(); - - for (let start = 0; start < contentLength; start += chunkSize) { - const exceeded = start + chunkSize > contentLength; - const curChunkSize = exceeded ? contentLength - start : chunkSize; - const end = exceeded ? null : start + chunkSize; - tasks.push(() => { - console.log("dl start", url, start, end); - return getBuffer(start, end) - .then((buf) => { - console.log("dl done", url, start, end); - downloaded += curChunkSize; - data.set(new Uint8Array(buf), start); - const ds = (Date.now() - startTime + 1) / 1000; - progressCb({ - loaded: downloaded, - total: contentLength, - speed: downloaded / ds, - }); - }) - .catch((err) => { - console.log("Download error"); - }); - }); - } - await promiseAllStepN(6, tasks); - return data; -}; - -window.onload = () => { - const yt_data = JSON.parse( - localStorage.getItem("ufs_youtube_localDownloader") ?? "{}" - ); - - console.log(yt_data); - - const streamingData = [ - ...(yt_data.streamingData?.formats || []), - ...(yt_data.streamingData?.adaptiveFormats || []), - ].filter((_) => _.url); - - const videoDetails = yt_data.videoDetails; - const videos = streamingData.filter((d) => d.mimeType.includes("video")); - const audios = streamingData.filter((d) => d.mimeType.includes("audio")); - const captions = - yt_data.captions?.playerCaptionsTracklistRenderer?.captionTracks || []; - - console.log(captions); - - // video details - const detailDiv = document.createElement("div"); - const thumbs = videoDetails.thumbnail?.thumbnails || []; - const lastThumbnail = thumbs[thumbs.length - 1]; - - detailDiv.innerHTML = ` - -

${videoDetails.title}

-

${videoDetails.author}

-

${videoDetails.shortDescription}

`; - document.body.appendChild(detailDiv); - - // video - for (let video of videos) { - const button = document.createElement("button"); - button.style = "display:block;margin-bottom:5px"; - button.innerHTML = ` - ${video.qualityLabel} - - ${video.width}x${video.height} - - ${formatSize(video.contentLength, 2)} - ${video.audioQuality ? "" : " (no audio)"}`; - button.onclick = () => { - let data = xhrDownloadUint8Array(video, (progress) => { - console.log(progress); - }); - // saveAs(video.url, "video.mp4", { - // onprogress: (e) => { - // console.log(e); - // }, - // }); - }; - document.body.appendChild(button); - } - - // audio - for (let audio of audios) { - const div = document.createElement("div"); - div.innerHTML = ` - -

- ${audio.audioTrack?.displayName || audio.audioQuality} - - ${formatSize(audio.contentLength, 2)} -

- `; - document.body.appendChild(div); - } - - // caption - for (let caption of captions) { - const div = document.createElement("div"); - div.innerHTML = ` -

${caption.name?.simpleText}

- - Download - - `; - document.body.appendChild(div); - } -}; diff --git a/scripts/youtube_nonstop.js b/scripts/youtube_nonstop.js index a186c083..3a4a683b 100644 --- a/scripts/youtube_nonstop.js +++ b/scripts/youtube_nonstop.js @@ -1,5 +1,5 @@ export default { - icon: "https://lh3.googleusercontent.com/OS9P4SJOFAg8lhCyaRTJ7y4ADF0TGpqFF904BcpCtdBjJIDBbNb_J8PpgoJ9QvariiG_RzgH8fCSSY_kQu-chQQ0Aw=s0", + icon: '', name: { en: "Youtube nonstop", vi: "Youtube nonstop", diff --git a/scripts/youtube_toggleLight.js b/scripts/youtube_toggleLight.js index d3e6185b..7cde55ed 100644 --- a/scripts/youtube_toggleLight.js +++ b/scripts/youtube_toggleLight.js @@ -1,5 +1,5 @@ export default { - icon: "https://lh3.googleusercontent.com/Apmrldj2Vnje0MIEvqYslaGRjDj2R3u72YboNiUHJ8sSORBmLCYJNJ50FTCFhXrCuXs3e6vaCTJqOKeq-I3AMkIFLw=w128-h128-e365-rj-sc0x00ffffff", + icon: '', name: { en: "Toggle light youtube", vi: "Tắt/Mở đèn youtube", diff --git a/scripts/youtube_viewDislikes.js b/scripts/youtube_viewDislikes.js index 21d9cb62..38696d7b 100644 --- a/scripts/youtube_viewDislikes.js +++ b/scripts/youtube_viewDislikes.js @@ -2,7 +2,7 @@ import { UfsGlobal } from "./content-scripts/ufs_global.js"; import { BADGES } from "./helpers/badge.js"; export default { - icon: "https://lh3.googleusercontent.com/X0-M21C_VbWyXYuUjN55oyMDvOukjbzAxbs_WrUjwzsebWbyjFCIEchOtczI0DBvbyL9MUpuEWnghm19gF6dp8Vriw=w128-h128-e365-rj-sc0x00ffffff", + icon: '', name: { en: "Return youtube dislike", vi: "Hiện lượt không thích youtube", diff --git a/working_note.md b/working_note.md index 98439369..3a4891ac 100644 --- a/working_note.md +++ b/working_note.md @@ -1,9 +1,31 @@ # WORKING NOTES -## 30/05/2024 - 01/07/2024 +## 01/07/2024 - ? + +- [ ] take a look at + +- [ ] ffmpeg in browser + +- [ ] youtube reverse api??? + +- [x] add this beautiful video downloader tool + +- [ ] savefile using new api + +- [x] hotfix - use chrome.downloads instead of library => can not apply to all scripts + +- [x] get fb profile pic -> dont know now cuid was generated + +- [x] find fb account using phone or email -> too hard, fb not always show user's avatar/name + +- [ ] analyze this + +- [ ] check down video - [ ] analyze this +## 30/05/2024 - 01/07/2024 + - [x] check linux compatible -> relative path in manifest + file name camelcase - [x] modify responseText xhr => hard