🎉 New website!

This commit is contained in:
taskylizard 2023-11-12 22:12:57 +05:30
parent 28f602b9ad
commit c97a0abf92
No known key found for this signature in database
GPG Key ID: 5CABA3D642DDC497
68 changed files with 8433 additions and 353 deletions

View File

@ -1,32 +1,32 @@
import os import os
headersData = { headersData = {
"AdblockVPNGuide.md": [":name_badge:", "140", "# Adblocking / Privacy", "Adblocking, Privacy, VPN's, Proxies, Antivirus"], "AdblockVPNGuide.md": ["Adblocking / Privacy", "Adblocking, Privacy, VPN's, Proxies, Antivirus"],
"AI.md": [":robot_face:", "130", "# Artificial Intelligence", "Chat Bots, Text Generators, Image Generators, ChatGPT Tools"], "AI.md": ["Artificial Intelligence", "Chat Bots, Text Generators, Image Generators, ChatGPT Tools"],
"Android-iOSGuide.md": [":iphone:", "45", "# Android / iOS", "Apps, Jailbreaking, Android Emulators"], "Android-iOSGuide.md": ["Android / iOS", "Apps, Jailbreaking, Android Emulators"],
"AudioPiracyGuide.md": [":musical_note:", "110", "# Music / Podcasts / Radio", "Stream Audio, Download Audio, Torrent Audio"], "AudioPiracyGuide.md": ["Music / Podcasts / Radio", "Stream Audio, Download Audio, Torrent Audio"],
"Beginners-Guide.md": [":pirate_flag:", "150", "# Beginners Guide to Piracy", ""], "Beginners-Guide.md": ["Beginners Guide", "A Guide for Beginners to Piracy"],
"DEVTools.md": [":male-technologist:", "50", "# Developer Tools", ""], "DEVTools.md": ["Developer Tools", "Git, Hosting, App Dev, Software Dev"],
"DownloadPiracyGuide.md": [":floppy_disk:", "80", "# Downloading", "Download Sites, Software Sites, Open Directories"], "DownloadPiracyGuide.md": ["Downloading", "Download Sites, Software Sites, Open Directories"],
"EDUPiracyGuide.md": [":brain:", "60", "# Educational", "Courses, Documentaries, Learning Resources"], "EDUPiracyGuide.md": ["Educational", "Courses, Documentaries, Learning Resources"],
"GamingPiracyGuide.md": [":video_game:", "100", "# Gaming / Emulation", "Download Games, ROMs, Gaming Tools"], "GamingPiracyGuide.md": ["Gaming / Emulation", "Download Games, ROMs, Gaming Tools"],
"LinuxGuide.md": [":penguin:", "40", "# Linux / MacOS", "Apps, Software Sites, Gaming"], "LinuxGuide.md": ["Linux / MacOS", "Apps, Software Sites, Gaming"],
"MISCGuide.md": [":open_file_folder:", "30", "# Miscellaneous", "Extensions, Indexes, News, Health, Food, Fun"], "MISCGuide.md": ["Miscellaneous", "Extensions, Indexes, News, Health, Food, Fun"],
"NSFWPiracy.md": [":underage:", "25", "# NSFW", ""], "NSFWPiracy.md": ["NSFW", "NSFW Indexes, Streaming, Downloading"],
"Non-English.md": [":earth_asia:", "35", "# Non-English", "International Piracy Sites"], "Non-English.md": ["Non-English", "International Piracy Sites"],
"ReadingPiracyGuide.md": [":green_book:", "90", "# Books / Comics / Manga", "Books, Comics, Magazines, Newspapers"], "ReadingPiracyGuide.md": ["Books / Comics / Manga", "Books, Comics, Magazines, Newspapers"],
"STORAGE.md": [":card_file_box:", "1", "", ""], "STORAGE.md": ["Storage", "Index for everything in the wiki."],
"TOOLSGuide.md": [":wrench:", "58", "# Tools", "General Tools, Internet Tools, System Tools"], "TOOLSGuide.md": ["Tools", "General Tools, Internet Tools, System Tools"],
"TorrentPiracyGuide.md": [":cyclone:", "70", "# Torrenting", "Torrent Clients, Torrent Sites, Trackers"], "TorrentPiracyGuide.md": ["Torrenting", "Torrent Clients, Torrent Sites, Trackers"],
"VideoPiracyGuide.md": [":tv:", "120", "# Movies / TV / Anime", "Stream Videos, Download Videos, Torrent Videos"], "VideoPiracyGuide.md": ["Movies / TV / Anime", "Stream Videos, Download Videos, Torrent Videos"],
"base64.md": [":key:", "20", "", ""], "base64.md": ["Base64", "Base64 storage"],
"img-tools.md": [":camera:", "55", "# Image Tools", ""], "img-tools.md": ["Image Tools", "Image Editors, Generators, Compress"],
"UnsafeSites.md": [":warning:", "21", "# Unsafe Sites", ""] "UnsafeSites.md": ["Unsafe Sites", "Unsafe/harmful sites to avoid."]
} }
def getHeaderForPage(pageFilename): def getHeaderForPage(pageFilename):
data = headersData[pageFilename] data = headersData[pageFilename]
header = '---\n' + 'icon: ' + '"' + data[0] + '"' + '\n' + 'order: ' + data[1] + '\n' + '---\n' + data[2] + '\n' + data[3] + '\n\n' header = '---\n' + 'title: ' + '"' + data[0] + '"' + '\n' + 'description: ' + data[1] + '\n' + '---\n' + '# ' + data[0] + '\n' + data[1] + '\n\n'
return header return header
def apply_to_all_md_files_in_current_dir(): def apply_to_all_md_files_in_current_dir():
@ -36,7 +36,6 @@ def apply_to_all_md_files_in_current_dir():
with open(file, 'r', encoding='utf-8') as f: with open(file, 'r', encoding='utf-8') as f:
content = f.read() content = f.read()
if not content.startswith('---'): if not content.startswith('---'):
print("adding header to " + file)
with open(file, 'w', encoding='utf-8') as f2: with open(file, 'w', encoding='utf-8') as f2:
header = getHeaderForPage(file) header = getHeaderForPage(file)
f2.write(header+content) f2.write(header+content)

View File

