Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion streetview_dl/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -410,7 +410,11 @@ def process_single_url(
console.print(f"[dim]Date: {street_view_metadata.date}[/dim]")
if url_date:
console.print(f"[dim]URL Date: {url_date}[/dim]")


if street_view_metadata.image_width <= 8192 and quality == "high":
console.print("High quality not available for this pano, switching to medium")
quality = "medium"

# Handle historical discovery mode
if historical or historical_download:
if not street_view_metadata.lat or not street_view_metadata.lng:
Expand Down
6 changes: 5 additions & 1 deletion streetview_dl/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,11 @@ def download_panorama(
session = self.create_session()

# Calculate tile grid dimensions
scale_factor = 2 ** (5 - z) # Scale down from max resolution
if metadata.image_width <= 8192:
scale_factor = 2 ** (4 - z) # Scale down from max resolution, level 4 is max for smaller panos
else:
scale_factor = 2 ** (5 - z) # Scale down from max resolution

scaled_width = metadata.image_width // scale_factor
scaled_height = metadata.image_height // scale_factor

Expand Down
19 changes: 16 additions & 3 deletions streetview_dl/metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import re
import urllib.parse as urlparse
from typing import Any, Dict, Optional, Tuple

import base64
from pydantic import BaseModel, Field


Expand Down Expand Up @@ -175,9 +175,9 @@ def extract_from_maps_url(
return pano_id, yaw, pitch, fov, mode_token, date

# Fallback: try to extract panorama ID from the !1s token pattern
pano_match = re.search(r"!3m5!1s([^!]+)", haystack)
pano_match = re.search(r"!1s([^!]+)", haystack)
if pano_match:
return pano_match.group(1), yaw_from_path, pitch_from_path, fov, mode_token, date
return check_panoid(pano_match.group(1)), yaw_from_path, pitch_from_path, fov, mode_token, date

# Last resort: try direct panoid parameter
pano_match = re.search(r"[?&]panoid=([^&]+)", haystack)
Expand Down Expand Up @@ -209,3 +209,16 @@ def validate_maps_url(url: str) -> bool:
"panoid=", # direct pano id parameter
]
return any(indicator in url for indicator in street_view_indicators)

def check_panoid(data: str) -> str:
"""Check if pano ID needs to be converted to base64, as is required for many/all non-Google panos"""
# Needs to be converted if the ID starts with these prefixes (no definitive list, may need to expand in the future)
if data.startswith(("CIHM", "AF1Q", "CIAB")):
print("Converting pano ID to base64 format")
return convert_panoid(data)
return data # Do not modify if no conversion is required

def convert_panoid(data: str) -> str:
"""Convert pano ID to base64 format"""
payload = f"\x08\n\x12{chr(len(data))}{data}".encode("utf-8") # Preamble includes length of pano ID to follow
return base64.b64encode(payload).decode("utf-8").replace("=", ".")