Repository: fmhy/edit Branch: main Commit: 4a33c13cd339 Files: 286 Total size: 5.0 MB Directory structure: gitextract_e2k2ctcw/ ├── .devcontainer/ │ └── devcontainer.json ├── .dockerignore ├── .gitattributes ├── .github/ │ ├── CODEOWNERS │ ├── CONTRIBUTING.md │ ├── ISSUE_TEMPLATE/ │ │ └── wiki.yml │ ├── POST_TEMPLATE.md │ ├── README.md │ ├── assets/ │ │ └── nginx.conf │ └── workflows/ │ ├── deploy-api.yml │ └── deploy-gh-pages.yml ├── .gitignore ├── .gitpod.yml ├── .licenserc.json ├── .mise.toml ├── .npmrc ├── .prettierignore ├── .prettierrc.yaml ├── Dockerfile ├── api/ │ ├── README.md │ ├── middleware/ │ │ ├── cors.ts │ │ └── ratelimit.ts │ ├── routes/ │ │ ├── feedback.post.ts │ │ ├── index.ts │ │ └── single-page.ts │ ├── tsconfig.json │ └── worker-configuration.d.ts ├── docker-compose.yaml ├── docs/ │ ├── .vitepress/ │ │ ├── LICENSE │ │ ├── README.md │ │ ├── config.mts │ │ ├── constants.ts │ │ ├── fonts/ │ │ │ ├── Inter-Bold.otf │ │ │ ├── Inter-Medium.otf │ │ │ ├── Inter-Regular.otf │ │ │ └── Inter-SemiBold.otf │ │ ├── hooks/ │ │ │ ├── Template.vue │ │ │ ├── index.ts │ │ │ ├── meta.ts │ │ │ ├── opengraph.ts │ │ │ ├── rss.ts │ │ │ └── satoriConfig.ts │ │ ├── markdown/ │ │ │ ├── base64.ts │ │ │ ├── emoji.ts │ │ │ ├── headers.ts │ │ │ └── toggleStarred.ts │ │ ├── notes/ │ │ │ ├── 1337x-ranks.md │ │ │ ├── CodeRabbit.md │ │ │ ├── advanced-logic-calculators.md │ │ │ ├── affine-note.md │ │ │ ├── alt-twitch-player-extensions.md │ │ │ ├── alt-warp-clients.md │ │ │ ├── android-spotify-note.md │ │ │ ├── apkmirror-extensions.md │ │ │ ├── audiobookbay-warning.md │ │ │ ├── aurora-note.md │ │ │ ├── better-reasoning.md │ │ │ ├── bookmarkeddit.md │ │ │ ├── buster-note.md │ │ │ ├── buzzheavier-warning.md │ │ │ ├── bypass-freedlink.md │ │ │ ├── captcha-4pda.md │ │ │ ├── chatgpt-limits.md │ │ │ ├── clipboard2file-addons.md │ │ │ ├── cofi-note.md │ │ │ ├── crystaldiskinfo.md │ │ │ ├── csrin-search.md │ │ │ ├── cute-save-button-icon.md │ │ │ ├── dodi-warning.md │ │ │ ├── dolby-access-atmos-note.md │ │ │ ├── driver-note.md │ │ │ ├── eaglercraft-note.md │ │ │ ├── eruda.md │ │ │ ├── filebin-warning.md │ │ │ ├── filelu-warning.md │ │ │ ├── filezilla-warning.md │ │ │ ├── flicker-proxy.md │ │ │ ├── fluxy-repacks.md │ │ │ ├── forest-extensions.md │ │ │ ├── foxit-warning.md │ │ │ ├── freegogpcgames-note.md │ │ │ ├── gemai.md │ │ │ ├── general-tweak-warning.md │ │ │ ├── glitchwave-note.md │ │ │ ├── google-song-identification.md │ │ │ ├── google-translate-note.md │ │ │ ├── hdo-box-note.md │ │ │ ├── hugging-face-warning.md │ │ │ ├── instaeclipse-note.md │ │ │ ├── irc-highway-note.md │ │ │ ├── jdownloader-warning.md │ │ │ ├── limit-bypass-note.md │ │ │ ├── liteapk-modyolo-note.md │ │ │ ├── malware-removal-forums.md │ │ │ ├── megabasterd-note.md │ │ │ ├── mobilism-ranks.md │ │ │ ├── modelscope.md │ │ │ ├── mori-note.md │ │ │ ├── movie-web-sources.md │ │ │ ├── movieparadise-code.md │ │ │ ├── mp-opensubs.md │ │ │ ├── mvsep-note.md │ │ │ ├── oneclick-note.md │ │ │ ├── openasar.md │ │ │ ├── openrgb-beta.md │ │ │ ├── pollinations-limits.md │ │ │ ├── printeditwe-addons.md │ │ │ ├── proton-torrenting.md │ │ │ ├── reaper-note.md │ │ │ ├── redditfilter-note.md │ │ │ ├── rgshows-autoplay.md │ │ │ ├── sanet-warning.md │ │ │ ├── savepagewe.md │ │ │ ├── scrollanywhere-addons.md │ │ │ ├── sd-maid.md │ │ │ ├── sh-note.md │ │ │ ├── site-favicon-dl.md │ │ │ ├── soft98-note.md │ │ │ ├── sora.md │ │ │ ├── spacewar.md │ │ │ ├── spicetify-note.md │ │ │ ├── sport7.md │ │ │ ├── steam-controller-support.md │ │ │ ├── steam-currency-converter-note.md │ │ │ ├── tabiverse-extensions.md │ │ │ ├── tautulli-note.md │ │ │ ├── teamspeak-warning.md │ │ │ ├── thunderbird.md │ │ │ ├── tinyurl-note.md │ │ │ ├── video-downloadhelper.md │ │ │ ├── welib-note.md │ │ │ ├── winrar.md │ │ │ ├── yet-another-call-blocker-note.md │ │ │ ├── youtube-tweaks.md │ │ │ └── yts-yify-note.md │ │ ├── shared.ts │ │ ├── theme/ │ │ │ ├── Appearance.vue │ │ │ ├── Layout.vue │ │ │ ├── PostLayout.vue │ │ │ ├── Posts.vue │ │ │ ├── components/ │ │ │ │ ├── Announcement.vue │ │ │ │ ├── Authors.vue │ │ │ │ ├── Base64Dialog.vue │ │ │ │ ├── CardField.vue │ │ │ │ ├── ColorPicker.vue │ │ │ │ ├── Feedback.vue │ │ │ │ ├── InputField.vue │ │ │ │ ├── SidebarCard.vue │ │ │ │ ├── Switch.vue │ │ │ │ ├── ThemeDropdown.vue │ │ │ │ ├── ThemeSelector.vue │ │ │ │ ├── ToggleIndexes.vue │ │ │ │ ├── ToggleStarred.vue │ │ │ │ ├── Tooltip.vue │ │ │ │ ├── VPLocalSearchBox.vue │ │ │ │ ├── VPNav.vue │ │ │ │ ├── WallpaperCard.vue │ │ │ │ └── startpage/ │ │ │ │ ├── Bookmarks.vue │ │ │ │ ├── Clock.vue │ │ │ │ ├── SearchBar.vue │ │ │ │ └── Startpage.vue │ │ │ ├── composables/ │ │ │ │ └── nprogress.ts │ │ │ ├── index.ts │ │ │ ├── posts.data.ts │ │ │ ├── style.scss │ │ │ └── themes/ │ │ │ ├── README.md │ │ │ ├── configs/ │ │ │ │ ├── catppuccin.ts │ │ │ │ ├── christmas.ts │ │ │ │ ├── index.ts │ │ │ │ └── monochrome.ts │ │ │ ├── index.ts │ │ │ ├── themeHandler.ts │ │ │ └── types.ts │ │ ├── transformer/ │ │ │ ├── constants.ts │ │ │ └── core.ts │ │ ├── transformer.ts │ │ ├── types/ │ │ │ └── Feedback.ts │ │ ├── utils/ │ │ │ ├── markdown.ts │ │ │ └── tooltips.ts │ │ ├── utils.ts │ │ └── vue-shim.d.ts │ ├── ai.md │ ├── audio.md │ ├── beginners-guide.md │ ├── developer-tools.md │ ├── downloading.md │ ├── educational.md │ ├── feedback.md │ ├── file-tools.md │ ├── gaming-tools.md │ ├── gaming.md │ ├── image-tools.md │ ├── index.md │ ├── internet-tools.md │ ├── linux-macos.md │ ├── misc.md │ ├── mobile.md │ ├── non-english.md │ ├── other/ │ │ ├── FAQ.md │ │ ├── backups.md │ │ ├── contributing.md │ │ ├── selfhosting.md │ │ └── wallpapers.md │ ├── posts/ │ │ ├── FCC.md │ │ ├── Internet-Archive.md │ │ ├── KeepAndroidOpen.md │ │ ├── Nov-2025.md │ │ ├── WWH.md │ │ ├── april-2023.md │ │ ├── april-2024.md │ │ ├── april-2025.md │ │ ├── aug-2023.md │ │ ├── aug-2024.md │ │ ├── aug-2025.md │ │ ├── changelog-sites.md │ │ ├── dec-2023.md │ │ ├── dec-2024.md │ │ ├── dec-2025.md │ │ ├── discord.md │ │ ├── feb-2024.md │ │ ├── feb-2025.md │ │ ├── feb-2026.md │ │ ├── jan-2024.md │ │ ├── jan-2025.md │ │ ├── jan-2026.md │ │ ├── july-2023.md │ │ ├── july-2024.md │ │ ├── july-2025.md │ │ ├── jun-2023.md │ │ ├── june-2024.md │ │ ├── june-2025.md │ │ ├── mar-2025.md │ │ ├── mar-2026.md │ │ ├── march-2024.md │ │ ├── may-2023.md │ │ ├── may-2024.md │ │ ├── may-2025.md │ │ ├── new-site.md │ │ ├── nov-2023.md │ │ ├── nov-2024.md │ │ ├── oct-2023.md │ │ ├── oct-2024.md │ │ ├── oct-2025.md │ │ ├── search.md │ │ ├── sept-2023.md │ │ ├── sept-2024.md │ │ ├── sept-2025.md │ │ └── support-ia.md │ ├── posts.md │ ├── privacy.md │ ├── public/ │ │ ├── _headers │ │ ├── key.txt │ │ ├── manifest.json │ │ └── robots.txt │ ├── reading.md │ ├── sandbox.md │ ├── social-media-tools.md │ ├── startpage.md │ ├── storage.md │ ├── system-tools.md │ ├── text-tools.md │ ├── torrenting.md │ ├── unsafe.md │ ├── video-tools.md │ └── video.md ├── flake.nix ├── nitro.config.ts ├── package.json ├── pests-repellent/ │ ├── .editorconfig │ ├── .gitignore │ ├── .prettierrc │ ├── .vscode/ │ │ └── settings.json │ ├── package.json │ ├── src/ │ │ └── index.ts │ ├── test/ │ │ ├── env.d.ts │ │ ├── index.spec.ts │ │ └── tsconfig.json │ ├── tsconfig.json │ ├── vitest.config.mts │ ├── worker-configuration.d.ts │ └── wrangler.jsonc ├── scripts/ │ ├── lint-markdown.js │ └── typos.csv ├── tsconfig.json ├── unocss.config.ts └── wrangler.toml ================================================ FILE CONTENTS ================================================ ================================================ FILE: .devcontainer/devcontainer.json ================================================ { "appPort": 5173, "features": {}, "image": "mcr.microsoft.com/devcontainers/universal:2", "name": "FMHYedit", "postAttachCommand": "pnpm docs:dev", "postStartCommand": "pnpm install" } ================================================ FILE: .dockerignore ================================================ node_modules .git .gitignore dist cache ================================================ FILE: .gitattributes ================================================ # Common settings that generally should always be used with your language specific settings # Auto detect text files and perform LF normalization * text=auto # # The above will handle all files NOT found below # # Documents *.bibtex text diff=bibtex *.doc diff=astextplain *.DOC diff=astextplain *.docx diff=astextplain *.DOCX diff=astextplain *.dot diff=astextplain *.DOT diff=astextplain *.pdf diff=astextplain *.PDF diff=astextplain *.rtf diff=astextplain *.RTF diff=astextplain *.md text diff=markdown *.mdx text diff=markdown *.tex text diff=tex *.adoc text *.textile text *.mustache text *.csv text eol=crlf *.tab text *.tsv text *.txt text *.sql text *.epub diff=astextplain # Graphics *.png binary *.jpg binary *.jpeg binary *.gif binary *.tif binary *.tiff binary *.ico binary # SVG treated as text by default. *.svg text # If you want to treat it as binary, # use the following line instead. # *.svg binary *.eps binary # Scripts *.bash text eol=lf *.fish text eol=lf *.ksh text eol=lf *.sh text eol=lf *.zsh text eol=lf # These are explicitly windows files and should use crlf *.bat text eol=crlf *.cmd text eol=crlf *.ps1 text eol=crlf # Serialisation *.json text *.toml text *.xml text *.yaml text *.yml text # Archives *.7z binary *.bz binary *.bz2 binary *.bzip2 binary *.gz binary *.lz binary *.lzma binary *.rar binary *.tar binary *.taz binary *.tbz binary *.tbz2 binary *.tgz binary *.tlz binary *.txz binary *.xz binary *.Z binary *.zip binary *.zst binary # Text files where line endings should be preserved *.patch -text # # Exclude files from exporting # .gitattributes export-ignore .gitignore export-ignore .gitkeep export-ignore ## GITATTRIBUTES FOR WEB PROJECTS # # These settings are for any web project. # # Details per file setting: # text These files should be normalized (i.e. convert CRLF to LF). # binary These files are binary and should be left untouched. # # Note that binary is a macro for -text -diff. ###################################################################### # Auto detect ## Handle line endings automatically for files detected as ## text and leave all files detected as binary untouched. ## This will handle all files NOT defined below. * text=auto # Source code *.bash text eol=lf *.bat text eol=crlf *.cmd text eol=crlf *.coffee text *.css text diff=css *.htm text diff=html *.html text diff=html *.inc text *.ini text *.js text *.mjs text *.cjs text *.json text *.jsx text *.less text *.ls text *.map text -diff *.od text *.onlydata text *.php text diff=php *.pl text *.ps1 text eol=crlf *.py text diff=python *.rb text diff=ruby *.sass text *.scm text *.scss text diff=css *.sh text eol=lf .husky/* text eol=lf *.sql text *.styl text *.tag text *.ts text *.tsx text *.xml text *.xhtml text diff=html # Docker Dockerfile text # Documentation *.ipynb text eol=lf *.markdown text diff=markdown *.md text diff=markdown *.mdwn text diff=markdown *.mdown text diff=markdown *.mkd text diff=markdown *.mkdn text diff=markdown *.mdtxt text *.mdtext text *.txt text AUTHORS text CHANGELOG text CHANGES text CONTRIBUTING text COPYING text copyright text *COPYRIGHT* text INSTALL text license text LICENSE text NEWS text readme text *README* text TODO text # Templates *.dot text *.ejs text *.erb text *.haml text *.handlebars text *.hbs text *.hbt text *.jade text *.latte text *.mustache text *.njk text *.phtml text *.svelte text *.tmpl text *.tpl text *.twig text *.vue text diff=vue # Configs *.cnf text *.conf text *.config text .editorconfig text .env text .gitattributes text .gitconfig text .htaccess text *.lock text -diff package.json text eol=lf package-lock.json text eol=lf -diff pnpm-lock.yaml text eol=lf -diff .prettierrc text yarn.lock text -diff *.toml text *.yaml text *.yml text browserslist text Makefile text makefile text # Fixes syntax highlighting on GitHub to allow comments tsconfig.json linguist-language=JSON-with-Comments # Heroku Procfile text # Graphics *.ai binary *.bmp binary *.eps binary *.gif binary *.gifv binary *.ico binary *.jng binary *.jp2 binary *.jpg binary *.jpeg binary *.jpx binary *.jxr binary *.pdf binary *.png binary *.psb binary *.psd binary # SVG treated as an asset (binary) by default. *.svg text # If you want to treat it as binary, # use the following line instead. # *.svg binary *.svgz binary *.tif binary *.tiff binary *.wbmp binary *.webp binary # Audio *.kar binary *.m4a binary *.mid binary *.midi binary *.mp3 binary *.ogg binary *.ra binary # Video *.3gpp binary *.3gp binary *.as binary *.asf binary *.asx binary *.avi binary *.fla binary *.flv binary *.m4v binary *.mng binary *.mov binary *.mp4 binary *.mpeg binary *.mpg binary *.ogv binary *.swc binary *.swf binary *.webm binary # Archives *.7z binary *.gz binary *.jar binary *.rar binary *.tar binary *.zip binary # Fonts *.ttf binary *.eot binary *.otf binary *.woff binary *.woff2 binary # Executables *.exe binary *.pyc binary # Prevents massive diffs caused by vendored, minified files **/.yarn/releases/** binary **/.yarn/plugins/** binary # RC files (like .babelrc or .eslintrc) *.*rc text # Ignore files (like .npmignore or .gitignore) *.*ignore text # Prevents massive diffs from built files dist/* binary ================================================ FILE: .github/CODEOWNERS ================================================ docs/.vitepress/**/* @taskylizard api/**/* @taskylizard index.md @taskylizard ================================================ FILE: .github/CONTRIBUTING.md ================================================ # Contribute Guide > [!INFO] NOTE > Some of these steps are easier if you're in our [Discord](https://github.com/fmhy/FMHY/wiki/FMHY-Discord). It opens every Friday. Here you'll find some general guidelines for those who would like to start contributing. There are multiple ways to do this: - [Link Submissions](#submissions) - [Reporting an Existing Site](#reporting-a-site) - [How to Edit and Preview Changes](#making-changes) - [Finding New Sites](https://www.reddit.com/r/FREEMEDIAHECKYEAH/wiki/find-new-sites/) ## Submissions > [!INFO] NOTE > For bigger changes to the wiki, such as debloating efforts or the restructuring of a page/section, you must first discuss these with us via [Discord](https://github.com/fmhy/FMHY/wiki/FMHY-Discord) before opening a [Pull Request](https://github.com/fmhy/edit/pulls). **Don't submit any of the following:** - **💰️ Paid / Trial Sites** - We don't accept any paid or free trial only entries, with the exception of select paid [VPNs](/privacy#vpn) and [Debrid](/downloading#debrid-leeches). - **🕹️ Emulators** - Already listed on [Index Sites](/gaming#emulators). - **🌐 Web Browsers** - Good open-source browsers are already listed, so we just accept indexes, privacy-focused, and good mobile ones. - **🔻 Leeches** - Unless it's not already listed on existing [Leech Lists](/downloading#debrid-leeches), don't submit these. - **🐧 Linux Distros** - Already listed on [Index Sites](/linux-macos#linux-distros). - **🌍 Non-english Software** - We don't add non-english software sites (APKs, games, torrents, etc.) unless they have a very good reputation. - **🗂️ Coding Libraries** - There's too many of them and there are better places to find them. - **🎲 Mining / Betting Sites** - Don't submit anything related to betting, mining, BINs, CCs, etc. - **🎮 Multiplayer Hacks** - Don't submit any hacks or exploits that give an unfair advantage in multiplayer games. - **🖥️ Custom OSs** - We don't recommend people use these. ### Adding a Site For submitting new links, follow these steps: - Make sure it's not already in the wiki. The easiest way to do this is to check our [Single Page](https://api.fmhy.net/single-page) using `ctrl+f`. - Don't spam a bunch of un-tested links at once. Try to only send things you genuinely feel might be worth adding. - Reach out via the feedback system, [GitHub](https://github.com/fmhy/edit), or join our [Discord](https://github.com/fmhy/FMHY/wiki/FMHY-Discord). Note that we have to check sites ourselves, so using a issue, rather than pull request is easier. - You can optionally include socials, tools, or any other additional info alongside the entry. ### Reporting a Site > [!INFO] NOTE > If it's urgent, you're allowed to request an invite via our feedback system. For changes to existing entries, follow these steps: - Reach out via the feedback system, [GitHub](https://github.com/fmhy/edit), or join our [Discord](https://github.com/fmhy/FMHY/wiki/FMHY-Discord). - Feel free to leave contact info when using the feedback system, if needed. Only trusted staff can view this. - If you'd like to report a site removal or star change, you must include details as to why your changes should be accepted. ### Link Testing All additions have to first go through our testing process on [Discord](https://github.com/fmhy/FMHY/wiki/FMHY-Discord). You can help us test new sites to figure out their use-case, safety, and whether they'd be a good fit for the wiki. Keep in mind certain sites (such as piracy sites) require more testing/vetting before they can be added. ### Formatting Rules The wiki will always have some variation either due to exceptions being made, the layout/structure, or the flexible nature of markdown itself. For these reasons, there are too many conditions and nuances to satisfy to make an easy-to-follow guide. However, you can generally get an idea by looking at how existing links are structured. Note that we do try to order sections from best to worst, and if multiple links are on the same line, only the **bold** ones are considered stars. If you're unsure, ask in the wiki channels on [Discord](https://github.com/fmhy/FMHY/wiki/FMHY-Discord) and wait for a staff member to reply. ## Making Changes Instructions on various ways to edit the wiki and preview changes. ### GitHub Editor You can use the built-in web editor in two ways: 1. Find the file you want to edit, look for the edit icon (of a pencil) and click on it, then make your changes. ![Edit Button](https://files.catbox.moe/7w3hnm.png) 2. When you're done, click "Commit Changes..." then "Propose changes". Optionally add a commit description. 3. You should now see a comparison page showing all your edits. Click "Create pull request", fill in the box describing your changes, then hit submit. **OR** 1. Fork the repository by clicking the "Fork" button in the top right. 2. Navigate to your fork's homepage and press the `.` (period) key on your keyboard. This will open the repository in a VSCode-like environment on `github.dev`. 3. Make your changes, then commit via the source control tab. ![Source Control](https://files.catbox.moe/pa571v.png) 4. Back on your fork's homepage, click "Contribute" then "Open pull request". 5. You should now see a comparison page showing all your edits. Click "Create pull request", fill in the box describing your changes, then hit submit. ### Dev Environment If you're going to work on the site itself, or simply want to preview the site and any changes, you can do so by setting up a development environment. #### GitHub Codespaces This creates an environment in the browser [(with 60h/month free quota)](https://docs.github.com/en/billing/concepts/product-billing/github-codespaces#free-and-billed-use-by-personal-accounts). To use Codespaces, follow these steps: 1. Fork the repository by clicking the "Fork" button in the top right. 2. Navigate to your fork's homepage and click on the green "Code" button above your repository, open "Codespaces" tab and click "Create codespace". 3. You may have to wait ~5-10 minutes for the codespace to load. ![Codespace Status](https://files.catbox.moe/5bp38f.png) 4. Once it has loaded, run `pnpm i && pnpm docs:dev` to start the preview. Then when it appears, click "Open in Browser" in the bottom right. 5. Make your changes and commit. 6. To shut it down, click the "Code" button again and look for the `...` dropdown next to your codespace, then click "Stop codespace". #### Local Instance Making changes on a local repository may require a basic understanding of Git. You can find learning resources [here](/educational#developer-learning). More info on manual setup can be found [here](/other/selfhosting). ================================================ FILE: .github/ISSUE_TEMPLATE/wiki.yml ================================================ name: Create Issue description: 'Help us improve FMHY for everyone' title: 'Issue form title' body: - type: markdown attributes: value: | Thanks for taking the time to fill out this issue! Please select your issue type. - type: markdown attributes: value: | ### Things to note * Anyone can suggest [changes or corrections](https://rentry.org/fmhyedit) to the wiki. Please read our [Contribution Guide](https://rentry.co/Contrib-Guide) before trying to add or remove anything. * If you're adding a new site, please [search](https://raw.githubusercontent.com/fmhy/edit/main/single-page) (control + f) first to make sure we don't already have it. * Approved changes will be applied to the [site](https://fmhy.net) and all [🔒 backups](https://github.com/fmhy/FMHY/wiki/Backups). * You can send us stuff directly via [💬 Discord](https://github.com/fmhy/FMHY/wiki/FMHY-Discord). * You can also check out our [website](https://fmhy.net) and the [posts](https://fmhy.net/posts) section to know about any major updates to the wiki. - type: dropdown id: type attributes: label: Type description: Type that best describes this issue. options: - Bad sites - Grammar / Markdown - Site suggestion - Wiki section suggestion default: 0 validations: required: true - type: textarea id: context attributes: label: Add additional context description: A clear and concise description of what the issue is, as per your selected issue type. placeholder: https://fmhy.net is cool and should be added validations: required: true ================================================ FILE: .github/POST_TEMPLATE.md ================================================ ### Post Template > [!NOTE] > This is a template for creating a post for the freemediaheckyeah blog, and is meant for **collaborators** only. Notes: - The title should be a short, descriptive title. - The date should be in the format `YYYY-MM-DD`. - The filename should be in the format `month-year.md`. - The description should be a short, descriptive description of the post. - Authors should be in the format `['username', ....]` - The ending shouldn't have a line break (`---`/`***`). - Links to the website should be turned into relative links, i.e. `[Text Tools](https://fmhy.net/text-tools)` -> `[Text Tools](/text-tools)`. Template: ``` --- title: Monthly Updates [Month] description: Month 20YY updates date: 20YY-MM-DD next: false aside: right prev: false sidebar: false footer: true --- :::info These update threads only contains major updates. If you're interested in seeing all minor changes you can follow our [Commits Page](https://github.com/fmhy/edit/commits/main) on GitHub or [Updates Channel](https://redd.it/17f8msf) in Discord. ::: ### Wiki Updates .... --- ### Stars Added ⭐ .... --- ### Things Removed .... ``` ================================================ FILE: .github/README.md ================================================ # FMHY ![FMHY Banner](https://github.com/user-attachments/assets/0d43950d-a56f-437f-b9f6-afaed2313370)