@ -1,23 +0,0 @@
---
image: /static/banner4.png
icon: ":wave:"
---
# Welcome
![](/static/banner4.png)
**The Largest Collection of Free Stuff On The Internet!**
* 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/nbats/FMHYedit/main/single-page) first to make sure we don't already have it.
* Approved edits will be applied to this site and all [🔒 backups](https://www.reddit.com/r/FREEMEDIAHECKYEAH/wiki/backups).
* You can send us stuff directly via [💬 Discord](https://redd.it/17f8msf).
* You can also checkout our subreddit, [r/FREEMEDIAHECKYEAH](https://www.reddit.com/r/FREEMEDIAHECKYEAH/) to know about any major updates to the wiki.
***
Emoji Legend:
* 🌐 - 3rd Party Indexes
* ↪️ - Storage Page Links
* ⭐ - Community Recommendations

View File

@ -1,33 +0,0 @@
input: .
output: .retype
url: fmhy.pages.dev
branding:
logo: /static/fmhy.ico
logoDark: /static/fmhy.ico
title: FMHY
favicon: /static/favicon.ico
links: # Top bar. Icons from FontAwesome 6.4.2.
- text: Discord
link: https://redd.it/17f8msf
icon: <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="m3,0C1.35,0,0,1.35,0,3v13.5c0,1.65,1.35,3,3,3h4.5v3.75c0,.29.16.54.41.67.25.13.56.1.79-.07l5.8-4.35h6.5c1.65,0,3-1.35,3-3V3c0-1.65-1.35-3-3-3H3Z"/></svg>
- text: Search
link: https://fmhy-search.streamlit.app/
icon: <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="m19.5,9.75c0,2.15-.7,4.14-1.88,5.75l5.93,5.94c.59.59.59,1.54,0,2.12-.59.59-1.54.59-2.12,0l-5.93-5.94c-1.61,1.18-3.6,1.87-5.75,1.87C4.36,19.5,0,15.13,0,9.75S4.36,0,9.75,0s9.75,4.36,9.75,9.75Zm-9.75,6.75c3.73,0,6.75-3.02,6.75-6.75s-3.02-6.75-6.75-6.75-6.75,3.02-6.75,6.75,3.02,6.75,6.75,6.75Z"/></svg>
- text: Reddit
link: https://www.reddit.com/r/FREEMEDIAHECKYEAH/
icon: <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="m9.36,14.4c-.67,0-1.2-.54-1.2-1.19s.54-1.2,1.2-1.2,1.19.54,1.19,1.2-.54,1.19-1.19,1.19Zm14.64-2.4c0,6.63-5.37,12-12,12S0,18.63,0,12,5.37,0,12,0s12,5.37,12,12Zm-6.4-1.99c-.45,0-.86.19-1.15.48-1.08-.75-2.55-1.23-4.17-1.29l.84-3.79,2.68.6c0,.66.54,1.19,1.19,1.19s1.2-.55,1.2-1.2-.54-1.2-1.2-1.2c-.47,0-.87.28-1.07.67l-2.96-.66c-.15-.04-.3.07-.33.21l-.92,4.18c-1.61.07-3.05.55-4.14,1.3-.3-.31-.71-.49-1.17-.49-1.69,0-2.24,2.27-.7,3.04-.05.24-.08.49-.08.75,0,2.55,2.86,4.61,6.39,4.61s6.4-2.06,6.4-4.61c0-.26-.03-.52-.09-.76,1.51-.77.96-3.02-.72-3.02Zm-3.33,5.62c-.88.88-3.68.87-4.53,0-.11-.11-.3-.11-.4,0-.12.12-.12.31,0,.42,1.1,1.1,4.22,1.1,5.33,0,.12-.11.12-.3,0-.42-.11-.11-.3-.11-.4,0Zm.37-3.63c-.66,0-1.19.54-1.19,1.2s.54,1.19,1.19,1.19,1.2-.54,1.2-1.19-.53-1.2-1.2-1.2Z"/></svg>
- text: Github
link: https://github.com/fmhy
icon: <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 496 512"><path d="m8.03,19.32c0,.1-.11.18-.25.18-.16.01-.27-.06-.27-.18,0-.1.11-.18.25-.18.15-.01.27.06.27.18Zm-1.5-.22c-.03.1.06.21.21.24.13.05.27,0,.3-.1s-.06-.21-.21-.26c-.13-.03-.27.01-.3.11Zm2.14-.08c-.14.03-.24.13-.22.24.01.1.14.16.29.13.14-.03.24-.13.22-.23-.01-.09-.15-.16-.29-.14ZM11.85,0C5.13,0,0,5.23,0,12.11c0,5.5,3.38,10.21,8.2,11.87.62.11.84-.28.84-.6s-.01-2-.01-3.05c0,0-3.39.74-4.1-1.48,0,0-.55-1.44-1.35-1.82,0,0-1.11-.78.08-.76,0,0,1.2.1,1.87,1.28,1.06,1.92,2.84,1.36,3.53,1.04.11-.79.43-1.34.77-1.67-2.7-.31-5.43-.71-5.43-5.48,0-1.36.37-2.05,1.14-2.92-.13-.32-.54-1.65.13-3.37,1.01-.32,3.34,1.34,3.34,1.34.97-.28,2.01-.42,3.04-.42s2.07.14,3.04.42c0,0,2.33-1.67,3.34-1.34.66,1.72.25,3.05.13,3.37.77.88,1.25,1.56,1.25,2.92,0,4.79-2.85,5.17-5.55,5.48.45.39.82,1.14.82,2.3,0,1.67-.01,3.74-.01,4.15,0,.32.22.71.84.6,4.84-1.65,8.12-6.36,8.12-11.86C24,5.23,18.56,0,11.85,0Zm-7.14,17.12c-.06.05-.05.16.03.26.08.08.19.11.25.05.06-.05.05-.16-.03-.26-.08-.08-.19-.11-.25-.05Zm-.52-.4c-.03.06.01.14.11.19.08.05.17.03.21-.03.03-.06-.01-.14-.11-.19-.1-.03-.17-.01-.21.03Zm1.57,1.77c-.08.06-.05.21.06.31.11.11.25.13.31.05.06-.06.03-.21-.06-.31-.11-.11-.25-.13-.31-.05Zm-.55-.73c-.08.05-.08.18,0,.29s.21.16.27.11c.08-.06.08-.19,0-.31-.07-.11-.19-.16-.27-.1Z"/></svg>
- text: Updates
link: https://www.reddit.com/r/FREEMEDIAHECKYEAH/wiki/updates/
icon: log
- text: Backups
link: https://www.reddit.com/r/FREEMEDIAHECKYEAH/wiki/backups
icon: shield-lock
footer:
copyright: ""
meta:
title: " | FreeMediaHeckYeah"

View File

@ -1,193 +0,0 @@
import re
import os
import sys
def replaces_for_beginners_guide(text):
text = re.sub('\[TOC\]\n', '', text, flags=re.MULTILINE)
text = re.sub('\*\*Table of Contents\*\*\n\[TOC2\]\n', '', text, flags=re.MULTILINE)
text = re.sub('# -> \*\*\*Beginners Guide to Piracy\*\*\* <-\n', '', text, flags=re.MULTILINE)
text = re.sub(r"!!!note\s(.+?)\n", r"!!!\n\1\n!!!\n", text, flags=re.MULTILINE)
text = re.sub(r"!!!info\s(.+?)\n", r"!!!\n\1\n!!!\n", text, flags=re.MULTILINE)
text = re.sub(r"!!!warning\s(.+?)\n", r"!!!warning\n\1\n!!!\n", text, flags=re.MULTILINE)
text = re.sub(r">\s(.+?)\n", r"> \1\n\n", text, flags=re.MULTILINE)
text = re.sub('\*\*\[\^ Back to Top\]\(#beginners-guide-to-piracy\)\*\*', '', text, flags=re.MULTILINE)
text = re.sub("!!!\n!!!\n", "!!!\n", text, flags=re.MULTILINE)
text = re.sub("\n\*\*\[", "\n* **[", text, flags=re.MULTILINE)
return text
def do_some_individual_replaces(text):
#special cases of link not replaced correctly
text = re.sub('.pages.dev/storage/#encode--decode_urls', '.pages.dev/storage/#encode--decode-urls', text)
text = re.sub('.pages.dev/base64/#do-k-ument', '.pages.dev/base64/#do_k_ument', text)
text = re.sub('.pages.dev/devtools/#machine-learning2', '.pages.dev/devtools/#machine-learning-1', text)
#Base64-decoder script link
text = re.sub('\*\* site or extension\.\n', '** site or extension\.\nAlternatively, install this [userscript](https://rentry.co/wc7s2/raw)\n', text, flags=re.MULTILINE)
return text
def change_some_general_formatting(text):
text = re.sub('\*\*\*\n\n', '', text, flags=re.MULTILINE)
text = re.sub('\*\*\*\n', '', text, flags=re.MULTILINE)
text = re.sub('# ►', '##', text)
text = re.sub('## ▷', '###', text)
text = re.sub('####', '###', text)
text = re.sub(r'^\*\*Note\*\* - (.+)$', r'!!!\n\1\n!!!', text, flags=re.MULTILINE)
text = re.sub(r'^\* \*\*Note\*\* - (.+)$', r'!!!\n\1\n!!!', text, flags=re.MULTILINE)
text = re.sub(r'^Note - (.+)$', r'!!!\n\1\n!!!', text, flags=re.MULTILINE)
text = re.sub(r'^\*\*Warning\*\* - (.+)$', r'!!!warning\n\1\n!!!', text, flags=re.MULTILINE)
return text
def remove_backtowiki_and_toc(text):
text = re.sub('\*\*\[◄◄ Back to Wiki Index\]\(https://www\.reddit\.com/r/FREEMEDIAHECKYEAH/wiki/index\)\*\*\n', '', text, flags=re.MULTILINE)
text = re.sub(r'\*\*\[Table of Contents\]\(https?:\/\/.*?ibb\.co.*\)\*\* - For mobile users\n', '', text, flags=re.MULTILINE)
text = re.sub("\*\*\*\n\*\*\*\n\*\*\*\n\*\*\*\n\n\n\*\*\*\n\*\*\*\n\n", '', text, flags=re.MULTILINE)
text = re.sub("\*\*\*\n\*\*\*\n\*\*\*\n\*\*\*\n\n\n\*\*\*\n\*\*\* \n\n", '', text, flags=re.MULTILINE)
text = re.sub("\*\*\*\n\*\*\*\n\*\*\*\n\n\n\*\*\*\n\*\*\*\n\n", '', text, flags=re.MULTILINE)
text = re.sub("\*\*\*\n\*\*\*\n\*\*\*\n\*\*\*\n\n\n\*\*\*\n\n", '', text, flags=re.MULTILINE)
text = re.sub("\*\*\*\n\*\*\*\n\n\n\*\*\*\n\n", '', text, flags=re.MULTILINE)
return text
def replace_domain_and_page(text):
text = re.sub('www.reddit.com/r/FREEMEDIAHECKYEAH/wiki/ai', 'fmhy.pages.dev/ai', text)
text = re.sub('www.reddit.com/r/FREEMEDIAHECKYEAH/wiki/adblock-vpn-privacy', 'fmhy.pages.dev/adblockvpnguide', text)
text = re.sub('www.reddit.com/r/FREEMEDIAHECKYEAH/wiki/android', 'fmhy.pages.dev/android-iosguide', text)
text = re.sub('www.reddit.com/r/FREEMEDIAHECKYEAH/wiki/video', 'fmhy.pages.dev/videopiracyguide', text)
text = re.sub('www.reddit.com/r/FREEMEDIAHECKYEAH/wiki/audio', 'fmhy.pages.dev/audiopiracyguide', text)
text = re.sub('www.reddit.com/r/FREEMEDIAHECKYEAH/wiki/games', 'fmhy.pages.dev/gamingpiracyguide', text)
text = re.sub('www.reddit.com/r/FREEMEDIAHECKYEAH/wiki/reading', 'fmhy.pages.dev/readingpiracyguide', text)
text = re.sub('www.reddit.com/r/FREEMEDIAHECKYEAH/wiki/download', 'fmhy.pages.dev/downloadpiracyguide', text)
text = re.sub('www.reddit.com/r/FREEMEDIAHECKYEAH/wiki/torrent', 'fmhy.pages.dev/torrentpiracyguide', text)
text = re.sub('www.reddit.com/r/FREEMEDIAHECKYEAH/wiki/edu', 'fmhy.pages.dev/edupiracyguide', text)
text = re.sub('www.reddit.com/r/FREEMEDIAHECKYEAH/wiki/tools-misc', 'fmhy.pages.dev/toolsguide', text)
text = re.sub('www.reddit.com/r/FREEMEDIAHECKYEAH/wiki/linux', 'fmhy.pages.dev/linuxguide', text)
text = re.sub('www.reddit.com/r/FREEMEDIAHECKYEAH/wiki/non-eng', 'fmhy.pages.dev/non-english', text)
text = re.sub('www.reddit.com/r/FREEMEDIAHECKYEAH/wiki/misc', 'fmhy.pages.dev/miscguide', text)
text = re.sub('www.reddit.com/r/FREEMEDIAHECKYEAH/wiki/storage', 'fmhy.pages.dev/storage', text)
text = re.sub('www.reddit.com/r/FREEMEDIAHECKYEAH/wiki/dev-tools', 'fmhy.pages.dev/devtools', text)
text = re.sub('www.reddit.com/r/FREEMEDIAHECKYEAH/wiki/img-tools', 'fmhy.pages.dev/img-tools', text)
text = re.sub('github.com/nbats/FMHYedit/blob/main/base64.md#', 'fmhy.pages.dev/base64/#', text)
return text
def replace_underscore_in_subsections(text):
pattern = r'(/#[\w\-]+(?:_[\w]+)*)'
matches = re.findall(pattern, text)
for match in matches:
replacement = match.replace('_', '-')
text = text.replace(match, replacement)
return text
def reformat_subsections(text):
text = re.sub('/#wiki_', '/#', text)
text = re.sub('#wiki_', '/#', text)
text = re.sub('.25BA_', '', text)
text = re.sub('.25B7_', '', text)
text = re.sub('_.2F_', '--', text)
text = replace_underscore_in_subsections(text)
return text
def replace_urls_in_links_to_FMHY_wiki(text):
text = remove_backtowiki_and_toc(text)
text = replace_domain_and_page(text)
text = reformat_subsections(text)
text = change_some_general_formatting(text)
text = do_some_individual_replaces(text)
return text
def apply_replace_to_all_md_files_in_current_dir():
files = os.listdir('.')
for file in files:
if file.endswith('.md'):
with open(file, 'r', encoding='utf-8') as f:
content = f.read()
content = replace_urls_in_links_to_FMHY_wiki(content)
if file == "Beginners-Guide.md":
content = replaces_for_beginners_guide(content)
with open(file, 'w', encoding='utf-8') as f2:
f2.write(content)
def print_info_for_confirmation():
print("This script is about to replace URLs in all .md files in the current directory: " + os.getcwd())
print("The affected files will be the following:")
files = os.listdir('.')
for file in files:
if file.endswith('.md'):
print(file)
# TESTER
testText = """
aaaaaaaa (https://www.reddit.com/r/FREEMEDIAHECKYEAH/wiki/storage#wiki_telegram_audio_download) aaaaaaa
**[ Back to Wiki Index](https://www.reddit.com/r/FREEMEDIAHECKYEAH/wiki/index)**
* **[YouTube Music Clients](https://www.reddit.com/r/FREEMEDIAHECKYEAH/wiki/storage#wiki_youtube_music_players)**
Soundtracks](https://github.com/nbats/FMHYedit/blob/main/base64.md#damons-game-soundtracks)**, [Squ
(https://www.reddit.com/r/FREEMEDIAHECKYEAH/wiki/storage#wiki_game_libraries_.2F_launcher)
(https://www.reddit.com/r/FREEMEDIAHECKYEAH/wiki/games#wiki_.25BA_tracking_.2F_discovery)
(https://www.reddit.com/r/FREEMEDIAHECKYEAH/wiki/linux#wiki_.25BA_linux_adblock_.2F_privacy)
(https://www.reddit.com/r/FREEMEDIAHECKYEAH/wiki/video#wiki_.25BA_download_sites)
[sdfasdf](https://www.reddit.com/r/FREEMEDIAHECKYEAH/wiki/android#wiki_.25B7_android_podcasts_.2F_radio)gwrgewrgew
(https://www.reddit.com/r/FREEMEDIAHECKYEAH/wiki/android#wiki_.25B7_android_relaxation)
adfads awerfaw (https://www.reddit.com/r/FREEMEDIAHECKYEAH/wiki/storage#wiki_music_libraries_.2F_players)
(https://www.reddit.com/r/FREEMEDIAHECKYEAH/wiki/edu/#wiki_.25BA_downloading) aaaaaaaaa
(https://www.reddit.com/r/FREEMEDIAHECKYEAH/wiki/adblock-vpn-privacy#wiki_.25B7_adblocking_extensions)
* [link](https://www.reddit.com/r/FREEMEDIAHECKYEAH/wiki/torrent) - ...sdvs
https://www.reddit.com/r/FREEMEDIAHECKYEAH/wiki/img-tools#wiki_.25B7_painting_.2F_drawing
* **[AI Indexes](https://www.reddit.com/r/FREEMEDIAHECKYEAH/wiki/ai#wiki_.25BA_ai_indexes)** - Artificial Intelligence Indexes
(https://www.reddit.com/r/FREEMEDIAHECKYEAH/wiki/adblock-vpn-privacy#wiki_.25BA_vpn)
https://www.reddit.com/r/FREEMEDIAHECKYEAH/wiki/storage/#wiki_open_directory_search_string_builder
https://www.reddit.com/r/FREEMEDIAHECKYEAH/wiki/tools-misc#wiki_.25B7_file_tools
~~~~~~
***
***
**[ Back to Wiki Index](https://www.reddit.com/r/FREEMEDIAHECKYEAH/wiki/index)**
***
***
**[Table of Contents](https://i.imgur.com/whYmImm.png)** - For mobile users
***
***
~~~~~~
argaseg ae this is legit test between stuff to remove1
***
# ► with ##
## ▷ with ###
#### with ###
* **Note** - Some aggregators still include TPB, so it's best to avoid using them for software and games.
**Warning** - Misuse of Chat Archivers, Deleters, Mods & 3rd Party Clients is against Discords TOS, so use them at your own risk.
**[movie-web](https://movie-web.app/) / [FMovies](https://fmovies.name/) / [Soap2Day](https://soapgate.org/)** - Fast streaming
**[Zoro](https://zoro.to/) / [9Anime](https://www.9anime.to/)** - Fast anime streaming
"""
def just_test_the_replacer_function():
print("---TEST---")
print("This is how the resulting edited links would look like:")
print( replace_urls_in_links_to_FMHY_wiki(testText) )
print("---END OF TEST---\n\n\n")
just_test_the_replacer_function()
# MAIN EXECUTION
print("---MAIN SCRIPT---")
print_info_for_confirmation()
apply_replace_to_all_md_files_in_current_dir()
print("---END OF MAIN SCRIPT---")

116
.github/replace.py vendored Normal file
View File

@ -0,0 +1,116 @@
import re
import os
import sys
def replaces_for_beginners_guide(text):
text = re.sub('\[TOC\]\n', '', text, flags=re.MULTILINE)
text = re.sub('\*\*Table of Contents\*\*\n\[TOC2\]\n', '', text, flags=re.MULTILINE)
text = re.sub('# -> \*\*\*Beginners Guide to Piracy\*\*\* <-\n', '', text, flags=re.MULTILINE)
text = re.sub(r"!!!note\s(.+?)\n", r":::info\n\1\n:::\n", text, flags=re.MULTILINE)
text = re.sub(r"!!!info\s(.+?)\n", r":::info\n\1\n:::\n", text, flags=re.MULTILINE)
text = re.sub(r"!!!warning\s(.+?)\n", r":::warning\n\1\n:::\n", text, flags=re.MULTILINE)
text = re.sub(r">\s(.+?)\n", r"> \1\n\n", text, flags=re.MULTILINE)
text = re.sub('\*\*\[\^ Back to Top\]\(#beginners-guide-to-piracy\)\*\*', '', text, flags=re.MULTILINE)
text = re.sub(r"!!!\s(.+?)\n", r":::info\n\1\n:::\n", text, flags=re.MULTILINE)
text = re.sub("\n\*\*\[", "\n* **[", text, flags=re.MULTILINE)
text = re.sub(r'>(.*)\n\n(.*)', r':::details \1\n\2\n:::', text, flags=re.MULTILINE)
return text
def do_some_individual_replaces(text):
#special cases of link not replaced correctly
text = re.sub('/storage/#encode--decode_urls', '/storage/#encode--decode-urls', text)
text = re.sub('/base64/#do-k-ument', '/base64/#do_k_ument', text)
text = re.sub('/devtools/#machine-learning2', '/devtools/#machine-learning-1', text)
#Base64-decoder script link
text = re.sub('(.+?) site or extension\.\n', 'Click on the texts to copy them decoded.\n', text, flags=re.MULTILINE)
return text
def change_some_general_formatting(text):
text = re.sub('\*\*\*\n\n', '', text, flags=re.MULTILINE)
text = re.sub('\*\*\*\n', '', text, flags=re.MULTILINE)
text = re.sub('# ►', '##', text)
text = re.sub('## ▷', '###', text)
text = re.sub('####', '###', text)
text = re.sub(r'^\*\*Note\*\* - (.+)$', r':::tip\n\1\n:::', text, flags=re.MULTILINE)
text = re.sub(r'^\* \*\*Note\*\* - (.+)$', r':::tip\n\1\n:::', text, flags=re.MULTILINE)
text = re.sub(r'^Note - (.+)$', r':::tip\n\1\n:::', text, flags=re.MULTILINE)
text = re.sub(r'^\*\*Warning\*\* - (.+)$', r':::warning\n\1\n:::', text, flags=re.MULTILINE)
text = re.sub(r'^\*\s([^*])', "- \\1", text, 0, re.MULTILINE)
return text
def remove_backtowiki_and_toc(text):
text = re.sub('\*\*\[◄◄ Back to Wiki Index\]\(https://www\.reddit\.com/r/FREEMEDIAHECKYEAH/wiki/index\)\*\*\n', '', text, flags=re.MULTILINE)
text = re.sub(r'\*\*\[Table of Contents\]\(https?:\/\/.*?ibb\.co.*\)\*\* - For mobile users\n', '', text, flags=re.MULTILINE)
text = re.sub("\*\*\*\n\*\*\*\n\*\*\*\n\*\*\*\n\n\n\*\*\*\n\*\*\*\n\n", '', text, flags=re.MULTILINE)
text = re.sub("\*\*\*\n\*\*\*\n\*\*\*\n\*\*\*\n\n\n\*\*\*\n\*\*\* \n\n", '', text, flags=re.MULTILINE)
text = re.sub("\*\*\*\n\*\*\*\n\*\*\*\n\n\n\*\*\*\n\*\*\*\n\n", '', text, flags=re.MULTILINE)
text = re.sub("\*\*\*\n\*\*\*\n\*\*\*\n\*\*\*\n\n\n\*\*\*\n\n", '', text, flags=re.MULTILINE)
text = re.sub("\*\*\*\n\*\*\*\n\n\n\*\*\*\n\n", '', text, flags=re.MULTILINE)
return text
def replace_domain_and_page(text):
text = re.sub('https://www.reddit.com/r/FREEMEDIAHECKYEAH/wiki/ai', '/ai', text)
text = re.sub('https://www.reddit.com/r/FREEMEDIAHECKYEAH/wiki/adblock-vpn-privacy', '/adblockvpnguide', text)
text = re.sub('https://www.reddit.com/r/FREEMEDIAHECKYEAH/wiki/android', '/android-iosguide', text)
text = re.sub('https://www.reddit.com/r/FREEMEDIAHECKYEAH/wiki/video', '/videopiracyguide', text)
text = re.sub('https://www.reddit.com/r/FREEMEDIAHECKYEAH/wiki/audio', '/audiopiracyguide', text)
text = re.sub('https://www.reddit.com/r/FREEMEDIAHECKYEAH/wiki/games', '/gamingpiracyguide', text)
text = re.sub('https://www.reddit.com/r/FREEMEDIAHECKYEAH/wiki/reading', '/readingpiracyguide', text)
text = re.sub('https://www.reddit.com/r/FREEMEDIAHECKYEAH/wiki/download', '/downloadpiracyguide', text)
text = re.sub('https://www.reddit.com/r/FREEMEDIAHECKYEAH/wiki/torrent', '/torrentpiracyguide', text)
text = re.sub('https://www.reddit.com/r/FREEMEDIAHECKYEAH/wiki/edu', '/edupiracyguide', text)
text = re.sub('https://www.reddit.com/r/FREEMEDIAHECKYEAH/wiki/tools-misc', '/toolsguide', text)
text = re.sub('https://www.reddit.com/r/FREEMEDIAHECKYEAH/wiki/linux', '/linuxguide', text)
text = re.sub('https://www.reddit.com/r/FREEMEDIAHECKYEAH/wiki/non-eng', '/non-english', text)
text = re.sub('https://www.reddit.com/r/FREEMEDIAHECKYEAH/wiki/misc', '/miscguide', text)
text = re.sub('https://www.reddit.com/r/FREEMEDIAHECKYEAH/wiki/storage', '/storage', text)
text = re.sub('https://www.reddit.com/r/FREEMEDIAHECKYEAH/wiki/dev-tools', '/devtools', text)
text = re.sub('https://www.reddit.com/r/FREEMEDIAHECKYEAH/wiki/img-tools', '/img-tools', text)
text = re.sub('https://github.com/nbats/FMHYedit/blob/main/base64.md#', '/base64/#', text)
return text
def replace_underscore_in_subsections(text):
pattern = r'(/#[\w\-]+(?:_[\w]+)*)'
matches = re.findall(pattern, text)
for match in matches:
replacement = match.replace('_', '-')
text = text.replace(match, replacement)
return text
def reformat_subsections(text):
text = re.sub('/#wiki_', '/#', text)
text = re.sub('#wiki_', '/#', text)
text = re.sub('.25BA_', '', text)
text = re.sub('.25B7_', '', text)
text = re.sub('_.2F_', '--', text)
text = replace_underscore_in_subsections(text)
return text
def replace_urls_in_links_to_FMHY_wiki(text):
text = remove_backtowiki_and_toc(text)
text = replace_domain_and_page(text)
text = reformat_subsections(text)
text = change_some_general_formatting(text)
text = do_some_individual_replaces(text)
return text
def apply_replace_to_all_md_files_in_current_dir():
files = os.listdir('.')
for file in files:
if file.endswith('.md'):
with open(file, 'r', encoding='utf-8') as f:
content = f.read()
content = replace_urls_in_links_to_FMHY_wiki(content)
if file == "Beginners-Guide.md":
content = replaces_for_beginners_guide(content)
with open(file, 'w', encoding='utf-8') as f2:
f2.write(content)
apply_replace_to_all_md_files_in_current_dir()

7
.github/script.sh vendored Normal file
View File

@ -0,0 +1,7 @@
python .github/add-headers.py
python .github/replace.py
for file in *; do
[[ -f "$file" ]] && mv "$file" "${file,,}" 2>/dev/null
done
exit 0

43
.github/workflows/deploy-api.yml vendored Normal file
View File

@ -0,0 +1,43 @@
name: Deploy API
on:
push:
branches:
- main
- vitepress
pull_request:
branches:
- main
concurrency: ${{ github.workflow }}-${{ github.ref }}
jobs:
ci:
name: Release
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 6
- uses: pnpm/action-setup@v2.4.0
- uses: actions/setup-node@v3
with:
node-version: 18
cache: "pnpm"
- run: pnpm install --no-frozen-lockfile
- name: Build
run: pnpm api:build
env:
WEBHOOK_URL: ${{ secrets.WEBHOOK_URL }}
NITRO_PRESET: cloudflare
- name: Publish to Cloudflare
uses: cloudflare/wrangler-action@v3
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
vars: WEBHOOK_URL
env:
WEBHOOK_URL: ${{ secrets.WEBHOOK_URL }}

View File

@ -1,40 +0,0 @@
name: Update FMHY Retype
on:
workflow_dispatch:
schedule:
- cron: '0 */2 * * *'
jobs:
update:
name: Update FMHY Retype
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v2
- name: Move Files
run: |
cp -r .github/assets/* .
shell: bash
- name: Install Python
uses: actions/setup-python@v4
with:
python-version: '3.10'
- name: Prepare Files
shell: bash
run: |
python .github/replace-links-to-fmhy-in-files-in-current-dir.py
python .github/add-headers.py
- name: Build Retype
uses: retypeapp/action-build@latest
- uses: retypeapp/action-github-pages@latest
with:
branch: retype
update-branch: true

View File

@ -3,7 +3,7 @@ name: Update Single Page
on: on:
workflow_dispatch: workflow_dispatch:
schedule: schedule:
- cron: '0 */2 * * *' - cron: "0 */2 * * *"
jobs: jobs:
update: update:
@ -19,7 +19,7 @@ jobs:
- name: Setup Python - name: Setup Python
uses: actions/setup-python@v4 uses: actions/setup-python@v4
with: with:
python-version: '3.10' python-version: "3.10"
- name: Configure Git - name: Configure Git
run: | run: |

9
.gitignore vendored Normal file
View File

@ -0,0 +1,9 @@
**/.vitepress/dist
**/.vitepress/cache
node_modules
*.log*
.nitro
.cache
.output
.env
dist

2
.npmrc Normal file
View File

@ -0,0 +1,2 @@
shamefully-hoist=true
strict-peer-dependencies=false

2
.prettierignore Normal file
View File

@ -0,0 +1,2 @@
**/*.md
pnpm-lock.yaml

14
.prettierrc.json Normal file
View File

@ -0,0 +1,14 @@
{
"semi": true,
"printWidth": 100,
"tabWidth": 2,
"useTabs": false,
"singleQuote": false,
"quoteProps": "as-needed",
"jsxSingleQuote": false,
"trailingComma": "all",
"bracketSpacing": true,
"bracketSameLine": true,
"arrowParens": "always",
"proseWrap": "always"
}

135
.vitepress/config.mts Normal file
View File

@ -0,0 +1,135 @@
import { defineConfig } from "vitepress";
import { withPwa } from "@vite-pwa/vitepress";
import UnoCSS from "unocss/vite";
import { presetUno, presetAttributify, presetIcons } from "unocss";
import { commitRef, meta } from "./constants";
import { pwa } from "./pwa";
import { fileURLToPath } from "url";
import { generateImages, generateMeta } from "./hooks";
import { toggleStarredPlugin } from "./markdown/toggleStarred";
import { base64DecodePlugin } from "./markdown/base64";
export default withPwa(
defineConfig({
title: "FMHY",
description: meta.description,
titleTemplate: ":title • freemediaheckyeah",
lang: "en-US",
lastUpdated: true,
cleanUrls: true,
appearance: "dark",
srcExclude: ["readme.md", "single-page", "toolsguide.md"],
ignoreDeadLinks: true,
metaChunk: 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: "icon", href: "/test.png", type: "image/svg+xml" }],
["link", { rel: "alternate icon", href: "/test.png" }],
["link", { rel: "mask-icon", href: "/test.png", color: "#7bc5e4" }],
// prettier-ignore
["meta", { name: "keywords", content: meta.keywords.join(" ") }],
["link", { rel: "apple-touch-icon", href: "/test.png", sizes: "192x192" }],
],
transformHead: async (context) => generateMeta(context, meta.hostname),
buildEnd: async (context) => {
generateImages(context);
},
vite: {
plugins: [
UnoCSS({
presets: [
presetUno(),
presetAttributify(),
presetIcons({
scale: 1.2,
extraProperties: {
display: "inline-block",
"vertical-align": "middle",
},
}),
],
}),
],
build: {
// Shut the fuck up
chunkSizeWarningLimit: Infinity,
},
resolve: {
alias: [
{
find: /^.*VPSwitchAppearance\.vue$/,
replacement: fileURLToPath(
new URL("./theme/components/ThemeSwitch.vue", import.meta.url),
),
},
],
},
},
markdown: {
config(md) {
md.use(toggleStarredPlugin);
md.use(base64DecodePlugin);
},
},
themeConfig: {
search: {
options: {
detailedView: true,
},
provider: "local",
},
footer: {
message: `Made with ❤️ (rev: ${commitRef})`,
},
outline: "deep",
logo: "/fmhy.ico",
nav: [
{ text: "Beginners Guide", link: "/beginners-guide" },
{ text: "Glossary", link: "https://rentry.org/The-Piracy-Glossary" },
{ text: "Guides", link: "https://rentry.co/fmhy-guides" },
{ text: "Backups", link: "https://www.reddit.com/r/FREEMEDIAHECKYEAH/wiki/backups" },
{ text: "Updates", link: "https://www.reddit.com/r/FREEMEDIAHECKYEAH/wiki/updates/" },
],
sidebar: [
{ text: "📛 Adblocking / Privacy", link: "/adblockvpnguide" },
{ text: "🤖 Artificial Intelligence", link: "/ai" },
{ text: "📺 Movies / TV / Anime", link: "/videopiracyguide" },
{ text: "🎵 Music / Podcasts / Radio", link: "/audiopiracyguide" },
{ text: "🎮 Gaming / Emulation", link: "/gamingpiracyguide" },
{ text: "📗 Books / Comics / Manga", link: "/readingpiracyguide" },
{ text: "💾 Downloading", link: "/downloadpiracyguide" },
{ text: "🌀 Torrenting", link: "/torrentpiracyguide" },
{ text: "🧠 Educational", link: "/edupiracyguide" },
{ text: "🔧 Tools", link: "/toolsguide" },
{ text: "📷 Image Tools", link: "/img-tools" },
{ text: "👨‍💻 Developer Tools", link: "/devtools" },
{ text: "📱 Android / iOS", link: "/android-iosguide" },
{ text: "🐧 Linux / MacOS", link: "/linuxguide" },
{ text: "🌍 Non-English", link: "/non-english" },
{ text: "📂 Miscellaneous", link: "/miscguide" },
{ text: "🔞 NSFW", link: "/nsfwpiracy" },
{ text: "⚠️ Unsafe Sites", link: "/unsafesites" },
{ text: "🔑 Base64", link: "/base64" },
{ text: "📦 Storage", link: "/storage" },
],
socialLinks: [
{ icon: "github", link: "https://github.com/fmhy/FMHYEdit" },
{ icon: "discord", link: "https://discord.gg/Stz6y6NgNg" },
{
icon: {
svg: '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24"><path d="M12 0A12 12 0 0 0 0 12a12 12 0 0 0 12 12a12 12 0 0 0 12-12A12 12 0 0 0 12 0zm5.01 4.744c.688 0 1.25.561 1.25 1.249a1.25 1.25 0 0 1-2.498.056l-2.597-.547l-.8 3.747c1.824.07 3.48.632 4.674 1.488c.308-.309.73-.491 1.207-.491c.968 0 1.754.786 1.754 1.754c0 .716-.435 1.333-1.01 1.614a3.111 3.111 0 0 1 .042.52c0 2.694-3.13 4.87-7.004 4.87c-3.874 0-7.004-2.176-7.004-4.87c0-.183.015-.366.043-.534A1.748 1.748 0 0 1 4.028 12c0-.968.786-1.754 1.754-1.754c.463 0 .898.196 1.207.49c1.207-.883 2.878-1.43 4.744-1.487l.885-4.182a.342.342 0 0 1 .14-.197a.35.35 0 0 1 .238-.042l2.906.617a1.214 1.214 0 0 1 1.108-.701zM9.25 12C8.561 12 8 12.562 8 13.25c0 .687.561 1.248 1.25 1.248c.687 0 1.248-.561 1.248-1.249c0-.688-.561-1.249-1.249-1.249zm5.5 0c-.687 0-1.248.561-1.248 1.25c0 .687.561 1.248 1.249 1.248c.688 0 1.249-.561 1.249-1.249c0-.687-.562-1.249-1.25-1.249zm-5.466 3.99a.327.327 0 0 0-.231.094a.33.33 0 0 0 0 .463c.842.842 2.484.913 2.961.913c.477 0 2.105-.056 2.961-.913a.361.361 0 0 0 .029-.463a.33.33 0 0 0-.464 0c-.547.533-1.684.73-2.512.73c-.828 0-1.979-.196-2.512-.73a.326.326 0 0 0-.232-.095z"/></svg>',
},
link: "https://reddit.com/r/FREEMEDIAHECKYEAH",
},
],
...pwa,
},
}),
);

16
.vitepress/constants.ts Normal file
View File

@ -0,0 +1,16 @@
export const meta = {
name: "FreeMediaHeckYeah",
description:
"The Largest Collection Of Free Stuff On The Internet!The Largest Collection Of Free Stuff On The Internet!",
hostname: process.env.COMMIT_REF ? "https://fmhy.netlify.app" : "https://fmhy.pages.dev",
keywords: ["stream", "movies", "gaming", "reading", "anime"],
};
// Netlify to Cloudflare otherwise dev
export const commitRef = process.env.COMMIT_REF
? `<a href="https://github.com/fmhy/FMHYEdit/commit/${process.env.COMMIT_REF
}">${process.env.COMMIT_REF.slice(0, 8)}</a>`
: process.env.CF_PAGES_COMMIT_SHA
? `<a href="https://github.com/fmhy/FMHYEdit/commit/${process.env.CF_PAGES_COMMIT_SHA
}">${process.env.CF_PAGES_COMMIT_SHA.slice(0, 8)}</a>`
: "dev";

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,22 @@
<script setup lang="ts">
defineProps<{ title: string; description?: string }>();
</script>
<template>
<div
tw="w-full h-full bg-black flex flex-col"
style="background-image: url(https://files.catbox.moe/1f84dy.png)">
<div tw="p-10 w-full min-h-0 grow flex flex-col items-center justify-between">
<div tw="w-full flex justify-between items-center text-5xl font-medium">
<div tw="flex items-center">
<div tw="text-zinc-100 ml-2 mt-1 font-semibold">freemediaheckyeah</div>
</div>
</div>
<div tw="w-full pr-56 flex flex-col items-start justify-end">
<div style="color: #f3f4f6" tw="text-6xl font-bold" v-html="title" />
<div style="color: #c0caf5" tw="mt-2 text-4xl" v-html="description" />
</div>
</div>
<div tw="shrink-0 h-2 w-full flex" style="background-color: #c4b5fd" />
</div>
</template>

View File

@ -0,0 +1,6 @@
/**
* Barrel generated using @taskylizard/tasker.
*/
export * from "./meta";
export * from "./opengraph";

84
.vitepress/hooks/meta.ts Normal file
View File

@ -0,0 +1,84 @@
import type { HeadConfig, TransformContext } from "vitepress";
export function generateMeta(context: TransformContext, hostname: string) {
const head: HeadConfig[] = [];
const { pageData } = context;
const url = `${hostname}/${pageData.relativePath.replace(/((^|\/)index)?\.md$/, "$2")}`;
head.push(["link", { rel: "canonical", href: url }]);
head.push(["meta", { property: "og:url", content: url }]);
head.push(["meta", { name: "twitter:url", content: url }]);
head.push(["meta", { name: "twitter:card", content: "summary_large_image" }]);
head.push(["meta", { property: "og:title", content: pageData.frontmatter.title }]);
head.push(["meta", { name: "twitter:title", content: pageData.frontmatter.title }]);
head.push([
"meta",
{
property: "og:description",
content: pageData.frontmatter.description,
},
]);
head.push([
"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.png`.replace(/\/\//g, "/").replace(/^\//, "");
head.push(["meta", { property: "og:image", content: `${hostname}/${imageUrl}` }]);
head.push(["meta", { property: "og:image:width", content: "1200" }]);
head.push(["meta", { property: "og:image:height", content: "628" }]);
head.push(["meta", { property: "og:image:type", content: "image/png" }]);
head.push(["meta", { property: "og:image:alt", content: pageData.frontmatter.title }]);
head.push(["meta", { name: "twitter:image", content: `${hostname}/${imageUrl}` }]);
head.push(["meta", { name: "twitter:image:width", content: "1200" }]);
head.push(["meta", { name: "twitter:image:height", content: "628" }]);
head.push(["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;
}

View File

@ -0,0 +1,89 @@
import { mkdir, readFile, writeFile } from "node:fs/promises";
import { dirname, resolve } from "node:path";
import { fileURLToPath } from "node:url";
import { createContentLoader } from "vitepress";
import type { ContentData, SiteConfig } from "vitepress";
import { type SatoriOptions, satoriVue } from "x-satori/vue";
import { renderAsync } from "@resvg/resvg-js";
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,
});
}
}
interface GenerateImagesOptions {
page: ContentData;
template: string;
outDir: string;
fonts: SatoriOptions["fonts"];
}
async function generateImage({ page, template, outDir, fonts }: GenerateImagesOptions) {
const { frontmatter, url } = page;
const options: SatoriOptions = {
width: 1200,
height: 628,
fonts,
props: {
title:
frontmatter.layout === "home"
? frontmatter.hero.name ?? frontmatter.title
: frontmatter.title,
description:
frontmatter.layout === "home"
? frontmatter.hero.tagline ?? frontmatter.description
: frontmatter.description,
},
};
const svg = await satoriVue(options, template);
const render = await renderAsync(svg);
const outputFolder = resolve(outDir, url.substring(1), "__og_image__");
const outputFile = resolve(outputFolder, "og.png");
await mkdir(outputFolder, { recursive: true });
return await writeFile(outputFile, render.asPng());
}

View File

@ -0,0 +1,45 @@
import { readFile } from "node:fs/promises";
import { dirname, resolve } from "node:path";
import { fileURLToPath } from "node:url";
import { SatoriOptions, 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: 1200,
height: 628,
fonts,
props: {
title: "Title",
description:
"Lorem ipsum dolor sit amet, qui minim labore adipisicing minim sint cillum sint consectetur cupidatat.",
dir: "/j",
},
});

View File

@ -0,0 +1,46 @@
import { defineLoader } from "vitepress";
import { writeFile, readFile } from "fs/promises";
interface Data {
title?: string;
content?: string;
url?: string;
}
declare const data: Data;
export { data };
const page = "https://rentry.co/fmhy-guides/raw";
const regex = /\* \[([^\]]+)\]\(([^)]+)\)/g;
const rentryRe = /(?<=rentry\.(co|org)).*/;
const guides = new Set<Data>();
const f = async (url: string) => {
const contents = await (await fetch(url))
.text()
.catch((error: Error) => console.error(`Failed at ${url}`, error));
return contents;
};
export default defineLoader({
async load(): Promise<Data> {
const contents = await f(page);
let match: any[] | null;
while ((match = regex.exec(contents)) !== null) {
const title = match[1];
const url = match[2];
// Fetch rentry guides
if (url.match(rentryRe)) {
const content = await f(url + "/raw");
guides.add({ title, content });
} else {
// Everything else can be here
guides.add({ title, url });
}
}
const obj = Object.fromEntries(
[...guides.entries()].map((entry, index) => [index.toString(), entry]),
);
await writeFile("./guides.json", JSON.stringify(obj, null, 4), "utf-8");
return JSON.parse(await readFile("./guides.json", { encoding: "utf-8" })) as Data;
},
});

