├── .gitignore ├── Dockerfile ├── LICENSE ├── README.md ├── config.py.example ├── extensions ├── chatgpt │ ├── chatgpt.py │ └── requirements.txt ├── claude │ ├── claude.py │ └── requirements.txt ├── gemini │ ├── gemini.py │ └── requirements.txt ├── hackaday │ └── hackaday.py ├── hacksburg │ └── hacksburg.py ├── hunterirving │ └── hunterirving.py ├── kagi │ ├── kagi.py │ └── template.html ├── mistral │ ├── mistral.py │ └── requirements.txt ├── notyoutube │ ├── notyoutube.py │ └── videos.json ├── npr │ └── npr.py ├── override │ └── override.py ├── reddit │ └── reddit.py ├── waybackmachine │ └── waybackmachine.py ├── weather │ └── weather.py ├── websimulator │ └── websimulator.py ├── wiby │ └── wiby.py └── wikipedia │ └── wikipedia.py ├── macproxy.service ├── presets ├── macweb2 │ └── macweb2.py └── wii_internet_channel │ └── wii_internet_channel.py ├── proxy.py ├── readme_images ├── macintosh_plus.jpg ├── proxy_settings.gif └── youtube_thumbnail.jpg ├── requirements.txt ├── start_macproxy.ps1 ├── start_macproxy.sh └── utils ├── html_utils.py ├── image_utils.py └── system_utils.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | 5 | # Distribution / packaging 6 | venv/ 7 | current 8 | 9 | # PyCharm metadata 10 | .idea/ 11 | 12 | # Ignore all instances of config.py 13 | **/config.py 14 | 15 | # Ignore video files 16 | *.mp4 17 | *.flim 18 | 19 | # Other 20 | extensions/youtube 21 | **/cached_images/ 22 | **/.DS_Store -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:alpine3.18 2 | 3 | # use PROXY_ARGS to pass flags to the proxy via command line 4 | # see the README for supported flags. 5 | ENV PROXY_ARGS "" 6 | 7 | # install the proxy code in the container 8 | WORKDIR /macproxy 9 | COPY . . 10 | RUN pip3 install -r requirements.txt 11 | 12 | # command to execute when container runs 13 | CMD python3 proxy.py ${PROXY_ARGS} -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2013 Tyler G. Hicks-Wright 2 | 3 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 4 | 5 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 6 | 7 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 8 | 9 | 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 10 | 11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## MacProxy Plus 2 | An extensible HTTP proxy that connects early computers to the Internet. 3 | 4 | This fork of MacProxy adds support for ```extensions```, which intercept requests for specific domains to serve simplified HTML interfaces, making it possible to browse the modern web from vintage hardware. Though originally designed for compatibility with early Macintoshes, MacProxy Plus should work to get many other vintage machines online. 5 | 6 | ### Demonstration Video (on YouTube) 7 | 8 | 9 | Teaching an Old Mac New Tricks 10 | 11 | 12 | ### Extensions 13 | 14 | Each extension has its own folder within the `extensions` directory. Extensions can be individually enabled or disabled via a `config.py` file in the root directory. 15 | 16 | To enable extensions: 17 | 18 | 1. In the root directory, rename ```config.py.example``` to ```config.py``` : 19 | 20 | ```shell 21 | mv config.py.example config.py 22 | ``` 23 | 24 | 2. In ```config.py```, enable/disable extensions by uncommenting/commenting lines in the ```ENABLED_EXTENSIONS``` list: 25 | 26 | ```python 27 | ENABLED_EXTENSIONS = [ 28 | #disabled_extension, 29 | "enabled_extension" 30 | ] 31 | ``` 32 | 33 | ### Starting MacProxy Plus 34 | 35 | On Unix-like systems (such as Linux or macOS), run the ```start_macproxy.sh``` script. It will create a Python virtual environment, install the required Python packages, and make the proxy server available on your local network. 36 | 37 | ```shell 38 | ./start_macproxy.sh 39 | ``` 40 | 41 | On Windows, run the analogous PowerShell script, ```start_macproxy.ps1```: 42 | 43 | ```powershell 44 | .\start_macproxy.ps1 45 | ``` 46 | 47 | ### Connecting to MacProxy Plus from your Vintage Machine 48 | To use MacProxy Plus, you'll need to configure your vintage browser or operating system to connect to the proxy server running on your host machine. The specific steps will vary depending on your browser and OS, but if your system lets you set a proxy server, it should work. 49 | 50 | If you're using a BlueSCSI to get a vintage Mac online, this guide should help with the initial Internet setup. 51 |

