# Instagram -> Pixelfed Mirror in Python (3+) This Python scripts with a simple HTTP API to use it, can **mirror multiple accounts from Instagram to your Pixelfed** instance. ## Disclaimer Mirroring Instagram accounts **will copy (clone) the images and videos from Instagram** to your server, thus moving the data sovereignty to you as an Admin. Always make sure you mirror accounts whos **content is not strictly copyrighted (or branded) and keep the tagging system of the source code** that marks accounts on Pixelfed as Mirrors. **Users** of your Pixelfed instance have to know **this accounts are not real accounts** as someone on Instagram could create a real Pixelfed account in the future. ## Pre-requisites - You **need an Instagram account** to make this bot work. - **A Pixelfed instance** you own. It must be hosted or managed by you (you need shell access for **php artisan commands**) - **Python 3+ installed** on the same machine as the Pixelfed instance (this is easy, mostly all standard Debian based Linux systems have python3) - A bit **more disk space** for Pixelfed media storage. (It depends on how many accounts you mirror and how often that accounts post on IG) - **Patch 1 file** on Pixelfed deployed code (being on docker or not) ## What can you mirror? - Posts with **images** (multiple images support). - Posts with **videos** (only 1 video). - Each **posts captions** (post description) is **represented as splitted comments**. ## What can't you mirror (yet) ? - **Stories**. (will support that soon) # Installation ### Patch some files As i said on the Pre-requisites, you will need to **patch the following files on Pixelfed** running code: This patch is **needed to disable Pixelfed API rate limiting completely** as it might pop-up when using your mirror bot. We asume your Pixelfed installation is at `/var/www` (if it isn't, just **change the steps to match your installation**) `/var/www/vendor/laravel/framework/src/Illuminate/Routing/Middleware/ThrottleRequests.php` Add `return 99999999;` after the line where it checks if the user is authenticated. ```php /** * Resolve the number of attempts if the user is authenticated or not. * * @param \Illuminate\Http\Request $request * @param int|string $maxAttempts * @return int */ protected function resolveMaxAttempts($request, $maxAttempts) { if (Str::contains($maxAttempts, '|')) { $maxAttempts = explode('|', $maxAttempts, 2)[$request->user() ? 1 : 0]; } if (! is_numeric($maxAttempts) && $request->user()) { return 99999999; $maxAttempts = $request->user()->{$maxAttempts}; } return (int) $maxAttempts; } ``` ### Setup the environment 1. Clone the project somewhere `git clone https://git.nogafam.es/nogafam/ig-pixelfed-mirror.git` 2. Create needed directories for the environment ```bash cd ig-pixelfed-mirror/ mkdir cache db headers # DIRECTORIES EXPLAINED # ---- # "cache" will keep the cached html/json/jpg/mp4 files from Instagram (it can be safely cleaned, it doesn't need backup) # "db" will keep files containing information about your mirrored accounts # (such as: login credentials, cookies for Pixelfed, IG posts that was already added (to avoid duplicates), etc...) # "headers" is a directory you need to fill with TXT plain text files containing some key headers from Instagram Web sessions # (I explain this on step 5!) ``` 3. Copy `config.json.example` to `config.json` and configure to your needs. Make sure you **remove the comments from the file** because Python doesn't like them. 4. Copy `scripts/user_create.example` to `scripts/user_create`. This script runs the `php artisan user:create` command with the given positional parameters to **automatically create local Pixelfed accounts** with forced email verification. **Adapt to your needs**. 5. [Log in](https://www.instagram.com) to your Instagram account on a **Browser** (with remember ticked ON), **open your browser's developer console at "Network" tab**, navigate throught IG a bit and **copy the Request Headers** of any request done to _instagram.com_. Make sure there is `X-IG-App-ID, X-IG-WWW-Claim, Cookie` headers set. ```bash # create a new headers file on "headers/" on your working directory # you can view an example at "headers.example" file vim headers/1.txt # FILE EDITING # ---- # 1. Add the headers you copied from the browser. # 2. Keep only the "X-IG-App-ID, X-IG-WWW-Claim, Cookie" headers, # "User-Agent" might be also good to keep (to match the browser) # (It uses a common User-Agent by default) # - # Done editing ``` Create as much headers TXT files as you wish. It will be **used randomly on requests to Instagram** by the mirror bot. ## Run the server The server is just a **simple HTTP Python server** that acts as an API to manage your mirrors. ¡¡IMPORTANT: run on the project root path!! `python3 server.py` will run the server API at 0.0.0.0:8080. Optionally, you can set a **binding port** with a positional argument like this: `python3 server.py 8081` ## API Documentation **List** accounts: `curl 127.0.0.1:8080/list` **List** accounts in a pretty HTML/CSS interface: `curl 127.0.0.1:8080/mirrors` **Add a new Instagram account to mirror**. This is done **syncronously until it finishes adding** account information, once it's done, it **calls update asyncronously**. `curl 127.0.0.1:8080//add` **Update Instagram account/s mirror** on Pixelfed (mirrors new content). This is **done fully asyncronously** ```bash # Update just the given account curl 127.0.0.1:8080//update` # API supports wildcard to update all accounts mirrors curl '127.0.0.1:8080/*/update'` ``` **Configure parameters** of the Pixelfed account (on local mirror file-based DB) ```bash # Get the value of a parameter (except: password, cookie) curl 127.0.0.1:8080//cfg/var1 # Set the value of a parameter # this keys are inmutable: name, username, password, cookie curl 127.0.0.1:8080//cfg/var1?valueyouwant # CONFIGURABLE PARAMETERS: # ------------------ # "sched" key sets a weight schedule so you can make an account update less often. # # For example: if you set the value to "3", only 1 times out of 3 (counted) will actually update the account # "sched_now" is an automatic variable that counts the current status (used when "sched" is set). # # This will skip the account on wildcard or single /update action, until the count hits it's max value ("sched") # As in the example above (sched = 3), you would set this value like this: curl 127.0.0.1:8080//cfg/sched?3 # ------------------ ``` **Log in or log out** the account from Pixelfed. ```bash curl 127.0.0.1:8080//login curl '127.0.0.1:8080/*/login' curl 127.0.0.1:8080//logout curl '127.0.0.1:8080/*/logout' ``` In case of repeated posts or disaster, **prune/nuke all Pixelfed posts** from the given account. `curl 127.0.0.1:8080//nuke` ## Automatically updating posts of mirrored accounts You have to **create a cronjob or systemd timer** (or whatever scheduled) to run `curl '127.0.0.1:8080/*/update'` Please consider **how many accounts you mirror** + **how often you want to update posts** + **how often you want to bother Instagram** servers... A good reference is **a job every 4 hours for more-or-less 20 accounts** to be "completely safe". ## Happy Mirroring! Any problem/bug/request you might encounter **you may contact me** at https://contact.nogafam.es