🎉 New website!
45
.github/add-headers.py
vendored
@ -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)
|
||||||
|
23
.github/assets/README.md
vendored
@ -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
|
|
33
.github/assets/retype.yml
vendored
@ -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"
|
|
@ -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
@ -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
@ -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
@ -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 }}
|
40
.github/workflows/retype.yml
vendored
@ -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
|
|
4
.github/workflows/single-page.yml
vendored
@ -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
@ -0,0 +1,9 @@
|
|||||||
|
**/.vitepress/dist
|
||||||
|
**/.vitepress/cache
|
||||||
|
node_modules
|
||||||
|
*.log*
|
||||||
|
.nitro
|
||||||
|
.cache
|
||||||
|
.output
|
||||||
|
.env
|
||||||
|
dist
|
2
.prettierignore
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
**/*.md
|
||||||
|
pnpm-lock.yaml
|
14
.prettierrc.json
Normal 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
@ -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
@ -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";
|
BIN
.vitepress/fonts/Inter-Bold.otf
Normal file
BIN
.vitepress/fonts/Inter-Medium.otf
Normal file
BIN
.vitepress/fonts/Inter-Regular.otf
Normal file
BIN
.vitepress/fonts/Inter-SemiBold.otf
Normal file
22
.vitepress/hooks/Template.vue
Normal 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>
|
6
.vitepress/hooks/index.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
/**
|
||||||
|
* Barrel generated using @taskylizard/tasker.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export * from "./meta";
|
||||||
|
export * from "./opengraph";
|
84
.vitepress/hooks/meta.ts
Normal 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;
|
||||||
|
}
|
89
.vitepress/hooks/opengraph.ts
Normal 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());
|
||||||
|
}
|
45
.vitepress/hooks/satoriConfig.ts
Normal 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",
|
||||||
|
},
|
||||||
|
});
|
46
.vitepress/loaders/guides.data.ts
Normal 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;
|
||||||
|
},
|
||||||
|
});
|
25
.vitepress/markdown/base64.ts
Normal 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>`;
|
||||||
|
};
|
||||||
|
}
|
17
.vitepress/markdown/toggleStarred.ts
Normal 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);
|
||||||
|
};
|
||||||
|
}
|
6
.vitepress/middleware/cors.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
import { corsEventHandler } from "nitro-cors";
|
||||||
|
|
||||||
|
export default corsEventHandler((_event) => {}, {
|
||||||
|
origin: "*",
|
||||||
|
methods: "*",
|
||||||
|
});
|
102
.vitepress/pwa.ts
Normal 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;
|
49
.vitepress/routes/index.post.ts
Normal 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" };
|
||||||
|
});
|
3
.vitepress/routes/test.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export default eventHandler(() => {
|
||||||
|
return { nitro: "works" };
|
||||||
|
});
|
19
.vitepress/theme/Layout.vue
Normal 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>
|
15
.vitepress/theme/components/Announcement.vue
Normal 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>
|
16
.vitepress/theme/components/CardField.vue
Normal 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>
|
199
.vitepress/theme/components/Feedback.vue
Normal 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>
|
47
.vitepress/theme/components/InputField.vue
Normal 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>
|
78
.vitepress/theme/components/Modal.vue
Normal 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>
|
60
.vitepress/theme/components/SidebarCard.vue
Normal 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>
|
52
.vitepress/theme/components/Switch.vue
Normal 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>
|
53
.vitepress/theme/components/ThemeSwitch.vue
Normal 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>
|
15
.vitepress/theme/components/ToggleStarred.vue
Normal 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
@ -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
@ -0,0 +1,3 @@
|
|||||||
|
import { registerSW } from "virtual:pwa-register";
|
||||||
|
|
||||||
|
registerSW({ immediate: true });
|
145
.vitepress/theme/style.css
Normal 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;
|
||||||
|
}
|
10
.vitepress/types/Feedback.ts
Normal 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
@ -0,0 +1,4 @@
|
|||||||
|
declare module "*.vue" {
|
||||||
|
const component: import("vue").Component;
|
||||||
|
export default component;
|
||||||
|
}
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -1 +0,0 @@
|
|||||||
<link rel="stylesheet" href="static/styles.css">
|
|
13
guides.md
Normal 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
@ -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
@ -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
@ -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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
60
patches/vitepress@1.0.0-rc.25.patch
Normal 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
9
public/_headers
Normal 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
|
Before Width: | Height: | Size: 1.9 MiB After Width: | Height: | Size: 1.9 MiB |
Before Width: | Height: | Size: 738 KiB After Width: | Height: | Size: 738 KiB |
Before Width: | Height: | Size: 601 KiB After Width: | Height: | Size: 601 KiB |
Before Width: | Height: | Size: 601 KiB After Width: | Height: | Size: 601 KiB |
Before Width: | Height: | Size: 8.6 KiB After Width: | Height: | Size: 8.6 KiB |
Before Width: | Height: | Size: 8.6 KiB After Width: | Height: | Size: 8.6 KiB |
2
public/robots.txt
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
User-agent: *
|
||||||
|
Allow: /
|
BIN
public/test.png
Normal file
After Width: | Height: | Size: 329 KiB |
@ -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
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"extends": "./.nitro/types/tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"verbatimModuleSyntax": true
|
||||||
|
}
|
||||||
|
}
|
5
wrangler.toml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
name = "feedback"
|
||||||
|
main = ".output/server/index.mjs"
|
||||||
|
workers_dev = true
|
||||||
|
account_id = "fe5d9bd14160b07939282e45f63eb5ad"
|
||||||
|
compatibility_date = "2022-09-10"
|