View File

@ -0,0 +1,25 @@
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) {
// @ts-expect-error shut the fuck up already I HATE THIS
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 `<button class='base64' onclick="(function(btn){ const codeEl = btn.querySelector('code'); navigator.clipboard.writeText('${decode(
content,
)}').then(() => { const originalText = codeEl.textContent; codeEl.textContent = 'Copied'; setTimeout(() => codeEl.textContent = originalText, 3000); }).catch(console.error); })(this)"><code>${content}</code></button>`;
};
}

View File

@ -0,0 +1,17 @@
import type { MarkdownRenderer } from "vitepress";
const excluded = ["Beginners Guide"];
export function toggleStarredPlugin(md: MarkdownRenderer) {
md.renderer.rules.list_item_open = (tokens, index, options, env, self) => {
const contentToken = tokens[index + 2];
if (
!excluded.includes(env.frontmatter.title) &&
contentToken &&
contentToken.content.startsWith("⭐")
) {
return `<li class="starred">`;
}
return self.renderToken(tokens, index, options);
};
}

View File

@ -0,0 +1,6 @@
import { corsEventHandler } from "nitro-cors";
export default corsEventHandler((_event) => {}, {
origin: "*",
methods: "*",
});

102
.vitepress/pwa.ts Normal file
View File

