python-ring-doorbell
python-ring-doorbell copied to clipboard
Cannot download ring videos
When trying to download a video i get the following error: Got error: RingError('HTTP error with status code 404 during query of url https://api.ring.com/clients_api/dings/
Please help
Can you provide a bit more information. How are you trying to download it? Do other queries work? Maybe post some logs etc?
Sure,
So I can run the following commands: ring-doorbell list
, ring-doorbell motion-detection --device-name "DEVICENAME" --on
, ring-doorbell history --device-name "Front Door"
but when I try running the following command ring-doorbell videos --download-all
command, I get the following error:
❯ ring-doorbell videos --download-all
---------------------------------
Ring CLI
Getting videos linked on your Ring account.
This may take some time....
Downloading 70 videos linked on your Ring account.
This may take some time....
1/70 Downloading xxxx.mp4
Got error: RingError('HTTP error with status code 404 during query of url https://api.ring.com/clients_api/dings/xxxx/recording: 404 Client Error: Not Found for url: https://share-service-download-bucket.s3.amazonaws.com/xxxxx.mp4?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=xxxxSignedHeaders=host&X-Amz-Signature=xxxx')
Traceback (most recent call last):
File "/Users/sergiu/miniforge3/lib/python3.10/site-packages/ring_doorbell/auth.py", line 163, in query
resp.raise_for_status()
File "/Users/sergiu/miniforge3/lib/python3.10/site-packages/requests/models.py", line 1021, in raise_for_status
raise HTTPError(http_error_msg, response=self)
requests.exceptions.HTTPError: 404 Client Error: Not Found for url: https://share-service-download-bucket.s3.amazonaws.com/xxxmp4?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/Users/sergiu/miniforge3/lib/python3.10/site-packages/ring_doorbell/cli.py", line 47, in __call__
asyncio.run(self.main(*args, **kwargs))
File "/Users/sergiu/miniforge3/lib/python3.10/asyncio/runners.py", line 44, in run
return loop.run_until_complete(main)
File "/Users/sergiu/miniforge3/lib/python3.10/asyncio/base_events.py", line 649, in run_until_complete
return future.result()
File "/Users/sergiu/miniforge3/lib/python3.10/site-packages/asyncclick/core.py", line 1120, in main
rv = await self.invoke(ctx)
File "/Users/sergiu/miniforge3/lib/python3.10/site-packages/asyncclick/core.py", line 1739, in invoke
return await _process_result(await sub_ctx.command.invoke(sub_ctx))
File "/Users/sergiu/miniforge3/lib/python3.10/site-packages/asyncclick/core.py", line 1485, in invoke
return await ctx.invoke(self.callback, **ctx.params)
File "/Users/sergiu/miniforge3/lib/python3.10/site-packages/asyncclick/core.py", line 824, in invoke
rv = await rv
File "/Users/sergiu/miniforge3/lib/python3.10/site-packages/asyncclick/core.py", line 824, in invoke
rv = await rv
File "/Users/sergiu/miniforge3/lib/python3.10/site-packages/ring_doorbell/cli.py", line 584, in videos
device.recording_download(event["id"], filename=filename, override=False)
File "/Users/sergiu/miniforge3/lib/python3.10/site-packages/ring_doorbell/doorbot.py", line 387, in recording_download
req = self._ring.query(url, timeout=timeout)
File "/Users/sergiu/miniforge3/lib/python3.10/site-packages/ring_doorbell/ring.py", line 142, in query
return self._query(url, method, extra_params, data, json, timeout)
File "/Users/sergiu/miniforge3/lib/python3.10/site-packages/ring_doorbell/ring.py", line 155, in _query
response = self.auth.query(
File "/Users/sergiu/miniforge3/lib/python3.10/site-packages/ring_doorbell/auth.py", line 165, in query
raise RingError(
ring_doorbell.exceptions.RingError: HTTP error with status code 404 during query of url https://api.ring.com/clients_api/dings/xxxx/recording: 404 Client Error: Not Found for url: https://share-service-download-bucket.s3.amazonaws.com/
unless python3 isn't supported?
Encountering the same error now using Python 3.8 (albeit a different endpoint) - yesterday it worked fine:
ring_doorbell.exceptions.RingError: HTTP error with status code 404 during query of url
https://api.ring.com/clients_api/doorbots/[...]/history: 404 Client Error: Not Found for url:
https://api.ring.com/clients_api/doorbots/[...]/history?limit=50&older_than=[...]
This is thrown when invoking the recording_download()
function only, in my case.
Other functions work fine and provide results properly, like update_data()
and devices()
.
Related #242
I have noticed the same thing using the cli
ring-doorbell videos --download
By manually clicking on the link after getting the 404, I realized that it works, and if i re-run the same cli command, the first video then downloads and the 2nd fails, and this can be repeated for the rest of the videos.
I believe what's happening is the download process is an async process. It takes a few moments for the file to get exported to the s3 bucket before it is actually available to download.
Same issue
I believe what's happening is the download process is an async process. It takes a few moments for the file to get exported to the s3 bucket before it is actually available to download.
I have noticed the same thing using the cli
ring-doorbell videos --download
By manually clicking on the link after getting the 404, I realized that it works, and if i re-run the same cli command, the first video then downloads and the 2nd fails, and this can be repeated for the rest of the videos.
I believe what's happening is the download process is an async process. It takes a few moments for the file to get exported to the s3 bucket before it is actually available to download.
Its actually nothing to do with AWS record / save time.
if you try to download older videos by manually specifying the event ID, you would run into same issue.
example
devices = ring.video_devices()
event_ids = [1234, 5678]
for eid in event_ids:
devices[0].recording_download(eid, filename)
That's not a contradiction to what I said. The ring server still needs to process the (albeit old) video file to S3 for sharing.
On Tue, Jun 11, 2024, 9:27 PM Dakku @.***> wrote:
I believe what's happening is the download process is an async process. It takes a few moments for the file to get exported to the s3 bucket before it is actually available to download.
I have noticed the same thing using the cli ring-doorbell videos --download
By manually clicking on the link after getting the 404, I realized that it works, and if i re-run the same cli command, the first video then downloads and the 2nd fails, and this can be repeated for the rest of the videos.
I believe what's happening is the download process is an async process. It takes a few moments for the file to get exported to the s3 bucket before it is actually available to download.
Its actually nothing to do with AWS record / save time.
if you try to download older videos by manually specifying the event ID, you would run into same issue.
example
devices = ring.video_devices()
event_ids = [1234, 5678]
for eid in event_ids: devices[0].recording_download(eid, filename)
— Reply to this email directly, view it on GitHub https://github.com/tchellomello/python-ring-doorbell/issues/350#issuecomment-2161369120, or unsubscribe https://github.com/notifications/unsubscribe-auth/AH33UMO7O2DG567VNFEKMCDZG46SFAVCNFSM6AAAAABDNHZRYGVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDCNRRGM3DSMJSGA . You are receiving this because you commented.Message ID: @.***>
I had the same issue - I solved it by making it wait 20 seconds until it tries the same file again. It usually works after one or 2 retries
try_again = True
while try_again:
try:
frontdoor.recording_download(id_value, filename=filename, override=True)
try_again = False
except RingError as e:
if '404' in str(e):
print(f"File for ID {id_value} not found. Wait for 20 seconds and retrying...")
time.sleep(20)
else:
print(f"An error occurred: {e}")
time.sleep(10)
try_again = False
I tried the time limit and still couldnt get it to work.
I had to roll my own download function using:
video_url = device.recording_url(event["id"])
and you can manually download the unbranded video without times burnt into it!
I had the same problem retrying fixed it. Here's a script to download all videos:
import time
import os
from pathlib import Path
import json
import requests
import getpass
from ring_doorbell import Auth, Ring, RingError, Requires2FAError
from datetime import datetime
# Define the base output directory
BASE_OUTPUT_DIR = Path("ring_output")
def token_updated(token):
cache_file.write_text(json.dumps(token))
def otp_callback():
return input("2FA code: ")
# Initialize Ring object
cache_file = Path("RingVideoDownloader.token.cache")
auth = None
if cache_file.is_file():
auth = Auth("RingVideoDownloader/1.0", json.loads(cache_file.read_text()), token_updated)
else:
username = input("Enter your Ring username: ")
password = getpass.getpass("Enter your Ring password: ")
auth = Auth("RingVideoDownloader/1.0", None, token_updated)
try:
auth.fetch_token(username, password)
except Requires2FAError:
print("2FA is enabled. You will receive a code via email or text.")
try:
auth.fetch_token(username, password, otp_callback())
except Exception as e:
print(f"2FA Authentication failed: {e}")
exit(1)
except Exception as e:
print(f"Authentication failed: {e}")
exit(1)
ring = Ring(auth)
ring.update_data()
def ensure_output_dir(device_name, date_str):
output_dir = BASE_OUTPUT_DIR / device_name / date_str
if not output_dir.exists():
output_dir.mkdir(parents=True)
print(f"Created output directory: {output_dir}")
return output_dir
def download_video(device, event, max_retries=3):
created_at = event.get('created_at', datetime.now().isoformat())
if isinstance(created_at, str):
date_str = created_at.split('T')[0] # Extract date part
created_at = created_at.replace(':', '-')
else:
date_str = created_at.date().isoformat()
created_at = created_at.isoformat().replace(':', '-')
output_dir = ensure_output_dir(device.name, date_str)
kind = event.get('kind', 'unknown')
filename = output_dir / f"{device.name}_{created_at}_{kind}.mp4"
for attempt in range(max_retries):
try:
device.recording_download(event['id'], filename=str(filename), override=True)
print(f"Successfully downloaded: {filename}")
return True
except RingError as e:
if '404' in str(e):
print(f"Video for ID {event['id']} not found (404 error). Attempt {attempt + 1}/{max_retries}")
else:
print(f"An error occurred: {e}. Attempt {attempt + 1}/{max_retries}")
if attempt < max_retries - 1:
print(f"Waiting 20 seconds before retrying...")
time.sleep(20)
else:
print(f"Failed to download video after {max_retries} attempts.")
return False
return False
def main():
devices = ring.devices()
all_devices = []
all_devices.extend(devices.doorbells)
all_devices.extend(devices.stickup_cams)
for device in all_devices:
print(f"Downloading videos for {device.name}")
events = device.history(limit=100) # Adjust the limit as needed
print(f"Total events for {device.name}: {len(events)}")
successful_downloads = 0
failed_downloads = 0
for index, event in enumerate(events, 1):
print(f"Attempting to download video {index}/{len(events)}")
if download_video(device, event):
successful_downloads += 1
else:
failed_downloads += 1
print("Skipping to next video...")
print(f"Download summary for {device.name}:")
print(f"Successfully downloaded: {successful_downloads}")
print(f"Failed to download: {failed_downloads}")
print(f"Videos saved in device and date-specific folders under: {BASE_OUTPUT_DIR}")
if __name__ == "__main__":
main()