├── .github
└── FUNDING.yml
├── .gitignore
├── LICENSE
├── README-en.md
├── README.md
├── assets
├── context.png
├── icon128.png
├── icon16.png
├── icon32.png
└── screenshots
│ ├── Screen Shot 2022-11-02 at 12.22.18.png
│ ├── Screen Shot 2022-11-05 at 12.10.00.png
│ ├── Screen Shot 2022-11-27 at 22.05.00.png
│ ├── Screen Shot 2022-12-25 at 20.00.00.png
│ ├── Screen Shot 2024-05-29_dark.png
│ ├── Screen Shot 2024-05-29_light.png
│ └── Screenshot_3.png
├── config.js
├── index.html
├── manifest.json
├── md
├── CHANGELOGS.md
├── CONTRIBUTE.md
├── exportScriptsToMd.js
├── facebook-post-hay.md
└── flow.pu
├── pages
└── viewScriptSource
│ ├── fonts
│ ├── JetBrainsMono-Bold.woff2
│ └── JetBrainsMono-Regular.woff2
│ ├── index.html
│ ├── libs
│ ├── highlight.min.js
│ ├── highlight_linenum.js
│ ├── javascript.min.js
│ └── styles
│ │ ├── atom-one-dark-reasonable.min.css
│ │ ├── atom-one-dark.min.css
│ │ ├── default.min.css
│ │ └── monokai-sublime.min.css
│ ├── main.js
│ └── style.css
├── popup
├── assets
│ ├── flag-en.png
│ └── flag-vi.png
├── helpers
│ ├── category.js
│ ├── checkForUpdate.js
│ ├── lang.js
│ ├── modal.js
│ ├── storage.js
│ ├── storageScripts.js
│ ├── theme.js
│ └── utils.js
├── index.js
├── libs
│ ├── less.js
│ ├── swal2.dark.css
│ └── swal2.min.js
├── main.js
├── popup.html
├── recommend.js
├── styles
│ ├── scrollbar.css
│ └── tooltip.less
├── tabs.js
└── themes
│ ├── default.less
│ ├── default_dark.less
│ └── xtri98.less
├── scripts
├── @allScripts.js
├── @index.js
├── archiveToday.js
├── auto_lockWebsite.css
├── auto_lockWebsite.html
├── auto_lockWebsite.js
├── auto_lockWebsite_main.js
├── auto_redirectLargestImageSrc.jpg
├── auto_redirectLargestImageSrc.js
├── auto_redirectLargestImageSrc_rules.js
├── background-scripts
│ └── background_script.js
├── backup
│ ├── bao-reaction.php
│ ├── code-f12-toolkit.js
│ ├── copy-ggdrive-folders.py
│ ├── fb-graphql.js
│ ├── fb-proxy.js
│ ├── fb-save-exporter.js
│ ├── fb_blockSeen_blockTyping.js
│ ├── find-friend-comments-in-page.js
│ ├── m38u_detector.js
│ ├── openfbchat.js
│ ├── remove-unavai-friends.js
│ ├── remove-unavai-friends_decoded.js
│ ├── remove-unavailable-member.js
│ ├── scripts.js
│ ├── tts.html
│ └── unfriend-nguoi-la.js
├── bookmark_exporter.js
├── bypass_LearnAnything.png
├── bypass_learnAnything.js
├── changeAudioOutput.js
├── checkWebDie.js
├── chongLuaDao.js
├── content-scripts
│ ├── backup.js
│ ├── content_script.js
│ └── ufs_global.js
├── createInvisibleText.html
├── createInvisibleText.js
├── createInvisibleText_main.js
├── cssSelectorViewer.js
├── darkModePDF.js
├── detect_zeroWidthCharacters.css
├── detect_zeroWidthCharacters.js
├── dino_hack.js
├── douyin_batchDownload.js
├── douyin_batchDownload.png
├── douyin_downloadAllVideoUser.js
├── douyin_downloadWachingVideo.js
├── downDetector.js
├── download_watchingVideo.js
├── duckRace_cheat.js
├── duckRage_cheat.png
├── fb_GLOBAL.js
├── fb_aio.png
├── fb_allInOne.js
├── fb_autoLike.js
├── fb_autoRemoveSpamPostGroup.css
├── fb_autoRemoveSpamPostGroup.html
├── fb_autoRemoveSpamPostGroup.js
├── fb_autoRemoveSpamPostGroup.png
├── fb_autoRemoveSpamPostGroup_main.js
├── fb_blockSeenAndTyping.js
├── fb_blockSeenStory.js
├── fb_checkToken.js
├── fb_downloadWatchingVideo.js
├── fb_exportSaved.js
├── fb_getAlbumId.js
├── fb_getAllAlbumIdFromCurrentWebsite.js
├── fb_getAllAlbumInformation.js
├── fb_getAllUidFromFbSearch.js
├── fb_getAllUidOfGroupMembers.js
├── fb_getAvatarFromUid.js
├── fb_getGroupId.js
├── fb_getPageId.js
├── fb_getPostReactionCount.jpg
├── fb_getPostReactionCount.js
├── fb_getTokenBussinessLocation.js
├── fb_getTokenCampaigns.js
├── fb_getTokenFacebook.js
├── fb_getTokenFfb.js
├── fb_getTokenMessage.js
├── fb_getUid.js
├── fb_getUidFromUrl.js
├── fb_moreReactionStory.css
├── fb_moreReactionStory.js
├── fb_moreReactionStory.png
├── fb_moreReactionStory_emoji.js
├── fb_revealDeletedMessages.js
├── fb_searchGroupForOther.html
├── fb_searchGroupForOther.js
├── fb_searchGroupForOther_main.js
├── fb_searchPageForOther.html
├── fb_searchPageForOther.js
├── fb_searchPageForOther_main.js
├── fb_searchPostsForOther.js
├── fb_stopNewFeed.js
├── fb_storySaver.js
├── fb_toggleLight.js
├── fb_toggleNewFeed.js
├── fb_videoDownloader.js
├── fb_whoIsTyping.css
├── fb_whoIsTyping.js
├── fireship_vip.js
├── getAllEmailsInWeb.js
├── getFavicon.js
├── getWindowSize.js
├── ggDrive_downloadAllVideosInFolder.js
├── ggdrive_copySheetText.js
├── ggdrive_downloadDoc.js
├── ggdrive_downloadPdf.js
├── ggdrive_downloadPresentation.js
├── ggdrive_downloadVideo.js
├── ggdrive_generateDirectLink.js
├── github1s.js
├── github_HTMLPreview.js
├── github_goToAnyCommit.js
├── github_openRepoPages.js
├── githubdev.js
├── googleCache.js
├── googleShortcuts.js
├── google_downloadAllYourData.js
├── google_mirror.js
├── guland_VIP.js
├── guland_VIP.png
├── helpers
│ ├── badge.js
│ ├── constants.js
│ ├── predefined_css.js
│ └── utils.js
├── injectScriptToWebsite.js
├── insta_GLOBAL.js
├── insta_anonymousStoryViewer.js
├── insta_getAllUserMedia.js
├── insta_getFollowForOther.js
├── insta_getUserInfo.js
├── insta_injectDownloadBtn.js
├── insta_injectDownloadBtn.png
├── internalOrExternalLink.js
├── internet_archive.png
├── letItSnow.js
├── letItSnow.png
├── libs
│ ├── ajax-hook
│ │ └── index.js
│ ├── canvas-toBlob
│ │ └── index.js
│ ├── crypto
│ │ └── md5.js
│ ├── file-saver
│ │ └── index.js
│ ├── js-hook
│ │ └── index.js
│ ├── jzip
│ │ └── index.js
│ ├── mqtt-packet
│ │ ├── README.md
│ │ └── index.js
│ ├── qrcode
│ │ └── index.js
│ ├── simple-datatables
│ │ ├── index.js
│ │ └── style.css
│ ├── utils
│ │ ├── attrObserver.js
│ │ ├── device.js
│ │ ├── dom.js
│ │ ├── fakeUA.js
│ │ ├── hackAttachShadow.js
│ │ ├── hackEventListener.js
│ │ ├── html.js
│ │ ├── iframe.js
│ │ ├── mouseObserver.js
│ │ ├── object.js
│ │ ├── original.js
│ │ ├── ready.js
│ │ ├── typeof.js
│ │ ├── url.js
│ │ ├── videoCapture.js
│ │ └── xmlParser.js
│ ├── vue
│ │ └── index.js
│ ├── workerize
│ │ └── index.js
│ └── xml-json
│ │ ├── json2xml.js
│ │ └── xml2json.js
├── listAllImagesInWeb.js
├── magnify_image.css
├── magnify_image.js
├── medium_fixVietnameseFont.css
├── medium_fixVietnameseFont.js
├── medium_readFullArticle.js
├── net-request-rules
│ ├── README.md
│ ├── dynamicRulesEditor
│ │ ├── index.html
│ │ └── index.js
│ └── rules.json
├── nhaccuatui_downloader.js
├── openWaybackUrl.js
├── passwordGenerator.js
├── performanceAnalyzer.js
├── pictureInPicture.js
├── pip_anything.js
├── pip_canvas.js
├── pip_fullWebsite.js
├── prevent_closeBrowser_lastTab.js
├── recommend_cloc.png
├── removeBloat.js
├── removeColours.js
├── removeCookies.js
├── removeImages.js
├── removeStylesheet.js
├── remove_tracking_in_url.js
├── remove_tracking_in_url_rules_simplified.js
├── saveAllVideo.js
├── savevideo_me.js
├── screenshotFullPage.js
├── screenshotVisiblePage.js
├── scribd_bypassPreview.css
├── scribd_bypassPreview.js
├── scribd_downloadDocuments.js
├── scrollToVeryEnd.js
├── search_googleSite.js
├── search_hopamchuan.js
├── search_paperWhere.js
├── search_sharedAccount.js
├── search_totalIndexedPages.js
├── send_shareFiles.js
├── shopee_topVariation.js
├── shopee_topVariation.png
├── shopee_totalSpendMoney.js
├── shopee_totalSpendMoney_excel.js
├── shortenURL.js
├── showFPS.js
├── showFps_v2.js
├── showHiddenFields.js
├── showImageOnHoverLink.js
├── showTheAudios.js
├── showTheVideos.js
├── similarWeb.js
├── similarWeb_bypassLimit.js
├── similarWeb_bypassLimit.png
├── simpleAllowCopy.js
├── smoothScroll.js
├── smoothscroll_cursor.png
├── soundcloud_downloadMusic.js
├── soundcloud_downloadMusic.png
├── spotify_downloadButton.js
├── spotify_downloadButton.png
├── studocu_bypassPreview.js
├── studocu_downs.js
├── studyphim_unlimited.js
├── table_addNumberColumn.js
├── table_addSortTable.js
├── table_swapRowAndColumn.js
├── tailieu_vn.js
├── test.js
├── textToQrCode.html
├── textToQrCode.js
├── textToQrCode_main.js
├── textToSpeech.js
├── tiki_totalSpendMoney.js
├── tiktok_GLOBAL.js
├── tiktok_batchDownload.css
├── tiktok_batchDownload.js
├── tiktok_batchDownload.png
├── tiktok_downloadVideo.js
├── tiktok_downloadWatchingVideo.js
├── toggleEditPage.js
├── toggle_passwordField.js
├── twitter_downloadButton.js
├── twitter_downloadButton.png
├── ufs_statistic.css
├── ufs_statistic.js
├── ufs_statistic_old.js
├── unshorten.js
├── viewAllLinks.js
├── viewCookies.js
├── viewScriptsUsed.js
├── viewStylesUsed.js
├── viewWebMetaInfo.js
├── vimeo_downloader.js
├── visualEvent.js
├── vuiz_createLogo.js
├── vuiz_getLink.js
├── webToPDF.js
├── web_timer.html
├── web_timer.js
├── web_timer.less
├── web_timer.png
├── web_timer_main.js
├── whatFont.js
├── whatWebsiteStack.js
├── wheelOfNames_hack.js
├── whois.js
├── youglish_search.js
├── youtube_changeCountry.js
├── youtube_downloadVideo.css
├── youtube_downloadVideo.js
├── youtube_downloadVideo.png
├── youtube_getVideoCaption.js
├── youtube_getVideoCaption.png
├── youtube_getVideoThumbnail.js
├── youtube_nonstop.js
├── youtube_nonstop.png
├── youtube_toggleLight.js
├── youtube_viewDislikes.js
└── zingmp3_downloadMusic.js
├── templates
├── full.js
└── simple.js
└── working_note.md
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | patreon: 99_hoangtran
4 | ko_fi: 99hoangtran
5 | buy_me_a_coffee: 99hoangtran
6 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | _metadata/*
2 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 Hoang Tran
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/assets/context.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Useful-Scripts-Extension/useful-script/3841517b641a602d6360cf9b43152bee2524bd7f/assets/context.png
--------------------------------------------------------------------------------
/assets/icon128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Useful-Scripts-Extension/useful-script/3841517b641a602d6360cf9b43152bee2524bd7f/assets/icon128.png
--------------------------------------------------------------------------------
/assets/icon16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Useful-Scripts-Extension/useful-script/3841517b641a602d6360cf9b43152bee2524bd7f/assets/icon16.png
--------------------------------------------------------------------------------
/assets/icon32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Useful-Scripts-Extension/useful-script/3841517b641a602d6360cf9b43152bee2524bd7f/assets/icon32.png
--------------------------------------------------------------------------------
/assets/screenshots/Screen Shot 2022-11-02 at 12.22.18.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Useful-Scripts-Extension/useful-script/3841517b641a602d6360cf9b43152bee2524bd7f/assets/screenshots/Screen Shot 2022-11-02 at 12.22.18.png
--------------------------------------------------------------------------------
/assets/screenshots/Screen Shot 2022-11-05 at 12.10.00.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Useful-Scripts-Extension/useful-script/3841517b641a602d6360cf9b43152bee2524bd7f/assets/screenshots/Screen Shot 2022-11-05 at 12.10.00.png
--------------------------------------------------------------------------------
/assets/screenshots/Screen Shot 2022-11-27 at 22.05.00.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Useful-Scripts-Extension/useful-script/3841517b641a602d6360cf9b43152bee2524bd7f/assets/screenshots/Screen Shot 2022-11-27 at 22.05.00.png
--------------------------------------------------------------------------------
/assets/screenshots/Screen Shot 2022-12-25 at 20.00.00.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Useful-Scripts-Extension/useful-script/3841517b641a602d6360cf9b43152bee2524bd7f/assets/screenshots/Screen Shot 2022-12-25 at 20.00.00.png
--------------------------------------------------------------------------------
/assets/screenshots/Screen Shot 2024-05-29_dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Useful-Scripts-Extension/useful-script/3841517b641a602d6360cf9b43152bee2524bd7f/assets/screenshots/Screen Shot 2024-05-29_dark.png
--------------------------------------------------------------------------------
/assets/screenshots/Screen Shot 2024-05-29_light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Useful-Scripts-Extension/useful-script/3841517b641a602d6360cf9b43152bee2524bd7f/assets/screenshots/Screen Shot 2024-05-29_light.png
--------------------------------------------------------------------------------
/assets/screenshots/Screenshot_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Useful-Scripts-Extension/useful-script/3841517b641a602d6360cf9b43152bee2524bd7f/assets/screenshots/Screenshot_3.png
--------------------------------------------------------------------------------
/config.js:
--------------------------------------------------------------------------------
1 | export default {
2 | version_check:
3 | "https://raw.githubusercontent.com/Useful-Scripts-Extension/useful-script/main/manifest.json",
4 | source_code: "https://github.com/Useful-Scripts-Extension/useful-script",
5 | store:
6 | "https://chrome.google.com/webstore/devconsole/ad27ff83-24b1-4348-810d-9cfdc30a5331/heoejcamgchindphgghdhmjpgmldnepl/edit/status",
7 | };
8 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Document
8 |
9 |
10 |
11 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/md/CONTRIBUTE.md:
--------------------------------------------------------------------------------
1 | # Useful script - Contribute
2 |
3 | ## Cấu trúc thư mục
4 |
5 | - [scripts/](/scripts/) : Chứa tất cả các scripts chức năng của extension.
6 | - [popup/](/popup/) : Chứa code giao diện, logic hiển thị giao diện của trang popup (khi click extension)
7 | - [pages/](/pages/) : Chứa các pages hỗ trợ *(Trang xem mã nguồn script, Trang cài đặt cho extension)*
8 | - [templates/](/templates/) : Chứa 2 file [simple.js](/templates/simple.js) và [full.js](/templates/full.js) là mẫu script được viết sẵn. Copy và sử dụng khi tạo script mới.
9 |
10 | ## Các cách contribute
11 |
12 | ### Cách 1: Thêm scripts của bạn
13 |
14 | Nếu bạn có 1 `script hay`, hoặc `bookmarklets hay`, muốn `thêm vào extension` để mọi người cùng sử dụng. Hãy làm theo các bước sau:
15 |
16 | 1. Tạo 1 file javascript mới trong folder [scripts/](/scripts/), với `tên file mô tả ngắn gọn` chức năng script của bạn.
17 |
18 | 2. Sao chép nội dung file [templates/simple.js](/templates/simple.js) và dán vào file vừa tạo.
19 |
20 | 3. Ghi nội dung script:
21 | - Đọc cấu trúc code và comment trong file [templates/full.js](/templates/full.js) để biết thêm chi tiết.
22 |
23 | 4. Import script của bạn trong file [/scripts/@index.js](/scripts/@index.js)
24 |
25 | 5. Ghi tên script của bạn trong biến `tabs` trong file [/popup/tabs.js](/popup/tabs.js)
26 |
27 | 6. Mở extension lên và dùng thử.
28 |
29 | ### Cách 2: Chỉnh sửa script có sẵn
30 |
31 | Nếu bạn thấy `script` nào trong danh sách hiện có `bị lỗi` hoặc `có thể nâng cấp`. và bạn muốn sửa nó, chỉ cần mở đúng `file tương ứng` của chức năng đó trong folder [scripts/](/scripts/) để chỉnh sửa.
32 |
33 | ### Cách 3: Cập nhập logic chính
34 |
35 | Nếu bạn có nhiều thời gian hơn để vọc code extension, và muốn `chỉnh sửa logic chính` của mình để `sửa lỗi` hoặc `nâng cấp`. Hãy cùng tìm hiểu nhé, cần giúp đỡ hãy chat hỏi mình.
36 |
37 | ### Cách 4: Dịch
38 |
39 | Bạn có thể giúp mình `dịch` các trang hướng dẫn này sang tiếng anh, hoặc bất kỳ ngôn ngữ mà bạn muốn.
40 |
41 | ## Liên hệ
42 |
43 | Gmail: <99.hoangtran@gmail.com>
44 |
45 | Facebook: [fb.com/99.hoangtran](https://fb.com/99.hoangtran)
46 |
--------------------------------------------------------------------------------
/md/exportScriptsToMd.js:
--------------------------------------------------------------------------------
1 | import { isTitle } from "../popup/helpers/utils.js";
2 | import { tabs } from "../popup/tabs.js";
3 |
4 | function generateMd(lang = "vi") {
5 | let index = 1;
6 | let md = tabs
7 | .map((tab) => {
8 | let title = tab.name[lang];
9 |
10 | let scripts = tab.scripts
11 | ?.map((script) => {
12 | if (isTitle(script)) {
13 | return "\n" + script.name[lang];
14 | }
15 |
16 | return `
17 | ${index++}. ${script.name[lang]}
18 |
19 | [${lang === "vi" ? "Xem mã nguồn" : "View source"}](/scripts/${script.id}.js)
20 |
21 | ${script.description[lang]}
22 |
23 | ${script.description.img ? `` : ""}
24 |
25 | `;
26 | })
27 | .join("\n");
28 |
29 | return `### ${title}\n${scripts}`;
30 | })
31 | .join("\n\n");
32 |
33 | console.log(md);
34 | }
35 |
36 | generateMd("vi");
37 | generateMd("en");
38 |
39 | export default null;
40 |
--------------------------------------------------------------------------------
/pages/viewScriptSource/fonts/JetBrainsMono-Bold.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Useful-Scripts-Extension/useful-script/3841517b641a602d6360cf9b43152bee2524bd7f/pages/viewScriptSource/fonts/JetBrainsMono-Bold.woff2
--------------------------------------------------------------------------------
/pages/viewScriptSource/fonts/JetBrainsMono-Regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Useful-Scripts-Extension/useful-script/3841517b641a602d6360cf9b43152bee2524bd7f/pages/viewScriptSource/fonts/JetBrainsMono-Regular.woff2
--------------------------------------------------------------------------------
/pages/viewScriptSource/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | viewsource://useful-scripts
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/pages/viewScriptSource/libs/styles/atom-one-dark-reasonable.min.css:
--------------------------------------------------------------------------------
1 | pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{color:#abb2bf;background:#282c34}.hljs-keyword,.hljs-operator,.hljs-pattern-match{color:#f92672}.hljs-function,.hljs-pattern-match .hljs-constructor{color:#61aeee}.hljs-function .hljs-params{color:#a6e22e}.hljs-function .hljs-params .hljs-typing{color:#fd971f}.hljs-module-access .hljs-module{color:#7e57c2}.hljs-constructor{color:#e2b93d}.hljs-constructor .hljs-string{color:#9ccc65}.hljs-comment,.hljs-quote{color:#b18eb1;font-style:italic}.hljs-doctag,.hljs-formula{color:#c678dd}.hljs-deletion,.hljs-name,.hljs-section,.hljs-selector-tag,.hljs-subst{color:#e06c75}.hljs-literal{color:#56b6c2}.hljs-addition,.hljs-attribute,.hljs-meta .hljs-string,.hljs-regexp,.hljs-string{color:#98c379}.hljs-built_in,.hljs-class .hljs-title,.hljs-title.class_{color:#e6c07b}.hljs-attr,.hljs-number,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-pseudo,.hljs-template-variable,.hljs-type,.hljs-variable{color:#d19a66}.hljs-bullet,.hljs-link,.hljs-meta,.hljs-selector-id,.hljs-symbol,.hljs-title{color:#61aeee}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}.hljs-link{text-decoration:underline}
--------------------------------------------------------------------------------
/pages/viewScriptSource/libs/styles/atom-one-dark.min.css:
--------------------------------------------------------------------------------
1 | pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{color:#abb2bf;background:#282c34}.hljs-comment,.hljs-quote{color:#5c6370;font-style:italic}.hljs-doctag,.hljs-formula,.hljs-keyword{color:#c678dd}.hljs-deletion,.hljs-name,.hljs-section,.hljs-selector-tag,.hljs-subst{color:#e06c75}.hljs-literal{color:#56b6c2}.hljs-addition,.hljs-attribute,.hljs-meta .hljs-string,.hljs-regexp,.hljs-string{color:#98c379}.hljs-attr,.hljs-number,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-pseudo,.hljs-template-variable,.hljs-type,.hljs-variable{color:#d19a66}.hljs-bullet,.hljs-link,.hljs-meta,.hljs-selector-id,.hljs-symbol,.hljs-title{color:#61aeee}.hljs-built_in,.hljs-class .hljs-title,.hljs-title.class_{color:#e6c07b}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}.hljs-link{text-decoration:underline}
--------------------------------------------------------------------------------
/pages/viewScriptSource/libs/styles/default.min.css:
--------------------------------------------------------------------------------
1 | /*!
2 | Theme: Default
3 | Description: Original highlight.js style
4 | Author: (c) Ivan Sagalaev
5 | Maintainer: @highlightjs/core-team
6 | Website: https://highlightjs.org/
7 | License: see project LICENSE
8 | Touched: 2021
9 | */pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{background:#f3f3f3;color:#444}.hljs-comment{color:#697070}.hljs-punctuation,.hljs-tag{color:#444a}.hljs-tag .hljs-attr,.hljs-tag .hljs-name{color:#444}.hljs-attribute,.hljs-doctag,.hljs-keyword,.hljs-meta .hljs-keyword,.hljs-name,.hljs-selector-tag{font-weight:700}.hljs-deletion,.hljs-number,.hljs-quote,.hljs-selector-class,.hljs-selector-id,.hljs-string,.hljs-template-tag,.hljs-type{color:#800}.hljs-section,.hljs-title{color:#800;font-weight:700}.hljs-link,.hljs-operator,.hljs-regexp,.hljs-selector-attr,.hljs-selector-pseudo,.hljs-symbol,.hljs-template-variable,.hljs-variable{color:#ab5656}.hljs-literal{color:#695}.hljs-addition,.hljs-built_in,.hljs-bullet,.hljs-code{color:#397300}.hljs-meta{color:#1f7199}.hljs-meta .hljs-string{color:#38a}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}
--------------------------------------------------------------------------------
/pages/viewScriptSource/libs/styles/monokai-sublime.min.css:
--------------------------------------------------------------------------------
1 | pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{background:#23241f;color:#f8f8f2}.hljs-subst,.hljs-tag{color:#f8f8f2}.hljs-emphasis,.hljs-strong{color:#a8a8a2}.hljs-bullet,.hljs-link,.hljs-literal,.hljs-number,.hljs-quote,.hljs-regexp{color:#ae81ff}.hljs-code,.hljs-section,.hljs-selector-class,.hljs-title{color:#a6e22e}.hljs-strong{font-weight:700}.hljs-emphasis{font-style:italic}.hljs-attr,.hljs-keyword,.hljs-name,.hljs-selector-tag{color:#f92672}.hljs-attribute,.hljs-symbol{color:#66d9ef}.hljs-class .hljs-title,.hljs-params,.hljs-title.class_{color:#f8f8f2}.hljs-addition,.hljs-built_in,.hljs-selector-attr,.hljs-selector-id,.hljs-selector-pseudo,.hljs-string,.hljs-template-variable,.hljs-type,.hljs-variable{color:#e6db74}.hljs-comment,.hljs-deletion,.hljs-meta{color:#75715e}
--------------------------------------------------------------------------------
/pages/viewScriptSource/main.js:
--------------------------------------------------------------------------------
1 | import { disableSmoothScrollSaver } from "../../popup/helpers/storage.js";
2 | import { enableSmoothScroll } from "../../scripts/smoothScroll.js";
3 |
4 | window.onload = async () => {
5 | if (!disableSmoothScrollSaver.get()) enableSmoothScroll();
6 | try {
7 | let id = new URL(location.href).searchParams.get("file");
8 | let source = await getScriptSource(id);
9 |
10 | if (source) {
11 | let fileName = id + ".js";
12 | let comment = "// File: " + fileName;
13 |
14 | document.querySelector("#copy-btn").onclick = () => copy(source);
15 | document.querySelector("code").innerHTML =
16 | comment + "\n\n" + escapeHTML(source);
17 | document.title = fileName;
18 |
19 | hljs.highlightAll();
20 | hljs.initLineNumbersOnLoad();
21 | }
22 | } catch (e) {}
23 | };
24 |
25 | function copy(text) {
26 | navigator.clipboard.writeText(text);
27 | alert("Copied");
28 | }
29 |
30 | // https://stackoverflow.com/a/26276924/11898496
31 | async function getScriptSource(scriptId) {
32 | try {
33 | let fileName = scriptId + ".js";
34 | let path = "/scripts/" + fileName;
35 | let res = await fetch(path);
36 | let source = await res.text();
37 | return source;
38 | } catch (e) {
39 | return "// Không lấy được source code\n// Cannot load source code";
40 | }
41 | }
42 |
43 | // https://stackoverflow.com/a/6234804/11898496
44 | function escapeHTML(unsafe_str) {
45 | return unsafe_str
46 | .replace(/&/g, "&")
47 | .replace(//g, ">")
49 | .replace(/\"/g, """)
50 | .replace(/\'/g, "'")
51 | .replace(/\//g, "/");
52 | }
53 |
--------------------------------------------------------------------------------
/pages/viewScriptSource/style.css:
--------------------------------------------------------------------------------
1 | @font-face {
2 | font-family: JetBrainsMono;
3 | src: url(fonts/JetBrainsMono-Regular.woff2);
4 | }
5 |
6 | @font-face {
7 | font-family: JetBrainsMono;
8 | src: url(fonts/JetBrainsMono-Bold.woff2);
9 | font-weight: bold;
10 | }
11 |
12 | * {
13 | font-family: JetBrainsMono, 'Courier New', Courier, monospace;
14 | }
15 |
16 | *::-webkit-scrollbar {
17 | height: 10px;
18 | width: 10px;
19 | }
20 |
21 | *::-webkit-scrollbar-track,
22 | *::-webkit-scrollbar-track-piece {
23 | background-color: #23241f;
24 | }
25 |
26 | *::-webkit-scrollbar-thumb {
27 | background-color: #828282;
28 | border-radius: 10px;
29 | }
30 |
31 | body,
32 | pre,
33 | code {
34 | margin: 0;
35 | padding: 0;
36 | }
37 |
38 | body {
39 | overflow: auto;
40 | width: 100vw;
41 | height: 100vh;
42 | }
43 |
44 | pre {
45 | background-color: #23241f;
46 | width: max-content;
47 | height: max-content;
48 | }
49 |
50 | code {
51 | font-size: 14px;
52 | font-style: normal;
53 | font-variant: normal;
54 | font-weight: 400;
55 | line-height: 20px;
56 | }
57 |
58 | button {
59 | position: fixed;
60 | top: 0px;
61 | left: 0px;
62 | padding: 5px 10px;
63 | border: none;
64 | cursor: pointer;
65 | color: #eee;
66 | background-color: #555;
67 | transition: background-color ease-in-out 0.2s;
68 | }
69 |
70 | button:hover {
71 | background-color: #828282;
72 | }
73 |
--------------------------------------------------------------------------------
/popup/assets/flag-en.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Useful-Scripts-Extension/useful-script/3841517b641a602d6360cf9b43152bee2524bd7f/popup/assets/flag-en.png
--------------------------------------------------------------------------------
/popup/assets/flag-vi.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Useful-Scripts-Extension/useful-script/3841517b641a602d6360cf9b43152bee2524bd7f/popup/assets/flag-vi.png
--------------------------------------------------------------------------------
/popup/helpers/checkForUpdate.js:
--------------------------------------------------------------------------------
1 | import config from "../../config.js";
2 | import { trackEvent } from "../../scripts/helpers/utils.js";
3 | import { t } from "./lang.js";
4 |
5 | const versionSpan = document.querySelector("#version");
6 | const updateBtn = document.querySelector("#update-btn");
7 |
8 | export async function checkForUpdate() {
9 | try {
10 | const currentVer = (await chrome.runtime.getManifest()).version;
11 | versionSpan.innerHTML = "v" + currentVer;
12 |
13 | const { version_check, source_code } = config;
14 | const lastestVer = (await (await fetch(version_check)).json()).version;
15 | if (lastestVer > currentVer) {
16 | updateBtn.style.display = "inline-block";
17 | updateBtn.innerHTML = t({
18 | vi: "cập nhật v" + lastestVer,
19 | en: "update v" + lastestVer,
20 | });
21 | updateBtn.setAttribute(
22 | "data-tooltip",
23 | t({
24 | vi: "Đã có phiên bản mới v" + lastestVer,
25 | en: "Update available v" + lastestVer,
26 | })
27 | );
28 | updateBtn.setAttribute("data-flow", "bottom");
29 | updateBtn.onclick = () => {
30 | trackEvent("CHECK-FOR-UPDATE");
31 | window.open(source_code);
32 | };
33 | } else {
34 | updateBtn.style.display = "none";
35 | versionSpan.innerHTML += t({ vi: " (mới nhất)", en: " (lastest)" });
36 | }
37 | } catch (e) {
38 | console.warn("Check for update failed", e);
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/popup/helpers/lang.js:
--------------------------------------------------------------------------------
1 | import { langSaver } from "./storage.js";
2 |
3 | export const LANG = {
4 | vi: "Tiếng Việt",
5 | en: "English",
6 | };
7 |
8 | export const LANG_KEY = Object.keys(LANG);
9 |
10 | let currentLangKey = langSaver.get() || "vi";
11 |
12 | export function setLang(key) {
13 | if (key in LANG) {
14 | currentLangKey = key;
15 | langSaver.set(key);
16 | } else {
17 | alert("WRONG LANG KEY " + key);
18 | }
19 | }
20 |
21 | export function getLang() {
22 | return currentLangKey;
23 | }
24 |
25 | export function getFlag(key = currentLangKey) {
26 | return "./assets/flag-" + key + ".png";
27 | }
28 |
29 | export function t(o) {
30 | if (typeof o === "string") return o;
31 | if (typeof o === "object") {
32 | for (let key of [currentLangKey, ...LANG_KEY]) {
33 | if (key in o && o[key] != "") {
34 | return o[key];
35 | }
36 | }
37 | }
38 |
39 | return "?";
40 | }
41 |
--------------------------------------------------------------------------------
/popup/helpers/modal.js:
--------------------------------------------------------------------------------
1 | const modal = document.querySelector("#myModal");
2 | const closeModalBtn = modal.querySelector(".close");
3 | const modalTitle = modal.querySelector(".title");
4 | const modalBody = modal.querySelector(".body");
5 |
6 | function initModal() {
7 | // When the user clicks on (x), close the modal
8 | closeModalBtn.onclick = function () {
9 | toggleModal(false);
10 | };
11 |
12 | // When the user clicks anywhere outside of the modal, close it
13 | window.addEventListener("click", function (event) {
14 | if (event.target == modal) {
15 | toggleModal(false);
16 | }
17 | });
18 | }
19 |
20 | export function toggleModal(show = true) {
21 | modal.classList.toggle("hide", !show);
22 | }
23 |
24 | export function openModal(title, body) {
25 | modalTitle.innerHTML = title;
26 | if (typeof body === "string") {
27 | modalBody.innerHTML = body;
28 | } else if (typeof body === "object" && "nodeName" in body) {
29 | modalBody.innerHTML = "";
30 | modalBody.appendChild(body);
31 | }
32 | toggleModal(true);
33 |
34 | return () => {
35 | toggleModal(false);
36 | };
37 | }
38 |
39 | (() => {
40 | initModal();
41 | })();
42 |
--------------------------------------------------------------------------------
/popup/helpers/storage.js:
--------------------------------------------------------------------------------
1 | const createVariableSaver = (key, defaultValue = null) => ({
2 | set: (data) => {
3 | localStorage.setItem(key, JSON.stringify(data));
4 | },
5 | get: (_defaultValue) => {
6 | return (
7 | JSON.parse(localStorage.getItem(key) || "null") ??
8 | _defaultValue ??
9 | defaultValue
10 | );
11 | },
12 | });
13 |
14 | export const themeSaver = createVariableSaver("useful-scripts-theme");
15 | export const langSaver = createVariableSaver("useful-scripts-lang");
16 | export const activeTabIdSaver = createVariableSaver(
17 | "useful-scripts-activeTabId"
18 | );
19 |
20 | // default is false => enabled; true => disabled
21 | export const disableSmoothScrollSaver = createVariableSaver(
22 | "useful-scripts-disable-smoothScroll"
23 | );
24 |
--------------------------------------------------------------------------------
/popup/helpers/storageScripts.js:
--------------------------------------------------------------------------------
1 | import allScripts from "../../scripts/@allScripts.js";
2 |
3 | const createScriptsSaver = (key, addToHead = true) => {
4 | const getIds = () =>
5 | JSON.parse(localStorage.getItem(key) ?? "[]").filter(
6 | (savedScriptId) => savedScriptId in allScripts
7 | );
8 | const has = (script) => {
9 | let current = getIds();
10 | let exist = current.findIndex((id) => id === script.id) >= 0;
11 | return exist;
12 | };
13 | const add = (script) => {
14 | let current = getIds();
15 | let newList = current.filter((id) => id != script.id); // remove duplicate
16 | if (addToHead) newList.unshift(script.id); // only save script id
17 | else newList.push(script.id);
18 | localStorage.setItem(key, JSON.stringify(newList));
19 | };
20 | const remove = (script) => {
21 | let current = getIds();
22 | let newList = current.filter((id) => id !== script.id);
23 | localStorage.setItem(key, JSON.stringify(newList));
24 | console.log("removed ", script);
25 | };
26 | const toggle = (script) => {
27 | let exist = has(script);
28 | if (exist) remove(script);
29 | else add(script);
30 | };
31 | const clear = () => {
32 | localStorage.setItem(key, "[]");
33 | };
34 | const get = () => getIds().map((savedScriptId) => allScripts[savedScriptId]);
35 |
36 | return { add, remove, has, toggle, clear, getIds, get };
37 | };
38 |
39 | export const recentScriptsSaver = createScriptsSaver("useful-scripts-recently");
40 | export const favoriteScriptsSaver = createScriptsSaver(
41 | "useful-scripts-favorite"
42 | );
43 |
--------------------------------------------------------------------------------
/popup/helpers/theme.js:
--------------------------------------------------------------------------------
1 | import { themeSaver } from "./storage.js";
2 |
3 | const cssTag = document.querySelector("link[rel='stylesheet/less']");
4 |
5 | const me = {
6 | name: "HoangTran",
7 | link: "https://github.com/hoangTran0410",
8 | avatar: "https://avatars.githubusercontent.com/u/36368107",
9 | };
10 |
11 | export const THEME = {
12 | default: {
13 | vi: "Sáng",
14 | en: "Light",
15 | author: me,
16 | },
17 | default_dark: {
18 | vi: "Tối",
19 | en: "Dark",
20 | author: me,
21 | },
22 | xtri98: {
23 | en: "xtri98",
24 | vi: "xtri98",
25 | author: {
26 | name: "xtri98",
27 | link: "https://github.com/xtri98",
28 | avatar: "https://avatars.githubusercontent.com/u/154915091",
29 | },
30 | },
31 | };
32 |
33 | export const THEME_KEY = Object.keys(THEME);
34 |
35 | let currentThemeKey = themeSaver.get() || "default";
36 | if (currentThemeKey !== "default") setTheme(currentThemeKey);
37 |
38 | export function getTheme() {
39 | return currentThemeKey;
40 | }
41 |
42 | export function setTheme(themeKey) {
43 | if (themeKey in THEME) {
44 | currentThemeKey = themeKey;
45 | themeSaver.set(themeKey);
46 | cssTag.href = `themes/${themeKey}.less`;
47 |
48 | // remove old compiled css
49 | document.querySelector("style[id^=less]")?.remove?.();
50 |
51 | // compile new css
52 | less?.refresh?.();
53 | } else {
54 | alert("WRONG THEME KEY " + themeKey);
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/popup/helpers/utils.js:
--------------------------------------------------------------------------------
1 | const CONTEXTS = [
2 | "popupScript",
3 | "contentScript",
4 | "pageScript",
5 | "backgroundScript",
6 | ];
7 |
8 | export const canClick = (script) => {
9 | for (let context of CONTEXTS) {
10 | for (let fn of injectAllFramesFns(["onClick"])) {
11 | if (typeof script[context]?.[fn] === "function") {
12 | return true;
13 | }
14 | }
15 | }
16 | return false;
17 | };
18 |
19 | function hasChildFunction(object, excludedNamesSet = new Set()) {
20 | for (let key in object) {
21 | if (key.startsWith("_")) continue; // ignore private member
22 | if (!object[key]) continue;
23 | if (excludedNamesSet.has(key)) continue;
24 | if (typeof object[key] === "function") return true;
25 | if (typeof object[key] !== "object") continue;
26 | if (hasChildFunction(object[key], excludedNamesSet)) return true;
27 | }
28 | return false;
29 | }
30 |
31 | export const canAutoRun = (script) => {
32 | let excludedNameSet = new Set(
33 | injectAllFramesFns([
34 | "onClick",
35 | "onInstalled",
36 | "onStartup",
37 | "onMessage",
38 | "onMessageExternal",
39 | "contextMenus",
40 | ])
41 | );
42 | for (let context of CONTEXTS) {
43 | if (hasChildFunction(script[context], excludedNameSet)) return true;
44 | }
45 | return false;
46 | };
47 |
48 | // input ["onClick", "abc"] => output ["onClick", "onClick_", "abc", "abc_"]
49 | const injectAllFramesFns = (fns) => fns.map((key) => [key, key + "_"]).flat();
50 |
51 | export const isTitle = (script) => !(canClick(script) || canAutoRun(script));
52 |
53 | export async function viewScriptSource(script) {
54 | chrome.windows.create({
55 | url: chrome.runtime.getURL(
56 | "pages/viewScriptSource/index.html?file=" + script.id
57 | ),
58 | type: "popup",
59 | height: window.screen.height,
60 | width: 700,
61 | left: window.screen.width / 2 - 350,
62 | top: 0,
63 | });
64 | }
65 |
--------------------------------------------------------------------------------
/popup/main.js:
--------------------------------------------------------------------------------
1 | setTimeout(
2 | () =>
3 | import("./index.js").then(() => {
4 | document.querySelector("#loading-fullscreen")?.remove();
5 | }),
6 | 0
7 | );
8 |
--------------------------------------------------------------------------------
/popup/styles/scrollbar.css:
--------------------------------------------------------------------------------
1 | ::-webkit-scrollbar {
2 | width: 7px;
3 | height: 7px;
4 | }
5 |
6 | ::-webkit-scrollbar-track {
7 | background: transparent;
8 | }
9 |
10 | ::-webkit-scrollbar-thumb {
11 | background: #888;
12 | }
13 |
14 | ::-webkit-scrollbar-thumb:hover {
15 | background: #555;
16 | }
17 |
--------------------------------------------------------------------------------
/popup/themes/default_dark.less:
--------------------------------------------------------------------------------
1 | @import "./default.less"; // extends from default theme
2 | @import "../libs/swal2.dark.css";
3 |
4 | @font_family_1: "Roboto", sans-serif;
5 | @font-weight: 400;
6 | @bg_body: #223;
7 | @color_body: #c7c7c7;
8 |
9 | @bg_behind_modal: rgba(0, 0, 0, 0.4);
10 | @bg_modal: #4a4a4a;
11 | @color_modal_close_btn: #a2a2a2;
12 | @color_modal_close_btn_hover: #ededed;
13 |
14 | @bg_link: #3e3e3e;
15 | @bg_link_hover: #484848;
16 |
17 | @bg_update: #009e00;
18 | @bg_update_hover: #00c200;
19 |
20 | @bg_scrolltop: #606060;
21 | @color_scrolltop: #c6c6c6;
22 |
23 | @bg_tab: #2a2f37;
24 | @bg_tab_btn: #2a2f37;
25 | @bg_tab_btn_hover: #4b4b4b;
26 | @bg_tab_btn_active: #696969;
27 |
28 | @color_highlight: #3a8bfe;
29 | @bg_script_btn: #333;
30 | @bg_script_btn_hover: #565656;
31 |
32 | @bg_checkmark: #464646;
33 | @color_checkmark: white;
34 | @bg_checkmark_hover: #2e2e2e;
35 | @bg_checkmark_active: #04AA6D;
36 | @checkmark_border: #777777;
37 |
38 | @bg_search: #333333;
39 | @bg_inp_search: #3f3f3f;
40 | @bg_search_result: #3e3e3edd;
41 |
42 | @bg_tooltip: #434343;
43 | @color_tooltip: #d6d6d6;
44 | @border_tooltip: transparent transparent @bg_tooltip transparent;
45 | @border_change_logs: white;
46 |
47 | @color_tooltip2: #FFFFFF;
48 | @bg_tooltip2: #333333;
49 |
50 | @bg_loading_fullscreen: #494949db;
51 | @color_loading_text: #d3d3d3;
52 | @border_loading: #3498db;
53 | @border_loading_bg: white;
54 |
55 | @bg_scrollbar: #888;
56 | @bg_scrollbar_hover: #555;
57 |
58 |
59 | .popup-header {
60 | background: #676ba4;
61 | background: linear-gradient(to right, #676ba4 0%, #f14340 100%);
62 | -webkit-background-clip: text;
63 | -webkit-text-fill-color: transparent;
64 | }
65 |
--------------------------------------------------------------------------------
/scripts/@allScripts.js:
--------------------------------------------------------------------------------
1 | import * as allScripts from "./@index.js";
2 |
3 | // inject id to all scripts
4 | Object.entries(allScripts).forEach(([variableName, script]) => {
5 | script.id = variableName;
6 | });
7 |
8 | export default allScripts;
9 |
--------------------------------------------------------------------------------
/scripts/archiveToday.js:
--------------------------------------------------------------------------------
1 | export default {
2 | icon: `https://archive.ph/favicon.ico`,
3 | name: {
4 | en: "Archive the current Page online",
5 | vi: "Lưu trữ online trang hiện tại",
6 | },
7 | description: {
8 | en: "Creates an archive of the current page on archive.today.",
9 | vi: "Lưu trang web hiện tại lên archive.today",
10 | },
11 |
12 | popupScript: {
13 | onClick: async function () {
14 | const { getCurrentTab } = await import("./helpers/utils.js");
15 | let { url } = await getCurrentTab();
16 |
17 | var a = prompt(
18 | "Nhập URL muốn tạo archive: ",
19 | url.replace(/^http\:\/\/(.*)$/, "$1")
20 | );
21 | if (a != null) {
22 | window.open(
23 | "https://archive.today/?run=1&url=" + encodeURIComponent(a)
24 | );
25 | }
26 | },
27 | },
28 | };
29 |
--------------------------------------------------------------------------------
/scripts/auto_lockWebsite.css:
--------------------------------------------------------------------------------
1 | * {
2 | box-sizing: border-box;
3 | }
4 |
5 | html {
6 | display: flex;
7 | justify-content: center;
8 | width: 400px;
9 | height: 600px;
10 | margin: auto;
11 | }
12 |
13 | body {
14 | width: 100%;
15 | height: 100%;
16 | background-color: #333;
17 | color: #eee;
18 | display: flex;
19 | align-items: center;
20 | flex-direction: column;
21 | }
22 |
23 | .sites-container {
24 | width: 100%;
25 | text-align: center;
26 | margin-top: 10px;
27 | overflow-y: auto;
28 | overflow-x: hidden;
29 | }
30 |
31 | .site {
32 | display: flex;
33 | flex-direction: row;
34 | justify-content: space-between;
35 | align-items: center;
36 | width: 100%;
37 | padding: 5px 10px;
38 | border-radius: 5px;
39 | }
40 |
41 | .site:hover {
42 | background-color: #555;
43 | }
44 |
45 | .site p {
46 | font-size: 1.3em;
47 | }
48 |
49 | #change-pass {
50 | margin-bottom: 5px;
51 | }
52 |
53 | .button {
54 | background-color: #444;
55 | color: #eee;
56 | border: none;
57 | border-radius: 5px;
58 | padding: 7px 15px;
59 | cursor: pointer;
60 | /* transition: all 0.1s ease; */
61 | }
62 |
63 | .button:hover {
64 | background-color: #666;
65 | color: #fff;
66 | }
67 |
68 |
69 | #back {
70 | position: absolute;
71 | display: block;
72 | top: 5px;
73 | left: 5px;
74 | width: 35px;
75 | height: 35px;
76 | text-decoration: none;
77 | color: #fff;
78 | text-align: center;
79 | line-height: 30px;
80 | font-weight: bold;
81 | font-size: 24px;
82 | transition: all 0.2s ease;
83 | cursor: pointer;
84 | border: none;
85 | background-color: transparent;
86 | }
87 |
88 | #back:hover {
89 | font-size: 28px;
90 | }
91 |
--------------------------------------------------------------------------------
/scripts/auto_lockWebsite.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Useful Scripts - Auto lock websites
8 |
9 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | Auto lock websites
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/scripts/auto_redirectLargestImageSrc.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Useful-Scripts-Extension/useful-script/3841517b641a602d6360cf9b43152bee2524bd7f/scripts/auto_redirectLargestImageSrc.jpg
--------------------------------------------------------------------------------
/scripts/backup/bao-reaction.php:
--------------------------------------------------------------------------------
1 |
2 |
3 | ';
16 | }
17 | }
18 | function auto($url){
19 | $curl = curl_init();
20 | curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
21 | curl_setopt($curl, CURLOPT_URL, $url);
22 | $ch = curl_exec($curl);
23 | curl_close($curl);
24 | return $ch;
25 | }
26 | ?>
27 | // code by danhthong+lulzquan
28 |
29 | // bạn có thể không ghi nguồn khi dùng nhưng làm ơn đừng mang code của mình đi bán...đó là lý do mình rất ít share code -.-
30 | //domain.php/baocamxuc.php?token={{token}}&camxuc={{camxuc}}&id={{uid}}&limit={{soluong}}
31 |
32 |
--------------------------------------------------------------------------------
/scripts/bookmark_exporter.js:
--------------------------------------------------------------------------------
1 | import { UfsGlobal } from "./content-scripts/ufs_global.js";
2 |
3 | export default {
4 | icon: '',
5 | name: {
6 | en: "Export bookmarks to file",
7 | vi: "Xuất bookmarks ra file",
8 | },
9 | description: {
10 | en: "Export all your browser's bookmarks to JSON file",
11 | vi: "Xuất tất cả bookmarks trong trình duyệt của bạn ra file JSON",
12 | },
13 |
14 | changeLogs: {
15 | "2024-04-27": "support download as .json",
16 | },
17 |
18 | popupScript: {
19 | onClick: async function () {
20 | chrome.bookmarks.getTree((tree) => {
21 | console.log(tree);
22 |
23 | UfsGlobal.Utils.downloadData(
24 | JSON.stringify(tree, null, 4),
25 | "bookmarks.json"
26 | );
27 | });
28 | },
29 | },
30 | };
31 |
--------------------------------------------------------------------------------
/scripts/bypass_LearnAnything.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Useful-Scripts-Extension/useful-script/3841517b641a602d6360cf9b43152bee2524bd7f/scripts/bypass_LearnAnything.png
--------------------------------------------------------------------------------
/scripts/bypass_learnAnything.js:
--------------------------------------------------------------------------------
1 | import { UfsGlobal } from "./content-scripts/ufs_global.js";
2 |
3 | export default {
4 | icon: "https://learn-anything.xyz/favicon.ico",
5 | name: {
6 | en: "Mở khoá Learn Anything",
7 | vi: "Bypass Learn Anything",
8 | },
9 | description: {
10 | en: "View learn-anything.xyz content without become a member",
11 | vi: "Xem nội dung web learn-anything.xyz không cần đăng ký member",
12 | img: "/scripts/bypass_LearnAnything.png",
13 | },
14 | changeLogs: {
15 | "2024-07-01": "init",
16 | },
17 | infoLink: "https://learn-anything.xyz/",
18 |
19 | whiteList: ["https://learn-anything.xyz/*"],
20 |
21 | contentScript: {
22 | onDocumentStart: (details) => {
23 | UfsGlobal.DOM.injectCssCode(`
24 | #InfoMain .absolute {
25 | visibility: hidden !important;
26 | }
27 | `);
28 | },
29 | },
30 | };
31 |
--------------------------------------------------------------------------------
/scripts/checkWebDie.js:
--------------------------------------------------------------------------------
1 | export default {
2 | icon: `https://s2.googleusercontent.com/s2/favicons?domain=downforeveryoneorjustme.com`,
3 | name: {
4 | en: "Dowfor - Check web die",
5 | vi: "Dowfor - Kiểm tra web die",
6 | },
7 | description: {
8 | en: "Check web die using downforeveryoneorjustme",
9 | vi: "Dùng bên thứ 3 để kiểm tra xem website có bị die thật không",
10 | },
11 |
12 | popupScript: {
13 | onClick: async function () {
14 | const { getCurrentTab } = await import("./helpers/utils.js");
15 | let { url } = await getCurrentTab();
16 | if (url) {
17 | let url_to_check = prompt("Enter web url to check", url);
18 | if (url_to_check) {
19 | window.open("https://downforeveryoneorjustme.com/" + url_to_check);
20 | }
21 | } else {
22 | alert("Không tìm thấy url web hiện tại");
23 | }
24 | },
25 | },
26 | };
27 |
--------------------------------------------------------------------------------
/scripts/content-scripts/content_script.js:
--------------------------------------------------------------------------------
1 | (() => {
2 | let utils;
3 |
4 | // communication between page-script and content-script
5 | function sendToPageScript(event, uuid, data) {
6 | // console.log("sendToPageScript", event, uuid, data);
7 | window.dispatchEvent(
8 | new CustomEvent("ufs-contentscript-sendto-pagescript" + uuid, {
9 | detail: { event, data },
10 | })
11 | );
12 | }
13 |
14 | async function getUtils() {
15 | if (!utils) utils = await import("../helpers/utils.js");
16 | return utils;
17 | }
18 |
19 | getUtils(); // import and save utils
20 |
21 | // listen page script (web page, cannot listen iframes ...)
22 | window.addEventListener("ufs-pagescript-sendto-contentscript", async (e) => {
23 | let { event, data, uuid } = e?.detail || {};
24 | try {
25 | switch (event) {
26 | case "ufs-runInContentScript":
27 | const { params = [], fnPath = "" } = data || {};
28 | // console.log("runInContentScript", fnPath, params);
29 | const res = await (await getUtils()).runFunc(fnPath, params);
30 | sendToPageScript(event, uuid, res);
31 | break;
32 | case "ufs-runInBackground":
33 | chrome.runtime.sendMessage(
34 | { action: "ufs-runInBackground", data },
35 | function (response) {
36 | // console.log("Response from background script:", response);
37 | sendToPageScript(event, uuid, response);
38 | }
39 | );
40 | break;
41 | }
42 | } catch (e) {
43 | console.log("ERROR: ", e);
44 | sendToPageScript(event, uuid, null);
45 | }
46 | });
47 | })();
48 |
--------------------------------------------------------------------------------
/scripts/createInvisibleText.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Useful Scripts - Giải mã tin nhắn tàng hình
8 |
9 |
10 |
11 |
12 |
13 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/scripts/createInvisibleText_main.js:
--------------------------------------------------------------------------------
1 | import createInvisibleText from "./createInvisibleText.js";
2 |
3 | (async () => {
4 | while (true) {
5 | await createInvisibleText.popupScript.onClick();
6 | }
7 | })();
8 |
--------------------------------------------------------------------------------
/scripts/cssSelectorViewer.js:
--------------------------------------------------------------------------------
1 | export default {
2 | icon: ``,
3 | name: {
4 | en: "CSS selector viewer",
5 | vi: "Trình kiểm tra css cục bộ",
6 | },
7 | description: {
8 | en: "Inspect css at specific element on the web",
9 | vi: "Kiểm tra mã css cho thành phần bất kỳ trong trang web",
10 | },
11 |
12 | contentScript: {
13 | onClick: function () {
14 | var div = document.createElement("div");
15 | div.innerHTML = "Loading...";
16 | div.style.color = "black";
17 | div.style.padding = "20px";
18 | div.style.position = "fixed";
19 | div.style.zIndex = "9999";
20 | div.style.fontSize = "3.0em";
21 | div.style.border = "2px solid black";
22 | div.style.right = "40px";
23 | div.style.top = "40px";
24 | div.setAttribute("class", "selector_gadget_loading");
25 | div.style.background = "white";
26 | document.body.appendChild(div);
27 |
28 | let script = document.createElement("script");
29 | script.setAttribute("type", "text/javascript");
30 | script.setAttribute(
31 | "src",
32 | "https://dv0akt2986vzh.cloudfront.net/unstable/lib/selectorgadget.js"
33 | );
34 | script.onerror = () => {
35 | div.remove();
36 | script.remove();
37 | alert("ERROR, cannot load remote script.");
38 | };
39 | document.body.appendChild(script);
40 | },
41 | },
42 | };
43 |
--------------------------------------------------------------------------------
/scripts/detect_zeroWidthCharacters.css:
--------------------------------------------------------------------------------
1 | .ufs-zero-width-characters-container {
2 | background-color: rgba(255, 0, 0, 0.2) !important;
3 | position: relative;
4 | }
5 |
6 | .ufs-zero-width-characters-container:after {
7 | background: #ffb2b2;
8 | bottom: -14px;
9 | color: #000;
10 | content: 'Warning: Contains zero-width characters.';
11 | float: right;
12 | font-family: monospace;
13 | font-size: 10px;
14 | font-weight: bold;
15 | line-height: 1;
16 | padding: 2px 4px;
17 | position: absolute;
18 | right: 0;
19 | }
20 |
21 | .ufs-zero-width-character:after {
22 | color: red;
23 | content: '\25CF';
24 | }
--------------------------------------------------------------------------------
/scripts/douyin_batchDownload.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Useful-Scripts-Extension/useful-script/3841517b641a602d6360cf9b43152bee2524bd7f/scripts/douyin_batchDownload.png
--------------------------------------------------------------------------------
/scripts/douyin_downloadWachingVideo.js:
--------------------------------------------------------------------------------
1 | import { UfsGlobal } from "./content-scripts/ufs_global.js";
2 |
3 | export default {
4 | icon: "https://www.douyin.com/favicon.ico",
5 | name: {
6 | en: "Douyin - Download watching video",
7 | vi: "Douyin - Tải video đang xem",
8 | },
9 | description: {
10 | en: "Show all downloadable videos in current douyin webpage",
11 | vi: "Hiển thị mọi video có thể tải trong trang douyin hiện tại",
12 | },
13 | whiteList: ["https://www.douyin.com/*"],
14 |
15 | popupScript: {
16 | onClick: async function () {
17 | const { runScriptInCurrentTab, showLoading } = await import(
18 | "./helpers/utils.js"
19 | );
20 |
21 | const { closeLoading, setLoadingText } = showLoading(
22 | "Đang tìm video url..."
23 | );
24 |
25 | const src = await runScriptInCurrentTab(async () => {
26 | return await UfsGlobal.DOM.getWatchingVideoSrc();
27 | });
28 |
29 | if (!src) {
30 | alert("Không tìm thấy video nào.");
31 | } else {
32 | setLoadingText("Đang tải video...");
33 | window.open(src);
34 | }
35 | closeLoading();
36 | },
37 | },
38 | };
39 |
--------------------------------------------------------------------------------
/scripts/download_watchingVideo.js:
--------------------------------------------------------------------------------
1 | import { UfsGlobal } from "./content-scripts/ufs_global.js";
2 | import { runScriptInCurrentTab, showLoading } from "./helpers/utils.js";
3 |
4 | export default {
5 | icon: "",
6 | name: {
7 | en: "Download watching video",
8 | vi: "Tải video đang xem",
9 | },
10 | description: {
11 | en: "tiktok, doutu.be, phimmoi2...",
12 | vi: "tiktok, doutu.be, phimmoi2...",
13 | },
14 |
15 | popupScript: {
16 | onClick: async () => {
17 | let src = await runScriptInCurrentTab(async () => {
18 | return UfsGlobal.DOM.getWatchingVideoSrc();
19 | });
20 |
21 | if (!src) {
22 | alert("Không tìm thấy video");
23 | return;
24 | }
25 |
26 | const { closeLoading, setLoadingText } = showLoading("Đang tải video...");
27 | await UfsGlobal.Utils.downloadBlobUrl(
28 | src,
29 | "video.mp4",
30 | (loaded, total) => {
31 | let loadedMB = ~~(loaded / 1024 / 1024);
32 | let totalMB = ~~(total / 1024 / 1024);
33 | let percent = ((loaded / total) * 100) | 0;
34 | setLoadingText(
35 | `Đang tải video... (${loadedMB}/${totalMB}MB - ${percent}%)`
36 | );
37 | }
38 | );
39 | closeLoading();
40 | },
41 | },
42 | };
43 |
--------------------------------------------------------------------------------
/scripts/duckRace_cheat.js:
--------------------------------------------------------------------------------
1 | import { BADGES } from "./helpers/badge.js";
2 |
3 | export default {
4 | icon: "https://www.online-stopwatch.com/favicon.ico",
5 | name: {
6 | en: "Hack Duck race",
7 | vi: "Hack Duck race",
8 | },
9 | description: {
10 | en: "Hack result of Duck race, always get the result you want",
11 | vi: "Hack kết quả Duck race, sẽ luôn ra kết quả bạn mong muốn",
12 | img: "/scripts/duckRage_cheat.png",
13 | },
14 | badges: [BADGES.hot],
15 | whiteList: ["https://www.online-stopwatch.com/*"],
16 |
17 | pageScript: {
18 | onClick: () => {
19 | let targets = prompt(
20 | "Nhập các kết quả mong muốn (tên hoặc số):\nCách nhau bởi dấu phẩy ,\n Ví dụ: 1,abc,5,20,test",
21 | ""
22 | );
23 | if (targets === null) return;
24 |
25 | targets = targets
26 | .split(",")
27 | .map((_) => _.trim())
28 | .filter((_) => _);
29 |
30 | let iframe = document.querySelector('iframe[src*="duck-race"]');
31 |
32 | [window, iframe?.contentWindow]
33 | .filter((_) => _)
34 | .forEach((win) => {
35 | if (!win.ufs_duckRace_originalShuffle)
36 | win.ufs_duckRace_originalShuffle = win.Array.prototype.shuffle;
37 |
38 | win.Array.prototype.shuffle = function () {
39 | const result = win.ufs_duckRace_originalShuffle.apply(
40 | this,
41 | arguments
42 | );
43 | if (result?.[0]?.instance) {
44 | for (let target of targets) {
45 | let targetIndex = result.findIndex(
46 | (i) => i?.name === target || i?.number == target
47 | );
48 | if (targetIndex >= 0) {
49 | let temp = result[0];
50 | result[0] = result[targetIndex];
51 | result[targetIndex] = temp;
52 | break;
53 | }
54 | }
55 | }
56 | console.log("shuffle", this, result, result[0]);
57 | return result;
58 | };
59 | });
60 | },
61 | },
62 | };
63 |
--------------------------------------------------------------------------------
/scripts/duckRage_cheat.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Useful-Scripts-Extension/useful-script/3841517b641a602d6360cf9b43152bee2524bd7f/scripts/duckRage_cheat.png
--------------------------------------------------------------------------------
/scripts/fb_aio.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Useful-Scripts-Extension/useful-script/3841517b641a602d6360cf9b43152bee2524bd7f/scripts/fb_aio.png
--------------------------------------------------------------------------------
/scripts/fb_allInOne.js:
--------------------------------------------------------------------------------
1 | import { BADGES } from "./helpers/badge.js";
2 | import { runFunc } from "./helpers/utils.js";
3 |
4 | const GLOBAL = {
5 | fetch: (url, options) => fetch(url, options || {}).then((res) => res.text()),
6 | };
7 |
8 | export default {
9 | icon: "/scripts/fb_aio.png",
10 | name: {
11 | en: "Facebook - All In One",
12 | vi: "Facebook - All In One",
13 | },
14 | badges: [BADGES.new, BADGES.hot],
15 | description: {
16 | en: "Combine all bulk download / statistic features on facebook into single page",
17 | vi: "Tổng hợp tất cả chức năng tải hàng loạt / thống kê facebook",
18 | },
19 |
20 | popupScript: {
21 | onClick: () => {
22 | window.open("https://facebook-all-in-one.com");
23 | },
24 | },
25 |
26 | backgroundScript: {
27 | runtime: {
28 | onMessageExternal: async ({ request, sender, sendResponse }, context) => {
29 | if (request.action === "fb_allInOne_runFunc") {
30 | runFunc(request.fnPath, request.params, GLOBAL).then(sendResponse);
31 | return true;
32 | }
33 | },
34 | },
35 | },
36 | };
37 |
--------------------------------------------------------------------------------
/scripts/fb_autoRemoveSpamPostGroup.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Auto duyệt bài spam group fb
8 |
9 |
10 |
11 |
12 |
13 | Auto duyệt bài spam group fb
14 |
15 | Chọn hành động
16 |
20 |
24 |
25 |
33 |
34 | Duyệt tối đa bao nhiêu bài?
35 | (nhập 0 để duyệt hết)
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/scripts/fb_autoRemoveSpamPostGroup.js:
--------------------------------------------------------------------------------
1 | import { BADGES } from "./helpers/badge.js";
2 |
3 | export default {
4 | icon: '',
5 | name: {
6 | en: "📝 Auto remove fb group's spam posts",
7 | vi: "📝 Auto duyệt bài spam group fb",
8 | },
9 | description: {
10 | en: "Auto Accept / Reject spam posts on your facebook group.",
11 | vi: "Tự động Đăng / Xoá những bài spam trong group facebook của bạn.",
12 | img: "/scripts/fb_autoRemoveSpamPostGroup.png",
13 | },
14 | badges: [BADGES.new],
15 |
16 | changeLogs: {
17 | "2024-08-09": "init",
18 | },
19 | whiteList: ["https://www.facebook.com/*"],
20 |
21 | popupScript: {
22 | onClick: () => {
23 | window.open("/scripts/fb_autoRemoveSpamPostGroup.html", "_self");
24 | },
25 | },
26 | };
27 |
--------------------------------------------------------------------------------
/scripts/fb_autoRemoveSpamPostGroup.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Useful-Scripts-Extension/useful-script/3841517b641a602d6360cf9b43152bee2524bd7f/scripts/fb_autoRemoveSpamPostGroup.png
--------------------------------------------------------------------------------
/scripts/fb_blockSeenStory.js:
--------------------------------------------------------------------------------
1 | import { UfsGlobal } from "./content-scripts/ufs_global.js";
2 | import { BADGES } from "./helpers/badge.js";
3 | import { hookXHR } from "./libs/ajax-hook/index.js";
4 |
5 | export default {
6 | icon: '',
7 | name: {
8 | en: "👀 Block seen story facebook",
9 | vi: '👀 Chặn "Đã xem" story facebook',
10 | },
11 | description: {
12 | en: "Block 'Seen' story in facebook. Your friend will not know that you have seen his/her stories.",
13 | vi: "Chặn 'Đã xem' cho story facebook. Bạn bè sẽ không biết được bạn đã xem story của họ.",
14 | },
15 | badges: [BADGES.hot],
16 | changeLogs: {
17 | "2024-05-31": "init",
18 | },
19 |
20 | whiteList: ["https://*facebook.com/*"],
21 |
22 | pageScript: {
23 | onDocumentStart_: (details) => {
24 | hookXHR({
25 | onBeforeSend: ({ method, url, async, user, password }, dataSend) => {
26 | if (
27 | method === "POST" &&
28 | dataSend?.toString?.()?.includes?.("storiesUpdateSeenStateMutation")
29 | ) {
30 | UfsGlobal.DOM.notify({
31 | msg: "Useful script: facebook story seen BLOCKED",
32 | });
33 | return null;
34 | }
35 | },
36 | });
37 | },
38 | },
39 | };
40 |
--------------------------------------------------------------------------------
/scripts/fb_checkToken.js:
--------------------------------------------------------------------------------
1 | export default {
2 | icon: ``,
3 | name: {
4 | en: "Check fb access token",
5 | vi: "Kiểm tra fb access token",
6 | },
7 | description: {
8 | en: "Check type, permissions, created date, expired date, ... of faceboook access token",
9 | vi: "Kiểm tra loại, quyền, ngày tạo, ngày hết hạn, ... của facebook access token",
10 | },
11 |
12 | popupScript: {
13 | onClick: function () {
14 | let token = prompt(
15 | "Enter accesstoken want to check\nNhập access token muốn kiểm tra:",
16 | ""
17 | );
18 | if (token) {
19 | window.open(
20 | "https://developers.facebook.com/tools/debug/accesstoken/?access_token=" +
21 | token
22 | );
23 | }
24 | },
25 | },
26 | };
27 |
--------------------------------------------------------------------------------
/scripts/fb_getAlbumId.js:
--------------------------------------------------------------------------------
1 | export default {
2 | icon: ``,
3 | name: {
4 | en: "Get fb Album ID",
5 | vi: "Lấy fb Album ID",
6 | },
7 | description: {
8 | en: "Get id of facebook album in current website",
9 | vi: "Lấy id của facebook album trong trang web hiện tại",
10 | },
11 | whiteList: ["https://*.facebook.com/*"],
12 |
13 | contentScript: {
14 | onClick: function () {
15 | // Lấy album id - khi đang xem 1 album, ví dụ https://www.facebook.com/media/set/?vanity=ColourfulSpace&set=a.945632905514659
16 |
17 | const list_a = document.querySelectorAll("a");
18 | for (let a of [location, ...Array.from(list_a)]) {
19 | const page_album_id = /(?<=\/photos\/a\.)(.\d+?)(?=\/)/.exec(a.href);
20 | if (page_album_id && page_album_id[0]) {
21 | prompt("PAGE ALBUM ID:", page_album_id[0]);
22 | return;
23 | }
24 | const group_album_id = /(?<=set\=oa\.)(.\d+?)($|(?=&))/.exec(a.href);
25 | if (group_album_id && group_album_id[0]) {
26 | prompt("GROUP ALBUM ID:", group_album_id[0]);
27 | return;
28 | }
29 | const user_album_id = /(?<=set\=a\.)(.\d+?)($|(?=&))/.exec(a.href);
30 | if (user_album_id && user_album_id[0]) {
31 | prompt("USER ALBUM ID:", user_album_id[0]);
32 | return;
33 | }
34 | }
35 | prompt(
36 | "Không tìm thấy ALBUM ID nào trong trang web!\nBạn có đang ở đúng trang album chưa?\nTrang web Ví dụ:",
37 | "https://www.facebook.com/media/set/?vanity=ColourfulSpace&set=a.945632905514659"
38 | );
39 | },
40 | },
41 | };
42 |
--------------------------------------------------------------------------------
/scripts/fb_getAllAlbumIdFromCurrentWebsite.js:
--------------------------------------------------------------------------------
1 | export default {
2 | icon: '',
3 | name: {
4 | en: "Get all fb Album ID from current page",
5 | vi: "Lấy tất cả fb album id từ trang hiện tại",
6 | },
7 | description: {
8 | en: "Get all id of album in facebook website",
9 | vi: "Lấy tất cả album id có trong trang facebook",
10 | },
11 | whiteList: ["https://*.facebook.com/*"],
12 |
13 | contentScript: {
14 | onClick: function () {
15 | // Lấy tất cả album id có trong trang web - Khi đang xem 1 danh sách album của user/group/page
16 |
17 | const list_a = document.querySelectorAll("a");
18 | let list_id = [];
19 | for (let a of [location, ...Array.from(list_a)]) {
20 | const page_album_id = /(?<=\/photos\/a\.)(.\d+?)(?=\/)/.exec(a.href);
21 | if (page_album_id && page_album_id[0]) {
22 | list_id.push(page_album_id[0]);
23 | }
24 | const group_album_id = /(?<=set\=oa\.)(.\d+?)($|(?=&))/.exec(a.href);
25 | if (group_album_id && group_album_id[0]) {
26 | list_id.push(group_album_id[0]);
27 | }
28 | const user_album_id = /(?<=set\=a\.)(.\d+?)($|(?=&))/.exec(a.href);
29 | if (user_album_id && user_album_id[0]) {
30 | list_id.push(user_album_id[0]);
31 | }
32 | }
33 | // filter duplicate: https://stackoverflow.com/a/14438954
34 | list_id = [...new Set(list_id)];
35 | if (list_id.length)
36 | prompt(
37 | `Tìm thấy ${list_id.length} album id trong trang web và trên url.`,
38 | list_id.join(", ")
39 | );
40 | else
41 | prompt(
42 | "Không tìm thấy ALBUM ID nào trong trang web!\nBạn có đang ở đúng trang album chưa?\nTrang web Ví dụ:",
43 | "https://www.facebook.com/media/set/?vanity=ColourfulSpace&set=a.945632905514659"
44 | );
45 | },
46 | },
47 | };
48 |
--------------------------------------------------------------------------------
/scripts/fb_getAllAlbumInformation.js:
--------------------------------------------------------------------------------
1 | export default {
2 | icon: '',
3 | name: {
4 | en: "Get all albums information",
5 | vi: "Lấy thông tin tất cả album",
6 | },
7 | description: {
8 | en: "Get all albums information from user, group, page (id, count, link, ...)",
9 | vi: "Lấy thông tin tất cả album từ user, group, page (id, số lượng, link, ...)",
10 | },
11 |
12 | popupScript: {
13 | onClick: () => {
14 | let ACCESS_TOKEN = prompt("Nhập access token của bạn vào đây");
15 | if (!ACCESS_TOKEN) return;
16 |
17 | let id = prompt("Nhập ID của user, group, page cần lấy albums", "");
18 | if (!id) return;
19 |
20 | fb_getAllAlbumInfos(id, ACCESS_TOKEN)
21 | .then((result) => {
22 | console.log(result);
23 | prompt(
24 | `Tìm được ${result?.length} albums:\n` +
25 | result.map((_) => _.name + ": " + _.count).join("\n") +
26 | "\n\nCopy ngay:",
27 | JSON.stringify(result)
28 | );
29 | })
30 | .catch((err) => {
31 | console.log(err);
32 | alert("Có lỗi xảy ra: " + err);
33 | });
34 | },
35 | },
36 | };
37 |
38 | export async function fb_getAllAlbumInfos(id, access_token) {
39 | let result = [];
40 | let after = "";
41 | while (true) {
42 | try {
43 | const res = await fetch(
44 | `https://graph.facebook.com/v20.0/${id}/albums?fields=type,name,count,link,created_time&limit=100&access_token=${access_token}&after=${after}`
45 | );
46 | const json = await res.json();
47 | if (json.data) result = result.concat(json.data);
48 |
49 | let nextAfter = json.paging?.cursors?.after;
50 | if (!nextAfter || nextAfter === after) break;
51 | after = nextAfter;
52 | } catch (e) {
53 | break;
54 | }
55 | }
56 | return result;
57 | }
58 |
--------------------------------------------------------------------------------
/scripts/fb_getAllUidFromFbSearch.js:
--------------------------------------------------------------------------------
1 | import { BADGES } from "./helpers/badge.js";
2 |
3 | export default {
4 | icon: '',
5 | name: {
6 | en: "Get all fb User ID from search page",
7 | vi: "Lấy tất cả fb user ID từ trang tìm kiếm",
8 | },
9 | description: {
10 | en: "Get id of all user from facebook search page",
11 | vi: "Lấy id của tất cả user từ trang tìm kiếm người dùng facebook",
12 | },
13 | badges: [BADGES.new],
14 | changeLogs: {
15 | "2024-04-27": "x100 faster api",
16 | },
17 |
18 | whiteList: ["https://*.facebook.com/*"],
19 |
20 | pageScript: {
21 | onClick: async function () {
22 | const { getUidFromUrl } = await import("./fb_GLOBAL.js");
23 |
24 | let list_a = Array.from(
25 | document.querySelectorAll("a[role='presentation']")
26 | );
27 | let uids = [];
28 | for (let a of list_a) {
29 | let l = a.href;
30 | let uid = l.split("profile.php?id=")[1];
31 | if (uid) {
32 | uids.push(uid);
33 | console.log(uid);
34 | continue;
35 | }
36 | let name = l.split("facebook.com/")[1];
37 | uid = await getUidFromUrl(l);
38 | uids.push(uid);
39 | console.log(name, uid);
40 | }
41 | console.log(uids);
42 | prompt(`Tìm được ${uids.length} UID, Copy ngay: `, uids.join("\n"));
43 | },
44 | },
45 | };
46 |
--------------------------------------------------------------------------------
/scripts/fb_getAvatarFromUid.js:
--------------------------------------------------------------------------------
1 | import { UfsGlobal } from "./content-scripts/ufs_global.js";
2 | import { getUserAvatarFromUid } from "./fb_GLOBAL.js";
3 | import { showLoading } from "./helpers/utils.js";
4 |
5 | export default {
6 | icon: '',
7 | name: {
8 | en: "Get avatar from fb user id",
9 | vi: "Tải avatar từ fb user id",
10 | },
11 | description: {
12 | en: "Get avatar from list facebook user ids",
13 | vi: "Tải danh sách avatar từ danh sách user id facebook",
14 | },
15 |
16 | popupScript: {
17 | onClick: async function () {
18 | let uids = prompt("Nhập danh sách uid, Mỗi uid 1 dòng:");
19 | if (!uids) return;
20 |
21 | const { closeLoading, setLoadingText } = showLoading();
22 | try {
23 | uids = uids.split("\n");
24 | let urls = [];
25 | for (let uid of uids) {
26 | setLoadingText("Đang lấy avatar của " + uid + "...");
27 | let url = getUserAvatarFromUid(uid);
28 | let res = await fetch(url);
29 | url = res.url;
30 | if (url) {
31 | urls.push(url);
32 | }
33 | }
34 |
35 | if (urls.length === 0) alert("Không tìm được avatar nào!");
36 | else if (urls.length === 1) window.open(urls[0]);
37 | else {
38 | if (
39 | confirm(
40 | "Tìm được " + urls.length + " avatars.\nBấm Ok để tải xuống."
41 | )
42 | )
43 | UfsGlobal.Utils.downloadData(
44 | urls.join("\n"),
45 | `uid-${new Date().toLocaleString()}.txt`
46 | );
47 | }
48 | } catch (e) {
49 | alert("ERROR: " + e);
50 | } finally {
51 | closeLoading();
52 | }
53 | },
54 | },
55 | };
56 |
--------------------------------------------------------------------------------
/scripts/fb_getGroupId.js:
--------------------------------------------------------------------------------
1 | export default {
2 | icon: '',
3 | name: {
4 | en: "Get fb Group ID",
5 | vi: "Lấy fb Group ID",
6 | },
7 | description: {
8 | en: "Get id of group in facebook website",
9 | vi: "Lấy id của group trong trang facebook hiện tại",
10 | },
11 | whiteList: ["https://*.facebook.com/*"],
12 |
13 | pageScript: {
14 | onClick: async function () {
15 | // Lấy group id - trường hợp url của group hiển thị tên chứ ko hiển thị id. Ví dụ: https://www.facebook.com/groups/j2team.community.girls
16 |
17 | const group_name = document.title;
18 | const found = (check) => {
19 | if (check && check[0]) {
20 | prompt(`GROUP ID của ${group_name}:`, check[0]);
21 | return true;
22 | }
23 | return false;
24 | };
25 | if (found(/(?<=\/groups\/)(.\d+?)($|(?=\/)|(?=&))/.exec(location.href)))
26 | return;
27 | const list_a = document.querySelectorAll("a");
28 | for (let a of Array.from(list_a)) {
29 | if (found(/(?<=\/groups\/)(.\d+?)(?=\/user\/)/.exec(a.href))) return;
30 | }
31 | prompt(
32 | "Không tìm thấy GROUP ID nào trong trang web!\nBạn có đang ở đúng trang group chưa?\nTrang web Ví dụ:",
33 | "https://www.facebook.com/groups/j2team.community.girls"
34 | );
35 | },
36 | },
37 | };
38 |
--------------------------------------------------------------------------------
/scripts/fb_getPageId.js:
--------------------------------------------------------------------------------
1 | export default {
2 | icon: '',
3 | name: {
4 | en: "Get fb Page ID",
5 | vi: "Lấy fb Page ID",
6 | },
7 | description: {
8 | en: "Get id of page in facebook website",
9 | vi: "Lấy id của page trong trang facebook hiện tại",
10 | },
11 | whiteList: ["https://www.facebook.com/*"],
12 |
13 | pageScript: {
14 | onClick: function () {
15 | // Lấy page id - khi đang trong trang của page fb. Ví dụ: https://www.facebook.com/ColourfulSpace
16 |
17 | let funcs = [
18 | () =>
19 | require("CometRouteStore").getRoute(location.pathname).rootView.props
20 | .userID,
21 | () => /(?<=\"pageID\"\:\")(.*?)(?=\")/.exec(document.body.innerHTML)[0],
22 | () =>
23 | /(?<=facebook\.com\/)(.*?)($|(?=\/)|(?=&))/.exec(location.href)[0],
24 | () => {
25 | const tags = Array.from(
26 | document.body.querySelectorAll("script:not([src])")
27 | );
28 | for (const tag of tags) {
29 | let matches = tag.textContent.match(/"pageID":"([0-9]+)"/);
30 | if (matches) {
31 | return matches[1];
32 | }
33 | }
34 | return null;
35 | },
36 | ];
37 |
38 | for (let fn of funcs) {
39 | try {
40 | let result = fn();
41 | if (result) {
42 | prompt("Page ID:", result);
43 | return;
44 | }
45 | } catch (e) {}
46 | }
47 |
48 | prompt(
49 | "Không tìm thấy PAGE ID nào trong url!\nBạn có đang ở đúng trang page fb chưa?\nTrang web Ví dụ:",
50 | "https://www.facebook.com/ColourfulSpace"
51 | );
52 | },
53 | },
54 | };
55 |
--------------------------------------------------------------------------------
/scripts/fb_getPostReactionCount.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Useful-Scripts-Extension/useful-script/3841517b641a602d6360cf9b43152bee2524bd7f/scripts/fb_getPostReactionCount.jpg
--------------------------------------------------------------------------------
/scripts/fb_getTokenBussinessLocation.js:
--------------------------------------------------------------------------------
1 | export default {
2 | icon: ``,
3 | name: {
4 | en: "Get fb token EAAG (business_locations)",
5 | vi: "Lấy fb token EAAG (business_locations)",
6 | },
7 | description: {
8 | en: "Get facebook token EAAG from business.facebook.com",
9 | vi: "Lấy facebook token EAAG từ business.facebook.com",
10 | },
11 |
12 | popupScript: {
13 | onClick: async function () {
14 | const { showLoading } = await import("./helpers/utils.js");
15 | // Get token using cookies https://github.com/dz-id/fb_get_token_from_cookie/blob/main/main.py
16 |
17 | const { closeLoading } = showLoading("Đang lấy access token...");
18 | fetch("https://business.facebook.com/business_locations")
19 | .then((res) => res.text())
20 | .then((htmlText) => {
21 | let regex = htmlText.match(/(EAAG\w+)/);
22 | if (null !== regex) {
23 | let accesstoken = regex[1];
24 | prompt("Access Token: ", accesstoken);
25 | } else {
26 | prompt(
27 | "Không thấy token. Hãy chắc rằng bạn đã đăng nhập vào",
28 | "https://business.facebook.com/business_locations"
29 | );
30 | }
31 | })
32 | .catch((e) => alert("Error: " + e))
33 | .finally(closeLoading);
34 | },
35 | },
36 | };
37 |
38 | // {
39 | // method: "GET",
40 | // credentials: "include",
41 | // headers: {
42 | // "user-agent":
43 | // "Mozilla/5.0 (Linux; Android 8.1.0; MI 8 Build/OPM1.171019.011) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.86 Mobile Safari/537.36", // don't change this user agent.
44 | // referer: "https://www.facebook.com/",
45 | // host: "business.facebook.com",
46 | // origin: "https://business.facebook.com",
47 | // "upgrade-insecure-requests": "1",
48 | // "accept-language": "id-ID,id;q=0.9,en-US;q=0.8,en;q=0.7",
49 | // "cache-control": "max-age=0",
50 | // accept:
51 | // "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
52 | // "content-type": "text/html; charset=utf-8",
53 | // },
54 | // }
55 |
56 | // if (-1 == htmlText.search("EAA")) {
57 | // alert("Token not found");
58 | // return;
59 | // }
60 | // var o = htmlText.match(/EAAGNO.*?\"/);
61 | // prompt("Token", o[0] ? o[0].replace(/\W/g, "") : "");
62 |
--------------------------------------------------------------------------------
/scripts/fb_getTokenFfb.js:
--------------------------------------------------------------------------------
1 | export default {
2 | icon: "https://ffb.vn/assets/img/illustrations/favicon.png",
3 | name: {
4 | en: "Get fb token from cookie (ffb.vn)",
5 | vi: "Lấy fb token từ cookie (ffb.vn)",
6 | },
7 | description: {
8 | en: "Post your facebook cookie to ffb.vn API",
9 | vi: "Gửi cookie facebook lên API của ffb.vn",
10 | },
11 |
12 | popupScript: {
13 | onClick: async function () {
14 | const { getCookie, showLoading } = await import("./helpers/utils.js");
15 | const { closeLoading, setLoadingText } =
16 | showLoading("Đang lấy cookie...");
17 | let cookie = await getCookie("facebook.com");
18 | if (!cookie) {
19 | alert("Không thấy cookie. Hãy chắc rằng bạn đã đăng nhập facebook!");
20 | } else {
21 | //prettier-ignore
22 | let types = ["eaaq","eaag","eaab","eaas","eaai","eaaa","Mở trang ffb.vn",];
23 | let typeIndex = prompt(
24 | "[Lưu ý]\n" +
25 | "+ Sẽ gửi cookie facebook của bạn lên ffb.vn\n" +
26 | "+ Mình không đảm bảo an toàn cho cookie của bạn\n" +
27 | "+ Ấn Cancel ngay nếu muốn huỷ\n\n" +
28 | "Chọn loại token muốn lấy:\n" +
29 | types.map((_, i) => ` ${i}: ${_.toUpperCase()}`).join("\n"),
30 | 0
31 | );
32 |
33 | if (typeIndex == null) {
34 | // cancel
35 | } else if (typeIndex < 0 || typeIndex >= types.length) {
36 | alert(
37 | "Invalid type. Please try again\nLựa chọn không hợp lệ. Vui lòng thử lại"
38 | );
39 | } else if (typeIndex == types.length - 1) {
40 | window.open("https://ffb.vn/get-token");
41 | } else {
42 | const formData = new FormData();
43 | formData.append("cookie", cookie);
44 | formData.append("type", types[typeIndex]);
45 |
46 | setLoadingText("Đang lấy accesstoken từ ffb.vn ...");
47 | let res = await fetch("https://ffb.vn/api/tool/cookie2token", {
48 | method: "POST",
49 | body: formData,
50 | });
51 | let json = await res.json();
52 | if (json.error) {
53 | alert("ERROR: " + json.msg);
54 | } else {
55 | prompt("Access token", json.token);
56 | }
57 | }
58 | }
59 | closeLoading();
60 | },
61 | },
62 | };
63 |
--------------------------------------------------------------------------------
/scripts/fb_getTokenMessage.js:
--------------------------------------------------------------------------------
1 | import { BADGES } from "./helpers/badge.js";
2 |
3 | export default {
4 | icon: ``,
5 | name: {
6 | en: "Get fb token EAADo1 (messenger)",
7 | vi: "Lấy fb token EAADo1 (messenger)",
8 | },
9 | description: {
10 | en: "Get facebook access token from www.facebook.com (messenger_for_android)",
11 | vi: "Lấy facebook access token từ trang www.facebook.com (messenger_for_android)",
12 | },
13 | badges: [BADGES.new],
14 | whiteList: ["https://*.facebook.com/*"],
15 |
16 | pageScript: {
17 | onClick: function () {
18 | try {
19 | let uid = /(?<=c_user=)(\d+)/.exec(document.cookie)?.[0];
20 | if (!uid) {
21 | alert("Không tìm thấy uid trong cookie. Bạn đã đăng nhập chưa?");
22 | return;
23 | }
24 | let dtsg =
25 | require("DTSGInitialData").token ||
26 | document.querySelector('[name="fb_dtsg"]').value,
27 | xhr = new XMLHttpRequest(),
28 | data = new FormData(),
29 | url = `https://www.facebook.com/dialog/oauth/business/cancel/?app_id=256002347743983&version=v19.0&logger_id=&user_scopes[0]=email&user_scopes[1]=read_insights&user_scopes[2]=read_page_mailboxes&user_scopes[3]=pages_show_list&redirect_uri=fbconnect%3A%2F%2Fsuccess&response_types[0]=token&response_types[1]=code&display=page&action=finish&return_scopes=false&return_format[0]=access_token&return_format[1]=code&tp=unspecified&sdk=&selected_business_id=&set_token_expires_in_60_days=false`;
30 | data.append("fb_dtsg", dtsg);
31 |
32 | xhr.open("POST", url, !0);
33 | xhr.onreadystatechange = function () {
34 | if (4 == xhr.readyState && 200 == xhr.status) {
35 | var a = xhr.responseText.match(/(?<=access_token=)(.*?)(?=\&)/);
36 | console.log(xhr.responseText);
37 | if (a && a[0]) {
38 | prompt("Token", a[0]);
39 | } else {
40 | alert("Failed to Get Access Token.");
41 | }
42 | }
43 | };
44 | xhr.send(data);
45 | } catch (e) {
46 | alert("ERROR: " + e);
47 | }
48 | },
49 | },
50 | };
51 |
--------------------------------------------------------------------------------
/scripts/fb_getUid.js:
--------------------------------------------------------------------------------
1 | export default {
2 | icon: ``,
3 | name: {
4 | en: "Get fb User ID",
5 | vi: "Lấy fb User ID",
6 | },
7 | description: {
8 | en: "Get id of user in facebook website",
9 | vi: "Lấy id của user trong trang facebook hiện tại",
10 | },
11 | whiteList: ["https://*.facebook.com/*"],
12 |
13 | pageScript: {
14 | onClick: async function () {
15 | // Lấy user id (uid) - khi đang trong tường của người dùng muốn lấy user id. Ví dụ: https://www.facebook.com/callchoulnhe
16 | const { getUidFromUrl } = await import("./fb_GLOBAL.js");
17 |
18 | let uid = await getUidFromUrl(location.href);
19 | if (uid) return prompt(`USER ID của ${document.title}:`, uid);
20 |
21 | const find = (r) => (r ? r[0] : 0);
22 | uid =
23 | find(
24 | /(?<=\"userID\"\:\")(.\d+?)(?=\")/.exec(
25 | document.querySelector("html").textContent
26 | )
27 | ) ||
28 | find(/(?<=\/profile\.php\?id=)(.\d+?)($|(?=&))/.exec(location.href)) ||
29 | (() => {
30 | for (let a of Array.from(document.querySelectorAll("a"))) {
31 | let _ = find(
32 | /(?<=set\=(pb|picfp|ecnf|pob)\.)(.\d+?)($|(?=\.))/.exec(a.href)
33 | );
34 | if (_) return _;
35 | }
36 | return 0;
37 | })() ||
38 | find(
39 | /(?<=\"user\"\:\{\"id\"\:\")(.\d+?)(?=\")/.exec(
40 | document.body.innerHTML
41 | )
42 | );
43 |
44 | if (uid) prompt(`USER ID của ${document.title}:`, uid);
45 | else
46 | prompt(
47 | "Không tìm thấy USER ID nào trong trang web!\nBạn có đang ở đúng trang profile chưa?\nTrang web Ví dụ: ",
48 | "https://www.facebook.com/callchoulnhe"
49 | );
50 | },
51 | },
52 | };
53 |
--------------------------------------------------------------------------------
/scripts/fb_getUidFromUrl.js:
--------------------------------------------------------------------------------
1 | export default {
2 | icon: '',
3 | name: {
4 | en: "Get fb User ID from url",
5 | vi: "Lấy fb User ID từ URL",
6 | },
7 | description: {
8 | en: "Get id of facebook user from entered url",
9 | vi: "Lấy id của facebook user từ URL truyền vào",
10 | },
11 |
12 | popupScript: {
13 | onClick: async function () {
14 | const { getUidFromUrl } = await import("./fb_GLOBAL.js");
15 |
16 | // Lấy UID từ url của user fb. Ví dụ: https://www.facebook.com/99.hoangtran
17 | const url = prompt("Nhập url của user fb:", "");
18 | if (url) {
19 | getUidFromUrl(url)
20 | .then((uid) => {
21 | if (uid) prompt(`UID của user ${url}:`, uid);
22 | else alert("Không tìm thấy uid của user!");
23 | })
24 | .catch((err) => alert("Lỗi: " + err.message));
25 | }
26 | },
27 | },
28 | };
29 |
--------------------------------------------------------------------------------
/scripts/fb_moreReactionStory.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Useful-Scripts-Extension/useful-script/3841517b641a602d6360cf9b43152bee2524bd7f/scripts/fb_moreReactionStory.png
--------------------------------------------------------------------------------
/scripts/fb_searchGroupForOther.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Facebook - Xem các nhóm mà bạn bè tham gia
8 |
9 |
59 |
60 |
61 |
62 | Useful script
63 | Facebook - Xem các nhóm (công khai) mà bạn bè tham gia
64 | đã tham gia ~ nhóm.
65 |
66 |
67 |
68 |
69 |
70 |
71 |
--------------------------------------------------------------------------------
/scripts/fb_searchGroupForOther.js:
--------------------------------------------------------------------------------
1 | export default {
2 | icon: '',
3 | name: {
4 | en: "Facebook - View your friends's joined groups",
5 | vi: "Facebook - Xem các nhóm bạn bè tham gia",
6 | },
7 | description: {
8 | en: "Know about your friends's joined groups (public groups) on facebook",
9 | vi: "Biết bạn bè của bạn đang tham gia các nhóm (công khai) nào trên facebook",
10 | },
11 |
12 | popupScript: {
13 | onClick: async () => {
14 | const {
15 | getUidFromUrl,
16 | getYourUserId,
17 | getFbdtsg,
18 | searchAllGroupForOther,
19 | getUserInfoFromUid,
20 | } = await import("./fb_GLOBAL.js");
21 | const { showLoading } = await import("./helpers/utils.js");
22 | let url = prompt("Nhập link facebook bạn bè (hoặc của bạn): ");
23 | if (url == null) return;
24 |
25 | let { setLoadingText, closeLoading } = showLoading("Đang chuẩn bị...");
26 | try {
27 | setLoadingText("Đang lấy uid, token...");
28 | let other_uid = await getUidFromUrl(url);
29 | let uid = await getYourUserId();
30 | let dtsg = await getFbdtsg();
31 | let info = await getUserInfoFromUid(other_uid);
32 | console.log(info);
33 |
34 | setLoadingText("Đang tải danh sách group...");
35 | let allGroups = await searchAllGroupForOther(
36 | other_uid,
37 | uid,
38 | dtsg,
39 | (groups, all) => {
40 | setLoadingText(
41 | "Đang tải danh sách group...
Tải được " +
42 | all.length +
43 | " group."
44 | );
45 | }
46 | );
47 | console.log(allGroups);
48 | localStorage.ufs_fb_searchGroupForOther = JSON.stringify(allGroups);
49 | localStorage.ufs_fb_searchGroupForOther_owner = JSON.stringify(info);
50 | window.open(
51 | chrome.runtime.getURL("scripts/fb_searchGroupForOther.html")
52 | );
53 | } catch (e) {
54 | alert("ERROR: " + e);
55 | } finally {
56 | closeLoading();
57 | }
58 | },
59 | },
60 | };
61 |
--------------------------------------------------------------------------------
/scripts/fb_searchPageForOther.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Facebook - Xem các nhóm mà bạn bè tham gia
8 |
9 |
59 |
60 |
61 |
62 | Useful script
63 | Facebook - Xem các trang (công khai) mà bạn bè thích
64 | đã thích ~ trang.
65 |
66 |
67 |
68 |
69 |
70 |
71 |
--------------------------------------------------------------------------------
/scripts/fb_searchPageForOther.js:
--------------------------------------------------------------------------------
1 | export default {
2 | icon: '',
3 | name: {
4 | en: "Facebook - View your friend's liked pages",
5 | vi: "Facebook - Xem các trang bạn bè thích",
6 | },
7 | description: {
8 | en: "Know about your friends's liked pages (public pages) on facebook",
9 | vi: "Biết bạn bè của bạn đang thích các trang (công khai) nào trên facebook",
10 | },
11 |
12 | popupScript: {
13 | onClick: async () => {
14 | const {
15 | getUidFromUrl,
16 | getYourUserId,
17 | getFbdtsg,
18 | searchAllPageForOther,
19 | getUserInfoFromUid,
20 | } = await import("./fb_GLOBAL.js");
21 | const { showLoading } = await import("./helpers/utils.js");
22 | let url = prompt("Nhập link facebook bạn bè (hoặc của bạn): ");
23 | if (url == null) return;
24 |
25 | let { setLoadingText, closeLoading } = showLoading("Đang chuẩn bị...");
26 | try {
27 | setLoadingText("Đang lấy uid, token...");
28 | let other_uid = await getUidFromUrl(url);
29 | let uid = await getYourUserId();
30 | let dtsg = await getFbdtsg();
31 | let info = await getUserInfoFromUid(other_uid);
32 | console.log(info);
33 |
34 | setLoadingText("Đang tải danh sách page...");
35 | let allPages = await searchAllPageForOther(
36 | other_uid,
37 | uid,
38 | dtsg,
39 | (pages, all, totalCount) => {
40 | setLoadingText(
41 | `Đang tải danh sách page...
Tải được ${all.length}/${totalCount} page.`
42 | );
43 | }
44 | );
45 | console.log(allPages);
46 | localStorage.ufs_fb_searchPageForOther = JSON.stringify(allPages);
47 | localStorage.ufs_fb_searchPageForOther_owner = JSON.stringify(info);
48 |
49 | window.open(
50 | chrome.runtime.getURL("scripts/fb_searchPageForOther.html")
51 | );
52 | } catch (e) {
53 | alert("ERROR: " + e);
54 | } finally {
55 | closeLoading();
56 | }
57 | },
58 | },
59 | };
60 |
--------------------------------------------------------------------------------
/scripts/fb_searchPageForOther_main.js:
--------------------------------------------------------------------------------
1 | const inputSearch = document.querySelector("#search-inp");
2 | const tableDiv = document.querySelector("table");
3 | const searchCount = document.querySelector("#searchCount");
4 | const ownerLink = document.querySelector("#owner");
5 |
6 | function numberWithCommas(x) {
7 | return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
8 | }
9 |
10 | function main() {
11 | try {
12 | let data = JSON.parse(localStorage.ufs_fb_searchPageForOther) || [];
13 | let owner =
14 | JSON.parse(localStorage.ufs_fb_searchPageForOther_owner || "{}") || {};
15 | console.log(data, owner);
16 |
17 | let link = "https://fb.com/" + owner.uid;
18 | ownerLink.innerHTML = `
19 |
20 |
21 | ${owner.name}
22 | `;
23 | searchCount.innerHTML = data.length;
24 |
25 | tableDiv.innerHTML = `
26 |
27 | STT |
28 | Ảnh |
29 | Tên |
30 |
31 | ${data
32 | .map((c, i) => {
33 | return `
34 | ${i + 1} |
35 |  |
36 |
37 | ${
38 | c.name
39 | }
40 |
41 | ${c.subTitle?.split?.("\n")?.[1] || ""}
42 | |
43 |
`;
44 | })
45 | .join("")}
46 | `;
47 |
48 | inputSearch.oninput = (e) => {
49 | search(inputSearch.value);
50 | };
51 | } catch (e) {
52 | alert("ERROR: " + e);
53 | }
54 | }
55 |
56 | function search(text) {
57 | let count = 0;
58 | [...tableDiv.querySelectorAll("tr")].forEach((tr, index) => {
59 | if (index == 0) return; // ignore table header
60 |
61 | let html = tr.innerHTML;
62 | if (!html.toLowerCase().includes(text.toLowerCase())) {
63 | tr.classList.add("hidden");
64 | } else {
65 | tr.classList.remove("hidden");
66 | count++;
67 | }
68 | });
69 | searchCount.innerHTML = count;
70 | }
71 |
72 | main();
73 |
--------------------------------------------------------------------------------
/scripts/fb_searchPostsForOther.js:
--------------------------------------------------------------------------------
1 | import { BADGES } from "./helpers/badge.js";
2 |
3 | export default {
4 | icon: '',
5 | name: {
6 | en: "Facebook - Find all posts of your friends",
7 | vi: "Facebook - Tìm mọi bài viết của bạn bè",
8 | },
9 | description: {
10 | en: "Search all public posts of your friends on facebook. Include posts in group, page, wall, ...",
11 | vi: "Tìm tất cả bài posts công khai của bạn bè trên facebook. Bao gồm bài post trong group, page, trên tường, ...",
12 | },
13 | badges: [BADGES.new],
14 | infoLink:
15 | "https://anonyviet.com/cach-tim-tat-ca-bai-viet-cua-nguoi-khac-tren-facebook/",
16 |
17 | changeLogs: {
18 | "2024-05-02": "init",
19 | },
20 |
21 | popupScript: {
22 | onClick: async () => {
23 | const { getUidFromUrl } = await import("./fb_GLOBAL.js");
24 | const { showLoading } = await import("./helpers/utils.js");
25 | let friendUrl = prompt("Nhập link fb bạn bè: ");
26 |
27 | if (friendUrl) {
28 | let keyword = prompt("Nhập từ khoá tìm kiếm: ");
29 | if (keyword == null) return;
30 |
31 | const { closeLoading } = showLoading("Đang tìm uid...");
32 | let uid = await getUidFromUrl(friendUrl);
33 | closeLoading();
34 |
35 | let str = `{"rp_author:0":"{\\"name\\":\\"author\\",\\"args\\":\\"${uid}\\"}"}`;
36 | let base64 = btoa(str);
37 | let url = `https://www.facebook.com/search/posts/?q=${encodeURI(
38 | keyword
39 | )}&filters=${encodeURI(base64)}`;
40 | window.open(url);
41 | }
42 | },
43 | },
44 | };
45 |
--------------------------------------------------------------------------------
/scripts/fb_toggleLight.js:
--------------------------------------------------------------------------------
1 | import { UfsGlobal } from "./content-scripts/ufs_global.js";
2 |
3 | export default {
4 | icon: ``,
5 | name: {
6 | en: "Turn off light facebook newfeed",
7 | vi: "Tắt đèn newfeed facebook",
8 | },
9 | description: {
10 | en:
11 | "Hide Navigator bar and complementary bar in facebook.
" +
12 | "" +
13 | "- Click to temporarily hide/show on this page.
" +
14 | "- Enable autorun to auto hide whenever open facebook.
" +
15 | "
",
16 | vi:
17 | "Ẩn giao diện 2 bên newfeed, giúp tập trung vào newfeed facebook.
" +
18 | "" +
19 | "- Click để ẩn/hiện tạm thời trong trang hiện tại.
" +
20 | "- Bật tự chạy để tự động ẩn mỗi khi mở facebook.
" +
21 | "
",
22 | },
23 | changeLogs: {
24 | "2024-05-19": "fix auto hide",
25 | },
26 |
27 | whiteList: ["https://*.facebook.com/*"],
28 |
29 | contentScript: {
30 | onDocumentIdle: () => {
31 | UfsGlobal.DOM.onElementsAdded(
32 | '[role="navigation"], [role="complementary"]',
33 | () => {
34 | [
35 | document.querySelectorAll('[role="navigation"]')?.[2],
36 | document.querySelectorAll('[role="complementary"]')?.[0],
37 | ].forEach((el) => {
38 | if (el) {
39 | el.style.display = "none";
40 | } else console.log("ERROR: Cannot find element");
41 | });
42 | }
43 | );
44 | },
45 |
46 | onClick: function () {
47 | [
48 | document.querySelectorAll('[role="navigation"]')?.[2],
49 | document.querySelectorAll('[role="complementary"]')?.[0],
50 | ].forEach((el) => {
51 | if (el) {
52 | el.style.display = el.style.display != "none" ? "none" : "";
53 | } else console.log("ERROR: Cannot find element");
54 | });
55 | },
56 | },
57 | };
58 |
--------------------------------------------------------------------------------
/scripts/fb_toggleNewFeed.js:
--------------------------------------------------------------------------------
1 | import { UfsGlobal } from "./content-scripts/ufs_global.js";
2 |
3 | export default {
4 | icon: '',
5 | name: {
6 | en: "Hide facebook new feed",
7 | vi: "Ẩn dòng thời gian facebook",
8 | },
9 | description: {
10 | en: "Hide facebook new feed (home page) for better focus to work",
11 | vi: "Ẩn dòng thời gian facebook (trang chủ) để tập trung làm việc",
12 | },
13 | infoLink:
14 | "https://www.facebook.com/groups/j2team.community/posts/1919935575005220/",
15 | whiteList: ["https://*.facebook.com/*"],
16 |
17 | contentScript: {
18 | onDocumentStart: () => {
19 | UfsGlobal.DOM.onElementsAdded("[role='feed'], [role='main']", (nodes) =>
20 | Array.from(nodes).forEach((node) => (node.style.display = "none"))
21 | );
22 | },
23 |
24 | onClick: async function () {
25 | [
26 | ...Array.from(
27 | document.querySelectorAll("[role='feed'], [role='main']")
28 | ),
29 | // document.querySelector("#watch_feed"),
30 | // document.querySelector("#ssrb_stories_start")?.parentElement,
31 | // document.querySelector("#ssrb_feed_start")?.parentElement,
32 | ].forEach((el) => {
33 | if (el) {
34 | el.style.display = el.style.display === "none" ? "" : "none";
35 | } else console.log("ERROR: Cannot find element");
36 | });
37 | },
38 | },
39 | };
40 |
--------------------------------------------------------------------------------
/scripts/fb_whoIsTyping.css:
--------------------------------------------------------------------------------
1 | #ufs-who-is-typing {
2 | position: fixed;
3 | top: 50px;
4 | left: 50px;
5 | max-height: calc(100vh - 100px);
6 | overflow: auto;
7 | background-color: #fff;
8 | border-radius: 3px;
9 | z-index: 99999;
10 | }
11 |
12 | #ufs-who-is-typing.collapsed .ufs-noti-item {
13 | display: none;
14 | }
15 |
16 | #ufs-who-is-typing .ufs-header {
17 | position: sticky;
18 | top: 0;
19 | z-index: 2;
20 | }
21 |
22 | #ufs-who-is-typing .ufs-header button {
23 | float: right;
24 | display: inline-block;
25 | font-size: 20px;
26 | line-height: 15px;
27 | cursor: pointer;
28 | }
29 |
30 | #ufs-who-is-typing .ufs-noti-item {
31 | position: relative;
32 | padding: 5px;
33 | margin: 10px;
34 | font-size: 1.3em;
35 | background-color: #f1f1f1;
36 | }
37 |
38 | #ufs-who-is-typing .ufs-close-btn {
39 | position: absolute;
40 | top: 5px;
41 | right: 5px;
42 | font-size: 12px;
43 | color: #fff;
44 | background-color: #d92e2e;
45 | border: none;
46 | cursor: pointer;
47 | border-radius: 3px;
48 | }
49 |
50 | #ufs-who-is-typing .ufs-avatar {
51 | width: 60px;
52 | height: 60px;
53 | border-radius: 5px;
54 | float: left;
55 | margin-right: 10px;
56 | border-radius: 50%;
57 | box-shadow: inset 0 0 0 1px #181a1b0d;
58 | }
59 |
60 | #ufs-who-is-typing .ufs-content p {
61 | padding: 0;
62 | margin: 0;
63 | }
64 |
65 | .clearfix::after {
66 | content: "";
67 | clear: both;
68 | display: table;
69 | }
--------------------------------------------------------------------------------
/scripts/getAllEmailsInWeb.js:
--------------------------------------------------------------------------------
1 | export default {
2 | icon: ``,
3 | name: {
4 | en: "Extract all Emails from website",
5 | vi: "Trích xuất mọi emails từ trang web",
6 | },
7 | description: {
8 | en: "Extracts all emails and displays them in a popup iFrame (enable popups!)",
9 | vi: "Trích xuất tất cả emails trong web và hiện trong popup mới",
10 | },
11 |
12 | changeLogs: {
13 | "2024-05-20": "remove duplicate emails",
14 | },
15 |
16 | contentScript: {
17 | onClick: function () {
18 | // source code from: https://bookmarklet.vercel.app/
19 |
20 | let StrObj = document.body.innerHTML;
21 | let haystack = StrObj.toString();
22 | let regex =
23 | /(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])/g;
24 | let found = haystack.match(regex);
25 | if (found !== null && found !== "") {
26 | let mailz = Array.from(new Set(found)).join("\r\n
");
27 | let w = window.open(
28 | "",
29 | "mailz",
30 | "scrollbars,resizable,width=400,height=600"
31 | );
32 | w.document.write(mailz);
33 | } else {
34 | alert("No emails found on page");
35 | }
36 | },
37 | },
38 | };
39 |
--------------------------------------------------------------------------------
/scripts/getWindowSize.js:
--------------------------------------------------------------------------------
1 | export default {
2 | icon: ``,
3 | name: {
4 | en: "Get window size",
5 | vi: "Lấy kích thước trang web",
6 | },
7 | description: {
8 | en: "Alerts the width and height in pixels of the inner window.",
9 | vi: "đơn vị pixels",
10 | },
11 |
12 | contentScript: {
13 | onClick: function () {
14 | alert(
15 | `Window inner dimensions:\n
16 | website: ${window.innerWidth} x ${window.innerHeight}
17 | your screen: ${screen.width} x ${screen.height}`
18 | );
19 | },
20 | },
21 | };
22 |
--------------------------------------------------------------------------------
/scripts/ggdrive_copySheetText.js:
--------------------------------------------------------------------------------
1 | export default {
2 | icon: "https://drive-thirdparty.googleusercontent.com/32/type/application/vnd.google-apps.spreadsheet",
3 | name: {
4 | en: "GG Drive - Download Sheet (copy Text)",
5 | vi: "GG Drive - Tải Sheet (copy nội dung)",
6 | },
7 | description: {
8 | en: "Copy google drive sheet (excel) that dont have download button (Just copy text, can't copy formula)",
9 | vi: "Copy nội dung file sheet (excel) không có nút tải xuống (Chỉ copy text, không copy được công thức)",
10 | },
11 |
12 | whiteList: ["https://docs.google.com/spreadsheets/*"],
13 |
14 | contentScript: {
15 | onClick: () => {
16 | let url = location.href;
17 | window.open(url.replace("/edit", "/preview"));
18 | },
19 | },
20 | };
21 |
--------------------------------------------------------------------------------
/scripts/ggdrive_downloadPresentation.js:
--------------------------------------------------------------------------------
1 | export default {
2 | icon: "https://drive-thirdparty.googleusercontent.com/32/type/application/vnd.openxmlformats-officedocument.presentationml.presentation",
3 | name: {
4 | en: "GG Drive - Download PowerPoint (Slides/Presentation)",
5 | vi: "GG Drive - Tải PowerPoint (Slides)",
6 | },
7 | description: {
8 | en: "Download google drive Presentation file that dont have download button, covert to HTML file.",
9 | vi: "Tải file Powerpoint (Slides) không có nút download trên google drive, tải về định dạng HTML.",
10 | },
11 |
12 | whiteList: ["https://docs.google.com/presentation/*"],
13 |
14 | popupScript: {
15 | onClick: async () => {
16 | const { t } = await import("../popup/helpers/lang.js");
17 | const { getCurrentTab, openWebAndRunScript } = await import(
18 | "./helpers/utils.js"
19 | );
20 | let tab = await getCurrentTab();
21 | let { url, title } = tab;
22 |
23 | let guide = t({
24 | vi: "Sử dụng chức năng\nTự động > In web ra PDF hoặc\nTự động > Chụp ảnh toàn bộ web\nđể tải slides nhé.",
25 | en: "Please use feature\nAutomation > Screenshot full page OR\nAutomation > Web to PDF\nto download this slides",
26 | });
27 |
28 | if (url.includes("/htmlpresent")) {
29 | alert(guide);
30 | } else {
31 | url = prompt(
32 | t({
33 | vi: "Nhập link file powerpoint (slide) google drive: \nĐịnh dạng: https://docs.google.com/presentation/*",
34 | en: "Enter google drive presentation url: \nFormat: https://docs.google.com/presentation/*",
35 | }),
36 | url
37 | );
38 | if (!url) return;
39 |
40 | let id = /d\/([^\/]+)\/?/.exec(url)?.[1];
41 | if (!id) {
42 | alert(
43 | t({
44 | vi: "Không tìm được id file trên url",
45 | en: "Can not find file id in url",
46 | })
47 | );
48 | return;
49 | }
50 |
51 | openWebAndRunScript({
52 | url: "https://docs.google.com/presentation/d/" + id + "/htmlpresent",
53 | func: async (guide) => {
54 | window.onload = alert(guide);
55 | },
56 | args: [guide],
57 | focusImmediately: true,
58 | waitUntilLoadEnd: false,
59 | });
60 | }
61 | },
62 | },
63 | };
64 |
--------------------------------------------------------------------------------
/scripts/ggdrive_generateDirectLink.js:
--------------------------------------------------------------------------------
1 | export default {
2 | icon: "https://drive.google.com/favicon.ico",
3 | name: {
4 | en: "Google drive - generate direct link",
5 | vi: "Google drive - tạo link tải ngay",
6 | },
7 | description: {
8 | en: "Generate a direct download link to files stored in Google Drive. A direct link will immediately start downloading the file.",
9 | vi: "Tạo đường link direct cho file trên google drive. Bấm vào đường link sẽ tải file trực tiếp thay vì mở trang xem trước file.",
10 | },
11 |
12 | popupScript: {
13 | onClick: async function () {
14 | const { getCurrentTab } = await import("./helpers/utils.js");
15 | try {
16 | let tab = await getCurrentTab();
17 | let url = prompt("Nhập link google drive: ", tab.url);
18 | if (url == null) return;
19 |
20 | let directLink = await shared.generateDirectLinkFromUrl(url);
21 | if (directLink) window.open(directLink);
22 | } catch (e) {
23 | alert("ERROR: " + e);
24 | }
25 | },
26 | },
27 | };
28 |
29 | export const shared = {
30 | generateDirectLinkFromUrl: async function (url) {
31 | const { shared: ggdrive_downloadVideo } = await import(
32 | "./ggdrive_downloadVideo.js"
33 | );
34 | let docId = ggdrive_downloadVideo.getDocIdFromUrl(url);
35 | if (!docId)
36 | throw Error("Link không hợp lệ. Không tìm được docId trong link.");
37 | return shared.generateDirectLink(docId);
38 | },
39 | generateDirectLink: function (docId) {
40 | return "https://drive.google.com/uc?export=download&id=" + docId;
41 | },
42 | };
43 |
--------------------------------------------------------------------------------
/scripts/github1s.js:
--------------------------------------------------------------------------------
1 | export default {
2 | icon: ``,
3 | name: {
4 | en: "Github - Open repo in github1s.com",
5 | vi: "Github - Mở repo trong github1s.com",
6 | },
7 | description: {
8 | en: "Open current repo in github1s.com",
9 | vi: "Mở repo hiện tại trong trang github1s.com để xem code",
10 | },
11 | whiteList: ["https://github.com/*"],
12 |
13 | contentScript: {
14 | onClick: function () {
15 | window.open("https://www.github1s.com" + location.pathname);
16 | },
17 | },
18 | };
19 |
--------------------------------------------------------------------------------
/scripts/github_HTMLPreview.js:
--------------------------------------------------------------------------------
1 | export default {
2 | icon: '',
3 | name: {
4 | en: "Github - HTML preview",
5 | vi: "Github - xem trước file HTML",
6 | },
7 | description: {
8 | en: "Preview github's HTML file in any repo without download code.",
9 | vi: "Xem trước giao diện file HTML trên bất kỳ repo github nào mà không cần tải code về.",
10 | },
11 | changeLogs: {
12 | "2024-06-14": "init",
13 | },
14 |
15 | whiteList: ["https://github.com/*", "https://bitbucket.org/*"],
16 |
17 | contentScript: {
18 | onClick: () => {
19 | window.open("https://htmlpreview.github.io/?" + location.href);
20 | },
21 | },
22 | };
23 |
--------------------------------------------------------------------------------
/scripts/github_openRepoPages.js:
--------------------------------------------------------------------------------
1 | import { getRepoNameFromUrl } from "./github_goToAnyCommit.js";
2 |
3 | export default {
4 | icon: '',
5 | name: {
6 | en: "Github - Open repo pages",
7 | vi: "Github - Mở repo pages",
8 | },
9 | description: {
10 | en: `Switch between github.com repo and github.io live demo pages
11 | username.github.io/repo
12 | github.com/username/repo
`,
13 | vi: `Chuyển đổi giữa trang github.com repo và github.io demo pages
14 | username.github.io/repo
15 | github.com/username/repo
`,
16 | },
17 | changeLogs: {
18 | "2024-06-03": "init",
19 | },
20 |
21 | whiteList: ["https://github.com/*/*", "https://*.github.io/*"],
22 |
23 | popupScript: {
24 | onClick: async () => {
25 | try {
26 | const { getCurrentTab } = await import("./helpers/utils.js");
27 | let tab = await getCurrentTab();
28 | let url = new URL(tab.url);
29 |
30 | if (url.hostname === "github.com") {
31 | let repoName = getRepoNameFromUrl(url.href);
32 | let [user, repo] = repoName?.split("/") || [];
33 | if (user && repo) window.open(`https://${user}.github.io/${repo}`);
34 | else throw Error(`URL not valid: user: ${user}, repo: ${repo}`);
35 | } else if (url.hostname.includes(".github.io")) {
36 | let user = url.hostname.split(".")[0];
37 | let repo = url.pathname.slice(1) || user + ".github.com";
38 | if (user) window.open(`https://github.com/${user}/${repo}`);
39 | else throw Error(`URL not valid: user: ${user}, repo: ${repo}`);
40 | }
41 | } catch (e) {
42 | alert("Error: " + e);
43 | }
44 | },
45 | },
46 | };
47 |
--------------------------------------------------------------------------------
/scripts/githubdev.js:
--------------------------------------------------------------------------------
1 | export default {
2 | icon: ``,
3 | name: {
4 | en: "Github - Open repo in github.dev",
5 | vi: "Github - Mở repo trong github.dev",
6 | },
7 | description: {
8 | en:
9 | "Open current repo in github.dev
" +
10 | "Tip
Press dot (.) when in github repo to open github.dev",
11 | vi:
12 | "Mở repo hiện tại trong trang github.dev để xem code
" +
13 | "Mẹo
Bấm dấu chấm (.) để mở repo github trong github.dev",
14 | },
15 |
16 | changeLogs: {
17 | "2024-04-27": "add tips",
18 | },
19 |
20 | whiteList: ["https://github.com/*"],
21 |
22 | contentScript: {
23 | onClick: function () {
24 | window.open("https://github.dev" + location.pathname);
25 | },
26 | },
27 | };
28 |
--------------------------------------------------------------------------------
/scripts/googleCache.js:
--------------------------------------------------------------------------------
1 | export default {
2 | // icon get from https://chrome.google.com/webstore/detail/google-cache-viewer/fgfklknfijhflahngajfoagmoilakebp
3 | icon: "https://lh3.googleusercontent.com/OoZ3sM4u01hfT9201pmeBasLOsaRlZe2CbXzcXQLBYOcgpKVDPEakpr_ZHxiXQ1IkQ5dYTvEYndU0m8RH7TOhb1H=w128-h128-e365-rj-sc0x00ffffff",
4 | name: {
5 | en: "View Google cache of website",
6 | vi: "Xem Google cache của trang web",
7 | },
8 | description: {
9 | en: "View blocked website",
10 | vi: "Phù hơp để xem các trang web bị block",
11 | },
12 |
13 | popupScript: {
14 | onClick: async function () {
15 | const { getCurrentTab } = await import("./helpers/utils.js");
16 | // https://cachedviews.com/
17 |
18 | let { url } = await getCurrentTab();
19 | let url_to_check = prompt(
20 | "Nhập URL muốn xem cache: ",
21 | url.replace(/^http\:\/\/(.*)$/, "$1")
22 | );
23 | if (url_to_check != null) {
24 | window.open(
25 | "http://www.google.com/search?q=cache:" +
26 | encodeURIComponent(url_to_check)
27 | );
28 | }
29 | },
30 | },
31 | };
32 |
--------------------------------------------------------------------------------
/scripts/googleShortcuts.js:
--------------------------------------------------------------------------------
1 | const URLs = [
2 | ["Google Doc ", "https://doc.new", "google_doc"],
3 | ["Google Sheet ", "https://sheet.new", "google_sheet"],
4 | ["Google Slide ", "https://slide.new", "google_slide"],
5 | ["Google Form ", "https://form.new", "google_form"],
6 | ["Google Site ", "https://site.new", "google_site"],
7 | ["Google Keep ", "https://keep.new", "google_keep"],
8 | ["Google Calendar", "https://calendar.new", "google_calendar"],
9 | ];
10 |
11 | export default {
12 | icon: '',
13 | name: {
14 | en: "Google shortcuts",
15 | vi: "Google phím tắt",
16 | },
17 | description: {
18 | en: "Create new google doc/sheet/slide/form/site/keep/calendar",
19 | vi: "Tạo mới google doc/sheet/slide/form/site/keep/calendar",
20 | },
21 |
22 | popupScript: {
23 | onClick: function () {
24 | let option = prompt(
25 | "Create new:\n\n" +
26 | URLs.map(
27 | ([name, url, id], index) => `- ${index}: ${name} (${url})\n`
28 | ).join(""),
29 | 0
30 | );
31 |
32 | if (option != undefined && option >= 0 && option < URLs.length) {
33 | window.open(URLs[option][1]);
34 | }
35 | },
36 | },
37 |
38 | backgroundScript: {
39 | runtime: {
40 | onInstalled: () => {
41 | const folder_id = "google-shortcuts";
42 | [
43 | {
44 | id: folder_id,
45 | title: "Google Shortcuts",
46 | type: "normal",
47 | parentId: "root",
48 | },
49 | ...URLs.map(([name, url, id], index) => ({
50 | id: id,
51 | title: name,
52 | type: "normal",
53 | parentId: folder_id,
54 | })),
55 | ].forEach((item) => {
56 | chrome.contextMenus.create(item);
57 | });
58 | },
59 | },
60 | contextMenus: {
61 | onClicked: ({ info, tab }, context) => {
62 | let item = URLs.find(([name, url, id]) => id == info.menuItemId);
63 | if (item) {
64 | chrome.tabs.create({
65 | url: item[1],
66 | active: true,
67 | });
68 | }
69 | },
70 | },
71 | },
72 | };
73 |
--------------------------------------------------------------------------------
/scripts/google_downloadAllYourData.js:
--------------------------------------------------------------------------------
1 | export default {
2 | icon: "https://www.google.com/favicon.ico",
3 | name: {
4 | en: "Google - Download all your data",
5 | vi: "Google - Tải xuống dữ liệu của bạn",
6 | },
7 | description: {
8 | en: "Download all your data on Google",
9 | vi: "Tải xuống thông tin của bạn trên Google",
10 | },
11 |
12 | popupScript: {
13 | onClick: () => window.open("https://takeout.google.com/settings/takeout"),
14 | },
15 | };
16 |
--------------------------------------------------------------------------------
/scripts/google_mirror.js:
--------------------------------------------------------------------------------
1 | export default {
2 | icon: "https://elgoog.im/favicon.ico",
3 | name: {
4 | en: "Google mirror - I'm elgooG",
5 | vi: "Google mirror - I'm elgooG",
6 | },
7 | description: {
8 | en: "Google games. We create, restore, and discover interactive Google Easter Eggs. Just click and play them online for free.",
9 | vi: "Chơi các trò chơi (minigame) từng có trên google tìm kiếm",
10 | },
11 |
12 | contentScript: {
13 | onClick: () => window.open("https://elgoog.im/"),
14 | },
15 | };
16 |
--------------------------------------------------------------------------------
/scripts/guland_VIP.js:
--------------------------------------------------------------------------------
1 | import { UfsGlobal } from "./content-scripts/ufs_global.js";
2 | import { BADGES } from "./helpers/badge.js";
3 |
4 | export default {
5 | icon: "https://guland.vn/bds/img/apple-touch-icon.png",
6 | name: {
7 | en: "Guland VIP",
8 | vi: "Guland VIP - Xem quy hoạch đất",
9 | },
10 | description: {
11 | en: "VIP for Guland.vn, view map without restriction",
12 | vi: "Xem quy hoạch đất không bị làm phiền bởi popup vip tại Guland.vn",
13 | img: "/scripts/guland_VIP.png",
14 | },
15 | badges: [BADGES.new],
16 | infoLink: "https://guland.vn",
17 | changeLogs: {
18 | "2024-07-14": "init",
19 | },
20 | whiteList: ["https://guland.vn/*"],
21 |
22 | contentScript: {
23 | onDocumentStart: (details) => {
24 | UfsGlobal.DOM.deleteElements(".modal-backdrop");
25 | UfsGlobal.DOM.deleteElements("#Modal-NotificationWithButton");
26 | },
27 | },
28 | };
29 |
--------------------------------------------------------------------------------
/scripts/guland_VIP.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Useful-Scripts-Extension/useful-script/3841517b641a602d6360cf9b43152bee2524bd7f/scripts/guland_VIP.png
--------------------------------------------------------------------------------
/scripts/helpers/badge.js:
--------------------------------------------------------------------------------
1 | export const BADGES = {
2 | hot: "hot",
3 | beta: "beta",
4 | new: "new",
5 | recommend: "recommend",
6 | comingSoon: "comingSoon",
7 | };
8 |
9 | export const BADGES_CONFIG = {
10 | [BADGES.hot]: {
11 | text: {
12 | en: 'hot ',
13 | vi: 'xịn xò ',
14 | },
15 | color: "#fff",
16 | backgroundColor: "#d40",
17 | },
18 | [BADGES.beta]: {
19 | text: { en: "beta", vi: "chưa ổn định" },
20 | color: "#000",
21 | backgroundColor: "#dd0",
22 | },
23 | [BADGES.new]: {
24 | text: { en: "new", vi: "mới" },
25 | color: "#fff",
26 | backgroundColor: "#44d",
27 | },
28 | [BADGES.recommend]: {
29 | text: {
30 | en: "suggest",
31 | vi: "gợi ý",
32 | },
33 | color: "#fff",
34 | backgroundColor: "#0a0",
35 | },
36 | [BADGES.comingSoon]: {
37 | text: {
38 | en: "coming soon",
39 | vi: "đang phát triển",
40 | },
41 | color: "#fff",
42 | backgroundColor: "#666",
43 | },
44 | };
45 |
--------------------------------------------------------------------------------
/scripts/helpers/constants.js:
--------------------------------------------------------------------------------
1 | export const AccessToken = {
2 | FacebookIphone: "6628568379%7Cc1e620fa708a1d5696fb991c1bde5662",
3 | };
4 |
--------------------------------------------------------------------------------
/scripts/helpers/predefined_css.js:
--------------------------------------------------------------------------------
1 | // W3 table css
2 | // https://www.w3schools.com/css/css_table.asp
3 | export const getTableStyle = (selector = "table") => `
4 | ${selector} {
5 | font-family: Arial, Helvetica, sans-serif;
6 | border-collapse: collapse;
7 | width: 100%;
8 | }
9 | ${selector} td, ${selector} th {
10 | border: 1px solid #ddd;
11 | padding: 8px;
12 | }
13 | ${selector} tr:nth-child(even){ background-color: #f2f2f2; }
14 | ${selector} tr:hover { background-color: #ddd; }
15 | ${selector} th {
16 | padding-top: 12px;
17 | padding-bottom: 12px;
18 | text-align: left;
19 | background-color: #04AA6D;
20 | color: white;
21 | }`;
22 |
--------------------------------------------------------------------------------
/scripts/injectScriptToWebsite.js:
--------------------------------------------------------------------------------
1 | import { UfsGlobal } from "./content-scripts/ufs_global.js";
2 |
3 | export default {
4 | icon: '',
5 | name: {
6 | en: "Inject script to website",
7 | vi: "Nhúng script vào trang web",
8 | },
9 | description: {
10 | en: "Inject script url to current website, eg. jquery, library, etc.",
11 | vi: "Nhúng link script vào website, ví dụ nhúng jquery, thư viện js, ...",
12 | },
13 |
14 | pageScript: {
15 | onClick: function () {
16 | let url = prompt(
17 | "Enter script url / Nhập link script: ",
18 | "//code.jquery.com/jquery-3.6.1.min.js"
19 | );
20 |
21 | if (url) {
22 | UfsGlobal.DOM.injectScriptSrc(url, (success, error) => {
23 | if (success) {
24 | alert("Inject SUCCESS.\n\n" + url);
25 | } else {
26 | alert("Inject FAILED.\n\n" + JSON.stringify(error));
27 | }
28 | });
29 | }
30 | },
31 | },
32 | };
33 |
34 | function backup() {
35 | // https://stackoverflow.com/a/38840724/11898496
36 | // Script loader: https://plnkr.co/edit/b9O19f?p=preview&preview
37 | }
38 |
--------------------------------------------------------------------------------
/scripts/insta_anonymousStoryViewer.js:
--------------------------------------------------------------------------------
1 | import { UfsGlobal } from "./content-scripts/ufs_global.js";
2 | import { hookXHR } from "./libs/ajax-hook/index.js";
3 |
4 | export default {
5 | icon: '',
6 | name: {
7 | en: "Insta - Anonymous story viewer",
8 | vi: "Insta - Xem story ẩn danh",
9 | },
10 | description: {
11 | en: "Watch instagram stories anonymously",
12 | vi: "Xem story instagram không bị đối phương phát hiện",
13 | },
14 | infoLink:
15 | "https://greasyfork.org/en/scripts/468385-instagram-anonymous-story-viewer",
16 |
17 | changeLogs: {
18 | "2024-04-15": "init",
19 | },
20 |
21 | whiteList: ["*://www.instagram.com/*"],
22 |
23 | pageScript: {
24 | onDocumentStart: () => {
25 | hookXHR({
26 | onBeforeSend: ({ method, url, async, user, password }, dataSend) => {
27 | let s = dataSend?.toString() || "";
28 | if (s.includes("viewSeenAt") || s.includes("SeenMutation")) {
29 | UfsGlobal.DOM.notify({
30 | msg: "Useful-script: Blocked story view tracking",
31 | });
32 | return null;
33 | }
34 | },
35 | });
36 | },
37 |
38 | onDocumentEnd: () => {
39 | UfsGlobal.DOM.notify({
40 | msg: "Useful-script: Blocked story view tracking READY",
41 | });
42 | },
43 | },
44 | };
45 |
--------------------------------------------------------------------------------
/scripts/insta_injectDownloadBtn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Useful-Scripts-Extension/useful-script/3841517b641a602d6360cf9b43152bee2524bd7f/scripts/insta_injectDownloadBtn.png
--------------------------------------------------------------------------------
/scripts/internalOrExternalLink.js:
--------------------------------------------------------------------------------
1 | export default {
2 | icon: ``,
3 | name: {
4 | en: "Highlight internal/external link",
5 | vi: "Tô màu cho link",
6 | },
7 | description: {
8 | en: "+Red = Internal_link\n+Orange = Currently_opened_link\n+Blue = External_link",
9 | vi: "+Đỏ: cùng domain\n+Cam: hiện tại\n+Xanh: khác domain",
10 | },
11 |
12 | contentScript: {
13 | onClick: function () {
14 | var i, x;
15 | for (i = 0; (x = document.links[i]); ++i)
16 | x.style.color = ["blue", "red", "orange"][sim(x, location)];
17 |
18 | function sim(a, b) {
19 | if (a.hostname != b.hostname) return 0;
20 | if (fixPath(a.pathname) != fixPath(b.pathname) || a.search != b.search)
21 | return 1;
22 | return 2;
23 | }
24 |
25 | function fixPath(p) {
26 | p = (p.charAt(0) == "/" ? "" : "/") + p; /*many browsers*/
27 | p = p.split("?")[0]; /*opera*/
28 | return p;
29 | }
30 | },
31 | },
32 | };
33 |
--------------------------------------------------------------------------------
/scripts/internet_archive.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Useful-Scripts-Extension/useful-script/3841517b641a602d6360cf9b43152bee2524bd7f/scripts/internet_archive.png
--------------------------------------------------------------------------------
/scripts/letItSnow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Useful-Scripts-Extension/useful-script/3841517b641a602d6360cf9b43152bee2524bd7f/scripts/letItSnow.png
--------------------------------------------------------------------------------
/scripts/libs/mqtt-packet/README.md:
--------------------------------------------------------------------------------
1 | # minified version of
2 |
--------------------------------------------------------------------------------
/scripts/libs/utils/attrObserver.js:
--------------------------------------------------------------------------------
1 | import { ready } from "./ready.js";
2 |
3 | /**
4 | * DOM object property listener
5 | * @param selector {String|Element} - required. It can be a selector or an existing DOM object. If it is a selector, ready will be called to monitor.
6 | * @param fn {Function} - required The callback function when the attribute changes
7 | * @param attrFilter {String|Array} -optional specifies the attributes to be monitored. If not specified, all attribute changes will be monitored.
8 | * @param shadowRoot
9 | */
10 | export function attrObserver(selector, fn, attrFilter, shadowRoot) {
11 | if (!selector || !fn) return false;
12 | function _attrObserver(element) {
13 | const MutationObserver =
14 | window.MutationObserver || window.WebKitMutationObserver;
15 | const observer = new MutationObserver(fn);
16 | const observeOpts = {
17 | attributes: true,
18 | attributeOldValue: true,
19 | };
20 |
21 | if (attrFilter) {
22 | attrFilter = Array.isArray(attrFilter) ? attrFilter : [attrFilter];
23 | observeOpts.attributeFilter = attrFilter;
24 | }
25 |
26 | observer.observe(element, observeOpts);
27 | }
28 |
29 | if (typeof selector === "string" || Array.isArray(selector)) {
30 | ready(selector, (element) => _attrObserver(element), shadowRoot);
31 | } else if (/Element/.test(Object.prototype.toString.call(selector))) {
32 | _attrObserver(selector);
33 | } else {
34 | return false;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/scripts/libs/utils/device.js:
--------------------------------------------------------------------------------
1 | export const device = {
2 | isMobile: () => {
3 | return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
4 | navigator.userAgent
5 | );
6 | },
7 | isTablet: () => {
8 | return /iPad/i.test(navigator.userAgent);
9 | },
10 | isDesktop: () => {
11 | return !device.isMobile() && !device.isTablet();
12 | },
13 | isChrome: () => {
14 | return /Chrome/i.test(navigator.userAgent);
15 | },
16 | isFirefox: () => {
17 | return /Firefox/i.test(navigator.userAgent);
18 | },
19 | isSafari: () => {
20 | return /Safari/i.test(navigator.userAgent);
21 | },
22 | isEdge: () => {
23 | return /Edge/i.test(navigator.userAgent);
24 | },
25 | };
26 |
--------------------------------------------------------------------------------
/scripts/libs/utils/fakeUA.js:
--------------------------------------------------------------------------------
1 | /* ua information disguise */
2 | export function fakeUA(ua) {
3 | // Object.defineProperty(navigator, 'userAgent', {
4 | // value: ua,
5 | // writable: false,
6 | // configurable: false,
7 | // enumerable: true
8 | // })
9 |
10 | const desc = Object.getOwnPropertyDescriptor(
11 | Navigator.prototype,
12 | "userAgent"
13 | );
14 | Object.defineProperty(Navigator.prototype, "userAgent", {
15 | ...desc,
16 | get: function () {
17 | return ua;
18 | },
19 | });
20 | }
21 |
22 | /* ua information source: https://developers.whatismybrowser.com */
23 | export const userAgentMap = {
24 | android: {
25 | chrome:
26 | "Mozilla/5.0 (Linux; Android 9; SM-G960F Build/PPR1.180610.011; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/74.0.3729.157 Mobile Safari/537.36",
27 | firefox:
28 | "Mozilla/5.0 (Android 7.0; Mobile; rv:57.0) Gecko/57.0 Firefox/57.0",
29 | },
30 | iPhone: {
31 | safari:
32 | "Mozilla/5.0 (iPhone; CPU iPhone OS 13_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/111.0.0.0 Mobile/15E148 Safari/604.1",
33 | chrome:
34 | "Mozilla/5.0 (iPhone; CPU iPhone OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/74.0.3729.121 Mobile/15E148 Safari/605.1",
35 | },
36 | iPad: {
37 | safari:
38 | "Mozilla/5.0 (iPad; CPU OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.1 Mobile/15E148 Safari/604.1",
39 | chrome:
40 | "Mozilla/5.0 (iPad; CPU OS 12_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/74.0.3729.155 Mobile/15E148 Safari/605.1",
41 | },
42 | mac: {
43 | safari:
44 | "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.1.1 Safari/605.1.15",
45 | chrome:
46 | "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Firefox) Chrome/74.0.3729.157 Safari/537.36",
47 | },
48 | };
49 |
--------------------------------------------------------------------------------
/scripts/libs/utils/hackAttachShadow.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Some web pages use attachShadow closed mode and need to be open to obtain the video tag, such as Baidu Cloud Disk
3 | * Solution reference:
4 | * https://developers.google.com/web/fundamentals/web-components/shadowdom?hl=zh-cn#closed
5 | * https://stackoverflow.com/questions/54954383/override-element-prototype-attachshadow-using-chrome-extension
6 | */
7 | export function hackAttachShadow() {
8 | if (window._hasHackAttachShadow_) return;
9 | try {
10 | window._shadowDomList_ = [];
11 | window.Element.prototype._attachShadow =
12 | window.Element.prototype.attachShadow;
13 | window.Element.prototype.attachShadow = function () {
14 | const arg = arguments;
15 | if (arg[0] && arg[0].mode) {
16 | // Force open mode
17 | arg[0].mode = "open";
18 | }
19 | const shadowRoot = this._attachShadow.apply(this, arg);
20 | // Save a copy of shadowDomList
21 | window._shadowDomList_.push(shadowRoot);
22 |
23 | /* Allow elements inside shadowRoot to have access to shadowHost */
24 | shadowRoot._shadowHost = this;
25 |
26 | // Add the addShadowRoot custom event below the document
27 | const shadowEvent = new window.CustomEvent("addShadowRoot", {
28 | shadowRoot,
29 | detail: {
30 | shadowRoot,
31 | message: "addShadowRoot",
32 | time: new Date(),
33 | },
34 | bubbles: true,
35 | cancelable: true,
36 | });
37 | document.dispatchEvent(shadowEvent);
38 |
39 | return shadowRoot;
40 | };
41 | window._hasHackAttachShadow_ = true;
42 | } catch (e) {
43 | console.error("hackAttachShadow error by h5player plug-in", e);
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/scripts/libs/utils/html.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Some websites enable CSP, which will prevent innerHTML from being used, so trustedTypes needs to be used.
3 | * https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/trusted-types
4 | * @param { String } htmlString - required HTML string
5 | * @returns
6 | */
7 | export function createTrustedHTML(htmlString) {
8 | if (window.trustedTypes && window.trustedTypes.createPolicy) {
9 | /* Before creating the default policy, check whether it already exists. */
10 | let policy = window.trustedTypes.defaultPolicy || null;
11 | if (!policy) {
12 | policy = window.trustedTypes.createPolicy("default", {
13 | createHTML: (string) => string,
14 | });
15 | }
16 |
17 | const trustedHTML = policy.createHTML(htmlString);
18 |
19 | return trustedHTML;
20 | } else {
21 | return htmlString;
22 | }
23 | }
24 |
25 | /**
26 | * Parse HTML string and return DOM node array
27 | * @param { String } -required htmlString HTML string
28 | * @param { HTMLElement } - optional targetElement target element, if passed in, the parsed node will be added to this element
29 | * @returns {Array} DOM node array
30 | */
31 | export function parseHTML(htmlString, targetElement) {
32 | if (typeof htmlString !== "string") {
33 | throw new Error("[parseHTML] Input must be a string");
34 | }
35 |
36 | const trustedHTML = createTrustedHTML(htmlString);
37 |
38 | const parser = new DOMParser();
39 | const doc = parser.parseFromString(trustedHTML, "text/html");
40 | const nodes = doc.body.childNodes;
41 | const result = [];
42 |
43 | if (targetElement && targetElement.appendChild) {
44 | nodes.forEach((node) => {
45 | const targetNode = node.cloneNode(true);
46 | try {
47 | /* Some websites will rewrite appendChild due to business needs, which may cause appendChild to report an error, so try catch is needed here. */
48 | targetElement.appendChild(targetNode);
49 | } catch (e) {
50 | console.error(
51 | "[parseHTML] appendChild error",
52 | e,
53 | targetElement,
54 | targetNode
55 | );
56 | }
57 | result.push(targetNode);
58 | });
59 | }
60 |
61 | return result.length ? result : nodes;
62 | }
63 |
--------------------------------------------------------------------------------
/scripts/libs/utils/iframe.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Determine whether it is in an Iframe
3 | * @returns {boolean}
4 | */
5 | export function isInIframe() {
6 | return window !== window.top;
7 | }
8 |
9 | /**
10 | * Determine whether it is in a cross-domain restricted Iframe
11 | * @returns {boolean}
12 | */
13 | export function isInCrossOriginFrame() {
14 | let result = true;
15 | try {
16 | if (window.top.localStorage || window.top.location.href) {
17 | result = false;
18 | }
19 | } catch (e) {
20 | result = true;
21 | }
22 | return result;
23 | }
24 |
--------------------------------------------------------------------------------
/scripts/libs/utils/original.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * @name original.js
3 | * @description Store some important native functions to prevent external contamination. This logic should be brought forward as much as possible, otherwise the contaminated functions will be stored.
4 | * @version 0.0.1
5 | * @author xxxily
6 | * @date 2022/10/16 10:32
7 | * @github https://github.com/xxxily
8 | */
9 |
10 | export const original = {
11 | // Prevent defineProperty and defineProperties from being overridden by AOP scripts
12 | Object: {
13 | defineProperty: Object.defineProperty,
14 | defineProperties: Object.defineProperties,
15 | },
16 |
17 | // Prevent this kind of gameplay:https://juejin.cn/post/6865910564817010702
18 | Proxy,
19 |
20 | Map,
21 | map: {
22 | clear: Map.prototype.clear,
23 | set: Map.prototype.set,
24 | has: Map.prototype.has,
25 | get: Map.prototype.get,
26 | delete: Map.prototype.delete,
27 | },
28 |
29 | console: {
30 | log: console.log,
31 | info: console.info,
32 | error: console.error,
33 | warn: console.warn,
34 | table: console.table,
35 | },
36 |
37 | ShadowRoot,
38 | HTMLMediaElement,
39 | CustomEvent,
40 | // appendChild: Node.prototype.appendChild,
41 |
42 | JSON: {
43 | parse: JSON.parse,
44 | stringify: JSON.stringify,
45 | },
46 |
47 | alert,
48 | confirm,
49 | prompt,
50 | };
51 |
--------------------------------------------------------------------------------
/scripts/libs/utils/ready.js:
--------------------------------------------------------------------------------
1 | /**
2 | *Element listener
3 | * @param selector - required
4 | * @param fn - required, callback when the element exists
5 | * @param shadowRoot - optional specifies to monitor the DOM element under a certain shadowRoot
6 | * Reference: https://javascript.ruanyifeng.com/dom/mutationobserver.html
7 | */
8 | export function ready(selector, fn, shadowRoot) {
9 | const win = window;
10 | const docRoot = shadowRoot || win.document.documentElement;
11 | if (!docRoot) return false;
12 | const MutationObserver = win.MutationObserver || win.WebKitMutationObserver;
13 | const listeners = docRoot._MutationListeners || [];
14 |
15 | function $ready(selector, fn) {
16 | // Store selectors and callback functions
17 | listeners.push({
18 | selector: selector,
19 | fn: fn,
20 | });
21 |
22 | /* Add listening objects */
23 | if (!docRoot._MutationListeners || !docRoot._MutationObserver) {
24 | docRoot._MutationListeners = listeners;
25 | docRoot._MutationObserver = new MutationObserver(() => {
26 | for (let i = 0; i < docRoot._MutationListeners.length; i++) {
27 | const item = docRoot._MutationListeners[i];
28 | check(item.selector, item.fn);
29 | }
30 | });
31 |
32 | docRoot._MutationObserver.observe(docRoot, {
33 | childList: true,
34 | subtree: true,
35 | });
36 | }
37 |
38 | // Check if the node is already in the DOM
39 | check(selector, fn);
40 | }
41 |
42 | function check(selector, fn) {
43 | const elements = docRoot.querySelectorAll(selector);
44 | for (let i = 0; i < elements.length; i++) {
45 | const element = elements[i];
46 | element._MutationReadyList_ = element._MutationReadyList_ || [];
47 | if (!element._MutationReadyList_.includes(fn)) {
48 | element._MutationReadyList_.push(fn);
49 | fn.call(element, element);
50 | }
51 | }
52 | }
53 |
54 | const selectorArr = Array.isArray(selector) ? selector : [selector];
55 | selectorArr.forEach((selector) => $ready(selector, fn));
56 | }
57 |
--------------------------------------------------------------------------------
/scripts/libs/utils/typeof.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * @name utils.js
3 | * @description Data type related methods
4 | * @version 0.0.1
5 | * @author Blaze
6 | * @date 22/03/2019 22:46
7 | * @github https://github.com/xxxily
8 | */
9 |
10 | /**
11 | * Accurately obtain the specific type of object. See: https://www.talkingcoder.com/article/6333557442705696719
12 | * @param obj { all } -Required The object to be judged
13 | * @returns {*} Returns the specific type of judgment
14 | */
15 | export function getType(obj) {
16 | if (obj == null) {
17 | return String(obj);
18 | }
19 | return typeof obj === "object" || typeof obj === "function"
20 | ? (obj.constructor &&
21 | obj.constructor.name &&
22 | obj.constructor.name.toLowerCase()) ||
23 | /function\s(.+?)\(/.exec(obj.constructor)[1].toLowerCase()
24 | : typeof obj;
25 | }
26 |
27 | export const isType = (obj, typeName) => getType(obj) === typeName;
28 | export const isObj = (obj) => isType(obj, "object");
29 | export const isErr = (obj) => isType(obj, "error");
30 | export const isArr = (obj) => isType(obj, "array");
31 | export const isRegExp = (obj) => isType(obj, "regexp");
32 | export const isFunction = (obj) => obj instanceof Function;
33 | export const isUndefined = (obj) => isType(obj, "undefined");
34 | export const isNull = (obj) => isType(obj, "null");
35 |
--------------------------------------------------------------------------------
/scripts/libs/utils/xmlParser.js:
--------------------------------------------------------------------------------
1 | // https://stackoverflow.com/a/1773571/11898496
2 | export function parseXml(xml) {
3 | var dom = null;
4 | if (window.DOMParser) {
5 | try {
6 | dom = new DOMParser().parseFromString(xml, "text/xml");
7 | } catch (e) {
8 | dom = null;
9 | }
10 | } else if (window.ActiveXObject) {
11 | try {
12 | dom = new ActiveXObject("Microsoft.XMLDOM");
13 | dom.async = false;
14 | if (!dom.loadXML(xml))
15 | // parse error ..
16 |
17 | window.alert(dom.parseError.reason + dom.parseError.srcText);
18 | } catch (e) {
19 | dom = null;
20 | }
21 | } else alert("cannot parse xml string!");
22 | return dom;
23 | }
24 |
25 | // https://stackoverflow.com/a/20861541/11898496
26 |
--------------------------------------------------------------------------------
/scripts/libs/xml-json/json2xml.js:
--------------------------------------------------------------------------------
1 | /* This work is licensed under Creative Commons GNU LGPL License.
2 |
3 | License: http://creativecommons.org/licenses/LGPL/2.1/
4 | Version: 0.9
5 | Author: Stefan Goessner/2006
6 | Web: http://goessner.net/
7 | */
8 | function json2xml(o, tab) {
9 | var toXml = function (v, name, ind) {
10 | var xml = "";
11 | if (v instanceof Array) {
12 | for (var i = 0, n = v.length; i < n; i++)
13 | xml += ind + toXml(v[i], name, ind + "\t") + "\n";
14 | } else if (typeof v == "object") {
15 | var hasChild = false;
16 | xml += ind + "<" + name;
17 | for (var m in v) {
18 | if (m.charAt(0) == "@")
19 | xml += " " + m.substr(1) + '="' + v[m].toString() + '"';
20 | else hasChild = true;
21 | }
22 | xml += hasChild ? ">" : "/>";
23 | if (hasChild) {
24 | for (var m in v) {
25 | if (m == "#text") xml += v[m];
26 | else if (m == "#cdata") xml += "";
27 | else if (m.charAt(0) != "@") xml += toXml(v[m], m, ind + "\t");
28 | }
29 | xml +=
30 | (xml.charAt(xml.length - 1) == "\n" ? ind : "") + "" + name + ">";
31 | }
32 | } else {
33 | xml += ind + "<" + name + ">" + v.toString() + "" + name + ">";
34 | }
35 | return xml;
36 | },
37 | xml = "";
38 | for (var m in o) xml += toXml(o[m], m, "");
39 | return tab ? xml.replace(/\t/g, tab) : xml.replace(/\t|\n/g, "");
40 | }
41 |
--------------------------------------------------------------------------------
/scripts/listAllImagesInWeb.js:
--------------------------------------------------------------------------------
1 | export default {
2 | icon: ``,
3 | name: {
4 | en: "View all images in web",
5 | vi: "Xem mọi hình ảnh có trong website",
6 | },
7 | description: {
8 | en: "View all images in web",
9 | vi: "Xem danh sách hình ảnh trong tab mới",
10 | },
11 |
12 | contentScript: {
13 | onClick: function () {
14 | var A = {},
15 | B = [],
16 | D = document,
17 | i,
18 | e,
19 | a,
20 | k,
21 | y,
22 | s,
23 | m,
24 | u,
25 | t,
26 | r,
27 | j,
28 | v,
29 | h,
30 | q,
31 | c,
32 | G;
33 | G = open().document;
34 | G.open();
35 | G.close();
36 |
37 | function C(t) {
38 | return G.createElement(t);
39 | }
40 |
41 | function P(p, c) {
42 | p.appendChild(c);
43 | }
44 |
45 | function T(t) {
46 | return G.createTextNode(t);
47 | }
48 | for (i = 0; (e = D.images[i]); ++i) {
49 | a = e.getAttribute("alt");
50 | k = escape(e.src) + "%" + (a != null) + a;
51 | if (!A[k]) {
52 | y = !!a + (a != null);
53 | s = C("span");
54 | s.style.color = ["red", "gray", "green"][y];
55 | s.style.fontStyle = ["italic", "italic", ""][y];
56 | P(s, T(["missing", "empty", a][y]));
57 | m = e.cloneNode(true);
58 | if (G.importNode) m = G.importNode(m, true);
59 | if (m.width > 350) m.width = 350;
60 | B.push([0, 7, T(e.src.split("/").reverse()[0]), m, s]);
61 | A[k] = B.length;
62 | }
63 | u = B[A[k] - 1];
64 | u[1] = T(++u[0]);
65 | }
66 | t = C("table");
67 | t.border = 1;
68 | r = t.createTHead().insertRow(-1);
69 | for (j = 0; (v = ["#", "Filename", "Image", "Alternate text"][j]); ++j) {
70 | h = C("th");
71 | P(h, T(v));
72 | P(r, h);
73 | }
74 | for (i = 0; (q = B[i]); ++i) {
75 | r = t.insertRow(-1);
76 | for (j = 1; (v = q[j]); ++j) {
77 | c = r.insertCell(-1);
78 | P(c, v);
79 | }
80 | }
81 | P(G.body, t);
82 | },
83 | },
84 | };
85 |
--------------------------------------------------------------------------------
/scripts/medium_fixVietnameseFont.js:
--------------------------------------------------------------------------------
1 | import { UfsGlobal } from "./content-scripts/ufs_global.js";
2 |
3 | export default {
4 | icon: "https://cdn-icons-png.flaticon.com/512/5968/5968906.png",
5 | name: {
6 | en: "Medium - Fix vietnamese font",
7 | vi: "Medium - Fix font Tiếng Việt",
8 | },
9 | description: {
10 | en: `Fix vietnamese font in Medium
11 |
12 | - Click 1 time to fix font in current Medium page (dont need to reload)
13 | - Enable autorun for next times you enter Medium
14 |
`,
15 | vi: `Sửa lỗi font Tiếng Việt khó nhìn trong Medium
16 |
17 | - Click 1 lần để sửa trang hiện tại (không cần tải lại trang)
18 | - Bật tự chạy cho các lần sau vào Medium
19 |
`,
20 | },
21 |
22 | changeLogs: {
23 | "2024-31-05": "init",
24 | },
25 |
26 | whiteList: ["https://medium.com/*", "https://*.medium.com/*"],
27 |
28 | contentScript: {
29 | onDocumentStart: injectCss,
30 | onClick: injectCss,
31 | },
32 | };
33 | function injectCss() {
34 | UfsGlobal.DOM.injectCssFile(
35 | chrome.runtime.getURL("/scripts/medium_fixVietnameseFont.css")
36 | );
37 | }
38 |
--------------------------------------------------------------------------------
/scripts/medium_readFullArticle.js:
--------------------------------------------------------------------------------
1 | export default {
2 | icon: "https://cdn-icons-png.flaticon.com/512/5968/5968906.png",
3 | name: {
4 | en: "Read full medium article",
5 | vi: "Đọc bài viết medium full",
6 | },
7 | description: {
8 | en: "Read full medium article without login",
9 | vi: "Đọc bài viết medium full không cần đăng nhập",
10 | },
11 |
12 | // whiteList: ["https://medium.com/*"],
13 |
14 | popupScript: {
15 | onClick: async () => {
16 | const { getCurrentTabUrl } = await import("./helpers/utils.js");
17 | let url = await getCurrentTabUrl();
18 | url = prompt("Nhập link medium:", url);
19 |
20 | if (url) {
21 | window.open("https://readmedium.com/" + url);
22 | // window.open("https://freedium.cfd/" + url);
23 | }
24 | },
25 | },
26 | };
27 |
--------------------------------------------------------------------------------
/scripts/net-request-rules/README.md:
--------------------------------------------------------------------------------
1 | https://developer.chrome.com/docs/extensions/reference/declarativeNetRequest/
--------------------------------------------------------------------------------
/scripts/net-request-rules/dynamicRulesEditor/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Dynamic Rules Editor
8 |
9 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/scripts/net-request-rules/dynamicRulesEditor/index.js:
--------------------------------------------------------------------------------
1 | import { t } from "../../../popup/helpers/lang.js";
2 |
3 | let h1 = document.createElement("h1");
4 | h1.style.textAlign = "center";
5 | document.body.appendChild(h1);
6 |
7 | chrome.declarativeNetRequest.getDynamicRules((rules) => {
8 | console.log(rules);
9 | h1.innerHTML = t({
10 | en: "..Feature in development..
Rules Count: " + rules.length,
11 | vi:
12 | "..Chức năng đang được phát triển..
Rules Count: " +
13 | rules.length,
14 | });
15 | });
16 |
17 | let deleteAllBtn = document.createElement("button");
18 | deleteAllBtn.innerText = "Delete all";
19 | deleteAllBtn.onclick = () => {
20 | chrome.declarativeNetRequest.getDynamicRules((rules) => {
21 | if (confirm("Delete " + rules.length + " rules?")) {
22 | chrome.declarativeNetRequest.updateDynamicRules(
23 | {
24 | removeRuleIds: rules.map((rule) => rule.id),
25 | },
26 | () => {
27 | alert("DONE");
28 | h1.innerText = "Rules Count: " + 0;
29 | }
30 | );
31 | }
32 | });
33 | };
34 | document.body.appendChild(deleteAllBtn);
35 |
--------------------------------------------------------------------------------
/scripts/openWaybackUrl.js:
--------------------------------------------------------------------------------
1 | export default {
2 | icon: "https://archive.org/images/glogo.jpg",
3 | name: {
4 | en: "Open wayback url",
5 | vi: "Xem wayback url của website",
6 | },
7 | description: {
8 | en: "Open wayback url for website",
9 | vi: "Giúp xem nội dung website trong quá khứ",
10 | },
11 |
12 | popupScript: {
13 | onClick: async function () {
14 | const { getCurrentTab } = await import("./helpers/utils.js");
15 | let { url } = await getCurrentTab();
16 | let url_to_check = prompt("Nhập URL muốn xem: ", url);
17 | if (url_to_check) {
18 | window.open("https://web.archive.org/web/*/" + url_to_check);
19 | }
20 | },
21 | },
22 | };
23 |
--------------------------------------------------------------------------------
/scripts/performanceAnalyzer.js:
--------------------------------------------------------------------------------
1 | export default {
2 | icon: `https://ssl.gstatic.com/pagespeed/insights/ui/logo/favicon_48.png`,
3 | name: {
4 | en: "Performance Analyzer",
5 | vi: "Phân tích hiệu suất",
6 | },
7 | description: {
8 | en: "Check performance metrics of website",
9 | vi: "Phân tích hiệu suất website không cần biết code",
10 | },
11 |
12 | contentScript: {
13 | onClick: function () {
14 | let options = [
15 | {
16 | name: "Sử dụng PageSpeed Insights",
17 | func: () => {
18 | window.open(
19 | "https://developers.google.com/speed/pagespeed/insights/?url=" +
20 | encodeURIComponent(location.href)
21 | );
22 | },
23 | },
24 | {
25 | name: "Sử dụng gtmetrix",
26 | func: () => {
27 | window.open("https://gtmetrix.com/?url=" + document.domain);
28 | },
29 | },
30 | {
31 | name: "Sử dụng performanceBookmarklet.min.js (beta)",
32 | func: () => {
33 | let src =
34 | "https://micmro.github.io/performance-bookmarklet/dist/performanceBookmarklet.min.js";
35 |
36 | let el = document.createElement("script");
37 | el.type = "text/javascript";
38 | el.src = src;
39 | el.onerror = function () {
40 | alert(
41 | 'Looks like the Content Security Policy directive is blocking the use of bookmarklets\n\nYou can copy and paste the content of:\n\n"https://micmro.github.io/performance-bookmarklet/dist/performanceBookmarklet.min.js"\n\ninto your console instead\n\n(link is in console already)'
42 | );
43 | console.log(src);
44 | };
45 | document.getElementsByTagName("head")[0].appendChild(el);
46 | },
47 | },
48 | ];
49 |
50 | let choice = prompt(
51 | options.map((_, i) => `${i}: ${_.name}`).join("\n") +
52 | "\n\n - Your choice:",
53 | 0
54 | );
55 |
56 | if (choice != null && choice >= 0 && choice < options.length) {
57 | options[choice]?.func?.();
58 | }
59 | },
60 | },
61 | };
62 |
--------------------------------------------------------------------------------
/scripts/recommend_cloc.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Useful-Scripts-Extension/useful-script/3841517b641a602d6360cf9b43152bee2524bd7f/scripts/recommend_cloc.png
--------------------------------------------------------------------------------
/scripts/removeBloat.js:
--------------------------------------------------------------------------------
1 | export default {
2 | name: {
3 | en: "Remove bloat (iframe, embed)",
4 | vi: "Xoá mọi iframe/embed",
5 | },
6 | description: {
7 | en: "Remove iframe, embeds, applets from website",
8 | vi: "Xoá mọi thứ gây xao nhãng (quảng cáo, web nhúng, ..)",
9 | },
10 |
11 | contentScript: {
12 | onClick: function () {
13 | function R(w) {
14 | try {
15 | var d = w.document,
16 | j,
17 | i,
18 | t,
19 | T,
20 | N,
21 | b,
22 | r = 1,
23 | C;
24 | for (j = 0; (t = ["object", "embed", "applet", "iframe"][j]); ++j) {
25 | T = d.getElementsByTagName(t);
26 | for (i = T.length - 1; i + 1 && (N = T[i]); --i)
27 | if (
28 | j != 3 ||
29 | !R((C = N.contentWindow) ? C : N.contentDocument.defaultView)
30 | ) {
31 | b = d.createElement("div");
32 | b.style.width = N.width;
33 | b.style.height = N.height;
34 | b.innerHTML =
35 | "" + (j == 3 ? "third-party " + t : t) + "";
36 | N.parentNode.replaceChild(b, N);
37 | }
38 | }
39 | } catch (E) {
40 | r = 0;
41 | }
42 | return r;
43 | }
44 | R(self);
45 | var i, x;
46 | for (i = 0; (x = frames[i]); ++i) R(x);
47 | },
48 | },
49 | };
50 |
--------------------------------------------------------------------------------
/scripts/removeColours.js:
--------------------------------------------------------------------------------
1 | export default {
2 | icon: ``,
3 | name: {
4 | en: "Remove all colors in web",
5 | vi: "Xoá màu website",
6 | },
7 | description: {
8 | en: "Remove all colours in the web.
Click again to undo.",
9 | vi: "Xoá mọi màu có trong website.
Bấm lại để hoàn tác.",
10 | },
11 | changeLogs: {
12 | "2024-05-01": "fix cors + undo",
13 | },
14 |
15 | contentScript: {
16 | onClick_: function () {
17 | const ufs_remove_colours_id = "ufs-remove-colours";
18 | let exist = document.getElementById(ufs_remove_colours_id);
19 | if (exist) {
20 | exist.remove();
21 | return;
22 | }
23 | let style = document.createElement("style");
24 | style.id = "ufs-remove-colours";
25 | style.textContent = `
26 | *, *::before, *::after {
27 | background: #ffffff4f ! important;
28 | color: black !important;
29 | }
30 | img, video, canvas, picture, svg, object {
31 | filter: grayscale(100%) !important;
32 | }`;
33 |
34 | // :link, :link * {
35 | // color: #0000EE !important
36 | // }
37 | // :visited, :visited * {
38 | // color: #551A8B !important
39 | // }
40 | document.head.appendChild(style);
41 | },
42 | },
43 | };
44 |
--------------------------------------------------------------------------------
/scripts/removeCookies.js:
--------------------------------------------------------------------------------
1 | export default {
2 | icon: ``,
3 | name: {
4 | en: "Remove cookies",
5 | vi: "Xoá Cookies",
6 | },
7 | description: {
8 | en: "Remove cookies from current website",
9 | vi: "Xoá cookies trang hiện tại",
10 | },
11 |
12 | contentScript: {
13 | onClick: function () {
14 | var c = document.cookie.replace(/; /g, "\n");
15 | if (c == "") {
16 | alert("There is No cookie here");
17 | } else {
18 | if (confirm("Are you sure want to delete all cookies?\n\n\n" + c)) {
19 | clearCookies();
20 | alert("Remove cookies DONE");
21 | }
22 | }
23 | },
24 | },
25 | };
26 |
27 | export function clearCookies() {
28 | let C = document.cookie.split("; ");
29 | for (let d = "." + location.host; d; d = ("" + d).substr(1).match(/\..*$/))
30 | for (let sl = 0; sl < 2; ++sl)
31 | for (
32 | let p = "/" + location.pathname;
33 | p;
34 | p = p.substring(0, p.lastIndexOf("/"))
35 | )
36 | for (let i in C) {
37 | let c = C[i];
38 | if (c) {
39 | document.cookie =
40 | c +
41 | "; domain=" +
42 | d.slice(sl) +
43 | "; path=" +
44 | p.slice(1) +
45 | "/" +
46 | "; expires=" +
47 | new Date(new Date().getTime() - 1e11).toGMTString();
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/scripts/removeImages.js:
--------------------------------------------------------------------------------
1 | export default {
2 | name: {
3 | en: "Remove images",
4 | vi: "Xoá mọi hình ảnh",
5 | },
6 | description: {
7 | en: "Remove all images from website.
Click again to undo.",
8 | vi: "Chỉ để lại văn bản, giúp tập trung hơn.
Bấm lại để hoàn tác.",
9 | },
10 | changeLogs: {
11 | "2024-05-01": "can undo",
12 | },
13 |
14 | contentScript: {
15 | onClick_: function () {
16 | var images,
17 | img,
18 | key = "data-ufs-remove-image";
19 | images = Array.from(
20 | document.querySelectorAll("img, picture, image, source")
21 | );
22 | for (var i = 0; i < images.length; ++i) {
23 | img = images[i];
24 | if (img.style.display == "none" && img.hasAttribute(key)) {
25 | img.style.display = img.getAttribute(key);
26 | img.removeAttribute(key);
27 | } else {
28 | let oldDisplay = img.style.display || "";
29 | img.setAttribute(key, oldDisplay);
30 | img.style.display = "none";
31 | }
32 | }
33 | },
34 | },
35 | };
36 |
--------------------------------------------------------------------------------
/scripts/removeStylesheet.js:
--------------------------------------------------------------------------------
1 | export default {
2 | name: {
3 | en: "Remove stylesheet",
4 | vi: "Xoá stylesheet",
5 | },
6 | description: {
7 | en: "Remove all stylesheet from website.
Click again to undo.",
8 | vi: "Xem trang web sẽ ra sao khi không có css.
Bấm lại để hoàn tác.",
9 | },
10 | changeLogs: {
11 | "2024-05-01": "can undo",
12 | },
13 |
14 | contentScript: {
15 | onClick_: function () {
16 | var i, x;
17 | for (i = 0; (x = document.styleSheets[i]); ++i) x.disabled = !x.disabled;
18 | },
19 | },
20 | };
21 |
--------------------------------------------------------------------------------
/scripts/saveAllVideo.js:
--------------------------------------------------------------------------------
1 | export default {
2 | icon: "https://saveallvideo.net/assets/img/favicon.png",
3 | name: {
4 | en: "Save All Video",
5 | vi: "Save All Video",
6 | },
7 | description: {
8 | en: "Download video from Douyin Twitter Instagram TikTok Youtube",
9 | vi: "Tải video từ Douyin Twitter Instagram TikTok Youtube",
10 | },
11 | infoLink: "https://saveallvideo.net",
12 | // "https://www.facebook.com/groups/j2team.community/posts/2316412945357479/",
13 |
14 | changeLogs: {
15 | "2024-03-13": "init",
16 | },
17 |
18 | popupScript: {
19 | onClick: async () => {
20 | const { getCurrentTab, showLoading } = await import("./helpers/utils.js");
21 | const { closeLoading, setLoadingText } = showLoading(
22 | "Đang lấy thông tin tab..."
23 | );
24 | try {
25 | let tab = await getCurrentTab();
26 | setLoadingText("Vui lòng nhập link video muốn tải...");
27 | let url = prompt(
28 | "Nhập link video (Douyin Twitter Instagram TikTok Youtube): ",
29 | tab.url
30 | );
31 | if (url == null) return;
32 |
33 | setLoadingText("Đang tải thông tin từ saveallvideo...");
34 | let res = await fetch(
35 | "https://saveallvideo.net/apiget?apiuser=j2team&apipass=j2team&url=" +
36 | url
37 | );
38 | setLoadingText("Đang xử lý thông tin...");
39 | let json = await res.json();
40 | let download_url = json?.url;
41 | if (download_url) window.open(download_url);
42 | else throw Error("API không trả link video.");
43 | } catch (e) {
44 | alert("ERROR: " + e);
45 | window.open("https://saveallvideo.net");
46 | } finally {
47 | closeLoading();
48 | }
49 | },
50 | },
51 | };
52 |
--------------------------------------------------------------------------------
/scripts/savevideo_me.js:
--------------------------------------------------------------------------------
1 | export default {
2 | icon: `https://savevideo.me/favicon.ico`,
3 | name: {
4 | en: "SaveVideo - Download video",
5 | vi: "SaveVideo - Tải video",
6 | },
7 | description: {
8 | en: "Download videos from Dailymotion, Facebook, Vimeo, Twitter, Instagram / Reels, TikTok, Rumble.com, Streamable.com, Aol Video, Bilibili.com (哔哩哔哩), Bilibili.tv, Coub, DouYin (抖音), Flickr Videos, Focus.de, GMX.net / WEB.DE, ItemFix, Magisto, Reddit, Sapo.pt, T.me (Telegram), Tiscali.it Video, Tudou, Veoh, Vidmax.com, Vine (archive), WorldStarHipHop, Youku",
9 | vi: "Tải videos từ Dailymotion, Facebook, Vimeo, Twitter, Instagram / Reels, TikTok, Rumble.com, Streamable.com, Aol Video, Bilibili.com (哔哩哔哩), Bilibili.tv, Coub, DouYin (抖音), Flickr Videos, Focus.de, GMX.net / WEB.DE, ItemFix, Magisto, Reddit, Sapo.pt, T.me (Telegram), Tiscali.it Video, Tudou, Veoh, Vidmax.com, Vine (archive), WorldStarHipHop, Youku",
10 | },
11 |
12 | popupScript: {
13 | onClick: async function () {
14 | const { getCurrentTab, openPopupWithHtml, showLoading } = await import(
15 | "./helpers/utils.js"
16 | );
17 |
18 | // https://savevideo.me/en/
19 |
20 | let { closeLoading } = showLoading("Đang get link video...");
21 | try {
22 | let tab = await getCurrentTab();
23 | let url = prompt("Enter video url: ", tab.url);
24 | if (url == null) return;
25 |
26 | let formData = new FormData();
27 | formData.append("url", url);
28 | formData.append("form", "Download");
29 |
30 | let res = await fetch("https://savevideo.me/en/get/", {
31 | method: "POST",
32 | body: formData,
33 | });
34 | let text = await res.text();
35 | openPopupWithHtml(text, 600, 400);
36 | } catch (e) {
37 | alert("ERROR: " + e);
38 | } finally {
39 | closeLoading();
40 | }
41 | },
42 | },
43 | };
44 |
--------------------------------------------------------------------------------
/scripts/screenshotFullPage.js:
--------------------------------------------------------------------------------
1 | import { UfsGlobal } from "./content-scripts/ufs_global.js";
2 | import { BADGES } from "./helpers/badge.js";
3 | import {
4 | attachDebugger,
5 | detachDebugger,
6 | getCurrentTab,
7 | sendDevtoolCommand,
8 | showLoading,
9 | } from "./helpers/utils.js";
10 |
11 | export default {
12 | icon: "https://gofullpage.com/favicon.ico",
13 | name: {
14 | en: "Screenshot full webpage",
15 | vi: "Chụp ảnh toàn bộ web",
16 | },
17 | description: {
18 | en: "Taking a screenshot of an entire webpage",
19 | vi: "Tạo 1 ảnh chụp màn hình chứa toàn bộ nội dung website",
20 | },
21 | badges: [BADGES.hot],
22 |
23 | popupScript: {
24 | onClick: async function () {
25 | const { setLoadingText, closeLoading } = showLoading(
26 | "Đang lấy kích thước trang..."
27 | );
28 | try {
29 | let tab = await getCurrentTab();
30 | await attachDebugger(tab);
31 | let res = await sendDevtoolCommand(tab, "Page.getLayoutMetrics", {});
32 | const { x, y, width, height } = res.cssContentSize;
33 |
34 | if (
35 | confirm(`Kích thước trang: ${width} x ${height}\n Bấm OK để chụp`)
36 | ) {
37 | setLoadingText("Đang tạo ảnh chụp màn hình...");
38 | let img = await sendDevtoolCommand(tab, "Page.captureScreenshot", {
39 | format: "png",
40 | quality: 100,
41 | fromSurface: true,
42 | captureBeyondViewport: true,
43 | clip: { x: 0, y: 0, width, height, scale: 1 },
44 | });
45 | console.log(img);
46 |
47 | setLoadingText("Đang lưu ảnh...");
48 | UfsGlobal.Extension.download({
49 | url: "data:image/png;base64," + img.data,
50 | filename: "fullpage.png",
51 | });
52 | }
53 | await detachDebugger(tab);
54 | } catch (e) {
55 | alert("Lỗi: " + e);
56 | } finally {
57 | closeLoading();
58 | }
59 | },
60 | },
61 | };
62 |
63 | function backup() {
64 | // var blob = new Blob(img.data, { type: "image/png" });
65 | // var url = URL.createObjectURL(blob);
66 | // chrome.downloads.download({
67 | // url: url,
68 | // filename: "screenshot.png",
69 | // });
70 | // window.open("data:image/png;base64," + img.data);
71 | }
72 |
--------------------------------------------------------------------------------
/scripts/scribd_bypassPreview.css:
--------------------------------------------------------------------------------
1 | .auto__doc_page_webpack_doc_page_blur_promo {
2 | display: none !important;
3 | }
--------------------------------------------------------------------------------
/scripts/scribd_bypassPreview.js:
--------------------------------------------------------------------------------
1 | import { UfsGlobal } from "./content-scripts/ufs_global.js";
2 |
3 | export default {
4 | icon: "https://s-f.scribdassets.com/scribd.ico?014e86d16?v=5",
5 | name: {
6 | en: "Scribd - bypass preview",
7 | vi: "Scribd - Xem miễn phí VIP",
8 | },
9 | description: {
10 | en: "View VIP document on Scribd.com, bypass preview popup / reveal blurred content.",
11 | vi: "Xem tài liệu VIP trên Scribd.com, loại bỏ popup chặn xem trước, loại bỏ hiệu ứng làm mờ.",
12 | },
13 | whiteList: ["https://www.scribd.com/*"],
14 |
15 | contentScript: {
16 | onDocumentIdle: async () => {
17 | UfsGlobal.DOM.injectCssFile(
18 | chrome.runtime.getURL("scripts/scribd_bypassPreview.css")
19 | );
20 |
21 | function ufs_scribd_bypass_preview() {
22 | [...document.querySelectorAll(".blurred_page .newpage *")].forEach(
23 | (el) => {
24 | if (el.style.color === "transparent") {
25 | el.style.color = "black";
26 | }
27 | }
28 | );
29 | [...document.querySelectorAll(".blurred_page")].forEach((el) => {
30 | el.classList.remove("blurred_page");
31 | });
32 | }
33 |
34 | ufs_scribd_bypass_preview();
35 | setInterval(ufs_scribd_bypass_preview, 3000);
36 | },
37 | },
38 | };
39 |
--------------------------------------------------------------------------------
/scripts/scribd_downloadDocuments.js:
--------------------------------------------------------------------------------
1 | export default {
2 | icon: "https://www.scribd.com/favicon.ico",
3 | name: {
4 | en: "Scribd - Download documents",
5 | vi: "Scribd - Tải documents",
6 | },
7 | description: {
8 | en: "Download document on Scribd for free",
9 | vi: "Tải miễn phí document trên Scribd",
10 | },
11 |
12 | popupScript: {
13 | onClick: async function () {
14 | const { getCurrentTab } = await import("./helpers/utils.js");
15 | // Post: https://www.facebook.com/groups/j2team.community/posts/1642123806119733/
16 | // Source: https://chrome.google.com/webstore/detail/documents-downloader/ikecplijfhabpahaolhdgglbbafknkdo?utm_source=j2team&utm_medium=url_shortener&utm_campaign=documents-downloader
17 |
18 | let tab = await getCurrentTab();
19 | let url = prompt(
20 | "Nhập link document:\nĐịnh dạng: https://www.scribd.com/document/...",
21 | tab.url
22 | );
23 | if (url != null)
24 | // window.open("https://documents-downloader.pages.dev/?documentUrl=" + url);
25 | window.open(
26 | "https://scribd.downloader.tips/" +
27 | url.replace("https://www.scribd.com", "")
28 | );
29 | },
30 | },
31 | };
32 |
--------------------------------------------------------------------------------
/scripts/search_googleSite.js:
--------------------------------------------------------------------------------
1 | export default {
2 | icon: ``,
3 | name: {
4 | en: "Google site search",
5 | vi: "Tìm kiếm trên trang web này",
6 | },
7 | description: {
8 | en: "Search in google while limiting the search result to currently opened webpage.",
9 | vi: "Sử dụng google site search",
10 | },
11 |
12 | contentScript: {
13 | onClick: function () {
14 | let q =
15 | "" +
16 | (window.getSelection?.() ||
17 | document.getSelection?.() ||
18 | document.selection.createRange?.()?.text);
19 |
20 | if (!q)
21 | q = prompt("You didn't select any text. Enter a search phrase:", "");
22 |
23 | if (q != null)
24 | window.open(
25 | (
26 | "http://www.google.com/search?num=100&q=site:" +
27 | escape(window.location.hostname) +
28 | ' "' +
29 | escape(q.replace(/\"/g, "")) +
30 | '"'
31 | ).replace(/ /g, "+")
32 | );
33 | },
34 | },
35 | };
36 |
--------------------------------------------------------------------------------
/scripts/search_hopamchuan.js:
--------------------------------------------------------------------------------
1 | export default {
2 | icon: "https://static.hopamchuan.com/assets/icons/hopamchuan.png",
3 | name: {
4 | en: "Search guitar chords",
5 | vi: "Tìm hợp âm guitar",
6 | },
7 | description: {
8 | en: "Search guitar chords",
9 | vi: "Tra cứu hợp âm chuẩn dành cho người chơi guitar",
10 | },
11 |
12 | popupScript: {
13 | onClick: () => window.open("https://hopamchuan.com/"),
14 | },
15 | };
16 |
--------------------------------------------------------------------------------
/scripts/search_paperWhere.js:
--------------------------------------------------------------------------------
1 | export default {
2 | icon: `https://airtable.com/favicon.ico`,
3 | name: {
4 | en: "Where to find papers/books/pdf/...",
5 | vi: "Tìm bài báo/sách/pdf/...ở đâu?",
6 | },
7 | description: {
8 | en: "Learn more and more",
9 | vi: "Học, học nữa, học mãi",
10 | },
11 |
12 | contentScript: {
13 | onClick: function () {
14 | // https://luyenthinoitru.com/tai-lieu/nghie-cuu-khoa-hoc-cach-tim-bai-bao-sci-hub_168.html
15 | // window.open("https://airtable.com/shrjkF2LcTpB2NqCw/tblEvDbsnM5AcOR6O");
16 |
17 | window.open(
18 | "https://docs.google.com/spreadsheets/d/1SluMr5tylO4n8Fx5cygYohxwRI3zWe0PYTC_fqdqbxo/edit?usp=sharing"
19 | );
20 | },
21 | },
22 | };
23 |
--------------------------------------------------------------------------------
/scripts/search_sharedAccount.js:
--------------------------------------------------------------------------------
1 | export default {
2 | icon: `http://bugmenot.com/favicon.ico`,
3 | name: {
4 | en: "Find shared login",
5 | vi: "Tìm tài khoản miễn phí",
6 | },
7 | description: {
8 | en: "Get free shared account on internet",
9 | vi: "Tìm tài khoản được chia sẻ trên mạng cho trang web hiện tại",
10 | },
11 |
12 | changeLogs: {
13 | "2024-04-27": "remove login2.me",
14 | },
15 |
16 | popupScript: {
17 | onClick: async function () {
18 | const { getCurrentTab } = await import("./helpers/utils.js");
19 |
20 | const providers = [
21 | {
22 | name: "bugmenot.com",
23 | getLink: (hostname) => "http://www.bugmenot.com/view/" + hostname,
24 | },
25 | // {
26 | // name: "login2.me",
27 | // getLink: (hostname) => `https://login2.me/#${hostname}`,
28 | // },
29 | {
30 | name: "password-login.com",
31 | getLink: (hostname) =>
32 | `https://password-login.com/passwords/${hostname}/`,
33 | },
34 | ];
35 |
36 | let providersText = providers.map((_, i) => `${i}: ${_.name}`).join("\n");
37 | let choice = prompt(`Choose provider:\n\n${providersText} `, 0);
38 |
39 | if (choice >= 0 && choice < providers.length) {
40 | let tab = await getCurrentTab();
41 | if (!tab.url) {
42 | alert("Lỗi: Không tìm thấy url trang web.");
43 | return;
44 | }
45 | let { hostname } = new URL(tab.url);
46 | var url = providers[choice].getLink(hostname);
47 | window.open(url);
48 | }
49 | },
50 | },
51 | };
52 |
--------------------------------------------------------------------------------
/scripts/search_totalIndexedPages.js:
--------------------------------------------------------------------------------
1 | export default {
2 | icon: ``,
3 | name: {
4 | en: "Check total indexed pages",
5 | vi: "Xem các pages được google quét",
6 | },
7 | description: {
8 | en: "Know how many pages of current website is indexed in Google",
9 | vi: "Biết có bao nhiêu trang con của website hiện tại đã được quét bởi Google",
10 | },
11 |
12 | contentScript: {
13 | onClick: function () {
14 | window.open(
15 | "http://www.google.com/search?num=100&q=site:" +
16 | escape(location.hostname)
17 | );
18 | },
19 | },
20 | };
21 |
--------------------------------------------------------------------------------
/scripts/send_shareFiles.js:
--------------------------------------------------------------------------------
1 | export default {
2 | icon: "https://send.zcyph.cc/favicon-32x32.c470c36d.png",
3 | name: {
4 | en: "Send - Share file faster",
5 | vi: "Send - Chia sẻ file nhanh",
6 | },
7 | description: {
8 | en: "Open send.zcyph.cc - share large file up to 20Gb",
9 | vi: "Mở send.zcyph.cc - chia sẻ file lớn lên tới 20Gb",
10 | },
11 |
12 | popupScript: {
13 | onClick: async function () {
14 | const { popupCenter } = await import("./helpers/utils.js");
15 | popupCenter({
16 | url: "https://send.zcyph.cc/",
17 | title: "Send",
18 | w: 500,
19 | h: 700,
20 | });
21 | },
22 | },
23 | };
24 |
--------------------------------------------------------------------------------
/scripts/shopee_topVariation.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Useful-Scripts-Extension/useful-script/3841517b641a602d6360cf9b43152bee2524bd7f/scripts/shopee_topVariation.png
--------------------------------------------------------------------------------
/scripts/showFPS.js:
--------------------------------------------------------------------------------
1 | import { UfsGlobal } from "./content-scripts/ufs_global.js";
2 |
3 | export default {
4 | icon: '',
5 | name: {
6 | en: "Show FPS",
7 | vi: "Hiện thị FPS",
8 | },
9 | description: {
10 | en: "Show frames per second of current website (inject stat.js library)",
11 | vi: "Hiện thị tốc độ khung hình của trang web hiện tại (sử dụng thư viện stat.js)",
12 | },
13 |
14 | pageScript: {
15 | onClick: async function () {
16 | UfsGlobal.DOM.injectScriptSrc(
17 | "//mrdoob.github.io/stats.js/build/stats.min.js",
18 | (success, error) => {
19 | if (success) {
20 | var stats = new Stats();
21 | document.body.appendChild(stats.dom);
22 | requestAnimationFrame(function loop() {
23 | stats.update();
24 | requestAnimationFrame(loop);
25 | });
26 | } else {
27 | alert("Inject FAILED. " + error);
28 | }
29 | }
30 | );
31 | },
32 | },
33 | };
34 |
--------------------------------------------------------------------------------
/scripts/showFps_v2.js:
--------------------------------------------------------------------------------
1 | import { BADGES } from "./helpers/badge.js";
2 |
3 | export default {
4 | icon: '',
5 | name: {
6 | en: "Show FPS - ver 2",
7 | vi: "Hiện thị FPS - ver 2",
8 | },
9 | description: {
10 | en: "Show frames per second of current website (use debugger)",
11 | vi: "Hiện thị tốc độ khung hình của trang web hiện tại (sử dụng debugger)",
12 | },
13 | badges: [BADGES.hot],
14 | changeLogs: {
15 | "2024-05-19": "init",
16 | },
17 |
18 | popupScript: {
19 | onClick: async () => {
20 | const {
21 | attachDebugger,
22 | detachDebugger,
23 | sendDevtoolCommand,
24 | getCurrentTab,
25 | } = await import("./helpers/utils.js");
26 |
27 | try {
28 | const tab = await getCurrentTab();
29 | await attachDebugger(tab);
30 | let res = await sendDevtoolCommand(tab, "Overlay.setShowFPSCounter", {
31 | show: true,
32 | });
33 | console.log(res);
34 | // await detachDebugger(tab);
35 | } catch (e) {
36 | alert(e);
37 | }
38 | },
39 | },
40 | };
41 |
--------------------------------------------------------------------------------
/scripts/showHiddenFields.js:
--------------------------------------------------------------------------------
1 | export default {
2 | icon: ``,
3 | name: {
4 | en: "Show hidden fields",
5 | vi: "Hiện các thành phần web bị ẩn",
6 | },
7 | description: {
8 | en: "Reveals hidden fields on a webpage. Find things like tokens, etc",
9 | vi: "Web thường ẩn mốt số thành phần như token, id, form, ...",
10 | },
11 |
12 | contentScript: {
13 | onClick: function () {
14 | // source code from: https://bookmarklet.vercel.app/
15 |
16 | var i,
17 | f,
18 | j,
19 | e,
20 | div,
21 | label,
22 | ne,
23 | found = false,
24 | D = document,
25 | count = 0;
26 | for (i = 0; (f = document.forms[i]); ++i)
27 | for (j = 0; (e = f[j]); ++j)
28 | if (e.type == "hidden") {
29 | function C(t) {
30 | return D.createElement(t);
31 | }
32 | function A(a, b) {
33 | a.appendChild(b);
34 | }
35 | div = C("div");
36 | label = C("label");
37 | A(div, label);
38 | A(label, D.createTextNode(e.name + ": "));
39 | e.parentNode.insertBefore(div, e);
40 | e.parentNode.removeChild(e);
41 | ne = C("input");
42 | /*for ie*/ ne.type = "text";
43 | ne.value = e.value;
44 | A(label, ne);
45 | label.style.MozOpacity = ".6";
46 | --j; /*for moz*/
47 |
48 | found = true;
49 | count++;
50 | }
51 |
52 | if (!found) alert("Nothing is hidden! / Không có thành phần nào bị ẩn!");
53 | alert("Showed " + count + " hidden fields.");
54 | },
55 | },
56 | };
57 |
--------------------------------------------------------------------------------
/scripts/showTheAudios.js:
--------------------------------------------------------------------------------
1 | export default {
2 | icon: ``,
3 | name: {
4 | en: "Show all audio in website",
5 | vi: "Hiển thị mọi audio trong trang web",
6 | },
7 | description: {
8 | en: "Will display all audio in website, easy to download/get link.",
9 | vi: "Hiển thị tất cả tag audio/âm thanh trong trang web, giúp dễ dàng tải xuống/lấy link.",
10 | },
11 |
12 | contentScript: {
13 | onClick: function () {
14 | function getSrc(audio) {
15 | let src = audio.getAttribute("src");
16 | if (src) return src;
17 | else {
18 | let source = audio.querySelector("source");
19 | if (source) return source.getAttribute("src");
20 | else return null;
21 | }
22 | }
23 |
24 | let audios = Array.from(document.querySelectorAll("audio") || []);
25 | audios = audios?.filter((_) => !!getSrc(_));
26 |
27 | if (!audios?.length) {
28 | alert(
29 | "Audio src not found.\n\nKhông tìm thấy âm thanh audio nào có thể tải trong trang web."
30 | );
31 | } else {
32 | let div = document.createElement("div");
33 | div.innerHTML = /*html*/ `
34 |
35 |
38 |
39 |
40 | ${audios
41 | .map((audio) => {
42 | let src = getSrc(audio);
43 | return `
44 |
Open in new tab`;
45 | })
46 | .join("
")}
47 |
48 |
49 |
50 | `;
51 | document.body.appendChild(div);
52 | }
53 | },
54 | },
55 | };
56 |
--------------------------------------------------------------------------------
/scripts/showTheVideos.js:
--------------------------------------------------------------------------------
1 | export default {
2 | icon: '',
3 | name: {
4 | en: "Show all videos in website",
5 | vi: "Hiển thị mọi video có trong web",
6 | },
7 | description: {
8 | en: "Download video easier",
9 | vi: "Tải video dễ dàng hơn",
10 | },
11 |
12 | contentScript: {
13 | onClick: function () {
14 | let videos = Array.from(document.querySelectorAll("video"));
15 |
16 | if (!videos.length) {
17 | alert("Không tìm thấy video nào.");
18 | return;
19 | }
20 |
21 | function getSrc(video) {
22 | if (video.src) {
23 | return video.src;
24 | }
25 | let sources = Array.from(video.querySelectorAll("source"));
26 | if (sources.length) {
27 | return sources[0].src;
28 | }
29 | return null;
30 | }
31 |
32 | videos.forEach((video) => (video.controls = "controls"));
33 |
34 | let html = /*html*/ `
35 |
36 |
37 | ${videos
38 | .map((video) => {
39 | let src = getSrc(video);
40 | if (src) {
41 | if (src.startsWith("blob:")) {
42 | return `
Download`;
43 | }
44 | return `
`;
45 | }
46 | return `
`;
47 | })
48 | .join("
")}
49 |
52 |
53 |
`;
54 |
55 | let div = document.createElement("div");
56 | div.innerHTML = html;
57 | document.body.appendChild(div);
58 | },
59 | },
60 | };
61 |
--------------------------------------------------------------------------------
/scripts/similarWeb.js:
--------------------------------------------------------------------------------
1 | export default {
2 | icon: "https://files.startupranking.com/startup/thumb/19950_8743c12283f6a62f069b5b05d518e1ba31465150_similarweb_l.png",
3 | name: {
4 | en: "Find alternative web",
5 | vi: "Tìm trang web tương tự",
6 | },
7 | description: {
8 | en: "SimilarWeb - Access behind-the-scenes analytics for every site online",
9 | vi: "SimilarWeb - Phân tích chi tiết cho mọi trang web trực tuyến",
10 | },
11 |
12 | contentScript: {
13 | onClick: function () {
14 | window.open(
15 | `https://www.similarweb.com/website/` +
16 | location.hostname +
17 | "/#competitors"
18 | );
19 | },
20 | },
21 | };
22 |
--------------------------------------------------------------------------------
/scripts/similarWeb_bypassLimit.js:
--------------------------------------------------------------------------------
1 | import { clearCookies } from "./removeCookies.js";
2 |
3 | export default {
4 | icon: "https://files.startupranking.com/startup/thumb/19950_8743c12283f6a62f069b5b05d518e1ba31465150_similarweb_l.png",
5 | name: {
6 | en: "Bypass limit in SimilarWeb",
7 | vi: "SimilarWeb - không bị giới hạn",
8 | },
9 | description: {
10 | en:
11 | "You can use SimilarWeb forever without login.
" +
12 | "How it work:
Your cookies will be deleted each times enter this web.",
13 | vi:
14 | "Sử dụng SimilarWeb không giới hạn, không cần đăng nhập.
" +
15 | "Cách hoạt động:
Cookies của bạn sẽ được xoá mỗi khi vào trang web",
16 | img: "/scripts/similarWeb_bypassLimit.png",
17 | },
18 |
19 | changeLogs: {
20 | "2024-04-27": "init",
21 | },
22 |
23 | whiteList: ["https://www.similarweb.com/*"],
24 |
25 | contentScript: {
26 | onDocumentEnd: clearCookies,
27 | },
28 | };
29 |
--------------------------------------------------------------------------------
/scripts/similarWeb_bypassLimit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Useful-Scripts-Extension/useful-script/3841517b641a602d6360cf9b43152bee2524bd7f/scripts/similarWeb_bypassLimit.png
--------------------------------------------------------------------------------
/scripts/smoothscroll_cursor.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Useful-Scripts-Extension/useful-script/3841517b641a602d6360cf9b43152bee2524bd7f/scripts/smoothscroll_cursor.png
--------------------------------------------------------------------------------
/scripts/soundcloud_downloadMusic.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Useful-Scripts-Extension/useful-script/3841517b641a602d6360cf9b43152bee2524bd7f/scripts/soundcloud_downloadMusic.png
--------------------------------------------------------------------------------
/scripts/spotify_downloadButton.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Useful-Scripts-Extension/useful-script/3841517b641a602d6360cf9b43152bee2524bd7f/scripts/spotify_downloadButton.png
--------------------------------------------------------------------------------
/scripts/studocu_downs.js:
--------------------------------------------------------------------------------
1 | import { BADGES } from "./helpers/badge.js";
2 |
3 | export default {
4 | icon: "https://d20ohkaloyme4g.cloudfront.net/img/favicon.ico",
5 | name: {
6 | en: "Studocu - Download documents",
7 | vi: "Studocu - Tải documents",
8 | },
9 | description: {
10 | en: "Download documents on Studocu.com for free",
11 | vi: "Tải tài liệu trên Studocu.com miễn phí",
12 | },
13 | badges: [BADGES.hot],
14 | changeLogs: {
15 | "2024-05-11": "combine + auto download",
16 | },
17 |
18 | popupScript: {
19 | onClick: async function () {
20 | const { getCurrentTab, openWebAndRunScript } = await import(
21 | "./helpers/utils.js"
22 | );
23 |
24 | let funcs = {
25 | "dlstudocu.com": async (url) => {
26 | openWebAndRunScript({
27 | url: "https://dlstudocu.com/",
28 | func: (url) => {
29 | let interval = setInterval(() => {
30 | if (window.st_url) {
31 | try {
32 | window.st_url.value = url;
33 | document.querySelector("form").submit();
34 | clearInterval(interval);
35 | } catch (e) {
36 | console.log(e);
37 | }
38 | }
39 | }, 100);
40 | },
41 | args: [url],
42 | waitUntilLoadEnd: false,
43 | focusImmediately: true,
44 | });
45 | },
46 | "downstudocu.com": async (url) => {
47 | url = new URL(url);
48 | url.hostname = "www.downstudocu.com";
49 | window.open(url);
50 | },
51 | };
52 |
53 | let tab = await getCurrentTab();
54 | let url = prompt(
55 | "Nhập link studocu document:\nĐịnh dạng: https://www.studocu.com/vn/document/...",
56 | tab.url
57 | );
58 | if (url == null) return;
59 |
60 | let keys = Object.keys(funcs);
61 | let choice = prompt(
62 | "Nhập website muốn download:\n\n" +
63 | keys.map((a, i) => i + ": " + a).join("\n"),
64 | 0
65 | );
66 | if (choice == null) return;
67 | if (keys[choice] == null) {
68 | alert("Nhập sai dữ liệu. Invalid choice");
69 | return;
70 | }
71 | funcs[keys[choice]]?.(url);
72 | },
73 | },
74 | };
75 |
--------------------------------------------------------------------------------
/scripts/studyphim_unlimited.js:
--------------------------------------------------------------------------------
1 | import { UfsGlobal } from "./content-scripts/ufs_global.js";
2 |
3 | export default {
4 | icon: "https://s2.googleusercontent.com/s2/favicons?domain=www.studyphim.vn",
5 | name: {
6 | en: "Studyphim - Watch free movies",
7 | vi: "Studyphim - Xem miễn phí",
8 | },
9 | description: {
10 | en: "Watch movies on Studyphim for free without login",
11 | vi: "Xem phim miễn phí trên Studyphim không cần đăng nhập",
12 | },
13 | infoLink:
14 | "https://www.facebook.com/groups/j2team.community/posts/565933393738785/",
15 |
16 | whiteList: ["https://www.studyphim.vn/*"],
17 |
18 | contentScript: {
19 | onDocumentStart: async () => {
20 | // Source: https://github.com/gys-dev/Unlimited-Stdphim
21 | UfsGlobal.DOM.deleteElements(
22 | ".overlay.playable.hide, .overlay.playable, #topchapter, #wrapper_header"
23 | );
24 | },
25 | },
26 | };
27 |
--------------------------------------------------------------------------------
/scripts/table_addNumberColumn.js:
--------------------------------------------------------------------------------
1 | export default {
2 | icon: ``,
3 | name: {
4 | en: "Add number columns",
5 | vi: "Thêm cột số thứ tự",
6 | },
7 | description: {
8 | en: "Add number columns to table",
9 | vi: "Thêm cột STT vào bên trái bảng",
10 | },
11 |
12 | contentScript: {
13 | onClick: function () {
14 | function has(par, ctag) {
15 | for (var k = 0; k < par.childNodes.length; ++k)
16 | if (par.childNodes[k].tagName == ctag) return true;
17 | }
18 |
19 | function add(par, ctag, text) {
20 | var c = document.createElement(ctag);
21 | c.appendChild(document.createTextNode(text));
22 | par.insertBefore(c, par.childNodes[0]);
23 | }
24 | var i,
25 | ts = document.getElementsByTagName("TABLE");
26 | for (i = 0; i < ts.length; ++i) {
27 | var n = 0,
28 | trs = ts[i].rows,
29 | j,
30 | tr;
31 | for (j = 0; j < trs.length; ++j) {
32 | tr = trs[j];
33 | if (has(tr, "TD")) add(tr, "TD", ++n);
34 | else if (has(tr, "TH")) add(tr, "TH", "Row");
35 | }
36 | }
37 | },
38 | },
39 | };
40 |
--------------------------------------------------------------------------------
/scripts/table_swapRowAndColumn.js:
--------------------------------------------------------------------------------
1 | export default {
2 | icon: ``,
3 | name: {
4 | en: "Swap rows and columns",
5 | vi: "Đổi chỗ hàng và cột",
6 | },
7 | description: {
8 | en: "Swap rows and columns (transpose)",
9 | vi: "Hàng thành cột và cột thành hàng",
10 | },
11 |
12 | contentScript: {
13 | onClick: function () {
14 | var d = document,
15 | q = "table",
16 | i,
17 | j,
18 | k,
19 | y,
20 | r,
21 | c,
22 | t;
23 | for (i = 0; (t = d.getElementsByTagName(q)[i]); ++i) {
24 | var w = 0,
25 | N = t.cloneNode(0);
26 | N.width = "";
27 | N.height = "";
28 | N.border = 1;
29 | for (j = 0; (r = t.rows[j]); ++j)
30 | for (y = k = 0; (c = r.cells[k]); ++k) {
31 | var z,
32 | a = c.rowSpan,
33 | b = c.colSpan,
34 | v = c.cloneNode(1);
35 | v.rowSpan = b;
36 | v.colSpan = a;
37 | v.width = "";
38 | v.height = "";
39 | if (!v.bgColor) v.bgColor = r.bgColor;
40 | while (w < y + b) N.insertRow(w++).p = 0;
41 | while (N.rows[y].p > j) ++y;
42 | N.rows[y].appendChild(v);
43 | for (z = 0; z < b; ++z) N.rows[y + z].p += a;
44 | y += b;
45 | }
46 | t.parentNode.replaceChild(N, t);
47 | }
48 | },
49 | },
50 | };
51 |
--------------------------------------------------------------------------------
/scripts/tailieu_vn.js:
--------------------------------------------------------------------------------
1 | export default {
2 | icon: "https://s2.googleusercontent.com/s2/favicons?domain_url=https://tailieu.vn/tim-kiem/lu%E1%BA%ADt.html",
3 | name: {
4 | en: "Download free from tailieu.vn",
5 | vi: "Tải miễn phí từ tailieu.vn",
6 | },
7 | description: {
8 | en: "Download any document on tailieu.vn without login",
9 | vi: "Tải bất kỳ tài liệu nào trên tailieu.vn không cần đăng nhập",
10 | },
11 |
12 | whiteList: ["*://tailieu.vn/doc/*", "*://m.tailieu.vn/doc/*"],
13 |
14 | // onDocumentStart: () => {
15 | // (function () {
16 | // var origOpen = XMLHttpRequest.prototype.open;
17 | // XMLHttpRequest.prototype.open = function () {
18 | // console.log("request started!");
19 | // this.addEventListener("load", function () {
20 | // console.log("request completed!");
21 | // console.log(this.readyState); //will always be 4 (ajax is completed successfully)
22 | // console.log(this.responseText); //whatever the response was
23 |
24 | // try {
25 | // let json = JSON.parse(this.responseText);
26 | // let { hash, time } = json;
27 | // if (hash && time) {
28 | // let url = `${window.DOMAIN}botailieu/pagedown?id=${window.intID}&hash=${hash}&t=${time}`;
29 | // console.log(url);
30 | // window.open(url, "_blank");
31 | // }
32 | // } catch (e) {
33 | // console.log(e);
34 | // }
35 | // });
36 | // origOpen.apply(this, arguments);
37 | // };
38 | // })();
39 | // },
40 |
41 | // onDocumentEnd: () => {
42 | // setInterval(() => {
43 | // window.isLogin = 1;
44 | // }, 1000);
45 |
46 | // window.addEventListener("beforeunload", function (event) {
47 | // event.preventDefault();
48 | // event.returnValue = "";
49 | // return "";
50 | // });
51 | // },
52 |
53 | pageScript: {
54 | onClick: async () => {
55 | let url =
56 | window.PDFView?.url ||
57 | document.querySelector("#loaddocdetail iframe")?.contentWindow?.PDFView
58 | ?.url;
59 |
60 | if (url) {
61 | window.open(url);
62 | } else {
63 | alert("Không tìm thấy file PDF nào");
64 | }
65 | },
66 | },
67 | };
68 |
--------------------------------------------------------------------------------
/scripts/textToQrCode.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Text to QRCode
8 |
9 |
10 |
11 |
12 |
25 |
26 |
27 |
28 | Useful Scripts
29 | Text to QRCode
30 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/scripts/textToQrCode.js:
--------------------------------------------------------------------------------
1 | export default {
2 | icon: '',
3 | name: {
4 | en: "Text to QRCode",
5 | vi: "Chữ sang QRCode",
6 | },
7 | description: {
8 | en: "Convert text/url to QRCode",
9 | vi: "Chuyển chữ/link sang QRCode",
10 | },
11 |
12 | popupScript: {
13 | onClick: async () => {
14 | const { getCurrentTab, popupCenter } = await import("./helpers/utils.js");
15 | const tab = await getCurrentTab();
16 |
17 | let text = prompt("Nhập text/url: ", tab.url);
18 | if (text) {
19 | popupCenter({
20 | url: "/scripts/textToQrCode.html#" + text,
21 | title: "Text to QRCode",
22 | w: 400,
23 | h: 500,
24 | });
25 | }
26 | },
27 | },
28 | };
29 |
--------------------------------------------------------------------------------
/scripts/textToQrCode_main.js:
--------------------------------------------------------------------------------
1 | window.onload = () => {
2 | let qrcode = new QRCode(document.getElementById("qrcode"), {
3 | width: 240,
4 | height: 240,
5 | });
6 | let qrwords = "Useful scripts";
7 | if (location.hash) {
8 | let hash = location.hash.slice(1);
9 | if (hash) {
10 | try {
11 | hash = decodeURIComponent(hash);
12 | qrwords = hash;
13 | } catch (e) {}
14 | }
15 | }
16 | let text = document.querySelector("#inp-text");
17 | function makeCode() {
18 | qrcode.makeCode(text.value);
19 | }
20 | text.value = qrwords;
21 | text.addEventListener("input", (_) => makeCode());
22 | makeCode();
23 | };
24 |
--------------------------------------------------------------------------------
/scripts/textToSpeech.js:
--------------------------------------------------------------------------------
1 | export default {
2 | icon: '',
3 | name: {
4 | en: "Text to Speech (j2team)",
5 | vi: "Văn bản thành Giọng nói (j2team)",
6 | },
7 | description: {
8 | en: "Convert text to speech using j2team tool",
9 | vi: "Chuyển đổi văn bản thành giọng nói sử dụng công cụ của j2team",
10 | },
11 |
12 | popupScript: {
13 | onClick: () => {
14 | window.open("https://j2team.dev/tools/text-to-speech");
15 | },
16 | },
17 | };
18 |
19 | const backup = () => {
20 | // https://developer.chrome.com/docs/extensions/reference/api/tts
21 | UfsGlobal.Extension.runInBackground("chrome.tts.speak", [
22 | "Xin chào tất cả mọi người.",
23 | { lang: "vi-VN", rate: 0.1 },
24 | ]);
25 | };
26 |
--------------------------------------------------------------------------------
/scripts/tiktok_batchDownload.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Useful-Scripts-Extension/useful-script/3841517b641a602d6360cf9b43152bee2524bd7f/scripts/tiktok_batchDownload.png
--------------------------------------------------------------------------------
/scripts/tiktok_downloadVideo.js:
--------------------------------------------------------------------------------
1 | export default {
2 | icon: "https://www.tiktok.com/favicon.ico",
3 | name: {
4 | en: "Tiktok - Download video from URL",
5 | vi: "Tiktok - Tải video từ URL",
6 | },
7 | description: {
8 | en: "Download tiktok video from url (no watermark)",
9 | vi: "Tải video tiktok từ link (không watermark)",
10 | },
11 |
12 | changeLogs: {
13 | "2024-04-27": "fix bug - use snaptik",
14 | },
15 |
16 | popupScript: {
17 | onClick: async function () {
18 | const { runScriptInCurrentTab, showLoading } = await import(
19 | "./helpers/utils.js"
20 | );
21 |
22 | let url = prompt(
23 | "Nhập link tiktok video: ",
24 | await runScriptInCurrentTab(() => location.href)
25 | );
26 | if (url == null) return;
27 |
28 | let { closeLoading } = showLoading(
29 | "Đang lấy link video không watermark..."
30 | );
31 | try {
32 | let link = "";
33 | link = await shared.getVideoNoWaterMark(url);
34 | if (link) window.open(link);
35 | else throw Error("Không tìm được video không watermark");
36 | } catch (e) {
37 | alert("ERROR: " + e);
38 | } finally {
39 | closeLoading();
40 | }
41 | },
42 | },
43 | };
44 |
45 | export const shared = {
46 | // Source code: https://github.com/karim0sec/tiktokdl
47 | getTiktokVideoIdFromUrl: function (url) {
48 | if (url.includes("@") && url.includes("/video/"))
49 | return url.split("/video/")[1].split("?")[0];
50 | throw Error("URL video tiktok không đúng địng dạng");
51 | },
52 |
53 | getVideoNoWaterMark: async function (video_url, isVideoId = false) {
54 | const { downloadTiktokVideoFromUrl, downloadTiktokVideoFromId } =
55 | await import("./tiktok_GLOBAL.js");
56 |
57 | let link = await downloadTiktokVideoFromUrl(video_url);
58 | if (!link) {
59 | let videoId = isVideoId
60 | ? video_url
61 | : shared.getTiktokVideoIdFromUrl(video_url);
62 | if (!videoId) throw Error("Video URL không đúng định dạng");
63 | link = await downloadTiktokVideoFromId(videoId);
64 | }
65 | return link;
66 | },
67 | };
68 |
--------------------------------------------------------------------------------
/scripts/toggleEditPage.js:
--------------------------------------------------------------------------------
1 | export default {
2 | icon: ``,
3 | name: {
4 | en: "Toggle edit page",
5 | vi: "Bật/tắt chế độ chỉnh sửa website",
6 | },
7 | description: {
8 | en: "Edit all text in website",
9 | vi: "Cho phép chỉnh sửa mọi văn bản trong website",
10 | },
11 |
12 | contentScript: {
13 | onClick: function () {
14 | let isOn = document.designMode == "on";
15 |
16 | if (!isOn) {
17 | document.body.contentEditable = "true";
18 | document.designMode = "on";
19 |
20 | alert("Bạn có thể chỉnh sửa ngay bây giờ");
21 | } else {
22 | document.body.contentEditable = "false";
23 | document.designMode = "off";
24 |
25 | alert("Đã tắt chế độ chỉnh sửa");
26 | }
27 | },
28 | },
29 | };
30 |
--------------------------------------------------------------------------------
/scripts/toggle_passwordField.js:
--------------------------------------------------------------------------------
1 | export default {
2 | icon: '',
3 | name: {
4 | en: "Hide/Show password field",
5 | vi: "Ẩn/Hiện ô nhập mật khẩu",
6 | },
7 | description: {
8 | en: "Show/hide value of password fields in website
(eg. **** -> 1234)",
9 | vi: "Ẩn/hiện giá trị trong các ô nhập mật khẩu
(ví dụ **** -> 1234)",
10 | img: "",
11 | },
12 |
13 | changeLogs: {
14 | ["2024-05-18"]: "init",
15 | },
16 |
17 | contentScript: {
18 | onClick: () => {
19 | let inpPass = Array.from(
20 | document.querySelectorAll(
21 | 'input[type="password"], input[ufs-toggle-pass="true"]'
22 | )
23 | );
24 |
25 | if (!inpPass.length) {
26 | alert("No password field found.\nKhông có ô nhập mật khẩu nào");
27 | return;
28 | }
29 |
30 | for (let inp of inpPass) {
31 | inp.type = inp.type == "password" ? "text" : "password";
32 | inp.setAttribute("ufs-toggle-pass", "true");
33 | }
34 | },
35 | },
36 | };
37 |
--------------------------------------------------------------------------------
/scripts/twitter_downloadButton.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Useful-Scripts-Extension/useful-script/3841517b641a602d6360cf9b43152bee2524bd7f/scripts/twitter_downloadButton.png
--------------------------------------------------------------------------------
/scripts/viewCookies.js:
--------------------------------------------------------------------------------
1 | export default {
2 | icon: ``,
3 | name: {
4 | en: "View cookies",
5 | vi: "Xem cookies",
6 | },
7 | description: {
8 | en: "View cookies saved in current website",
9 | vi: "Xem cookies được lưu trong website hiện tại",
10 | },
11 |
12 | contentScript: {
13 | onClick: function () {
14 | var c = document.cookie.replace(/; /g, "\n");
15 | if (c == "") {
16 | alert("There is No cookie here");
17 | } else {
18 | c = decodeURI(c);
19 | prompt(`Cookies found:\n\n${c}\n\nYou can copy cookie here:`, c);
20 | }
21 | },
22 | },
23 | };
24 |
--------------------------------------------------------------------------------
/scripts/viewStylesUsed.js:
--------------------------------------------------------------------------------
1 | export default {
2 | icon: ``,
3 | name: {
4 | en: "View stylesheet used",
5 | vi: "Xem tất cả stylesheet",
6 | },
7 | description: {
8 | en: "View all stylesheet used in current website",
9 | vi: "Mở danh sách css được dùng bởi website trong tab mới",
10 | },
11 |
12 | contentScript: {
13 | onClick: function () {
14 | let s = document.getElementsByTagName("STYLE"),
15 | ex = document.getElementsByTagName("LINK"),
16 | d = window.open().document /*set base href*/,
17 | b = d.body;
18 |
19 | function trim(s) {
20 | return s.replace(/^\s*\n/, "").replace(/\s*$/, "");
21 | }
22 |
23 | function iff(a, b, c) {
24 | return b ? a + b + c : "";
25 | }
26 |
27 | function add(h) {
28 | b.appendChild(h);
29 | }
30 |
31 | function makeTag(t) {
32 | return d.createElement(t);
33 | }
34 |
35 | function makeText(tag, text) {
36 | let t = makeTag(tag);
37 | t.appendChild(d.createTextNode(text));
38 | return t;
39 | }
40 | add(makeText("style", "iframe{width:100%;height:18em;border:1px solid;"));
41 | add(makeText("h3", (d.title = "Style sheets in " + location.href)));
42 | for (let i = 0; i < s.length; ++i) {
43 | add(
44 | makeText(
45 | "h4",
46 | "Inline style sheet" + iff(' title="', s[i].title, '"')
47 | )
48 | );
49 | add(makeText("pre", trim(s[i].innerHTML)));
50 | }
51 | for (let i = 0; i < ex.length; ++i) {
52 | let rs = ex[i].rel.split(" ");
53 | for (let j = 0; j < rs.length; ++j)
54 | if (rs[j].toLowerCase() == "stylesheet") {
55 | add(
56 | makeText(
57 | "h4",
58 | 'link rel="' +
59 | ex[i].rel +
60 | '" href="' +
61 | ex[i].href +
62 | '"' +
63 | iff(' title="', ex[i].title, '"')
64 | )
65 | );
66 | let iframe = makeTag("iframe");
67 | iframe.src = ex[i].href;
68 | add(iframe);
69 | break;
70 | }
71 | }
72 | },
73 | },
74 | };
75 |
--------------------------------------------------------------------------------
/scripts/viewWebMetaInfo.js:
--------------------------------------------------------------------------------
1 | import { UfsGlobal } from "./content-scripts/ufs_global.js";
2 |
3 | export default {
4 | icon: "https://s2.googleusercontent.com/s2/favicons?domain_url=https://www.ouiseo.com/",
5 | name: {
6 | en: "See web meta info (SEO)",
7 | vi: "Xem thông tin meta của web (SEO)",
8 | },
9 | description: {
10 | en: "Instantly shows meta information about the current site in an on-page iFrame.",
11 | vi: "Xem thông tin meta của website trực tiếp trong trang web",
12 | },
13 |
14 | pageScript: {
15 | onClick: async function () {
16 | // source code from: https://bookmarklet.vercel.app/
17 |
18 | if (window.ouiseo === undefined) {
19 | await UfsGlobal.DOM.injectScriptSrcAsync(
20 | "//carlsednaoui.s3.amazonaws.com/ouiseo/ouiseo.min.js",
21 | (success, fail) => {
22 | if (success) {
23 | console.log("ouiseo injected");
24 | ouiseo();
25 | } else {
26 | alert("Inject script failed. Cannot run script in this website");
27 | }
28 | }
29 | );
30 | } else if (!!window.ouiseo && !document.getElementById("ouiseo")) {
31 | ouiseo();
32 | } else {
33 | console.log("ouiseo is already open");
34 | }
35 | },
36 | },
37 | };
38 |
--------------------------------------------------------------------------------
/scripts/vimeo_downloader.js:
--------------------------------------------------------------------------------
1 | export default {
2 | icon: "https://vimeo.com/favicon.ico",
3 | name: {
4 | en: "Vimeo - video downloader",
5 | vi: "Vimeo - tải video",
6 | },
7 | description: {
8 | en: "Download video from vimeo",
9 | vi: "Tải video trên vimeo",
10 | },
11 |
12 | popupScript: {
13 | onClick: async function () {
14 | const { getCurrentTab } = await import("./helpers/utils.js");
15 |
16 | let tab = await getCurrentTab();
17 | let url = prompt("Enter vimeo video url: ", tab.url);
18 | if (url == null) return;
19 |
20 | window.open("https://www.savethevideo.com/vimeo-downloader?url=" + url);
21 | },
22 | },
23 | };
24 |
--------------------------------------------------------------------------------
/scripts/visualEvent.js:
--------------------------------------------------------------------------------
1 | export default {
2 | icon: "http://www.sprymedia.co.uk/favicon.ico",
3 | name: {
4 | en: "Show all javascript events",
5 | vi: "Xem tất cả tất cả javascript events",
6 | },
7 | description: {
8 | en: "Visual Event - Visually show Javascript events on a page",
9 | vi: "Visual Event - Hiển thị tất cả javascript events xuất hiện trong trang web",
10 | },
11 |
12 | pageScript: {
13 | onClick: function () {
14 | // http://www.sprymedia.co.uk/article/Visual+Event+2
15 |
16 | var protocol = window.location.protocol === "file:" ? "http:" : "";
17 | var url =
18 | protocol + "//www.sprymedia.co.uk/VisualEvent/VisualEvent_Loader.js";
19 | if (typeof VisualEvent != "undefined") {
20 | if (VisualEvent.instance !== null) {
21 | VisualEvent.close();
22 | } else {
23 | new VisualEvent();
24 | }
25 | } else {
26 | var n = document.createElement("script");
27 | n.setAttribute("language", "JavaScript");
28 | n.setAttribute("src", url + "?rand=" + new Date().getTime());
29 | document.body.appendChild(n);
30 | }
31 | },
32 | },
33 | };
34 |
35 | // https://stackoverflow.com/a/10213800/11898496
36 |
--------------------------------------------------------------------------------
/scripts/vuiz_createLogo.js:
--------------------------------------------------------------------------------
1 | export default {
2 | icon: "https://m.vuiz.net/template/favicon.ico",
3 | name: {
4 | en: "Vuiz - create logo WAP online",
5 | vi: "Vuiz - Tạo logo WAP online",
6 | },
7 | description: {
8 | en: "Create logo from text online",
9 | vi: "Tạo logo chữ đẹp theo mẫu có sẵn",
10 | },
11 |
12 | popupScript: {
13 | onClick: () => window.open("https://m.vuiz.net/logo/"),
14 | },
15 | };
16 |
--------------------------------------------------------------------------------
/scripts/vuiz_getLink.js:
--------------------------------------------------------------------------------
1 | export default {
2 | icon: "https://m.vuiz.net/template/favicon.ico",
3 | name: {
4 | en: "Vuiz - Get link audio/video/album",
5 | vi: "Vuiz - Get link nhạc/video/album",
6 | },
7 | description: {
8 | en: "Support youtube, facebook, tiktok, zing tv, zing mp3, xVideo, nhac.vn, mixcloud, soundcloud, keeng.vn, chiasenhac, nhaccuatui, mediafire, ggdrive, dropbox, ondrive",
9 | vi: "Hỗ trợ youtube, facebook, tiktok, zing tv, zing mp3, xVideo, nhac.vn, mixcloud, soundcloud, keeng.vn, chiasenhac, nhaccuatui, mediafire, ggdrive, dropbox, ondrive",
10 | },
11 |
12 | popupScript: {
13 | onClick: () => window.open("https://m.vuiz.net/"),
14 | },
15 | };
16 |
--------------------------------------------------------------------------------
/scripts/webToPDF.js:
--------------------------------------------------------------------------------
1 | import { UfsGlobal } from "./content-scripts/ufs_global.js";
2 | import { BADGES } from "./helpers/badge.js";
3 | import {
4 | attachDebugger,
5 | detachDebugger,
6 | getCurrentTab,
7 | sendDevtoolCommand,
8 | showLoading,
9 | } from "./helpers/utils.js";
10 |
11 | export default {
12 | icon: `https://lh3.googleusercontent.com/qz7_-nogEpLsoxevV_IQbz0UesDFWsbmKyv_vOGUhMRSu6pEYAJCUM50QkTBvw8saVNSmwB0DBpLSBZgfpmAYL3bgh4=w128-h128-e365-rj-sc0x00ffffff`,
13 | name: {
14 | en: "Web to PDF",
15 | vi: "In web ra PDF",
16 | },
17 | description: {
18 | en: "Convert current website to PDF",
19 | vi: "Chuyển trang web hiện tại thành PDF",
20 | },
21 | badges: [BADGES.hot],
22 |
23 | popupScript: {
24 | onClick: async function () {
25 | const { setLoadingText, closeLoading } = showLoading("Đang tạo PDF...");
26 | let tab = await getCurrentTab();
27 | try {
28 | // https://chromedevtools.github.io/devtools-protocol/tot/Page/#method-printToPDF
29 | await attachDebugger(tab);
30 | let res = await sendDevtoolCommand(tab, "Page.printToPDF", {
31 | // displayHeaderFooter: true,
32 | printBackground: true,
33 | });
34 | await detachDebugger(tab);
35 |
36 | UfsGlobal.Extension.download({
37 | url: "data:application/pdf;base64," + res.data,
38 | filename: "web.pdf",
39 | });
40 | } catch (e) {
41 | if (
42 | confirm(
43 | "Lỗi: " +
44 | e +
45 | "\n\nBạn có muốn dùng phương án 2? Dùng trang web web2pdfconvert?"
46 | )
47 | ) {
48 | window.open("https://www.web2pdfconvert.com#" + tab.url);
49 | }
50 | }
51 | closeLoading();
52 | },
53 | },
54 | };
55 |
--------------------------------------------------------------------------------
/scripts/web_timer.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Web Timer - Useful script
8 |
9 |
10 |
11 |
12 |
17 |
18 |
19 |
20 | Webtimer - Useful scripts
21 |
22 |
31 | No data
32 |
33 |
34 |
35 | ↗
36 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/scripts/web_timer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Useful-Scripts-Extension/useful-script/3841517b641a602d6360cf9b43152bee2524bd7f/scripts/web_timer.png
--------------------------------------------------------------------------------
/scripts/whatFont.js:
--------------------------------------------------------------------------------
1 | import { UfsGlobal } from "./content-scripts/ufs_global.js";
2 |
3 | export default {
4 | icon: `https://www.typewolf.com/favicon.ico`,
5 | name: {
6 | en: "What font",
7 | vi: "Kiểm tra font chữ",
8 | },
9 | description: {
10 | en: "Check font used in webpage",
11 | vi: "Kiểm tra xem từng phần tử trong web dùng font chữ gì",
12 | },
13 |
14 | pageScript: {
15 | onClick: async function () {
16 | // https://www.typewolf.com/type-sample
17 | UfsGlobal.DOM.injectScriptSrc(
18 | "https://www.typesample.com/assets/typesample.js?r=" +
19 | Math.random() * 99999999,
20 | (success, fail) => {
21 | if (success) {
22 | alert("Script loaded, now use can use WhatFont.");
23 | } else {
24 | alert("Inject failed, Cannot run script in this website");
25 | }
26 | }
27 | );
28 | },
29 | },
30 | };
31 |
--------------------------------------------------------------------------------
/scripts/whatWebsiteStack.js:
--------------------------------------------------------------------------------
1 | import { UfsGlobal } from "./content-scripts/ufs_global.js";
2 |
3 | export default {
4 | icon: `https://www.wappalyzer.com/favicon.ico`,
5 | name: {
6 | en: "View website stack",
7 | vi: "Web dùng công nghệ gì?",
8 | },
9 | description: {
10 | en: "Technology that current website is using",
11 | vi: "Xem những công nghệ/thư viện trang web đang dùng",
12 | },
13 |
14 | pageScript: {
15 | onClick: async function () {
16 | var doc = document,
17 | exist = doc.getElementById("wappalyzer-container");
18 | if (exist !== null) {
19 | doc.body.removeChild(exist);
20 | }
21 | var url = "https://www.wappalyzer.com/",
22 | time = new Date().getTime(),
23 | container = doc.createElement("div"),
24 | loading = doc.createElement("div"),
25 | link = doc.createElement("link");
26 |
27 | container.setAttribute("id", "wappalyzer-container");
28 | link.setAttribute("rel", "stylesheet");
29 | link.setAttribute("href", url + "css/bookmarklet.css");
30 | doc.head.appendChild(link);
31 |
32 | loading.setAttribute("id", "wappalyzer-pending");
33 | loading.setAttribute(
34 | "style",
35 | "background-image: url(" + url + "images/spinner.gif) !important"
36 | );
37 | container.appendChild(loading);
38 | doc.body.appendChild(container);
39 |
40 | const { setText, closeAfter } = UfsGlobal.DOM.notify({
41 | msg: "Useful-script: Injecting scripts...",
42 | align: "center",
43 | styleText: "",
44 | duration: 9999,
45 | });
46 |
47 | try {
48 | setText("Injecting wappalyzer.js ...");
49 | await UfsGlobal.DOM.injectScriptSrcAsync(
50 | url + "bookmarklet/wappalyzer.js"
51 | );
52 | window.wappalyzer = new Wappalyzer();
53 | setText("Injecting apps.js ...");
54 | await UfsGlobal.DOM.injectScriptSrcAsync(url + "bookmarklet/apps.js");
55 | setText("Injecting driver.js ...");
56 | await UfsGlobal.DOM.injectScriptSrcAsync(url + "bookmarklet/driver.js");
57 | } catch (e) {
58 | alert("Error: Cannot run script: " + JSON.stringify(e));
59 | closeAfter(0);
60 | }
61 | },
62 | },
63 | };
64 |
--------------------------------------------------------------------------------
/scripts/whois.js:
--------------------------------------------------------------------------------
1 | export default {
2 | icon: "https://who.is/favicon.ico",
3 | name: {
4 | en: "Who.is",
5 | vi: "Who.is",
6 | },
7 | description: {
8 | en: "Want to find out who owns a domain? Click on this!",
9 | vi: "Muốn biết ai đang giữ domain này? Click ngay!",
10 | },
11 |
12 | contentScript: {
13 | onClick: function () {
14 | window.open("http://who.is/whois/" + document.domain);
15 | },
16 | },
17 | };
18 |
--------------------------------------------------------------------------------
/scripts/youglish_search.js:
--------------------------------------------------------------------------------
1 | import { BADGES } from './helpers/badge.js';
2 |
3 | const contextMenuId = 'youglish-search';
4 |
5 | export default {
6 | icon: '',
7 | name: {
8 | en: 'YouGlish search',
9 | vi: 'Tìm kiếm trên YouGlish',
10 | },
11 | description: {
12 | 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')",
13 | 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")',
14 | },
15 | badges: [BADGES.new],
16 | changeLogs: {
17 | '2024-07-06': 'init',
18 | },
19 |
20 | popupScript: {
21 | onClick: () => window.close(),
22 | },
23 |
24 | backgroundScript: {
25 | runtime: {
26 | onInstalled: () => {
27 | chrome.contextMenus.create({
28 | title: 'YouGlish Search',
29 | contexts: ['selection'],
30 | id: contextMenuId,
31 | parentId: 'root',
32 | });
33 | },
34 | },
35 | contextMenus: {
36 | onClicked: ({ info }, context) => {
37 | if (info.menuItemId == contextMenuId) {
38 | const content = (info.selectionText || '').trim().toLowerCase();
39 | if (!content.length) return;
40 |
41 | const link = `https://youglish.com/pronounce/${content}/english`;
42 | chrome.tabs.create({ url: link });
43 | }
44 | },
45 | },
46 | },
47 | };
48 |
--------------------------------------------------------------------------------
/scripts/youtube_downloadVideo.css:
--------------------------------------------------------------------------------
1 | .ufs-ytDownloadVideo__btn {
2 | color: #f1f1f1;
3 | display: inline-block;
4 | padding: 2px 12px;
5 | border-radius: 6px;
6 | text-decoration: none;
7 | font-weight: bold;
8 | width: 100%;
9 | text-align: left;
10 | -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
11 | -webkit-tap-highlight-color: transparent;
12 | }
13 |
14 | .ufs-ytDownloadVideo__btn:hover {
15 | background-color: #333;
16 | }
17 |
18 | .ufs-ytDownloadVideo__dropdown {
19 | background-color: #272727;
20 | z-index: 999;
21 | position: absolute;
22 | top: 45px;
23 | left: 0;
24 |
25 | display: none;
26 | flex-flow: column;
27 | justify-content: start;
28 | align-items: start;
29 |
30 | overflow: hidden auto;
31 | width: max-content;
32 | max-height: 250px;
33 | padding: 8px;
34 | border-radius: 12px;
35 | }
36 |
--------------------------------------------------------------------------------
/scripts/youtube_downloadVideo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Useful-Scripts-Extension/useful-script/3841517b641a602d6360cf9b43152bee2524bd7f/scripts/youtube_downloadVideo.png
--------------------------------------------------------------------------------
/scripts/youtube_getVideoCaption.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Useful-Scripts-Extension/useful-script/3841517b641a602d6360cf9b43152bee2524bd7f/scripts/youtube_getVideoCaption.png
--------------------------------------------------------------------------------
/scripts/youtube_getVideoThumbnail.js:
--------------------------------------------------------------------------------
1 | import { getIdFromYoutubeURL } from "./youtube_downloadVideo.js";
2 |
3 | export default {
4 | icon: '',
5 | name: {
6 | en: "Get Youtube video's thumbnail",
7 | vi: "Lấy thumbnail video trên Youtube",
8 | },
9 | description: {
10 | en: "Get largest thumbnail of playing youtube video",
11 | vi: "Tải về hình thumbnail độ phân giải lớn nhất của video youtube đang xem",
12 | },
13 | changeLogs: {
14 | "2024-07-04": "init",
15 | },
16 |
17 | whiteList: ["https://*.youtube.com/*"],
18 |
19 | pageScript: {
20 | onClick: () => {
21 | const methods = [
22 | () =>
23 | document
24 | .getElementsByTagName("ytd-app")[0]
25 | .data.playerResponse.videoDetails.thumbnail.thumbnails.sort(
26 | (a, b) => b.width * b.height - a.width * a.height
27 | )[0].url,
28 | () =>
29 | ytplayer.config.args.raw_player_response.videoDetails.thumbnail.thumbnails.sort(
30 | (a, b) => b.width * b.height - a.width * a.height
31 | )[0].url,
32 | () =>
33 | `https://i.ytimg.com/vi/${getIdFromYoutubeURL(
34 | location.href
35 | )}/maxresdefault.jpg`,
36 | ];
37 |
38 | for (let f of methods) {
39 | try {
40 | let url = f();
41 | if (url) {
42 | window.open(url, "_blank");
43 | return;
44 | }
45 | } catch (e) {
46 | console.error(e);
47 | }
48 | }
49 | },
50 | },
51 | };
52 |
--------------------------------------------------------------------------------
/scripts/youtube_nonstop.js:
--------------------------------------------------------------------------------
1 | export default {
2 | icon: '',
3 | name: {
4 | en: "Youtube nonstop",
5 | vi: "Youtube nonstop",
6 | },
7 | description: {
8 | en: 'Kiss the annoying "Video paused. Continue watching?" confirmation goodbye!',
9 | vi: "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.",
10 | img: "/scripts/youtube_nonstop.png",
11 | },
12 | whiteList: ["*://*.youtube.com/*"],
13 |
14 | pageScript: {
15 | onDocumentStart: function () {
16 | // ==UserScript==
17 | // @name YouTube - Stay Active and Play Forever
18 | // @namespace q1k
19 | // @version 3.1.1
20 | // @description Tired of Youtube pausing playback asking you to click 'yes' to continue playing? This script will make the popup never appear, music will never stop. Never pause, never inactive, never worry. The script will keep you active and keep playing music FOREVER. Enables playing in background on mobile.
21 | // @author q1k
22 | // @match *://*.youtube.com/*
23 | // @run-at document-start
24 | // ==/UserScript==
25 |
26 | Object.defineProperties(document, {
27 | /*'hidden': {value: false},*/ webkitHidden: { value: false },
28 | visibilityState: { value: "visible" },
29 | webkitVisibilityState: { value: "visible" },
30 | });
31 |
32 | setInterval(function () {
33 | document.dispatchEvent(
34 | new KeyboardEvent("keyup", {
35 | bubbles: true,
36 | cancelable: true,
37 | keyCode: 143,
38 | which: 143,
39 | })
40 | );
41 | }, 60000);
42 | },
43 | },
44 | };
45 |
--------------------------------------------------------------------------------
/scripts/youtube_nonstop.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Useful-Scripts-Extension/useful-script/3841517b641a602d6360cf9b43152bee2524bd7f/scripts/youtube_nonstop.png
--------------------------------------------------------------------------------
/scripts/youtube_toggleLight.js:
--------------------------------------------------------------------------------
1 | export default {
2 | icon: '',
3 | name: {
4 | en: "Toggle light youtube",
5 | vi: "Tắt/Mở đèn youtube",
6 | },
7 | description: {
8 | en: "Toggle light on/off to focus to youtube video",
9 | vi: "Tắt/Mở đèn để tập trung xem video youtube",
10 | },
11 | whiteList: ["*://www.youtube.com/*"],
12 |
13 | contentScript: {
14 | onClick: function () {
15 | ["#below", "#secondary", "#masthead-container"].forEach((_) => {
16 | let doms = document.querySelectorAll(_);
17 | Array.from(doms).forEach((dom) => {
18 | let current = dom.style.opacity || 1;
19 | let newValue = current == 1 ? 0 : 1;
20 | dom.style.opacity = newValue;
21 | dom.style.pointerEvents = newValue ? "" : "none";
22 | });
23 | });
24 |
25 | document.querySelector("ytd-player")?.scrollIntoView?.({
26 | behavior: "smooth",
27 | block: "center",
28 | });
29 | },
30 | },
31 | };
32 |
--------------------------------------------------------------------------------
/templates/simple.js:
--------------------------------------------------------------------------------
1 | export default {
2 | icon: "",
3 | name: {
4 | en: "",
5 | vi: "",
6 | },
7 | description: {
8 | en: "",
9 | vi: "",
10 | img: "",
11 | },
12 |
13 | infoLink: "",
14 |
15 | changeLogs: {
16 | date: "description",
17 | },
18 |
19 | blackList: [],
20 | whiteList: [],
21 |
22 | popupScript: {
23 | onEnable: () => {},
24 | onDisable: () => {},
25 |
26 | onClick: () => {},
27 | },
28 |
29 | contentScript: {
30 | onDocumentStart: (details) => {},
31 | onDocumentIdle: (details) => {},
32 | onDocumentEnd: (details) => {},
33 |
34 | onClick: () => {},
35 | },
36 |
37 | pageScript: {
38 | onDocumentStart: (details) => {},
39 | onDocumentIdle: (details) => {},
40 | onDocumentEnd: (details) => {},
41 |
42 | onClick: () => {},
43 | },
44 |
45 | backgroundScript: {
46 | onDocumentStart: (details, context) => {},
47 | onDocumentIdle: (details, context) => {},
48 | onDocumentEnd: (details, context) => {},
49 | },
50 | };
51 |
--------------------------------------------------------------------------------