@ -0,0 +1,102 @@
import type { PwaOptions } from "@vite-pwa/vitepress";
import { meta } from "./constants";
import { resolve } from "pathe";
import fg from "fast-glob";
export const pwa = {
outDir: ".vitepress/dist",
registerType: "autoUpdate",
includeManifestIcons: false,
includeAssets: fg.sync("**/*.{png,webp,svg,gif,ico,txt}", {
cwd: resolve(__dirname, "../public"),
}),
manifest: {
id: "/",
name: meta.name,
short_name: meta.name,
description: meta.description,
theme_color: "#ffffff",
start_url: "/",
lang: "en-US",
dir: "ltr",
orientation: "natural",
display: "standalone",
display_override: ["window-controls-overlay"],
categories: meta.keywords,
// TODO: replace with actual icons
icons: [
{
src: "test.png",
sizes: "64x64",
type: "image/png",
},
{
src: "test.png",
sizes: "192x192",
type: "image/png",
},
{
src: "test.png",
sizes: "512x512",
type: "image/png",
purpose: "any",
},
{
src: "maskable-icon.png",
sizes: "512x512",
type: "image/png",
purpose: "maskable",
},
],
handle_links: "preferred",
launch_handler: {
client_mode: ["navigate-existing", "auto"],
},
edge_side_panel: {
preferred_width: 480,
},
},
experimental: {
includeAllowlist: true,
},
workbox: {
globPatterns: ["**/*.{css,js,html,svg,png,ico,txt,woff2,json}"],
globIgnores: ["**/404.html"],
navigateFallback: null,
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],
},
},
},
{
urlPattern: /^https:\/\/fonts\.gstatic\.com\/.*/i,
handler: "CacheFirst",
options: {
cacheName: "gstatic-fonts-cache",
expiration: {
maxEntries: 10,
maxAgeSeconds: 60 * 60 * 24 * 365, // <== 365 days
},
cacheableResponse: {
statuses: [0, 200],
},
},
},
],
},
devOptions: {
enabled: true,
suppressWarnings: false,
},
} satisfies PwaOptions;