The largest collection of free stuff on the internet!

## 📖 Wiki - Website: [fmhy.net](https://fmhy.net) - News & Monthly Updates: [fmhy.net/posts](https://fmhy.net/posts) - Backups, Markdown, JSON API: [github.com/fmhy/FMHY/wiki/Backups](https://github.com/fmhy/FMHY/wiki/Backups) - Neither the site nor GitHub host any files ## 🗺️ Emoji Legend * 🌐 - **3rd Party Indexes** * ↪️ - **Storage Page Links** * ⭐ - **Community Recommendations** ## 📝 Contribute We invite you to contribute and help improve the wiki! 💙 Here are a few ways you can get involved: * Anyone can suggest changes or corrections to the wiki. Please read our [contribution guide](https://fmhy.net/other/contributing) before trying to add or remove anything. * If you're adding a new site, please [search](https://api.fmhy.net/single-page) (`Ctrl + F`) first to make sure we don't already have it. * Approved changes will be applied to the [site](https://fmhy.net) and all [🔒 backups](https://github.com/fmhy/FMHY/wiki/Backups). * You can send us stuff directly via [💬 Discord](https://github.com/fmhy/FMHY/wiki/FMHY-Discord). * To help us find new sites, check out the lists of links in [site hunting](https://www.reddit.com/r/FREEMEDIAHECKYEAH/wiki/find-new-sites/). ## 🔔 Follow

Discord  GitHub

================================================ FILE: .github/assets/nginx.conf ================================================ server { listen 80; server_name _; root /usr/share/nginx/html; index index.html; location / { try_files $uri $uri.html $uri/ =404; add_header X-Frame-Options "DENY"; add_header X-Content-Type-Options "nosniff"; add_header X-XSS-Protection "1; mode=block"; add_header Referrer-Policy "no-referrer-when-downgrade"; } location ~* \.(?:css|js|jpg|jpeg|gif|png|svg|ico|woff2?)$ { expires 30d; add_header Cache-Control "public"; } error_log /var/log/nginx/error.log warn; access_log /var/log/nginx/access.log; } gzip on; gzip_types text/plain text/css application/javascript application/json image/svg+xml; gzip_min_length 1000; gzip_proxied any; gzip_vary on; ================================================ FILE: .github/workflows/deploy-api.yml ================================================ name: Deploy API # Only run this workflow when the API directory changes on: push: paths: - 'api/**' branches: - main workflow_dispatch: concurrency: ${{ github.workflow }}-${{ github.ref }} jobs: ci: name: Build and Deploy runs-on: ubuntu-latest strategy: matrix: node-version: [20] steps: - uses: actions/checkout@v4 with: fetch-depth: 6 - name: Install pnpm uses: pnpm/action-setup@v4 - name: Use Node.js ${{ matrix.node-version }} uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} cache: 'pnpm' - name: Install dependencies run: pnpm install - name: Build run: pnpm api:build env: WEBHOOK_URL: ${{ secrets.WEBHOOK_URL }} - name: Publish to Cloudflare uses: cloudflare/wrangler-action@v3 with: apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} vars: WEBHOOK_URL env: WEBHOOK_URL: ${{ secrets.WEBHOOK_URL }} ================================================ FILE: .github/workflows/deploy-gh-pages.yml ================================================ name: Deploy to GitHub Pages on: workflow_dispatch: permissions: contents: read pages: write id-token: write concurrency: group: pages cancel-in-progress: false jobs: build: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 with: fetch-depth: 1 - uses: pnpm/action-setup@v2 - name: Setup Node uses: actions/setup-node@v4 with: node-version: 20 cache: pnpm - name: Setup Pages uses: actions/configure-pages@v5 - name: Install dependencies run: pnpm install - name: Build with VitePress run: | pnpm docs:build touch docs/.vitepress/dist/.nojekyll - name: Upload artifact id: deployment uses: actions/upload-pages-artifact@v3 with: path: docs/.vitepress/dist deploy: environment: name: github-pages url: ${{ steps.deployment.outputs.page_url }} needs: build runs-on: ubuntu-latest name: Deploy steps: - name: Deploy to GitHub Pages id: deployment uses: actions/deploy-pages@v4 ================================================ FILE: .gitignore ================================================ **/.vitepress/dist **/.vitepress/cache node_modules *.log* .nitro .cache .output .env dist .eslintcache docs/.vitepress/.temp result ================================================ FILE: .gitpod.yml ================================================ tasks: - init: pnpm install command: pnpm run docs:dev ports: - port: 5173 onOpen: open-preview ================================================ FILE: .licenserc.json ================================================ { "**/*.ts": [ "/**", "* Copyright (c) 2025 taskylizard. Apache License 2.0.", "*", "* Licensed under the Apache License, Version 2.0 (the \"License\");", "* you may not use this file except in compliance with the License.", "* You may obtain a copy of the License at", "*", "* http://www.apache.org/licenses/LICENSE-2.0", "*", "* Unless required by applicable law or agreed to in writing, software", "* distributed under the License is distributed on an \"AS IS\" BASIS,", "* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", "* See the License for the specific language governing permissions and", "* limitations under the License.", "*/" ], "**/*.css": [ "/**", "* Copyright (c) 2025 taskylizard. Apache License 2.0.", "* Licensed under the Apache License, Version 2.0 (the \"License\");", "* you may not use this file except in compliance with the License.", "* You may obtain a copy of the License at", "* http://www.apache.org/licenses/LICENSE-2.0", "*/" ], "ignore": [ "node_modules", "dist", "docs/.vitepress/dist", "docs/.vitepress/cache" ] } ================================================ FILE: .mise.toml ================================================ # https://github.com/vitejs/vite/issues/17291 [tools] node = "latest" pnpm = "latest" [tasks] d = "nrr docs:dev --host" b = "nrr docs:build" s = "nrr docs:preview --host" bb = "nrr docs:build && nrr docs:preview --host" ================================================ FILE: .npmrc ================================================ package-manager-strict=false shell-emulator=true auto-install-peers=false ================================================ FILE: .prettierignore ================================================ **/*.md !docs/index.md pnpm-lock.yaml .turbo .cache ================================================ FILE: .prettierrc.yaml ================================================ proseWrap: always semi: false singleQuote: true printWidth: 80 trailingComma: none htmlWhitespaceSensitivity: ignore plugins: - prettier-plugin-tailwindcss - prettier-plugin-pkgsort - '@ianvs/prettier-plugin-sort-imports' importOrder: [ '', '^(node:)', '', '^[.]', '', '', '^[.]', '^(?!.*[.]css$)[./].*$', '.css$' ] ================================================ FILE: Dockerfile ================================================ FROM node:25.7-alpine AS base ENV PNPM_HOME="/pnpm" ENV PATH="$PNPM_HOME:$PATH" RUN npm install -g pnpm@10.30.3 WORKDIR /app COPY package.json pnpm-lock.yaml ./ FROM base AS build RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile --config.autoInstallPeers=false COPY . . RUN pnpm run docs:build FROM nginx:alpine-slim COPY --from=build /app/docs/.vitepress/dist /usr/share/nginx/html COPY .github/assets/nginx.conf /etc/nginx/conf.d/default.conf EXPOSE 80 CMD ["nginx", "-g", "daemon off;"] ================================================ FILE: api/README.md ================================================ This is the API for the website and other related services. Licensed under the Apache License v2.0, see [LICENSE](../docs/.vitepress/LICENSE) for more information. ================================================ FILE: api/middleware/cors.ts ================================================ /** * Copyright (c) 2025 taskylizard. Apache License 2.0. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import { corsEventHandler } from 'nitro-cors' export default corsEventHandler( (_event) => { /** no-op */ }, { origin: '*', methods: '*' } ) ================================================ FILE: api/middleware/ratelimit.ts ================================================ /** * Copyright (c) 2025 taskylizard. Apache License 2.0. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ export default defineEventHandler(async (event) => { const { cloudflare } = event.context // FIXME: THIS IS NOT RECOMMENDED. BUT I WILL USE IT FOR NOW // Not recommended: many users may share a single IP, especially on mobile networks // or when using privacy-enabling proxies const ipAddress = getHeader(event, 'CF-Connecting-IP') ?? '' const { success } = await // KILL YOURSELF (cloudflare.env as unknown as Env).RATE_LIMITER.limit({ key: ipAddress }) if (!success) { throw createError('Failure – global rate limit exceeded') } }) ================================================ FILE: api/routes/feedback.post.ts ================================================ /** * Copyright (c) 2025 taskylizard. Apache License 2.0. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import { fetcher } from 'itty-fetcher' import { FeedbackSchema, getFeedbackOption } from '../../docs/.vitepress/types/Feedback' export default defineEventHandler(async (event) => { const { message, page, type, heading } = await readValidatedBody( event, FeedbackSchema.parseAsync ) const env = useRuntimeConfig(event) const pageURL = `https://fmhy.net${page}` const fields = [ { name: 'Page', value: `[${page}](${pageURL})`, inline: true }, { name: 'Message', value: message, inline: false } ] if (heading) { fields.unshift({ name: 'Section', value: heading, inline: true }) } // FIXME: somehow this is not working, but it worked before // const path = 'feedback' // // const { success } = await env.MY_RATE_LIMITER.limit({ key: path }) // if (!success) { // return new Response('429 Failure – global rate limit exceeded', { // status: 429 // }) // } await fetcher() .post(env.WEBHOOK_URL, { username: 'Feedback', avatar_url: 'https://i.kym-cdn.com/entries/icons/facebook/000/043/403/cover3.jpg', embeds: [ { color: 3447003, title: getFeedbackOption(type).label, fields } ] }) .catch((error) => { throw new Error(error) }) return { status: 'ok' } }) ================================================ FILE: api/routes/index.ts ================================================ /** * Copyright (c) 2025 taskylizard. Apache License 2.0. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ export default eventHandler(() => { return { nitro: 'works' } }) ================================================ FILE: api/routes/single-page.ts ================================================ /** * Copyright (c) 2025 taskylizard. Apache License 2.0. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ const files = ( [ 'privacy.md', 'ai.md', 'mobile.md', 'audio.md', 'beginners-guide.md', 'developer-tools.md', 'downloading.md', 'educational.md', 'file-tools.md', 'gaming-tools.md', 'gaming.md', 'image-tools.md', 'internet-tools.md', 'linux-macos.md', 'misc.md', 'non-english.md', 'reading.md', 'social-media-tools.md', 'storage.md', 'system-tools.md', 'text-tools.md', 'torrenting.md', 'unsafe.md', 'video-tools.md', 'video.md' ] as const ).map((file) => ({ name: file, url: `https://raw.githubusercontent.com/fmhy/edit/main/docs/${file}` })) export default defineCachedEventHandler( async (event) => { let body = '\n' const contents = await Promise.all( files.map(async (file) => { const content = await $fetch(file.url) return content }) ) body += contents.join('\n\n') appendResponseHeaders(event, { 'content-type': 'text/markdown;charset=utf-8', 'cache-control': 'public, max-age=7200' }) return body }, { maxAge: 60 * 60, name: 'single-page', getKey: () => 'default' /* Can be extended in the future */ } ) ================================================ FILE: api/tsconfig.json ================================================ { "extends": "../.nitro/types/tsconfig.json", "compilerOptions": { "types": ["@cloudflare/workers-types"] } } ================================================ FILE: api/worker-configuration.d.ts ================================================ /** * Copyright (c) 2025 taskylizard. Apache License 2.0. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // Generated by Wrangler by running `wrangler types api/worker-configuration.d.ts` interface Env { STORAGE: KVNamespace RATE_LIMITER: RateLimit } ================================================ FILE: docker-compose.yaml ================================================ services: docs: networks: [fmhy] build: context: . dockerfile: Dockerfile image: fmhy-docs container_name: docs restart: unless-stopped ports: - '4173:80' networks: fmhy: ================================================ FILE: docs/.vitepress/LICENSE ================================================ Copyright (c) taskylizard. Apache License 2.0 Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: docs/.vitepress/README.md ================================================ This is the website source code to be used with [VitePress](https://vitepress.dev/). Licensed under the Apache License v2.0, see [LICENSE](./LICENSE) for more information. ================================================ FILE: docs/.vitepress/config.mts ================================================ import { fileURLToPath } from 'node:url' import consola from 'consola' import UnoCSS from 'unocss/vite' import AutoImport from 'unplugin-auto-import/vite' import OptimizeExclude from 'vite-plugin-optimize-exclude' import Terminal from 'vite-plugin-terminal' import { VitePWA } from 'vite-plugin-pwa' import { defineConfig } from 'vitepress' import { commitRef, feedback, meta, nav, search, sidebar, socialLinks } from './constants' import { generateFeed, generateImages, generateMeta } from './hooks' import { defs, emojiRender, movePlugin } from './markdown/emoji' import { headersPlugin } from './markdown/headers' import { toggleStarredPlugin } from './markdown/toggleStarred' import { transformsPlugin } from './transformer' import { replaceNoteLink } from './utils/markdown' // @unocss-include const baseUrl = process.env.GITHUB_ACTIONS ? '/edit' : '/' export default defineConfig({ title: 'FMHY', description: meta.description, titleTemplate: ':title • freemediaheckyeah', lang: 'en-US', lastUpdated: false, cleanUrls: true, appearance: true, base: baseUrl, srcExclude: ['README.md', 'single-page'], ignoreDeadLinks: true, sitemap: { hostname: meta.hostname }, head: [ ['meta', { name: 'theme-color', content: '#7bc5e4' }], ['meta', { name: 'og:type', content: 'website' }], ['meta', { name: 'og:locale', content: 'en' }], ['link', { rel: 'icon', href: '/test.png' }], // PWA ['link', { rel: 'manifest', href: '/manifest.json' }], ['link', { rel: 'icon', href: '/pwa_icon.png', type: 'image/svg+xml' }], ['link', { rel: 'alternate icon', href: '/pwa_icon.png' }], ['link', { rel: 'mask-icon', href: '/pwa_icon.png', color: '#000000ff' }], ['meta', { name: 'keywords', content: meta.keywords.join(' ') }], ['link', { rel: 'apple-touch-icon', href: '/pwa_icon.png', sizes: '192x192' }], ['meta', { name: 'apple-mobile-web-app-capable', content: 'yes' }], ['meta', { name: 'apple-mobile-web-app-status-bar-style', content: 'default' }], // Bing site verification [ 'meta', { name: 'msvalidate.01', content: 'F3028112EF6F929B562F4B18E58E3691' } ], // Google site verification [ 'meta', { name: 'google-site-verification', content: 'XCq-ZTw6VJPQ7gVNEOl8u0JRqfadK7WcsJ0H598Wv9E' } ], // Redirect to main site if embedded in iframe [ 'script', {}, ` (function() { if (window.self !== window.top) { window.top.location = window.location.href; } })(); ` ] ], transformHead: async (context) => generateMeta(context, meta.hostname), buildEnd: async (context) => { generateImages(context) .then(() => generateFeed(context)) .finally(() => consola.success('Success!')) }, vite: { css: { preprocessorOptions: { scss: { api: 'modern-compiler' } } }, ssr: { noExternal: ['@fmhy/components'] }, resolve: { alias: [ { find: /^.*VPSwitchAppearance\.vue$/, replacement: fileURLToPath( new URL('./theme/components/ThemeDropdown.vue', import.meta.url) ) }, { find: /^.*VPLocalSearchBox\.vue$/, replacement: fileURLToPath( new URL('./theme/components/VPLocalSearchBox.vue', import.meta.url) ) }, { find: /^.*VPNav\.vue$/, replacement: fileURLToPath( new URL('./theme/components/VPNav.vue', import.meta.url) ) } ] }, optimizeDeps: { exclude: ['workbox-window'] }, plugins: [ OptimizeExclude(), Terminal({ console: 'terminal', output: ['console', 'terminal'] }), UnoCSS({ configFile: fileURLToPath( new URL('../../unocss.config.ts', import.meta.url) ) }), AutoImport({ dts: '../.cache/imports.d.ts', imports: ['vue', 'vitepress'], vueTemplate: true, biomelintrc: { enabled: true, filepath: './.cache/imports.json' } }), VitePWA({ registerType: 'autoUpdate', workbox: { globPatterns: ['**/*.{js,css,html,ico,png,svg,woff2}'], runtimeCaching: [ { urlPattern: /^https:\/\/fonts\.googleapis\.com\/.*/i, handler: 'CacheFirst', options: { cacheName: 'google-fonts-cache', expiration: { maxEntries: 10, maxAgeSeconds: 60 * 60 * 24 * 365 // 365 days }, cacheableResponse: { statuses: [0, 200] } } } ] }, manifest: { name: 'FMHY - freemediaheckyeah', short_name: 'FMHY', description: 'The largest collection of free stuff on the internet!', theme_color: '#000000ff', background_color: '#000000ff', display: 'standalone', orientation: 'portrait', scope: '/', start_url: '/', icons: [ { src: '/fmhy.ico', sizes: '16x16', type: 'image/x-icon' }, { src: '/pwa_icon.png', sizes: '192x192', type: 'image/png', purpose: 'any maskable' }, { src: '/pwa_icon.png', sizes: '512x512', type: 'image/png', purpose: 'any maskable' } ] } }), transformsPlugin(), { name: 'custom:adjust-order', configResolved(c) { movePlugin( c.plugins as any, 'vitepress', 'before', 'unocss:transformers:pre' ) movePlugin( c.plugins as any, 'custom:transform-content', 'before', 'vitepress' ) } } ], build: { // Shut the fuck up chunkSizeWarningLimit: Number.POSITIVE_INFINITY } }, markdown: { emoji: { defs }, config(md) { md.use(emojiRender) md.use(toggleStarredPlugin) meta.build.api && md.use(headersPlugin) replaceNoteLink(md) } }, themeConfig: { search, footer: { message: `${feedback} (rev: ${commitRef})`, copyright: `© ${new Date().getFullYear()}, Estd 2018.` + `
This site does not host any files.` }, editLink: { pattern: 'https://github.com/fmhy/edit/edit/main/docs/:path', text: '📝 Edit this page' }, outline: 'deep', logo: { src: '/fmhy.ico', alt: 'FMHY Logo' }, nav, sidebar, socialLinks } }) ================================================ FILE: docs/.vitepress/constants.ts ================================================ /** * Copyright (c) 2025 taskylizard. Apache License 2.0. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import type { DefaultTheme } from 'vitepress' import { excluded } from './shared' import { transform, transformGuide } from './transformer' // @unocss-include export * from './shared' export const search: DefaultTheme.Config['search'] = { options: { _render(src, env, md) { // Check if current file should be excluded from search const relativePath = env.relativePath || env.path || '' const shouldExclude = excluded.some(excludedFile => relativePath.includes(excludedFile) || relativePath.endsWith(excludedFile) ) // Return empty content for excluded files so they don't appear in search if (shouldExclude) { return '' } let contents = src // I do this as env.frontmatter is not available until I call `md.render` if (contents.includes('Beginners Guide')) contents = transformGuide(contents) contents = transform(contents) const html = md.render(contents, env) return html }, miniSearch: { options: { tokenize: (text) => text.replace(/[\u2060\u200B]/g, '').split(/[\n\r #%*,=/:;?[\]{}()&]+/u), // simplified charset: removed [-_.@] and non-english chars (diacritics etc.) processTerm: (term, fieldName) => { // biome-ignore lint/style/noParameterAssign: h term = term .trim() .toLowerCase() .replace(/^\.+/, '') .replace(/\.+$/, '') const stopWords = [ 'frontmatter', '$frontmatter.synopsis', 'and', 'about', 'but', 'now', 'the', 'with', 'you' ] if (term.length < 2 || stopWords.includes(term)) return false if (fieldName === 'text') { const parts = term.split('.') if (parts.length > 1) { const newTerms = [term, ...parts] .filter((t) => t.length >= 2) .filter((t) => !stopWords.includes(t)) return newTerms } } return term } }, searchOptions: { combineWith: 'AND', fuzzy: false, // @ts-ignore boostDocument: (documentId, term, storedFields: Record) => { const titles = (storedFields?.titles as string[]) .filter((t) => Boolean(t)) .map((t) => t.toLowerCase()) // Downrank posts if (documentId.match(/\/posts/)) return -5 // Downrank /other if (documentId.match(/\/other/)) return -5 // Uprate if term appears in titles. Add bonus for higher levels (i.e. lower index) const titleIndex = titles .map((t, i) => (t?.includes(term) ? i : -1)) .find((i) => i >= 0) ?? -1 if (titleIndex >= 0) return 10000 - titleIndex return 1 } } }, detailedView: true }, provider: 'local' } ================================================ FILE: docs/.vitepress/hooks/Template.vue ================================================ ================================================ FILE: docs/.vitepress/hooks/index.ts ================================================ /** * Copyright (c) 2025 taskylizard. Apache License 2.0. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Barrel generated using @taskylizard/tasker. */ export * from './meta' export * from './opengraph' export * from './rss' export * from './satoriConfig' ================================================ FILE: docs/.vitepress/hooks/meta.ts ================================================ /** * Copyright (c) 2025 taskylizard. Apache License 2.0. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import type { HeadConfig, TransformContext } from 'vitepress' export function generateMeta(context: TransformContext, hostname: string) { const head: HeadConfig[] = [] const { pageData } = context if (pageData.isNotFound) return head if (Object.keys(pageData.frontmatter).length === 0) return head const url = `${hostname}/${pageData.relativePath.replace(/((^|\/)index)?\.md$/, '$2')}` head.push( ['link', { rel: 'canonical', href: url }], ['meta', { property: 'og:url', content: url }], ['meta', { name: 'twitter:url', content: url }], ['meta', { name: 'twitter:card', content: 'summary_large_image' }], ['meta', { property: 'og:title', content: pageData.frontmatter.title }], ['meta', { name: 'twitter:title', content: pageData.frontmatter.title }] ) if (pageData.frontmatter.description) { head.push( [ 'meta', { property: 'og:description', content: pageData.frontmatter.description } ], [ 'meta', { name: 'twitter:description', content: pageData.frontmatter.description } ] ) } if (pageData.frontmatter.image) { head.push([ 'meta', { property: 'og:image', content: `${hostname}/${pageData.frontmatter.image.replace(/^\//, '')}` } ]) head.push([ 'meta', { name: 'twitter:image', content: `${hostname}/${pageData.frontmatter.image.replace(/^\//, '')}` } ]) } else { const url = pageData.filePath.replace('index.md', '').replace('.md', '') const imageUrl = `${url}/__og_image__/og.webp` .replaceAll('//', '/') .replace(/^\//, '') head.push( ['meta', { property: 'og:image', content: `${hostname}/${imageUrl}` }], ['meta', { property: 'og:image:width', content: '1200' }], ['meta', { property: 'og:image:height', content: '630' }], ['meta', { property: 'og:image:type', content: 'image/png' }], [ 'meta', { property: 'og:image:alt', content: pageData.frontmatter.title } ], ['meta', { name: 'twitter:image', content: `${hostname}/${imageUrl}` }], ['meta', { name: 'twitter:image:width', content: '1200' }], ['meta', { name: 'twitter:image:height', content: '630' }], [ 'meta', { name: 'twitter:image:alt', content: pageData.frontmatter.title } ] ) } if (pageData.frontmatter.tag) { head.push([ 'meta', { property: 'article:tag', content: pageData.frontmatter.tag } ]) } if (pageData.frontmatter.date) { head.push([ 'meta', { property: 'article:published_time', content: pageData.frontmatter.date } ]) } if (pageData.lastUpdated && pageData.frontmatter.lastUpdated !== false) { head.push([ 'meta', { property: 'article:modified_time', content: new Date(pageData.lastUpdated).toISOString() } ]) } return head } ================================================ FILE: docs/.vitepress/hooks/opengraph.ts ================================================ /** * Copyright (c) 2025 taskylizard. Apache License 2.0. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import type { ContentData, SiteConfig } from 'vitepress' import type { SatoriOptions } from 'x-satori/vue' import { mkdir, readFile, writeFile } from 'node:fs/promises' import { dirname, resolve } from 'node:path' import { fileURLToPath } from 'node:url' import { renderAsync } from '@resvg/resvg-js' import sharp from 'sharp' import consola from 'consola' import { createContentLoader } from 'vitepress' import { satoriVue } from 'x-satori/vue' import { headers } from '../transformer/constants' const __dirname = dirname(fileURLToPath(import.meta.url)) const __fonts = resolve(__dirname, '../fonts') export async function generateImages(config: SiteConfig) { const pages = await createContentLoader('**/*.md', { excerpt: true }).load() const template = await readFile(resolve(__dirname, './Template.vue'), 'utf-8') const fonts: SatoriOptions['fonts'] = [ { name: 'Inter', data: await readFile(resolve(__fonts, 'Inter-Regular.otf')), weight: 400, style: 'normal' }, { name: 'Inter', data: await readFile(resolve(__fonts, 'Inter-Medium.otf')), weight: 500, style: 'normal' }, { name: 'Inter', data: await readFile(resolve(__fonts, 'Inter-SemiBold.otf')), weight: 600, style: 'normal' }, { name: 'Inter', data: await readFile(resolve(__fonts, 'Inter-Bold.otf')), weight: 700, style: 'normal' } ] for (const page of pages) { await generateImage({ page, template, outDir: config.outDir, fonts }) } return consola.info('Generated opengraph images.') } interface GenerateImagesOptions { page: ContentData template: string outDir: string fonts: SatoriOptions['fonts'] } async function generateImage({ page, template, outDir, fonts }: GenerateImagesOptions) { const { frontmatter, url } = page const _page = getPage(url) const title = frontmatter.layout === 'home' ? (frontmatter.hero.name ?? frontmatter.title) : frontmatter.title ? frontmatter.title : _page?.title const description = frontmatter.layout === 'home' ? (frontmatter.hero.tagline ?? frontmatter.description) : frontmatter.description ? frontmatter.description : _page?.description // consola.info(url, title, description) const options: SatoriOptions = { width: 1200, height: 630, fonts, props: { title, description, image: 'https://i.fmhy.net/og-base.jpg' } } const svg = await satoriVue(options, template) const render = await renderAsync(svg) const compressed = await sharp(render.asPng()) .webp({ quality: 75 }) .toBuffer() const outputFolder = resolve(outDir, url.slice(1), '__og_image__') const outputFile = resolve(outputFolder, 'og.webp') await mkdir(outputFolder, { recursive: true }) await writeFile(outputFile, compressed) } function getPage(page: string) { // Get the page name const pageName = `${page}.md`.slice(1).split('/').at(-1) // Find the header // TODO: This is a hacky way to find the header const header = Object.entries(headers).find(([key]) => key === pageName) if (!header) return const { title, description } = header[1] return { title, description } } ================================================ FILE: docs/.vitepress/hooks/rss.ts ================================================ /** * Copyright (c) 2025 taskylizard. Apache License 2.0. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import type { ContentData, SiteConfig } from 'vitepress' import { writeFileSync } from 'node:fs' import path from 'node:path' import consola from 'consola' import { Feed } from 'feed' import { createContentLoader } from 'vitepress' import { meta } from '../constants' export async function generateFeed(config: SiteConfig): Promise { const feed: Feed = new Feed({ id: meta.hostname, link: meta.hostname, title: 'FMHY blog', description: meta.description, language: 'en-US', image: 'https://github.com/fmhy.png', favicon: `${meta.hostname}/favicon.ico`, copyright: 'Copyright (c) 2023-present FMHY' }) const posts: ContentData[] = await createContentLoader('posts/*.md', { excerpt: true, render: true, transform: (rawData) => { return rawData.sort((a, b) => { return ( Number(new Date(b.frontmatter.date)) - Number(new Date(a.frontmatter.date)) ) }) } }).load() for (const { url, frontmatter, html } of posts) { feed.addItem({ title: frontmatter.title as string, id: `${meta.hostname}${url.replace(/\/\d+\./, '/')}`, link: `${meta.hostname}${url.replace(/\/\d+\./, '/')}`, date: frontmatter.date, content: html?.replaceAll('​', '') }) } writeFileSync(path.join(config.outDir, 'feed.rss'), feed.rss2()) return consola.info('Generated rss feed.') } ================================================ FILE: docs/.vitepress/hooks/satoriConfig.ts ================================================ /** * Copyright (c) 2025 taskylizard. Apache License 2.0. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import type { SatoriOptions } from 'x-satori/vue' import { readFile } from 'node:fs/promises' import { dirname, resolve } from 'node:path' import { fileURLToPath } from 'node:url' import { defineSatoriConfig } from 'x-satori/vue' const __dirname = dirname(fileURLToPath(import.meta.url)) const __fonts = resolve(__dirname, '../fonts') const fonts: SatoriOptions['fonts'] = [ { name: 'Inter', data: await readFile(resolve(__fonts, 'Inter-Regular.otf')), weight: 400, style: 'normal' }, { name: 'Inter', data: await readFile(resolve(__fonts, 'Inter-Medium.otf')), weight: 500, style: 'normal' }, { name: 'Inter', data: await readFile(resolve(__fonts, 'Inter-SemiBold.otf')), weight: 600, style: 'normal' }, { name: 'Inter', data: await readFile(resolve(__fonts, 'Inter-Bold.otf')), weight: 700, style: 'normal' } ] export default defineSatoriConfig({ width: 1800, height: 900, fonts, props: { title: 'Title', description: 'Lorem ipsum dolor sit amet, qui minim labore adipisicing minim sint cillum sint consectetur cupidatat.', dir: '/j', // I almost killed myself for this shit image: 'https://i.fmhy.net/og-base.jpg' } }) ================================================ FILE: docs/.vitepress/markdown/base64.ts ================================================ /** * Copyright (c) 2025 taskylizard. Apache License 2.0. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import type { MarkdownRenderer } from 'vitepress' // FIXME: tasky: possibly write less horror jank? export function base64DecodePlugin(md: MarkdownRenderer) { const decode = (str: string): string => Buffer.from(str, 'base64').toString('binary') // Save the original rule for backticks const defaultRender = md.renderer.rules.code_inline || function (tokens, idx, options, _env, self) { return self.renderToken(tokens, idx, options) } md.renderer.rules.code_inline = function (tokens, idx, options, env, self) { if ( !env.frontmatter.title || (env.frontmatter.title && env.frontmatter.title !== 'base64') ) { return defaultRender(tokens, idx, options, env, self) } const token = tokens[idx] const content = token.content return `` } } ================================================ FILE: docs/.vitepress/markdown/emoji.ts ================================================ /** * Copyright (c) 2025 taskylizard. Apache License 2.0. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import type { MarkdownRenderer } from 'vitepress' import { icons as twemoji } from '@iconify-json/twemoji' export const defs = { ...Object.fromEntries( Object.entries(twemoji.icons).map(([key]) => { return [key, ''] }) ) } export function emojiRender(md: MarkdownRenderer) { md.renderer.rules.emoji = (tokens, idx) => { if (tokens[idx].markup.startsWith('star')) { return `` } return `` } } export function movePlugin( plugins: { name: string }[], pluginAName: string, order: 'before' | 'after', pluginBName: string ) { const pluginBIndex = plugins.findIndex((p) => p.name === pluginBName) if (pluginBIndex === -1) return const pluginAIndex = plugins.findIndex((p) => p.name === pluginAName) if (pluginAIndex === -1) return if (order === 'before' && pluginAIndex > pluginBIndex) { const pluginA = plugins.splice(pluginAIndex, 1)[0] plugins.splice(pluginBIndex, 0, pluginA) } if (order === 'after' && pluginAIndex < pluginBIndex) { const pluginA = plugins.splice(pluginAIndex, 1)[0] plugins.splice(pluginBIndex, 0, pluginA) } } ================================================ FILE: docs/.vitepress/markdown/headers.ts ================================================ /** * Copyright (c) 2025 taskylizard. Apache License 2.0. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Copyright (c) 2024 taskylizard * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import type { MarkdownRenderer } from 'vitepress' import { headers } from '../transformer/constants' const titles = Object.keys(headers).map((key) => headers[key].title) export const headersPlugin = (md: MarkdownRenderer) => { // Add the Feedback component in the heading, before the link. // // Adding it after the link is closed prevents vitepress from properly // indexing the file's content. md.renderer.rules.heading_open = (tokens, idx, options, env, self) => { const result = self.renderToken(tokens, idx, options) const idxClose = idx + tokens.slice(idx).findIndex((token) => token.type === 'heading_close') if (idxClose <= idx) return result const level = tokens[idx].tag.slice(1) if (!titles.includes(env.frontmatter.title) || level !== '2') return result // Find the token for the link. // // The token after `heading_open` contains the link as a child token. const children = tokens[idx + 1].children || [] const linkOpenToken = children.findLast((c) => c.type === 'link_open') if (!linkOpenToken) return result const heading = tokens[idxClose - 1] linkOpenToken.meta = linkOpenToken.meta || {} linkOpenToken.meta.feedback = { heading: heading.content } return result } const defaultRender = md.renderer.rules.link_open md.renderer.rules.link_open = (tokens, idx, options, env, self) => { const result = defaultRender!!!!!!!!!!(tokens, idx, options, env, self) const meta = tokens[idx].meta if (!meta || !meta.feedback) return result const heading = meta.feedback.heading || '' if (!heading) return result return `${result}` } } ================================================ FILE: docs/.vitepress/markdown/toggleStarred.ts ================================================ /** * Copyright (c) 2025 taskylizard. Apache License 2.0. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import type { MarkdownRenderer } from 'vitepress' const excluded = ['Beginners Guide'] const starredMarkers = [':star:', ':glowing-star:', '⭐', '🌟'] const indexMarkers = ['🌐', ':globe_with_meridians:', ':globe-with-meridians:'] export function toggleStarredPlugin(md: MarkdownRenderer) { md.renderer.rules.list_item_open = (tokens, index, options, env, self) => { const contentToken = tokens[index + 2] if (!contentToken) return self.renderToken(tokens, index, options) const content = contentToken.content const isStarred = !excluded.includes(env.frontmatter.title) && starredMarkers.some((marker) => content.includes(marker)) const isIndex = indexMarkers.some((marker) => content.includes(marker)) if (!isStarred && !isIndex) return self.renderToken(tokens, index, options) const classes = [] if (isStarred) classes.push('starred') if (isIndex) classes.push('index') return `
  • ` } } ================================================ FILE: docs/.vitepress/notes/1337x-ranks.md ================================================ #### 1337x Ranks * ⬛ Black - Administrators * 🟩 Green - Moderators * 🟦 Blue - VIP Uploaders (Very Trusted) * 🟨 Yellow - Uploaders (Trusted) * 🟥 Red - Trial Uploaders * ⬜ Grey - Users ================================================ FILE: docs/.vitepress/notes/CodeRabbit.md ================================================ Note you can get free pro by installing code rabbit on a public github/gitlab repo, as they offer a free open source plan with no popularity requirements or approval/forms. ================================================ FILE: docs/.vitepress/notes/advanced-logic-calculators.md ================================================ #### Advanced Logic Calculators * Analytic tableaux generator: https://www.umsu.de/trees/ * Natural deduction proof checker: https://proofs.openlogicproject.org/ * Propositional logic calculator (finds models): https://www.inf.unibz.it/~franconi/teaching/propcalc/ * A tutorial on sequent calculus: http://logitext.mit.edu/tutorial * Modal logic playground (for constructing models): https://rkirsling.github.io/modallogic/ ================================================ FILE: docs/.vitepress/notes/affine-note.md ================================================ #### AFFiNE Note Downloads for Windows, Mac, Linux are available on their [GitHub](https://github.com/toeverything/AFFiNE) ================================================ FILE: docs/.vitepress/notes/alt-twitch-player-extensions.md ================================================ #### Alternative Twitch Player Extensions * https://addons.mozilla.org/en-US/firefox/addon/twitch_5/ * https://chrome.google.com/webstore/detail/alternate-player-for-twit/bhplkbgoehhhddaoolmakpocnenplmhf ================================================ FILE: docs/.vitepress/notes/alt-warp-clients.md ================================================ #### Alternative Warp Clients If you can't connect, try `Scanner Settings` -> `Endpoint` -> `Suggested` -> then try different IP's to find one that works * https://github.com/bepass-org/oblivion-desktop * https://github.com/bepass-org/oblivion ================================================ FILE: docs/.vitepress/notes/android-spotify-note.md ================================================ #### Android Spotify Note None of Spotify apks (for rooted and non-rooted users) works for now due to server side restriction. ================================================ FILE: docs/.vitepress/notes/apkmirror-extensions.md ================================================ #### APKMirror Extensions * https://addons.mozilla.org/en-US/firefox/addon/toolbox-google-play-store/ * https://chrome.google.com/webstore/detail/toolbox-for-google-play-s/fepaalfjfchbdianlgginbmpeeacahoo * https://addons.opera.com/en/extensions/details/toolbox-for-google-play-storetm/ ================================================ FILE: docs/.vitepress/notes/audiobookbay-warning.md ================================================ #### AudiobookBay Warning Avoid fake download links, use [Torrents / Magnets](https://i.ibb.co/8sV2061/0fa8159b11bb.png), or paste info hash into torrent client. ================================================ FILE: docs/.vitepress/notes/aurora-note.md ================================================ #### Aurora Note Keep in mind that some apps will not work unless you installed them from the Google Play Store. This is usually true for things like banking, and other institutional apps. ================================================ FILE: docs/.vitepress/notes/better-reasoning.md ================================================ #### Better Reasoning To get better reasoning, switch to "Think Deeper" mode. ================================================ FILE: docs/.vitepress/notes/bookmarkeddit.md ================================================ #### Bookmarkeddit This also extends the amount of saved posts you can view (Reddit caps at 1000 by default). ================================================ FILE: docs/.vitepress/notes/buster-note.md ================================================ #### Buster Note The client app simulates user interactions which greatly improves the success rate of buster. You can download the app through the extensions option page, or from the link below: https://github.com/dessant/buster-client The app is available for Windows, Linux, and macOS. ================================================ FILE: docs/.vitepress/notes/buzzheavier-warning.md ================================================ #### Buzzheavier Warning Make sure you have an [adblocker](https://fmhy.net/adblockvpnguide#adblocking) when using Buzzheavier as there are hidden ads on download pages with malicious content. The download button should automatically start a download in your browser, NOT redirect you to another page. ================================================ FILE: docs/.vitepress/notes/bypass-freedlink.md ================================================ #### Bypass FREEdlink You still need to bypass Cloudflare captcha by yourself. This only bypasses timer on single downloads. You may still need to wait normal time to download another file which is enforced from server-side. ================================================ FILE: docs/.vitepress/notes/captcha-4pda.md ================================================ #### Captcha 4PDA Use Google Gemini to translate the captcha. ================================================ FILE: docs/.vitepress/notes/chatgpt-limits.md ================================================ #### ChatGPT Limits GPT-5.2 Instant (no reasoning; 16K context) / 10 messages every 5 hours, then GPT-5-mini. ================================================ FILE: docs/.vitepress/notes/clipboard2file-addons.md ================================================ #### Clipboard2File Addons * https://github.com/vord1080/clipboard2file/ * https://github.com/daijro/Clipboard2File-Chrome ================================================ FILE: docs/.vitepress/notes/cofi-note.md ================================================ #### Cofi Note Useful if you're a coffee enthusiast. The methods are created by James Hoffmann, he's a world champion barista and popular YouTuber. ================================================ FILE: docs/.vitepress/notes/crystaldiskinfo.md ================================================ #### CrystalDiskInfo Avoid versions labeled "Ads". ================================================ FILE: docs/.vitepress/notes/csrin-search.md ================================================ #### CS.RIN Search If your initial search doesn't work, trying searching the same term again within the "search these results" engine on the results screen. image ================================================ FILE: docs/.vitepress/notes/cute-save-button-icon.md ================================================ #### Changing the Cute Save Button Icon You can change the icon of the save button in the extension's settings. The setting is labeled "Your custom cute icon:" You can find standard image download icons to use instead here: https://rentry.co/image-download-icons. ================================================ FILE: docs/.vitepress/notes/dodi-warning.md ================================================ #### DODI Warning It is highly recommended to stick to DODI's 1337x page or main website, as sites they linked to have malicious fake download buttons, and shouldn't be used without an [adblocker](https://fmhy.net/privacy#adblocking). ================================================ FILE: docs/.vitepress/notes/dolby-access-atmos-note.md ================================================ #### Dolby Access / Atmos Note Many headsets come with Dolby Access for free without letting users know. You can check if you're licensed by opening Dolby Access, going to settings, and looking in the [bottom right corner](https://i.imgur.com/9vJA6CL.png). It's much better than things like iCue or similar apps. ================================================ FILE: docs/.vitepress/notes/driver-note.md ================================================ #### Driver Note Only install the drivers you actually need. Don't install new drivers all at once, as this could lead to things breaking, especially system audio. ================================================ FILE: docs/.vitepress/notes/eaglercraft-note.md ================================================ #### Eaglercraft Note Play on Chromium-based browsers for the best performance. ================================================ FILE: docs/.vitepress/notes/eruda.md ================================================ #### Eruda Eruda Console for mobile browsers [bookmarklet](https://wikipedia.org/wiki/Bookmarklet): ``` javascript:(function () { var script = document.createElement('script'); script.src="//cdn.jsdelivr.net/npm/eruda"; document.body.appendChild(script); script.onload = function () { eruda.init() } })(); ``` ================================================ FILE: docs/.vitepress/notes/filebin-warning.md ================================================ #### Filebin Warning Anyone with a link to a "bin" has full access to it. They can add new files, delete existing files, etc. ================================================ FILE: docs/.vitepress/notes/filelu-warning.md ================================================ #### Filelu Warning According to their FAQ, you must login to your account at least once every 180 days to prevent your account and it's files being deleted. ================================================ FILE: docs/.vitepress/notes/filezilla-warning.md ================================================ #### FileZilla Warning The version of FileZilla on FileZilla's front page has adware, but the non-adware version is the only link on FMHY. You can also find the non-adware version by pressing download on the FileZilla front page, then clicking "Show additional download options" under "More download options" at the download page. ================================================ FILE: docs/.vitepress/notes/flicker-proxy.md ================================================ #### Flicker Proxy Note that the proxy may be slower, but it can be used in cases where the site or TMDb is blocked. ================================================ FILE: docs/.vitepress/notes/fluxy-repacks.md ================================================ #### Fluxy Repacks Note that although it has repacks in the name, its not actually a repack site. ================================================ FILE: docs/.vitepress/notes/forest-extensions.md ================================================ #### Forest Extensions * https://addons.mozilla.org/en-US/firefox/addon/forest-stay-focused-be-present/ * https://chrome.google.com/webstore/detail/forest-stay-focused-be-pr/kjacjjdnoddnpbbcjilcajfhhbdhkpgk ================================================ FILE: docs/.vitepress/notes/foxit-warning.md ================================================ #### Foxit Warning The installer tries to install McAfee WebAdvisor + PhantomPDF Business. They can be skipped by clicking "decline" both times. ================================================ FILE: docs/.vitepress/notes/freegogpcgames-note.md ================================================ #### FreeGOGPCGames Note The file checksum may not match with the original GOG installer. This is because many titles on the site are the older versions of the installers, the digital signature on the old installers are signed by *GOG Limited*, which is the old company's name before it was merged with *GOG Sp. z o.o* and all digital file signatures were updated to reflect this name change. The hash does not match the gog-games database because the digital file signatures differ on the installer. Installing either version will produce identical sets of files since the game version remains unchanged. - [/u/AtariRiot66](https://www.reddit.com/r/PiratedGames/comments/1br4m7o/comment/kx8hzz3/) ================================================ FILE: docs/.vitepress/notes/gemai.md ================================================ #### Nano Banana Pro Note Nano Banana Pro is a bit glitchy as of now, but it is being worked on according to their Discord staff. ================================================ FILE: docs/.vitepress/notes/general-tweak-warning.md ================================================ #### General Tweak Warning Make sure you know what you're doing before you apply these tweaks. Always research first, never just "Apply All" without knowing what what will happen. ================================================ FILE: docs/.vitepress/notes/glitchwave-note.md ================================================ #### Glitchwave Note For charts you can specify months and days using URLs like the following examples: January 2006: `https://glitchwave.com/charts/popular/game/2006.01/excl:ratings/` Jan - Feb 2018: `https://glitchwave.com/charts/popular/game/2018.01-2018.02/excl:ratings/` ================================================ FILE: docs/.vitepress/notes/google-song-identification.md ================================================ #### Google Song Identification Google and YouTube Music mobile apps have song identification button next to the search box. ================================================ FILE: docs/.vitepress/notes/google-translate-note.md ================================================ #### Google Translate Note Google Translate can be used as a web proxy. Simply paste your URL into the translate field and then click on the result and view the page in the original language. This way you can navigate any web-page via google.com. Google is almost never blocked so this trick works on most occasions. ================================================ FILE: docs/.vitepress/notes/hdo-box-note.md ================================================ #### HDO Box Note To use the app, HDO Box may ask you to install a third-party video player which contains ads. To block the ads, use the tools linked in [DNS Adblocking](https://fmhy.net/privacy#dns-adblocking). ================================================ FILE: docs/.vitepress/notes/hugging-face-warning.md ================================================ #### Hugging Face Warning HuggingFace uses a system called ZeroGPU to manage access to their high-end GPUs. To make sure that their GPUs don't get fully used up, there are limits on how long you can use the GPU on Spaces like this one. The rate limit is 120 seconds per day for non-logged in users. You can get around the limit by changing your IP address using a [proxy](https://fmhy.net/privacy#proxy) or [VPN](https://fmhy.net/privacy#vpn) while logged out. If you sign up for a free account, you get a much higher 300 second daily limit, but changing your IP address won't reset it. ================================================ FILE: docs/.vitepress/notes/instaeclipse-note.md ================================================ #### InstaEclipse Note Use [this guide](https://wispydocs.pages.dev/revanced-morphe-obtainium/#advanced) to build clean APKs, or use AntiSplit M with ReVanced manager. ================================================ FILE: docs/.vitepress/notes/irc-highway-note.md ================================================ #### IRC Highway Note To request a book run: @request [author] [title] - Requests without both [author] and [title] are deleted. To view request status and rules run: @request-list ================================================ FILE: docs/.vitepress/notes/jdownloader-warning.md ================================================ #### JDownloader Warning The version of JDownloader linked on JDownloader's front page has adware. The version linked on FMHY, however, does not contain any adware. ================================================ FILE: docs/.vitepress/notes/limit-bypass-note.md ================================================ #### Limit Bypass Note - SparseBox: iOS 17.0 - 18.1 Beta 4 (not including 17.7.1, 17.7.2) - Live container: iOS 16+ ================================================ FILE: docs/.vitepress/notes/liteapk-modyolo-note.md ================================================ #### LiteAPK + Modyolo Note The site is safe, but they are known for mislabeling things like RockMods releases as their own, and mislabeling versions to make it look like they have newer things than they really do. ================================================ FILE: docs/.vitepress/notes/malware-removal-forums.md ================================================ #### Malware Removal Forums Note that many of these will suggest removing pirated software, but if you got everything from trusted sources, there is no real need to do that. ================================================ FILE: docs/.vitepress/notes/megabasterd-note.md ================================================ #### Megabasterd Note Free proxies work but they are very hit and miss. ================================================ FILE: docs/.vitepress/notes/mobilism-ranks.md ================================================ #### Mobilism Ranks See what the different Mobilism Ranks mean [here](https://i.imgur.com/WpShSFp.png). ================================================ FILE: docs/.vitepress/notes/modelscope.md ================================================ ### ModelScope Note This site uses credits (called *magicubes*) to generate images and videos, you get 100 daily. It costs 2 magicubes per image for Qwen, 1 for Z-Image, and 28 for Wan 2.2 14b I2V. You can link an Alibaba Cloud account for free if you ignore the final part of account setup where it asks for payment info and link the account anyways, which gets you 50 extra magicubes daily. ================================================ FILE: docs/.vitepress/notes/mori-note.md ================================================ #### Māori Note Māori is the indigenous language of mainland New Zealand. Due to the [Native Schools Act](https://en.wikipedia.org/wiki/M%C4%81ori_language#Suppression_and_decline) in 1867, children were forbidden to speak it in the classroom, under penalty of corporal punishment, which led to a rapid decline of speakers. There are now [revitalization efforts](https://en.wikipedia.org/wiki/M%C4%81ori_language_revival) (such as Tōku Reo) attempting to promote and reinforce its use. ================================================ FILE: docs/.vitepress/notes/movie-web-sources.md ================================================ #### Adding sources to P-Stream (and all movie-web forks) You can [enable an extension](https://pstream.net/onboarding/) / [script](https://github.com/p-stream/userscript) that will add more sources, but it needs to connect to all sites to function. The extension is safe, and many people use it, the permissions are just needed in order for the extension to work correctly. Note that you can run it in a new browser or fresh browser profile if you don't want to use your main browser. Documentation and self-hosting guides can be found here: https://p-stream.github.io/docs/ ================================================ FILE: docs/.vitepress/notes/movieparadise-code.md ================================================ #### MovieParadise Code In order to unlock the better host (1fichier) you need a signup code. This is important as without it the site will be only Rapidgator links, which are very slow. You can get a code from the link below, or from the pinned messages in our `#free-stuff` [Discord channel](https://github.com/fmhy/FMHY/wiki/FMHY-Discord). **[Click Here To Get Code](https://rentry.org/he8fhzku)** ================================================ FILE: docs/.vitepress/notes/mp-opensubs.md ================================================ ### OpenSubtitles with MPC-HC You can create an OpenSubtitles account and link it in MPC-HC to bypass quota limits. You can do this via a panel in MPC-HC located at: `Options` -> `Subtitles` -> `Misc.` > Right-click on `OpenSubtitles.com` -> `Setup` -> Fill in username and password. ================================================ FILE: docs/.vitepress/notes/mvsep-note.md ================================================ #### MVSEP Note Register to get .wav and .flac output, and lower queue times. ================================================ FILE: docs/.vitepress/notes/oneclick-note.md ================================================ #### OneClick Note Main features include: - Download links straight to Google Drive. - Torrent to Google Drive. - Google Drive Download Manager (similar to pyLoad). - Spotify Downloader. - Jellyfin Support. - RClone + WebUI. - And much more. ================================================ FILE: docs/.vitepress/notes/openasar.md ================================================ #### OpenAsar Note The Vencord installer has an option to install OpenAsar, but you may need to click the install button twice (only once more after clicking "Accept"). ================================================ FILE: docs/.vitepress/notes/openrgb-beta.md ================================================ #### OpenRGB Beta The latest stable release (0.9) is from July, 2023. It is lacking support for many devices, so you may want to use a newer experimental release instead. * Supported devices for the latest stable release (0.9): https://openrgb.org/devices_0.9.html * Supported devices for the latest experimental release: https://openrgb.org/devices.html To use an experimental release go to https://gitlab.com/CalcProgrammer1/OpenRGB and in the left sidebar go to `Build` -> `Pipelines`, then click the download icon for a pipeline that has three green checkmarks, and pick the appropriate version for your computer. ================================================ FILE: docs/.vitepress/notes/pollinations-limits.md ================================================ #### Pollinations Limits For chat.pollinations.ai (and the underlying API), the rate limits depend on how you're using it: **Anonymous / Free Tier (No Login)** - **Text/Chat**: ~1 request every **3 seconds** (per IP). - **Images**: ~1 request every **5 seconds** (per IP). **Logged In (Pollen System)** - Users get a **daily free Pollen allowance** based on their tier. - **Publishable Keys (`pk_`)**: Rate limited to prevent abuse (e.g., ~1 pollen/hour per IP). - **Secret Keys (`sk_`)**: **No rate limits** (requests run as fast as you can pay for them with Pollen). If you're hitting limits on the chat site: 1. Slow down slightly (wait 3-5s between messages). 2. **Log in** at [enter.pollinations.ai](https://enter.pollinations.ai) to use your daily free credits. 3. If you need massive throughput, use an API key (`sk_`) with purchased credits. ================================================ FILE: docs/.vitepress/notes/printeditwe-addons.md ================================================ #### PrintEditWe Addons * https://addons.mozilla.org/en-US/firefox/addon/print-edit-we/ * https://chrome.google.com/webstore/detail/print-edit-we/olnblpmehglpcallpnbgmikjblmkopia ================================================ FILE: docs/.vitepress/notes/proton-torrenting.md ================================================ #### Proton Torrenting Torrenting on Proton VPN's free plan is only possible when using an OpenVPN configuration / [Guide](https://protonvpn.com/support/vpn-config-download). Note that they do expire, so you'll have to make new ones occasionally. OpenVPN login credentials are located [here](https://account.protonvpn.com/account-password). ================================================ FILE: docs/.vitepress/notes/reaper-note.md ================================================ #### Reaper Note Reaper asks you to buy it after 60 days, but you can just close the popup and keep using it for free. ================================================ FILE: docs/.vitepress/notes/redditfilter-note.md ================================================ #### RedditFilter Note Go to `Settings` -> `Feed Filter` and untoggle `Promoted` to not see ads. You can also untoggle `Recommended` to hide AI suggestions. ================================================ FILE: docs/.vitepress/notes/rgshows-autoplay.md ================================================ #### RGShows Autoplay To enable autoplay on Firefox: * Click the permissions button located to the left of your search bar and click `Allow Audio and Video` next to `Autoplay`. or * Do `Ctrl-I` -> `Permissions` -> set `Autoplay` to `Allow Audio and Video`. ================================================ FILE: docs/.vitepress/notes/sanet-warning.md ================================================ #### Sanet Warning Note that Sanet has been known to host unsafe things like KMS Matrix, so it's best to avoid it for software and games. SoftArchive Mirrors - https://sanet.download/ - https://softarchive.is/ - https://sanet.lc/ - https://sanet.ws/ - https://sanet.st/ - https://sanet.sb/ - https://soft.ac/ ================================================ FILE: docs/.vitepress/notes/savepagewe.md ================================================ #### SavePageWe * https://addons.mozilla.org/en-US/firefox/addon/save-page-we/ * https://chrome.google.com/webstore/detail/save-page-we/dhhpefjklgkmgeafimnjhojgjamoafof ================================================ FILE: docs/.vitepress/notes/scrollanywhere-addons.md ================================================ #### ScrollAnywhere Addons * https://addons.mozilla.org/en-US/firefox/addon/scroll_anywhere/ * https://chrome.google.com/webstore/detail/scrollanywhere/jehmdpemhgfgjblpkilmeoafmkhbckhi * https://addons.opera.com/en/extensions/details/scrollanywhere/?display=en ================================================ FILE: docs/.vitepress/notes/sd-maid.md ================================================ #### SD Maid Note The Google Play Store version is paid only. On the F-Droid and GitHub versions, however, you can use paid features for free by pressing `Support the development` and not donating. ================================================ FILE: docs/.vitepress/notes/sh-note.md ================================================ #### SH Note Based on [this](https://wikipedia.org/wiki/Secret_Hitler) popular card game which was created by a co-founder of [Cards Against Humanity](https://wikipedia.org/wiki/Cards_Against_Humanity). ================================================ FILE: docs/.vitepress/notes/site-favicon-dl.md ================================================ #### Site Favicon Downloading You can also go to `https://www.google.com/s2/favicons?domain=URL&sz=64` where `URL` is the URL of the site you want the favicon of and `sz` is the size in pixels. ================================================ FILE: docs/.vitepress/notes/soft98-note.md ================================================ #### Soft98 Note Enable the `AdGuard - Ads` filter list in uBlock to allow downloads to work. To remove all ads, you can also get the [AdGuard Extra Userscript](https://github.com/AdguardTeam/AdGuardExtra?tab=readme-ov-file#userscript) (not the extension) and enable it in your [userscript manager](https://fmhy.net/internet-tools#userscripts). Note that you may need to disable filter `ir: PersianBlocker`. ================================================ FILE: docs/.vitepress/notes/sora.md ================================================ #### Sora Bypass the need for a invite code by installing Sora Mobile, and logging into OpenAI. ================================================ FILE: docs/.vitepress/notes/spacewar.md ================================================ Spacewar! is a [1962 multiplayer game](https://wikipedia.org/wiki/Spacewar!) made for the DEC PDP-1 minicomputer. It was later ported to other systems, making it the first ever multi-computer game. ================================================ FILE: docs/.vitepress/notes/spicetify-note.md ================================================ #### Spicetify Note Join their [Discord](https://discord.gg/VnevqPp2Rr) for version compatibility. Note that you can use the store built in to get a full list of addons and themes. ================================================ FILE: docs/.vitepress/notes/sport7.md ================================================ #### Sport7 Many sites use this player but this was the original. ================================================ FILE: docs/.vitepress/notes/steam-controller-support.md ================================================ #### Steam Controller Support Steam has built in support for most controller types, just add your games to Steam, right click the game, and turn on your controller. ================================================ FILE: docs/.vitepress/notes/steam-currency-converter-note.md ================================================ #### Steam Currency Converter Note For instant currency conversion: Go to Firefox's add-on settings (or the link `about:addons`) -> click on the add-on -> go to the `Permissions and data` section -> enable the optional sites. ================================================ FILE: docs/.vitepress/notes/tabiverse-extensions.md ================================================ #### Tabiverse Extensions * https://addons.mozilla.org/firefox/addon/tabiverse/ * https://chromewebstore.google.com/detail/hpplgjkooibhfkmmepoikcjpadcojcik ================================================ FILE: docs/.vitepress/notes/tautulli-note.md ================================================ #### Tautulli Note This will sometimes get falsely flagged by Windows Defender and removed automatically, so it may need to be allowed manually. ================================================ FILE: docs/.vitepress/notes/teamspeak-warning.md ================================================ #### TeamSpeak Warning Note that TeamSpeak server admins can view user IP addresses, so only join servers you trust. ================================================ FILE: docs/.vitepress/notes/thunderbird.md ================================================ #### Thunderbird Notifications To get real-time notifications: Press the three lines in the top left corner -> select the account you want to configure -> select `Manage Folders` -> select the folder you want from below. You can then select inbox and enable push. (Notifications must be enabled). ================================================ FILE: docs/.vitepress/notes/tinyurl-note.md ================================================ #### TinyURL Note To reveal the destination URL, replace "www" with "preview" in the URL like so: https://preview.tinyurl.com/5erwtst5 ================================================ FILE: docs/.vitepress/notes/video-downloadhelper.md ================================================ #### Video DownloadHelper Note that some versions of this extension give a watermark on sites that need conversion. It seems to happen on the Windows + Firefox version. ================================================ FILE: docs/.vitepress/notes/welib-note.md ================================================ #### WeLib Note WeLib is *not* connected to Anna's Archive, they simply mirror Anna's content onto their own site that has a different UI. It is not updated as often, and they don't share their codebase improvements publicly, so they aren't endorsed by Anna's themselves. ================================================ FILE: docs/.vitepress/notes/winrar.md ================================================ #### WinRAR Note WinRAR does not auto-update, and because it had a remote code execution vulnerability in the past, you should make sure you've manually updated **to 7.13 or later** to be safe. ================================================ FILE: docs/.vitepress/notes/yet-another-call-blocker-note.md ================================================ #### Yet Another Call Blocker Note The app itself isn't updated, but the blocklists are. It has a main local blocklist by default, and if you have "Auto-update database" enabled the app receives daily blocklist updates directly from third-party services. More info in their [GitLab repository](https://gitlab.com/xynngh/YetAnotherCallBlocker#yet-another-call-blocker). ================================================ FILE: docs/.vitepress/notes/youtube-tweaks.md ================================================ #### YouTube Tweaks * https://addons.mozilla.org/firefox/addon/youtube-tweaks/ * https://chrome.google.com/webstore/detail/youtube-tweaks/oeakphpfoaeggagmgphfejmfjbhjfhhh ================================================ FILE: docs/.vitepress/notes/yts-yify-note.md ================================================ #### YTS / Yify Note YTS / Yify has many fake copycat sites out there, make sure you're on one of the official domains before downloading anything. To be extra protected from fake sites, check out [FMHY SafeGuard](https://github.com/fmhy/FMHY-SafeGuard) and the [FMHY Filterlist](https://github.com/fmhy/FMHYFilterlist). ================================================ FILE: docs/.vitepress/shared.ts ================================================ /** * Copyright (c) 2025 taskylizard. Apache License 2.0. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import type { DefaultTheme } from 'vitepress' // @unocss-include export const meta = { name: 'freemediaheckyeah', description: 'The largest collection of free stuff on the internet!', hostname: 'https://fmhy.net', keywords: ['stream', 'movies', 'gaming', 'reading', 'anime'], build: { api: true, nsfw: true } } export const excluded = [ 'readme.md', 'single-page', 'feedback.md', 'index.md', 'sandbox.md', 'startpage.md' ] const safeEnv = (key: string) => typeof process !== 'undefined' ? process.env?.[key] : undefined if (safeEnv('FMHY_BUILD_NSFW') === 'false') { meta.build.nsfw = false } if (safeEnv('FMHY_BUILD_API') === 'false') { meta.build.api = false } const formatCommitRef = (commitRef: string) => `${commitRef.slice(0, 8)}` const cfStart = safeEnv('CF_PAGES_COMMIT_SHA') const commitStart = safeEnv('COMMIT_REF') export const commitRef = safeEnv('CF_PAGES') && cfStart ? formatCommitRef(cfStart) : commitStart ? formatCommitRef(commitStart) : 'dev' export const feedback = `` export const socialLinks: DefaultTheme.SocialLink[] = [ { icon: 'github', link: 'https://github.com/fmhy/edit' }, { icon: 'discord', link: 'https://github.com/fmhy/FMHY/wiki/FMHY-Discord' }, { icon: 'reddit', link: 'https://reddit.com/r/FREEMEDIAHECKYEAH' } ] export const nav: DefaultTheme.NavItem[] = [ { text: '📑 Changelog', link: '/posts/changelog-sites' }, { text: '📖 Glossary', link: 'https://rentry.org/The-Piracy-Glossary' }, { text: '💾 Backups', link: '/other/backups' }, { text: '🌱 Ecosystem', items: [ { text: '🌐 Search', link: '/posts/search' }, { text: '❓ FAQs', link: '/other/FAQ' }, { text: '🔖 Bookmarks', link: 'https://github.com/fmhy/bookmarks' }, { text: '✅ SafeGuard', link: 'https://github.com/fmhy/FMHY-SafeGuard' }, { text: '🚀 Startpage', link: 'https://fmhy.net/startpage' }, { text: '✴️ rss.fmhy', link: 'https://rss.fmhy.bid/' }, { text: '🔎 SearXNG', link: 'https://searx.fmhy.net/' }, { text: '💡 Site Hunting', link: 'https://www.reddit.com/r/FREEMEDIAHECKYEAH/wiki/find-new-sites/' }, { text: '😇 SFW FMHY', link: 'https://fmhy.xyz/' }, { text: '🏠 Selfhosting', link: '/other/selfhosting' }, { text: '🏞 Wallpapers', link: '/other/wallpapers' }, { text: '💙 Feedback', link: '/feedback' } ] } ] export const sidebar: DefaultTheme.Sidebar | DefaultTheme.NavItemWithLink[] = [ { text: ' Beginners Guide', link: '/beginners-guide' }, { text: ' Posts', link: '/posts' }, { text: ' Contribute', link: '/other/contributing' }, { text: 'Wiki', collapsed: false, items: [ { text: ' Adblocking / Privacy', link: '/privacy' }, { text: ' Artificial Intelligence', link: '/ai' }, { text: ' Movies / TV / Anime', link: '/video' }, { text: ' Music / Podcasts / Radio', link: '/audio' }, { text: ' Gaming / Emulation', link: '/gaming' }, { text: ' Books / Comics / Manga', link: '/reading' }, { text: ' Downloading', link: '/downloading' }, { text: ' Torrenting', link: '/torrenting' }, { text: ' Educational', link: '/educational' }, { text: ' Android / iOS', link: '/mobile' }, { text: ' Linux / macOS', link: '/linux-macos' }, { text: ' Non-English', link: '/non-english' }, { text: ' Miscellaneous', link: '/misc' } ] }, { text: 'Tools', collapsed: false, items: [ { text: ' System Tools', link: '/system-tools' }, { text: ' File Tools', link: '/file-tools' }, { text: ' Internet Tools', link: '/internet-tools' }, { text: ' Social Media Tools', link: '/social-media-tools' }, { text: ' Text Tools', link: '/text-tools' }, { text: ' Gaming Tools', link: '/gaming-tools' }, { text: ' Image Tools', link: '/image-tools' }, { text: ' Video Tools', link: '/video-tools' }, { text: ' Audio Tools', link: '/audio#audio-tools' }, { text: ' Educational Tools', link: '/educational#educational-tools' }, { text: ' Developer Tools', link: '/developer-tools' } ] }, { text: 'More', collapsed: true, items: [ meta.build.nsfw ? { text: ' NSFW', link: 'https://rentry.org/NSFW-Checkpoint' } : {}, { text: ' Unsafe Sites', link: '/unsafe' }, { text: ' Storage', link: '/storage' } ] } ] ================================================ FILE: docs/.vitepress/theme/Appearance.vue ================================================ ================================================ FILE: docs/.vitepress/theme/Layout.vue ================================================ ================================================ FILE: docs/.vitepress/theme/PostLayout.vue ================================================ ================================================ FILE: docs/.vitepress/theme/Posts.vue ================================================ ================================================ FILE: docs/.vitepress/theme/components/Announcement.vue ================================================ ================================================ FILE: docs/.vitepress/theme/components/Authors.vue ================================================ ================================================ FILE: docs/.vitepress/theme/components/Base64Dialog.vue ================================================ ================================================ FILE: docs/.vitepress/theme/components/CardField.vue ================================================ ================================================ FILE: docs/.vitepress/theme/components/ColorPicker.vue ================================================ ================================================ FILE: docs/.vitepress/theme/components/Feedback.vue ================================================