52 | ![Configuring proxy settings in MacWeb 2.0c+](readme_images/proxy_settings.gif) 53 |
*Example: Configuring proxy settings in MacWeb 2.0c+* 54 | 55 | ### Example Extension: ChatGPT 56 | 57 | A ChatGPT extension is provided as an example. This extension serves a simple web interface that lets users interact with OpenAI's GPT models. 58 | 59 | To enable the ChatGPT extension, open ```config.py```, uncomment the ```chatgpt``` line in the ```ENABLED_EXTENSIONS``` list, and replace ```YOUR_OPENAI_API_KEY_HERE``` with your actual OpenAI API key. 60 | 61 | ```python 62 | open_ai_api_key = "YOUR_OPENAI_API_KEY_HERE" 63 | 64 | ENABLED_EXTENSIONS = [ 65 | "chatgpt" 66 | ] 67 | ``` 68 | 69 | Once enabled, Macproxy will reroute requests to ```http://chatgpt.com``` to this inteface. 70 |

71 | 72 | 73 | ### Other Extensions 74 | 75 | #### Claude (Anthropic) 76 | For the discerning LLM connoisseur. 77 | 78 | #### Weather 79 | Get the forecast for any zip code in the US. 80 | 81 | #### Wikipedia 82 | Read any of over 6 million encyclopedia articles - complete with clickable links and search function. 83 | 84 | #### Reddit 85 | Browse any subreddit or the Reddit homepage, with support for nested comments and downloadable images... in dithered black and white. 86 | 87 | #### WayBack Machine 88 | Enter any date between January 1st, 1996 and today, then browse the web as it existed at that point in time. Includes full download support for images and other files backed up by the Internet Archive. 89 | 90 | #### Web Simulator 91 | Type a URL that doesn't exist into the address bar, and Anthropic's Claude 3.5 Sonnet will interpret the domain and any query parameters to generate an imagined version of that page on the fly. Each HTTP request is serialized and sent to the AI, along with the full HTML of the last 3 pages you visited, allowing you to explore a vast, interconnected, alternate reality Internet where the only limit is your imagination. 92 | 93 | #### (not) YouTube 94 | A legally distinct parody of YouTube, which uses the fantastic homebrew application MacFlim (created by Fred Stark) to encode video files as a series of dithered black and white frames. 95 | 96 | #### Hackaday 97 | A pared-down, text-only version of hackaday.com, complete with articles, comments, and search functionality. 98 | 99 | #### npr.org 100 | Serves articles from the text-only version of the site (```text.npr.org```) and transforms relative urls into absolute urls for compatibility with MacWeb 2.0. 101 | 102 | #### wiby.me 103 | Browse Wiby's collection of personal, handmade webpages (fixes an issue where clicking "surprise me..." would not redirect users to their final destination). 104 | 105 | ### Future Work 106 | - more extensions for more sites 107 | - presets targeting specific vintage machines/browsers 108 | - wiki with how-to guides for different machines 109 | 110 | Happy Surfing 😎 -------------------------------------------------------------------------------- /config.py.example: -------------------------------------------------------------------------------- 1 | # To enable extensions, rename this file to "config.py" 2 | # and fill in the necessary API keys and other details. 3 | 4 | # Store API keys and other configuration details here: 5 | # OPEN_AI_API_KEY = "YOUR_OPENAI_API_KEY_HERE" 6 | # ANTHROPIC_API_KEY = "YOUR_ANTHROPIC_API_KEY_HERE" 7 | # GEMINI_API_KEY = "YOUR_GEMINI_API_KEY_HERE" 8 | # MISTRAL_API_KEY = "YOUR_MISTRAL_API_KEY_HERE" 9 | # KAGI_SESSION_TOKEN = "YOUR_KAGI_SESSION_TOKEN_HERE" 10 | 11 | # Used by weather extension (which currently only works for United States) 12 | # ZIP_CODE = "YOUR_ZIP_CODE" 13 | 14 | # Uncomment lines to enable desired extensions: 15 | ENABLED_EXTENSIONS = [ 16 | #"chatgpt", 17 | #"claude", 18 | #"gemini", 19 | #"hackaday", 20 | #"hacksburg", 21 | #"hunterirving", 22 | #"kagi", 23 | #"mistral", 24 | #"notyoutube", 25 | #"npr", 26 | #"reddit", 27 | #"waybackmachine", 28 | #"weather", 29 | #"websimulator", 30 | #"wiby", 31 | #"wikipedia", 32 | ] 33 | 34 | # While SIMPLIFY_HTML is True, you can use WHITELISTED_DOMAINS to disable post-processing for 35 | # specific sites (only perform HTTPS -> HTTP conversion and character conversion (if CONVERT_CHARACTERS is True), 36 | # without otherwise modifying the page's source code). 37 | WHITELISTED_DOMAINS = [ 38 | #"example.com", 39 | ] 40 | 41 | # Optionally, load a preset (.py file) from /presets, optimized for compatibility 42 | # with a specific web browser. Enabling a preset may override one or more of the 43 | # settings that follow below. 44 | # The default values target compatability with the MacWeb 2.0 browser. 45 | #PRESET = "wii_internet_channel" 46 | 47 | # -------------------------------------------------------------------------------------- 48 | # *** One or more of the following settings may be overridden if you enable a preset *** 49 | # -------------------------------------------------------------------------------------- 50 | 51 | # If True, parse HTML responses to strip specified tags and attributes. 52 | # If False, always return the full, unmodified HTML as served by the requested site or extension 53 | # (only perform HTTPS -> HTTP conversion and character conversion (if CONVERT_CHARACTERS is True), 54 | # without otherwise modifying the page's source code). 55 | SIMPLIFY_HTML = True 56 | 57 | # If SIMPLIFY_HTML is True, unwrap these HTML tags during processing: 58 | TAGS_TO_UNWRAP = [ 59 | "noscript", 60 | ] 61 | 62 | # If SIMPLIFY_HTML is True, strip these HTML tags during processing: 63 | TAGS_TO_STRIP = [ 64 | "script", 65 | "link", 66 | "style", 67 | "source", 68 | ] 69 | 70 | # If SIMPLIFY_HTML is True, strip these HTML attributes during processing: 71 | ATTRIBUTES_TO_STRIP = [ 72 | "style", 73 | "onclick", 74 | "class", 75 | "bgcolor", 76 | "text", 77 | "link", 78 | "vlink" 79 | ] 80 | 81 | # Process images for optimal rendering on your device/browser: 82 | CAN_RENDER_INLINE_IMAGES = False # Mostly used to conditionally enable landing page images (ex: waybackmachine.py) 83 | RESIZE_IMAGES = True 84 | MAX_IMAGE_WIDTH = 512 # Only used if RESIZE_IMAGES is True 85 | MAX_IMAGE_HEIGHT = 342 # Only used if RESIZE_IMAGES is True 86 | CONVERT_IMAGES = True 87 | CONVERT_IMAGES_TO_FILETYPE = "gif" # Only used if CONVERT_IMAGES is True 88 | DITHERING_ALGORITHM = "FLOYDSTEINBERG" # Only used if CONVERT_IMAGES is True and CONVERT_IMAGES_TO_FILETYPE == "gif" 89 | 90 | # In addition to the default web simulator prompt, add custom instructions to improve compatability with your web browser. 91 | WEB_SIMULATOR_PROMPT_ADDENDUM = """ 92 | IMPORTANT: The user's web browser only supports (most of) HTML 3.2 (you do not need to acknowledge this to the user, only understand it and use this knowledge to construct the HTML you respond with). 93 | Their browser has NO CSS support and NO JavaScript support. Never include