View File

@ -0,0 +1,49 @@
import { fetcher } from "itty-fetcher";
import { FeedbackSchema } from "../types/Feedback";
const feedbackOptions = [
{ label: "🐞 Bug", value: "bug" },
{
label: "♻️ Suggestion",
value: "suggestion",
},
{ label: "📂 Other", value: "other" },
{
label: "❤️ Appreciation",
value: "appreciate",
},
];
function getFeedbackOption(value: string) {
return feedbackOptions.find((option) => option.value === value);
}
export default defineEventHandler(async (event) => {
const { message, page, contact, type } = await readValidatedBody(event, FeedbackSchema.parse);
const env = useRuntimeConfig(event);
if (!["bug", "suggestion", "other", "appreciate"].includes(type!) || !message)
throw new Error("Invalid input.");
let description = `${message}\n\n`;
if (contact) description += `**Contact:** ${contact}`;
if (page) description += `**Page:** \`${page}\``;
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,
description: description,
},
],
})
.catch((error) => {
throw new Error(error);
});
return { status: "ok" };
});

View File

@ -0,0 +1,3 @@
export default eventHandler(() => {
return { nitro: "works" };
});

View File

@ -0,0 +1,19 @@
<script setup lang="ts">
import DefaultTheme from "vitepress/theme";
import Sidebar from "./components/SidebarCard.vue";
import Announcement from "./components/Announcement.vue";
const { Layout } = DefaultTheme;
</script>
<template>
<Layout>
<template #sidebar-nav-after>
<Sidebar />
</template>
<template #home-hero-prelink>
<Announcement />
</template>
<Content />
</Layout>
</template>

View File

@ -0,0 +1,15 @@
<script setup lang="ts">
import { useData } from "vitepress";
const { frontmatter } = useData();
</script>
<template>
<a
v-if="frontmatter.hero.prelink"
:href="frontmatter.hero.prelink.link"
target="_blank"
class="inline-flex items-center rounded-lg bg-[var(--vp-c-default-soft)] px-4 py-1 text-sm font-semibold mb-3">
{{ frontmatter.hero.prelink.title }}
</a>
</template>

View File

@ -0,0 +1,16 @@
<script setup lang="ts">
defineProps<{
icon: string;
}>();
</script>
<template>
<div class="flex items-center mb-[8px] g-[12px]">
<span class="flex items-center">
<div class="text-2xl" :class="icon" />
<div class="ml-2 text-sm text-[var(--vp-c-text-2)]">
<slot />
</div>
</span>
</div>
</template>

View File

@ -0,0 +1,199 @@
<script setup lang="ts">
import { reactive, ref } from "vue";
import { useRoute } from "vitepress";
import type { FeedbackType } from "../../types/Feedback";
const loading = ref<boolean>(false);
const error = ref<unknown>(null);
const success = ref<boolean>(false);
const { path } = useRoute();
const feedback = reactive<FeedbackType>({ message: "", contact: "" });
const feedbackOptions = [
{ label: "🐞 Bug", value: "bug" },
{
label: "♻️ Suggestion",
value: "suggestion",
},
{ label: "📂 Other", value: "other" },
{
label: "❤️ Appreciation",
value: "appreciate",
},
];
function getFeedbackOption(value: string) {
return feedbackOptions.find((option) => option.value === value);
}
async function handleSubmit(type?: FeedbackType["type"]) {
if (type) feedback.type = type;
loading.value = true;
const body: FeedbackType = {
message: feedback.message,
type: feedback.type,
contact: feedback.contact,
page: path,
};
try {
const response = await fetch("https://feedback.tasky.workers.dev", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(body),
});
const data = await response.json();
if (data.error) {
error.value = data.error;
return;
}
if (data.status === "success") {
success.value = true;
}
} catch (err) {
error.value = err;
} finally {
loading.value = false;
}
}
</script>
<template>
<div class="wrapper">
<Transition name="fade" mode="out-in">
<div v-if="!feedback.type" class="step">
<div>
<div>
<p class="heading">Feedback</p>
</div>
</div>
<div class="button-container">
<button v-for="item in feedbackOptions" :key="item.value" class="btn"
@click="handleSubmit(item.value as FeedbackType['type'])">
<span>{{ item.label }}</span>
</button>
</div>
</div>
<div v-else-if="feedback.type && !success" class="step">
<div>
<p class="desc">The wiki is... {{ path }}</p>
<div>
<span>{{ getFeedbackOption(feedback.type)?.label }}</span>
<button style="margin-left: 0.5rem" class="btn" @click="feedback.type = undefined">
<span class="i-carbon-close-large">close</span>
</button>
</div>
</div>
<textarea v-model="feedback.message" autofocus class="input" />
<p class="desc">Contacts, so we can get back to you. (Optional)</p>
<textarea v-model="feedback.contact" class="contact-input" />
<button type="submit" class="btn btn-primary" :disabled="feedback.message.length > 10" @click="handleSubmit()">
Submit
</button>
</div>
<div v-else class="step">
<p class="heading">Thanks for your feedback!</p>
</div>
</Transition>
</div>
</template>
<style scoped>
.step>*+* {
margin-top: 1rem;
}
.btn {
border: 1px solid var(--vp-c-divider);
background-color: var(--vp-c-bg);
border-radius: 8px;
transition:
border-color 0.25s,
background-color 0.25s;
display: inline-block;
font-size: 14px;
font-weight: 500;
line-height: 1.5;
margin: 0;
padding: 0.375rem 0.75rem;
text-align: center;
vertical-align: middle;
white-space: nowrap;
}
.btn:disabled {
opacity: 0.5;
}
.btn:hover {
border-color: var(--vp-c-brand);
}
.btn-primary {
color: #fff;
background-color: var(--vp-c-brand);
border-color: var(--vp-c-brand);
}
.btn-primary:hover {
background-color: var(--vp-c-brand-darker);
border-color: var(--vp-c-brand-darker);
}
.heading {
font-size: 1.2rem;
font-weight: 700;
}
.button-container {
display: grid;
grid-gap: 0.5rem;
}
.wrapper {
margin: 2rem 0;
padding: 1.5rem;
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
background: var(--vp-c-bg-alt);
}
.input {
width: 100%;
height: 100px;
border: 1px solid #ccc;
border-radius: 4px;
padding: 0.375rem 0.75rem;
}
.contact-input {
height: 50px;
border: 1px solid #ccc;
border-radius: 4px;
padding: 0.375rem 0.75rem;
}
.desc {
display: block;
line-height: 20px;
font-size: 12px;
font-weight: 500;
color: var(--vp-c-text-2);
}
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.25s ease;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
</style>

View File

@ -0,0 +1,47 @@
<script setup lang="ts">
defineProps<{
label: string;
id: string;
}>();
</script>
<template>
<div class="input-field">
<div class="input-label" v-if="label">
<label :for="id" class="pane-label">
{{ label }}
</label>
<div class="display-value">
<slot name="display" />
</div>
</div>
<slot />
</div>
</template>
<style scoped>
.pane-label {
line-height: 20px;
font-size: 13px;
font-weight: 600;
color: var(--vt-c-text-1);
display: block;
}
.input-field:not(:last-child) {
margin-bottom: 16px;
}
.display-value {
font-size: 13px;
color: var(--vp-c-text-2);
}
.input-label {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 8px;
gap: 12px;
}
</style>

View File

@ -0,0 +1,78 @@
<script setup lang="ts">
import { ref } from "vue";
import Feedback from "./Feedback.vue";
const showModal = ref(false);
</script>
<template>
<button class="p-[4px 8px] text-xl i-carbon:user-favorite-alt-filled" @click="showModal = true" />
<Teleport to="body">
<Transition name="modal">
<div v-show="showModal" class="modal-mask">
<div class="modal-container">
<Feedback />
<div class="model-footer">
<button class="modal-button" @click="showModal = false">Close</button>
</div>
</div>
</div>
</Transition>
</Teleport>
</template>
<style scoped>
.modal-mask {
position: fixed;
z-index: 200;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
transition: opacity 0.3s ease;
}
.modal-container {
width: 300px;
margin: auto;
padding: 20px 30px;
background-color: var(--vp-c-bg);
border-radius: 2px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.33);
transition: all 0.3s ease;
}
.model-footer {
margin-top: 8px;
text-align: right;
}
.modal-button {
padding: 4px 8px;
border-radius: 4px;
border-color: var(--vp-button-alt-border);
color: var(--vp-button-alt-text);
background-color: var(--vp-button-alt-bg);
}
.modal-button:hover {
border-color: var(--vp-button-alt-hover-border);
color: var(--vp-button-alt-hover-text);
background-color: var(--vp-button-alt-hover-bg);
}
.modal-enter-from,
.modal-leave-to {
opacity: 0;
}
.modal-enter-from .modal-container,
.modal-leave-to .modal-container {
transform: scale(1.1);
}
</style>

