Skip to content

Instantly share code, notes, and snippets.

@zone559
Created April 3, 2026 18:17
Show Gist options
  • Select an option

  • Save zone559/138df139fcc9ec7b7ec16484b987c547 to your computer and use it in GitHub Desktop.

Select an option

Save zone559/138df139fcc9ec7b7ec16484b987c547 to your computer and use it in GitHub Desktop.
import requests
import os
import json
import re
import yt_dlp
from concurrent.futures import ThreadPoolExecutor
# ANSI color codes for better console output
COLOR = {
'GREEN': '\033[92m',
'BLUE': '\033[94m',
'YELLOW': '\033[93m',
'CYAN': '\033[96m',
'MAGENTA': '\033[95m',
'RED': '\033[91m',
'RESET': '\033[0m'
}
class SnapchatDownloader:
def __init__(self, url):
self.url = url
self.username = self.extract_username()
self.headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3'
}
self.create_user_folder()
def extract_username(self):
"""Extract username from the URL"""
if "/add/" in self.url:
username = self.url.split("/add/")[-1].strip("/")
else:
username = self.url.split('/')[-2] if self.url.endswith('/') else self.url.split('/')[-1]
print(f"{COLOR['BLUE']}Username: {username}{COLOR['RESET']}")
return username
def create_user_folder(self):
"""Create a folder for the user if it doesn't exist"""
if not os.path.exists(self.username):
os.makedirs(self.username)
print(f"{COLOR['BLUE']}Created folder: {self.username}{COLOR['RESET']}")
def download_file(self, url, filename):
"""Download a file with progress tracking"""
try:
if os.path.exists(filename):
print(f"{COLOR['MAGENTA']}File exists, skipping: {filename}{COLOR['RESET']}")
return False
print(f"{COLOR['GREEN']}Downloading: {filename}{COLOR['RESET']}")
print(f"{COLOR['CYAN']}From URL: {url}{COLOR['RESET']}")
with requests.get(url, stream=True, headers=self.headers) as r:
r.raise_for_status()
total_size = int(r.headers.get('content-length', 0))
downloaded = 0
with open(filename, 'wb') as f:
for chunk in r.iter_content(chunk_size=8192):
f.write(chunk)
downloaded += len(chunk)
if total_size > 0:
progress = (downloaded / total_size) * 100
print(f"{COLOR['GREEN']}Progress: {progress:.1f}% ({downloaded}/{total_size} bytes){COLOR['RESET']}", end='\r')
print(f"{COLOR['GREEN']}\nDownload completed: {filename}{COLOR['RESET']}")
return True
except Exception as e:
print(f"{COLOR['RED']}Error downloading {filename}: {str(e)}{COLOR['RESET']}")
return False
def download_spotlight(self, snap_id):
"""Download a spotlight video using yt-dlp"""
spotlight_url = f"https://www.snapchat.com/spotlight/{snap_id}"
print(f"{COLOR['CYAN']}Spotlight URL: {spotlight_url}{COLOR['RESET']}")
try:
ydl_opts = {
'outtmpl': f'{self.username}/{snap_id}.%(ext)s',
'quiet': False,
'no_warnings': False,
}
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
ydl.download([spotlight_url])
print(f"{COLOR['GREEN']}Successfully downloaded video: {snap_id}{COLOR['RESET']}")
except Exception as e:
print(f"{COLOR['RED']}Error downloading video {snap_id}: {e}{COLOR['RESET']}")
def process_snap(self, snap, index=None, prefix=""):
"""Process a single snap (image or video)"""
snap_media_type = snap.get('snapMediaType')
media_url = snap['snapUrls'].get('mediaUrl') if 'snapUrls' in snap else None
preview_url = snap['snapUrls'].get('mediaPreviewUrl', {}).get('value') if 'snapUrls' in snap else None
# Get ID from different possible fields
snap_id = (
snap.get('snapId', {}).get('value') or
snap.get('storyId', {}).get('value') or
(media_url.split('/')[-1].split('.')[0] if media_url else f"snap_{index}")
)
if index is not None:
print(f"{COLOR['YELLOW']}\nProcessing snap {index + 1}:{COLOR['RESET']}")
else:
print(f"{COLOR['YELLOW']}\nProcessing snap:{COLOR['RESET']}")
print(f"{COLOR['CYAN']}Media Type: {snap_media_type} (0=Image, 1=Video){COLOR['RESET']}")
print(f"{COLOR['CYAN']}Media URL: {media_url}{COLOR['RESET']}")
print(f"{COLOR['CYAN']}Preview URL: {preview_url}{COLOR['RESET']}")
print(f"{COLOR['CYAN']}Snap ID: {snap_id}{COLOR['RESET']}")
if snap_media_type == 0: # Image
if media_url:
filename = f"{self.username}/{prefix}{snap_id}.jpg"
self.download_file(media_url, filename)
elif snap_media_type == 1: # Video
if media_url:
filename = f"{self.username}/{prefix}{snap_id}.mp4"
self.download_file(media_url, filename)
if preview_url: # Only download thumbnail for videos
filename = f"{self.username}/{prefix}{snap_id}-thumb.jpg"
self.download_file(preview_url, filename)
else:
print(f"{COLOR['RED']}Skipping snap: Unknown media type {snap_media_type}.{COLOR['RESET']}")
def fetch_page_data(self):
"""Fetch and parse the Snapchat page data"""
response = requests.get(self.url, headers=self.headers)
if response.status_code != 200:
print(f"{COLOR['RED']}Failed to retrieve data, status code: {response.status_code}{COLOR['RESET']}")
return None
script_pattern = re.compile(r'<script[^>]*type="application/json"[^>]*>(.*?)</script>', re.DOTALL)
match = script_pattern.search(response.text)
if not match:
print(f"{COLOR['RED']}No JSON data found in the HTML.{COLOR['RESET']}")
return None
try:
return json.loads(match.group(1).strip())
except json.JSONDecodeError as e:
print(f"{COLOR['RED']}Failed to decode JSON: {e}{COLOR['RESET']}")
return None
def download_content(self):
"""Main method to download all available content"""
json_data = self.fetch_page_data()
if not json_data:
return
if 'props' not in json_data or 'pageProps' not in json_data['props']:
print(f"{COLOR['RED']}No 'pageProps' found in JSON data.{COLOR['RESET']}")
return
page_props = json_data['props']['pageProps']
# Download regular story snaps
if 'story' in page_props and page_props['story']:
snap_list = page_props['story'].get('snapList', [])
print(f"{COLOR['BLUE']}Found {len(snap_list)} story snaps.{COLOR['RESET']}")
for index, snap in enumerate(snap_list):
self.process_snap(snap, index)
# Download curated highlights
if 'curatedHighlights' in page_props:
curated_highlights = page_props['curatedHighlights']
print(f"{COLOR['BLUE']}Found {len(curated_highlights)} curated highlights.{COLOR['RESET']}")
for highlight in curated_highlights:
snap_list = highlight.get('snapList', [])
print(f"{COLOR['BLUE']}Found {len(snap_list)} snaps in this highlight.{COLOR['RESET']}")
for index, snap in enumerate(snap_list):
self.process_snap(snap, index, "highlight_")
# Download spotlights
if 'spotlightHighlights' in page_props:
spotlight_highlights = page_props['spotlightHighlights']
print(f"{COLOR['BLUE']}Found {len(spotlight_highlights)} spotlight highlights.{COLOR['RESET']}")
# Use ThreadPoolExecutor to download spotlights in parallel
with ThreadPoolExecutor(max_workers=3) as executor:
for highlight in spotlight_highlights:
snap_id = highlight.get('storyId', {}).get('value')
if not snap_id:
continue
# Download video
executor.submit(self.download_spotlight, snap_id)
# Download thumbnail
thumbnail_url = highlight.get('thumbnailUrl', {}).get('value')
if thumbnail_url:
filename = f"{self.username}/{snap_id}_thumb.jpg"
executor.submit(self.download_file, thumbnail_url, filename)
if __name__ == "__main__":
# Example usage
url = "https://www.snapchat.com/add/snackattackshow" # Replace with your target URL
downloader = SnapchatDownloader(url)
downloader.download_content()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment