Last active
March 9, 2026 21:51
-
-
Save iAmNikola/f7b5f6bd18b0cc3832874a1d1c72a55e to your computer and use it in GitHub Desktop.
Download archive footage from a folder within Fishtank.live archive. NOTE: You DON'T need a season pass to have access to archives this way!
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| from concurrent.futures import ThreadPoolExecutor | |
| import json | |
| from pathlib import Path | |
| import sys | |
| from typing import List | |
| import requests | |
| ### How to extract the AUTHTOKEN: | |
| ### 1. Open DevTools (f12 on chrome) | |
| ### 2. Open Network tab | |
| ### 3. Go to fishtank.live | |
| ### 4. Find request with name "token?key=....." and click it | |
| ### 5. Open Response tab | |
| ### 6. Copy and paste bellow the "acces_token" value | |
| AUTHTOKEN = '<AUTHTOKEN>' | |
| class Globals: | |
| archive_headers = {'Authtoken': AUTHTOKEN} | |
| download_headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36', 'Accept-Language': 'en-RS,en-US;q=0.9,en;q=0.8', 'Authtoken': AUTHTOKEN, 'Origin': 'https://www.fishtank.live', 'Referer': 'https://www.fishtank.live/archive', 'Sec-Ch-Ua': '"Google Chrome";v="113", "Chromium";v="113", "Not-A.Brand";v="24"', 'Sec-Ch-Ua-Mobile': '?0', 'Sec-Ch-Ua-Platform': 'Windows', 'Sec-Fetch-Dest': 'empty', 'Sec-Fetch-Mode': 'cors', 'Sec-Fetch-Site': 'same-origin', 'Cookie': '', 'Accept-Encoding': 'gzip, deflate'} | |
| archive_url = 'https://www.fishtank.live/api/archive/' | |
| download_url = 'https://www.fishtank.live/api/archive/download' | |
| def get_videos(camera: str): | |
| response = requests.get(f'{Globals.archive_url}{camera}', headers= Globals.archive_headers) | |
| if response.status_code == 403: | |
| raise requests.exceptions.InvalidHeader('Bad authtoken.') | |
| videos: List[str] = [x['ObjectName'] for x in json.loads(response.text)['files'] if x['ObjectName'].endswith('.mp4')] | |
| camera_folder = Path(__file__).resolve().parent / camera | |
| camera_folder.mkdir(exist_ok=True) | |
| with ThreadPoolExecutor(max_workers=6) as executor: | |
| for video in videos: | |
| try: | |
| executor.submit(download_video, video, camera) | |
| except KeyError: | |
| print('The authtoken has expired. Refresh fishtank.live and get a new one.') | |
| sys.exit() | |
| def download_video(video: str, camera: str): | |
| video_path = Path(__file__).resolve().parent / camera / video | |
| if video_path.exists(): | |
| return | |
| response = requests.post(Globals.download_url, data={'path': f'/{camera}/{video}'}, headers=Globals.download_headers) | |
| with requests.get(json.loads(response.text)['url'], stream=True, headers=Globals.download_headers) as r: | |
| r.raise_for_status() | |
| with open(video_path, 'wb') as f: | |
| for chunk in r.iter_content(chunk_size=2048): | |
| f.write(chunk) | |
| class Camera: | |
| B1 = 'bedroom-1' | |
| B2 = 'bedroom-2' | |
| B3 = 'bedroom-3' | |
| B4 = 'bedroom-4' | |
| CONFESSIONAL = 'confessional' | |
| BATHROOM = 'bathroom' | |
| GARAGE = 'garage' | |
| HALL_DOWN = 'hallway-downstairs' | |
| HALL_UP = 'hallway-upstairs' | |
| KITCHEN = 'kitchen' | |
| LAUNDRY = 'laundry-room' | |
| LIVING_ROOM = 'living-room' | |
| if __name__ == '__main__': | |
| import argparse | |
| parsers = argparse.ArgumentParser() | |
| parsers.add_argument('camera', nargs='?', default=Camera.LIVING_ROOM) | |
| args = parsers.parse_args([Camera.B1]) | |
| get_videos(args.camera) |
Author
Hey, I'm wondering if it's possible to do this on android?
I can't run the python file, I downloaded some python apps to no avail.
I can get chrome in developer mode, by tapping on the version number of the chrome release I run.
But the only thing it unlocks that may be relevant that I can see, is recording traces.
If I do that I get a .gz file that I can't open swell.
Sorry for being so stupid and annoying, but I had to try to get this to work, leaving no stone unturned.
Have a nice day!
Kind regards from Odin
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Could you do a video tutorial? Cannot wrap my head around this, I'm not good with computers.