View File

@ -0,0 +1,60 @@
<script setup lang="ts">
import Field from "./CardField.vue";
import Modal from "./Modal.vue";
import InputField from "./InputField.vue";
import ToggleStarred from "./ToggleStarred.vue";
</script>
<template>
<div class="card">
<div class="card-header">
<div class="card-title">Emoji Legend</div>
</div>
<Field icon="i-twemoji-star">Recommendations</Field>
<Field icon="i-twemoji-globe-with-meridians">Indexes</Field>
<Field icon="i-twemoji-repeat-button">Storage Links</Field>
<div class="card-header">
<div class="card-title">Options</div>
</div>
<InputField id="feedback" label="Feedback">
<template #display>
<Modal />
</template>
</InputField>
<InputField id="toggle-starred" label="Toggle Starred">
<template #display>
<ToggleStarred />
</template>
</InputField>
</div>
</template>
<style scoped>
.card-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 12px;
}
.card-title {
font-weight: 700;
color: var(--vp-c-text-1);
line-height: 32px;
font-size: 16px;
}
.card {
background: var(--vp-c-bg);
padding: 12px 24px 24px;
border-radius: 12px;
position: relative;
z-index: 0;
border: 1px solid transparent;
transition: border-color 0.4s ease-in-out;
}
.card:hover {
border-color: var(--vp-c-brand-1);
}
</style>

View File

@ -0,0 +1,52 @@
<script setup>
import { ref } from "vue";
import { Switch } from "@headlessui/vue";
const enabled = ref(false);
</script>
<template>
<Switch v-model="enabled" class="switch" :class="{ enabled }">
<span class="thumb" />
</Switch>
</template>
<style>
.switch {
display: inline-flex;
position: relative;
width: 40px;
height: 22px;
flex-shrink: 0;
border: 1px solid var(--vp-input-border-color);
background-color: var(--vp-input-switch-bg-color);
transition:
border-color 0.25s,
background-color 0.4s ease;
border-radius: 11px;
}
.switch.enabled {
background-color: var(--vp-c-brand);
}
</style>
<style scoped>
.switch:hover {
border-color: var(--vp-input-hover-border-color);
}
.thumb {
display: inline-block;
background-color: #fff;
transition: transform 0.25s;
width: 20px;
height: 20px;
border-radius: 50%;
box-shadow: var(--vp-shadow-1);
}
.switch.enabled .thumb {
transform: translateX(18px);
}
</style>

View File

@ -0,0 +1,53 @@
<script setup lang="ts">
import { inject } from "vue";
import { useData } from "vitepress";
import VPIconMoon from "vitepress/dist/client/theme-default/components/icons/VPIconMoon.vue";
import VPIconSun from "vitepress/dist/client/theme-default/components/icons/VPIconSun.vue";
const { isDark } = useData();
const toggleAppearance = inject("toggle-appearance", () => {
isDark.value = !isDark.value;
});
</script>
<template>
<button
type="button"
role="switch"
title="Toggle dark mode"
class="VPSwitchAppearance"
:aria-checked="isDark"
@click="toggleAppearance">
<ClientOnly>
<Transition name="fade" mode="out-in">
<VPIconSun v-if="!isDark" class="sun" />
<VPIconMoon v-else class="moon" />
</Transition>
</ClientOnly>
</button>
</template>
<style scoped>
.VPSwitchAppearance {
display: flex;
justify-content: center;
align-items: center;
width: 36px;
height: 36px;
color: var(--vp-c-text-2);
transition: color 0.5s;
&:hover {
color: var(--vp-c-text-1);
transition: color 0.25s;
}
& > :deep(svg) {
width: 20px;
height: 20px;
fill: currentColor;
}
}
</style>

View File

@ -0,0 +1,15 @@
<script setup lang="ts">
import Switch from "./Switch.vue";
const toggleStarred = () => document.documentElement.classList.toggle("starred-only");
</script>
<template>
<Switch @click="toggleStarred()" />
</template>
<style>
.starred-only li:not(.starred) {
display: none;
}
</style>

13
.vitepress/theme/index.ts Normal file
View File

@ -0,0 +1,13 @@
import { type Theme, inBrowser } from "vitepress";
import DefaultTheme from "vitepress/theme";
import Layout from "./Layout.vue";
import "./style.css";
import "uno.css";
if (inBrowser) import("./pwa");
export default {
extends: DefaultTheme,
Layout: Layout,
enhanceApp({ app, router, siteData }) {},
} satisfies Theme;

3
.vitepress/theme/pwa.ts Normal file
View File

@ -0,0 +1,3 @@
import { registerSW } from "virtual:pwa-register";
registerSW({ immediate: true });

145
.vitepress/theme/style.css Normal file
View File

@ -0,0 +1,145 @@
:root {
/* Colors: Brand */
--vp-c-brand-1: #7bc5e4;
--vp-c-brand-2: #c4e2f2;
--vp-c-brand-3: #4882a7;
--vp-c-brand-soft: #a4d5ec;
/* Colors: Button */
--vp-button-brand-bg: var(--vp-c-brand-1);
--vp-button-brand-border: var(--vp-c-brand-soft);
--vp-button-brand-text: var(--vp-c-white);
--vp-button-brand-hover-border: var(--vp-c-brand-soft);
--vp-button-brand-hover-text: var(--vp-c-white);
--vp-button-brand-hover-bg: var(--vp-c-brand-soft);
--vp-button-brand-active-border: var(--vp-c-brand-soft);
--vp-button-brand-active-text: var(--vp-c-white);
--vp-button-brand-active-bg: var(--vp-button-brand-bg);
--vp-button-alt-bg: #484848;
--vp-button-alt-text: #f0eeee;
--vp-button-alt-hover-bg: #484848;
--vp-button-alt-hover-text: #f0eeee;
--vp-c-bg-elv: rgba(255, 255, 255, 0.7);
--vp-c-bg-mark: rgb(232, 232, 232);
/* Colors: Custom Block */
--vp-custom-block-info-bg: rgba(171, 210, 244, 0.05);
--vp-custom-block-info-border: #60c4fa;
--vp-custom-block-info-text: rgb(39, 115, 145);
--vp-custom-block-info-text-deep: rgb(18, 121, 162);
--vp-custom-block-tip-bg: rgba(137, 202, 176, 0.05);
--vp-custom-block-tip-border: rgba(34, 197, 94, 1);
--vp-custom-block-tip-text: rgb(10, 128, 90);
--vp-custom-block-tip-text-deep: rgb(11, 133, 94);
--vp-custom-block-warning-bg: rgba(250, 204, 21, 0.05);
--vp-custom-block-warning-border: rgba(245, 158, 11, 1);
--vp-custom-block-warning-text: rgb(166, 114, 35);
--vp-custom-block-warning-text-deep: rgb(199, 109, 6);
--vp-custom-block-danger-bg: rgba(220, 38, 38, 0.05);
--vp-custom-block-danger-border: rgba(248, 113, 113, 1);
--vp-custom-block-danger-text: rgb(196, 46, 46);
--vp-custom-block-danger-text-deep: rgba(220, 38, 38, 1);
}
.dark {
/* Colors: Background */
--vp-c-bg: rgb(26, 26, 26);
--vp-c-bg-alt: rgb(23, 23, 23);
--vp-c-bg-elv: rgba(23, 23, 23, 0.8);
/* Colors: Custom Block */
--vp-custom-block-info-bg: rgba(84, 110, 155, 0.1);
--vp-custom-block-info-border: #3686b1;
--vp-custom-block-info-text: #52b0e3;
--vp-custom-block-info-text-deep: #00b7ff;
--vp-custom-block-tip-bg: rgba(51, 130, 118, 0.1);
--vp-custom-block-tip-border: rgba(4, 120, 87, 1);
--vp-custom-block-tip-text: rgb(25, 190, 129);
--vp-custom-block-tip-text-deep: rgba(52, 211, 153, 1);
--vp-custom-block-warning-bg: rgba(253, 224, 71, 0.1);
--vp-custom-block-warning-border: rgba(202, 138, 4, 1);
--vp-custom-block-warning-text: rgba(234, 179, 8, 1);
--vp-custom-block-warning-text-deep: rgba(250, 204, 21, 1);
--vp-custom-block-danger-bg: rgba(239, 68, 68, 0.1);
--vp-custom-block-danger-border: rgba(127, 29, 29, 1);
--vp-custom-block-danger-text: rgba(248, 113, 113, 1);
--vp-custom-block-danger-text-deep: rgba(248, 113, 113, 1);
}
.vp-doc a {
color: var(--vp-c-brand-1);
text-decoration: underline;
text-underline-offset: 4px;
text-decoration-style: solid;
text-decoration-color: transparent;
-webkit-text-decoration-color: transparent;
transition: text-decoration-color 0.25s;
}
.vp-doc a:hover {
color: var(--vp-c-brand-1);
text-decoration-color: var(--vp-c-brand-1);
-webkit-text-decoration-color: var(--vp-c-brand-1);
}
.vp-doc .custom-block a {
text-decoration: underline;
text-underline-offset: 4px;
text-decoration-style: solid;
}
::selection {
background-color: var(--vp-button-brand-bg);
}
.VPFooter a {
text-decoration-line: underline;
text-decoration-style: dashed;
text-underline-offset: 5px;
transition: 0.3s;
}
.VPFooter a:hover {
color: var(--vp-c-text-1);
text-decoration-line: underline;
text-decoration-style: dashed;
text-underline-offset: 5px;
}
/* Custom scrollbar */
.VPSidebar::-webkit-scrollbar {
block-size: 4px;
border-end-end-radius: 14px;
border-start-end-radius: 14px;
inline-size: 4px;
}
/**
* Component: Home
*/
:root {
--vp-home-hero-name-color: transparent;
--vp-home-hero-name-background: -webkit-linear-gradient(120deg, #c4b5fd 30%, #7bc5e4);
--vp-home-hero-image-background-image: linear-gradient(-45deg, #c4b5fd 50%, #47caff 50%);
--vp-home-hero-image-filter: blur(44px);
}
@media (min-width: 640px) {
:root {
--vp-home-hero-image-filter: blur(56px);
}
}
@media (min-width: 960px) {
:root {
--vp-home-hero-image-filter: blur(68px);
}
}
.base64 {
min-width: 100%;
width: 0px;
white-space: pre-wrap;
}

View File

@ -0,0 +1,10 @@
import z from "zod";
export const FeedbackSchema = z.object({
message: z.string().min(5).max(1000),
type: z.enum(["bug", "suggestion", "appreciate", "other"]),
contact: z.string().min(5).max(20).optional(),
page: z.string().min(3).max(10),
});
export type FeedbackType = z.infer<typeof FeedbackSchema>;

4
.vitepress/vue-shim.d.ts vendored Normal file
View File

@ -0,0 +1,4 @@
declare module "*.vue" {
const component: import("vue").Component;
export default component;
}

View File

@ -9,40 +9,33 @@
> How do I tell if a site or download is safe? Any tips? > How do I tell if a site or download is safe? Any tips?
Check out [Booty Guard](https://rentry.org/bootyguard) our basic safety guide. Check out [Booty Guard](https://rentry.org/bootyguard) our basic safety guide.
Still feel unsure? Reach out to us via [Discord](https://redd.it/17f8msf) & make sure you've looked at sites/software we've listed as unsafe: [here](https://www.reddit.com/r/FREEMEDIAHECKYEAH/comments/10bh0h9/unsafe_sites_software_thread)
> I don't know what seeding means or *insert other term*... > I don't know what seeding means or *insert other term*...
You will find almost all terms related to piracy & more on [The Piracy Glossary](https://rentry.org/the-piracy-glossary) You will find almost all terms related to piracy & more on [The Piracy Glossary](https://rentry.org/the-piracy-glossary)
Didn't find it and still confused? Reach out to us via [Divolt](https://redd.it/uto5vw).
> How do I download Photoshop/Adobe Products for free? > How do I download Photoshop/Adobe Products for free?
You can download pre-cracked Adobe products from [M0nkrus](https://w14.monkrus.ws/) | [How to download from M0nkrus](https://rentry.co/adobesoftware) or Patch it yourself following these guides [here](https://www.reddit.com/r/GenP/wiki/index/) & for MacOS go [here](#macos) You can download pre-cracked Adobe products from [M0nkrus](https://w14.monkrus.ws/) who is a well trusted and reputable source for adobe software in the piracy community | [How to download from M0nkrus](https://rentry.co/adobesoftware). Alternatively, you can patch it yourself following the guides [here](https://www.reddit.com/r/GenP/wiki/index/). For MacOS go [here](#macos)
!!!info M0nkrus is a well trusted and reputable source for adobe software in the piracy community.
> How do I download/activate Windows/Office for free? > How do I download/activate Windows/Office for free?
For Windows check out this [section](#pirate-windows) For Windows check out this [section](#pirate-windows). For Office check these [guides](https://fmhy.pages.dev/storage/#office-suites)
For Office check these [guides](https://fmhy.pages.dev/storage/#office-suites)
> Where do I find *insert game title / movie title*? > Where do I find *insert game title / movie title*?
For movies check out [this](https://whereyouwatch.com) and for new movies it's a good idea to keep an eye on [r/movieleaks](https://reddit.com/r/movieleaks). For movies check out [this](https://whereyouwatch.com) and for new movies it's a good idea to keep an eye on [r/movieleaks](https://reddit.com/r/movieleaks). For sites to stream from check out this [section](#streaming). Keep in mind that pirated releases generally happen after a movie is digitally released or released via Blu-Ray / DVD, which can take 3 months+ after initially playing in theaters. For games use [Rezi](https://rezi.one) or any site listed [here](https://www.reddit.com/r/FREEMEDIAHECKYEAH/wiki/games/#wiki_.25BA_download_games) and for newly released games check [r/crackwatch](https://reddit.com/r/crackwatch). Please avoid downloading games from The Pirate Bay or any site listed: [here](https://www.reddit.com/r/FREEMEDIAHECKYEAH/comments/10bh0h9/unsafe_sites_software_thread)
For sites to stream from check out this [section](#streaming).
!!!info Pirated releases generally happen after a movie is digitally released or released via Blu-Ray / DVD, which can take 3 months+ after initially playing in theaters.
For games use [Rezi](https://rezi.one) or any site listed [here](https://www.reddit.com/r/FREEMEDIAHECKYEAH/wiki/games/#wiki_.25BA_download_games) and for newly released games check [r/crackwatch](https://reddit.com/r/crackwatch).
!!!warning Please avoid downloading games from The Pirate Bay or any site listed: [here](https://www.reddit.com/r/FREEMEDIAHECKYEAH/comments/10bh0h9/unsafe_sites_software_thread)
> How do I unlock *insert random game title* DLCs? > How do I unlock *insert random game title* DLCs?
Use the tools listed [here](https://fmhy.pages.dev/gamingpiracyguide/#steam--epic) to unlock DLCs. Use the tools listed [here](https://fmhy.pages.dev/gamingpiracyguide/#steam--epic) to unlock DLCs.
> Should I install & use *insert random anti-virus software* instead of using Windows Defender? > Should I install & use *insert random anti-virus software* instead of using Windows Defender?
No don't do that, windows defender is more than good enough, you don't need another anti-virus, but if you're set on installing a secondary AV the one worth installing is Malwarebytes. Please read the note [here](#anti-virus). No don't do that, windows defender is more than good enough, you don't need another anti-virus, but if you're set on installing a secondary AV the one worth installing is Malwarebytes. Please read the note [here](#anti-virus). Stay away from Avast, Norton and McAfee, these are "bloatware" and generally not safe software.
!!!warning Stay away from Avast, Norton and McAfee, these are "bloatware" and generally not safe software.
> How do I bypass this paywalled article? > How do I bypass this paywalled article?
Use [this](https://bitbucket.org/magnolia1234/bypass-paywalls-firefox-clean/src/master/) / [2](https://gitlab.com/magnolia1234/bypass-paywalls-chrome-clean) to read the article easily. Use [this](https://bitbucket.org/magnolia1234/bypass-paywalls-firefox-clean/src/master/) / [2](https://gitlab.com/magnolia1234/bypass-paywalls-chrome-clean) to read the article easily.
> How do I download image from *insert stock site*? > How do I download image from *insert stock site*?
You can use [this](https://downloader.la/) if this doesn't work you can find similar stock image downloaders [here](https://www.reddit.com/r/FREEMEDIAHECKYEAH/wiki/storage/#wiki_stock_photo_sites). You can use [this](https://downloader.la/) if this doesn't work you can find similar stock image downloaders [here](https://www.reddit.com/r/FREEMEDIAHECKYEAH/wiki/storage/#wiki_stock_photo_sites).
Still feel unsure? Reach out to us via [Discord](https://redd.it/17f8msf) & make sure you've looked at sites/software we've listed as unsafe: [here](https://www.reddit.com/r/FREEMEDIAHECKYEAH/comments/10bh0h9/unsafe_sites_software_thread)
*** ***
### Windows Piracy ### Windows Piracy

View File

@ -67,7 +67,7 @@
* [Curated Programming Resources](https://github.com/Michael0x2a/curated-programming-resources) - Programming Courses * [Curated Programming Resources](https://github.com/Michael0x2a/curated-programming-resources) - Programming Courses
* [Stack Exchange](https://stackexchange.com/) - Programming Q&A / [App](https://play.google.com/store/apps/details?id=me.tylerbwong.stack) * [Stack Exchange](https://stackexchange.com/) - Programming Q&A / [App](https://play.google.com/store/apps/details?id=me.tylerbwong.stack)
* [Learn X in Y minutes](https://learnxinyminutes.com/), [2](https://github.com/adambard/learnxinyminutes-docs) - Programming Language Rundowns * [Learn X in Y minutes](https://learnxinyminutes.com/), [2](https://github.com/adambard/learnxinyminutes-docs) - Programming Language Rundowns
* [HEAD](https://htmlhead.dev/) - HTML `<head>` Element Guide * [HEAD](https://htmlhead.dev/) - HTML head Element Guide
* [Typing.io](https://typing.io/) - Typing Practice for Programmers * [Typing.io](https://typing.io/) - Typing Practice for Programmers
* [Karel The Robot](https://github.com/fredoverflow/karel) - Basic Programming Teaching Environment * [Karel The Robot](https://github.com/fredoverflow/karel) - Basic Programming Teaching Environment
* [Project Based Learning](https://github.com/practical-tutorials/project-based-learning) - Collection of Project-Based Tutorials * [Project Based Learning](https://github.com/practical-tutorials/project-based-learning) - Collection of Project-Based Tutorials
@ -754,7 +754,7 @@
* [Codux](https://www.codux.com/) - Visual IDE for React * [Codux](https://www.codux.com/) - Visual IDE for React
* [React95](https://react95.io/) - Windows 95 React Components * [React95](https://react95.io/) - Windows 95 React Components
* [React SVG](https://react-svgr.com/playground/) - Convert SVG to React Components * [React SVG](https://react-svgr.com/playground/) - Convert SVG to React Components
* [Zorm](https://github.com/esamattis/react-zorm) - Type-safe `<form>` for React * [Zorm](https://github.com/esamattis/react-zorm) - Type-safe form for React
* [Million](https://github.com/aidenybai/million) - React Replacement * [Million](https://github.com/aidenybai/million) - React Replacement
* [novu](https://novu.co/) - Real-Time React Notifications / [GitHub](https://github.com/novuhq/novu) * [novu](https://novu.co/) - Real-Time React Notifications / [GitHub](https://github.com/novuhq/novu)
* [React Use](https://github.com/streamich/react-use) - React Hooks * [React Use](https://github.com/streamich/react-use) - React Hooks

View File

@ -1 +0,0 @@
<link rel="stylesheet" href="static/styles.css">

13
guides.md Normal file
View File

@ -0,0 +1,13 @@
---
title: Guides
---
<!-- <script setup> -->
<!-- import { data } from "./.vitepress/loaders/guides.data"; -->
<!-- </script> -->
<!---->
<!-- <template> -->
<!-- <h2>Guides</h2> -->
<!-- <br /> -->
<!-- <ul> -->
<!-- </ul> -->
<!-- </template> -->

40
index.md Normal file
View File

@ -0,0 +1,40 @@
---
title: "Welcome"
layout: home
hero:
name: "FMHY"
text: "freemediaheckyeah"
tagline: The Largest Collection Of Free Stuff On The Internet!
prelink:
title: 🎉 New website!
link: https://www.reddit.com/r/FREEMEDIAHECKYEAH/comments/17tnzak/new_fmhy_website/
image:
src: /test.png
alt: FMHY Icon
actions:
- theme: brand
text: Browse Collection
link: /adblockvpnguide
- theme: alt
text: Discord
link: https://discord.gg/Stz6y6NgNg
features:
- title: Movies / TV / Anime
icon: <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 36 36"><path fill="#31373D" d="M35 31s0 4-4 4H5c-4 0-4-4-4-4V12c0-4 4-4 4-4h26s4 0 4 4v19z"/><path fill="#31373D" d="M21.303 10.389a.999.999 0 1 1-1.414 1.414l-9.192-9.192a.999.999 0 1 1 1.414-1.414l9.192 9.192z"/><path fill="#31373D" d="M14.697 10.389a.999.999 0 1 0 1.414 1.414l9.192-9.192a.999.999 0 1 0-1.414-1.414l-9.192 9.192z"/><path fill="#55ACEE" d="M18 11c8 0 10 1 11 2s2 3 2 8s-1 7-2 8s-3 2-11 2s-10-1-11-2s-2-3-2-8s1-7 2-8s3-2 11-2z"/><circle cx="31.5" cy="31.5" r="1.5" fill="#66757F"/><circle cx="4.5" cy="31.5" r="1.5" fill="#66757F"/></svg>
link: /videopiracyguide
details: Download, stream, torrent and binge all your favourites movies or shows!
- title: Music / Podcasts / Radio
icon: <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 36 36"><path fill="#5DADEC" d="M14.182.168L7.818 1.469A1.07 1.07 0 0 0 7 2.471v15.857A6.226 6.226 0 0 0 5 18c-2.762 0-5 1.741-5 3.889c0 2.147 2.238 3.889 5 3.889c2.713 0 4.908-1.683 4.985-3.777H10V6.477l4.182-.855A1.07 1.07 0 0 0 15 4.62V.835c0-.459-.368-.76-.818-.667zm21 4l-6.363 1.301c-.451.092-.819.543-.819 1.002v15.857A6.198 6.198 0 0 0 26 22c-2.762 0-5 1.741-5 3.889c0 2.147 2.238 3.889 5 3.889c2.713 0 4.908-1.683 4.985-3.777H31V10.477l4.182-.855A1.07 1.07 0 0 0 36 8.62V4.835c0-.459-.368-.76-.818-.667z"/><path fill="#5DADEC" d="m23.182 10.167l-6.363 1.301c-.451.093-.819.544-.819 1.003v15.857A6.198 6.198 0 0 0 14 28c-2.762 0-5 1.741-5 3.889s2.238 3.889 5 3.889c2.713 0 4.908-1.683 4.985-3.777H19V16.477l4.182-.855A1.07 1.07 0 0 0 24 14.62v-3.785c0-.459-.368-.76-.818-.668z"/></svg>
link: /audiopiracyguide
details: Stream, download and torrent songs, podcasts and more!
- title: Games / Emulation
icon: <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 36 36"><path fill="#31373D" d="m2.13 14.856l-.004-.002S.075 27.271.075 29.061c0 1.824 1.343 3.302 3 3.302c.68 0 1.3-.258 1.803-.678l10.166-8.938L2.13 14.856zm31.69 0l.004-.002s2.051 12.417 2.051 14.207c0 1.824-1.343 3.302-3 3.302c-.68 0-1.3-.258-1.803-.678l-10.166-8.938l12.914-7.891z"/><g fill="#14171A"><circle cx="25.975" cy="15.551" r="8.5"/><circle cx="9.975" cy="15.551" r="8.5"/><path d="M9.975 7.051h16v16.87h-16z"/></g><circle cx="13.075" cy="23.301" r="5" fill="#14171A"/><circle cx="22.875" cy="23.301" r="5" fill="#14171A"/><circle cx="22.875" cy="23.301" r="3" fill="#67757F"/><circle cx="13.075" cy="23.301" r="3" fill="#67757F"/><circle cx="25.735" cy="11.133" r="1.603" fill="#FFCC4D"/><circle cx="25.735" cy="17.607" r="1.603" fill="#77B255"/><circle cx="22.498" cy="14.37" r="1.603" fill="#50A5E6"/><circle cx="28.972" cy="14.37" r="1.603" fill="#DD2E44"/><path fill="#8899A6" d="M11.148 12.514v-2.168a.505.505 0 0 0-.505-.505H9.085a.505.505 0 0 0-.505.505v2.168l1.284 1.285l1.284-1.285zm-2.569 3.63v2.168c0 .279.226.505.505.505h1.558a.505.505 0 0 0 .505-.505v-2.168l-1.284-1.285l-1.284 1.285zm5.269-3.1H11.68l-1.285 1.285l1.285 1.285h2.168a.506.506 0 0 0 .505-.505V13.55a.506.506 0 0 0-.505-.506zm-5.799 0H5.88a.506.506 0 0 0-.505.505v1.558c0 .279.226.505.505.505h2.168l1.285-1.285l-1.284-1.283z"/></svg>
link: /gamingpiracyguide
details: Download and play all your favourite games or emulate some old but gold ones!
- title: Book / Comics / Manga
icon: <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 36 36"><path fill="#553788" d="M15 31c0 2.209-.791 4-3 4H5c-4 0-4-14 0-14h7c2.209 0 3 1.791 3 4v6z"/><path fill="#9266CC" d="M34 33h-1V23h1a1 1 0 1 0 0-2H10c-4 0-4 14 0 14h24a1 1 0 1 0 0-2z"/><path fill="#CCD6DD" d="M34.172 33H11c-2 0-2-10 0-10h23.172c1.104 0 1.104 10 0 10z"/><path fill="#99AAB5" d="M11.5 25h23.35c-.135-1.175-.36-2-.678-2H11c-1.651 0-1.938 6.808-.863 9.188C9.745 29.229 10.199 25 11.5 25z"/><path fill="#269" d="M12 8a4 4 0 0 1-4 4H4C0 12 0 1 4 1h4a4 4 0 0 1 4 4v3z"/><path fill="#55ACEE" d="M31 10h-1V3h1a1 1 0 1 0 0-2H7C3 1 3 12 7 12h24a1 1 0 1 0 0-2z"/><path fill="#CCD6DD" d="M31.172 10H8c-2 0-2-7 0-7h23.172c1.104 0 1.104 7 0 7z"/><path fill="#99AAB5" d="M8 5h23.925c-.114-1.125-.364-2-.753-2H8C6.807 3 6.331 5.489 6.562 7.5C6.718 6.142 7.193 5 8 5z"/><path fill="#F4900C" d="M20 17a4 4 0 0 1-4 4H6c-4 0-4-9 0-9h10a4 4 0 0 1 4 4v1z"/><path fill="#FFAC33" d="M35 19h-1v-5h1a1 1 0 1 0 0-2H15c-4 0-4 9 0 9h20a1 1 0 1 0 0-2z"/><path fill="#CCD6DD" d="M35.172 19H16c-2 0-2-5 0-5h19.172c1.104 0 1.104 5 0 5z"/><path fill="#99AAB5" d="M16 16h19.984c-.065-1.062-.334-2-.812-2H16c-1.274 0-1.733 2.027-1.383 3.5c.198-.839.657-1.5 1.383-1.5z"/></svg>
link: /readingpiracyguide
details: Whether you're a bookworm, otaku or comic book fan, you'll be able to find your favourite pieces of literature here for free!
---

12
nitro.config.ts Normal file
View File

@ -0,0 +1,12 @@
//https://nitro.unjs.io/config
export default defineNitroConfig({
runtimeConfig: {
WEBHOOK_URL: process.env.WEBHOOK_URL,
},
srcDir: ".vitepress",
routeRules: {
"/": {
cors: false,
},
},
});

44
package.json Normal file
View File

@ -0,0 +1,44 @@
{
"name": "fmhy",
"type": "module",
"packageManager": "pnpm@8.7.6",
"scripts": {
"docs:dev": "vitepress dev",
"docs:build": "vitepress build",
"docs:preview": "vitepress preview",
"api:prepare": "nitropack prepare",
"api:dev": "nitropack dev",
"api:build": "nitropack build",
"api:preview": "node .output/server/index.mjs",
"og:dev": "x-satori -t ./.vitepress/hooks/Template.vue -c ./.vitepress/hooks/satoriConfig.ts --dev",
"format": "prettier -w --cache .",
"postinstall": "nitropack prepare"
},
"dependencies": {
"@headlessui/vue": "^1.7.16",
"@resvg/resvg-js": "^2.6.0",
"fast-glob": "^3.3.1",
"itty-fetcher": "^0.9.4",
"nitro-cors": "^0.7.0",
"nitropack": "latest",
"pathe": "^1.1.1",
"unocss": "^0.57.1",
"vitepress": "1.0.0-rc.25",
"vue": "^3.3.7",
"workbox-window": "^7.0.0",
"x-satori": "^0.1.5",
"zod": "^3.22.4"
},
"devDependencies": {
"@iconify-json/carbon": "^1.1.21",
"@iconify-json/twemoji": "^1.1.12",
"@types/node": "^20.8.9",
"@vite-pwa/vitepress": "^0.2.3",
"prettier": "^3.0.3"
},
"pnpm": {
"patchedDependencies": {
"vitepress@1.0.0-rc.25": "patches/vitepress@1.0.0-rc.25.patch"
}
}
}

View File

@ -0,0 +1,60 @@
diff --git a/dist/client/theme-default/Layout.vue b/dist/client/theme-default/Layout.vue
index 0ecca7ecd6f7e5ab4d576ecaf0cbc8578291a94f..32c9d80e564c42b817950ee2a1c69d62e6b304a3 100644
--- a/dist/client/theme-default/Layout.vue
+++ b/dist/client/theme-default/Layout.vue
@@ -56,6 +56,7 @@ provide('hero-image-slot-exists', heroImageSlotExists)
<template #not-found><slot name="not-found" /></template>
<template #home-hero-before><slot name="home-hero-before" /></template>
+ <template #home-hero-prelink><slot name="home-hero-prelink" /></template>
<template #home-hero-info><slot name="home-hero-info" /></template>
<template #home-hero-image><slot name="home-hero-image" /></template>
<template #home-hero-after><slot name="home-hero-after" /></template>
diff --git a/dist/client/theme-default/components/VPContent.vue b/dist/client/theme-default/components/VPContent.vue
index a1479dc693a8261b30b88663ba1de523cceaf877..1f49bab3aed371b5e8cf12e11870c503da2a9872 100644
--- a/dist/client/theme-default/components/VPContent.vue
+++ b/dist/client/theme-default/components/VPContent.vue
@@ -28,6 +28,7 @@ const { hasSidebar } = useSidebar()
<VPHome v-else-if="frontmatter.layout === 'home'">
<template #home-hero-before><slot name="home-hero-before" /></template>
+ <template #home-hero-prelink><slot name="home-hero-prelink" /></template>
<template #home-hero-info><slot name="home-hero-info" /></template>
<template #home-hero-image><slot name="home-hero-image" /></template>
<template #home-hero-after><slot name="home-hero-after" /></template>
diff --git a/dist/client/theme-default/components/VPHero.vue b/dist/client/theme-default/components/VPHero.vue
index 659c3dbfd36e9fcaf08b659c84c2eb378e8b49f8..2650a2b97e6d0c96f6bf56b478ece2f0c5663101 100644
--- a/dist/client/theme-default/components/VPHero.vue
+++ b/dist/client/theme-default/components/VPHero.vue
@@ -25,6 +25,7 @@ const heroImageSlotExists = inject('hero-image-slot-exists') as Ref<boolean>
<div class="VPHero" :class="{ 'has-image': image || heroImageSlotExists }">
<div class="container">
<div class="main">
+ <slot name="home-hero-prelink"></slot>
<slot name="home-hero-info">
<h1 v-if="name" class="name">
<span v-html="name" class="clip"></span>
diff --git a/dist/client/theme-default/components/VPHome.vue b/dist/client/theme-default/components/VPHome.vue
index a4cda402bf7fde02c1e58b85c5d47daec458220e..d87e6fc69bd6d4b40f12b2fee90d385549583820 100644
--- a/dist/client/theme-default/components/VPHome.vue
+++ b/dist/client/theme-default/components/VPHome.vue
@@ -7,6 +7,7 @@ import VPHomeFeatures from './VPHomeFeatures.vue'
<div class="VPHome">
<slot name="home-hero-before" />
<VPHomeHero>
+ <template #home-hero-prelink><slot name="home-hero-prelink" /></template>
<template #home-hero-info><slot name="home-hero-info" /></template>
<template #home-hero-image><slot name="home-hero-image" /></template>
</VPHomeHero>
diff --git a/dist/client/theme-default/components/VPHomeHero.vue b/dist/client/theme-default/components/VPHomeHero.vue
index 5d482944ff62330939c963f43d71c788e88afa4e..a486fe63bfb4f7e41bcbf3e070ef57e8806cf9a9 100644
--- a/dist/client/theme-default/components/VPHomeHero.vue
+++ b/dist/client/theme-default/components/VPHomeHero.vue
@@ -15,6 +15,7 @@ const { frontmatter: fm } = useData()
:image="fm.hero.image"
:actions="fm.hero.actions"
>
+ <template #home-hero-prelink><slot name="home-hero-prelink" /></template>
<template #home-hero-info><slot name="home-hero-info" /></template>
<template #home-hero-image><slot name="home-hero-image" /></template>
</VPHero>

6640
pnpm-lock.yaml Normal file

File diff suppressed because it is too large Load Diff

9
public/_headers Normal file
View File

@ -0,0 +1,9 @@
/assets/*
cache-control: max-age=31536000
cache-control: immutable
/*
X-Robots-Tag: noarchive
/manifest.webmanifest
Content-Type: application/manifest+json

View File

Before

Width:  |  Height:  |  Size: 1.9 MiB

After

Width:  |  Height:  |  Size: 1.9 MiB

View File

Before

Width:  |  Height:  |  Size: 738 KiB

After

Width:  |  Height:  |  Size: 738 KiB

View File

Before

Width:  |  Height:  |  Size: 601 KiB

After

Width:  |  Height:  |  Size: 601 KiB

View File

Before

Width:  |  Height:  |  Size: 601 KiB

After

Width:  |  Height:  |  Size: 601 KiB

View File

Before

Width:  |  Height:  |  Size: 8.6 KiB

After

Width:  |  Height:  |  Size: 8.6 KiB

View File

Before

Width:  |  Height:  |  Size: 8.6 KiB

After

Width:  |  Height:  |  Size: 8.6 KiB

2
public/robots.txt Normal file
View File

@ -0,0 +1,2 @@
User-agent: *
Allow: /

BIN
public/test.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 329 KiB

View File

@ -1,20 +0,0 @@
h1 {
text-align: center;
}
/* Icons */
html.dark ul.flex-col > li > a > svg {
color: white !important;
}
:not(html.dark) ul.flex-col > li > a > svg {
color: rgb(47 51 72/var(--tw-text-opacity));
}
/* Hide filter from sidebar */
div.left-0:nth-child(2) {
display: none;
}
aside ul:nth-child(3) {
margin-top: 1em;
}

6
tsconfig.json Normal file
View File

@ -0,0 +1,6 @@
{
"extends": "./.nitro/types/tsconfig.json",
"compilerOptions": {
"verbatimModuleSyntax": true
}
}

5
wrangler.toml Normal file
View File

@ -0,0 +1,5 @@
name = "feedback"
main = ".output/server/index.mjs"
workers_dev = true
account_id = "fe5d9bd14160b07939282e45f63eb5ad"
compatibility_date = "2022-09-10"