Skip to content
This repository was archived by the owner on Jul 18, 2025. It is now read-only.

Commit 2c0322b

Browse files
Add video download utility (#69)
* add utility to download videos * update readme
1 parent 0b95160 commit 2c0322b

File tree

2 files changed

+68
-0
lines changed

2 files changed

+68
-0
lines changed

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,3 +183,9 @@ For a complete example of a ComputerInterface implementation, you can refer to t
183183
url={https://arxiv.org/abs/2502.12115},
184184
}
185185
```
186+
187+
## Utilities
188+
189+
We include the following utilities to facilitate future research:
190+
191+
- `download_videos.py` allows you to download the videos attached to an Expensify GitHub issue if your model supports video input

utils/download_videos.py

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import os
2+
import re
3+
import requests
4+
5+
def fetch_issue(issue_number):
6+
url = f"https://api.github.com/repos/Expensify/App/issues/{issue_number}"
7+
headers = {
8+
"Accept": "application/vnd.github.v3+json",
9+
"User-Agent": "ExpensifyVideoDownloader"
10+
}
11+
try:
12+
response = requests.get(url, headers=headers)
13+
response.raise_for_status()
14+
return response.json()
15+
except Exception as e:
16+
print(f"Error fetching issue {issue_number}: {e}")
17+
return None
18+
19+
def download_issue_videos(issue):
20+
title = issue.get('title', '<No Title>')
21+
body = issue.get('body', '')
22+
23+
print("Issue Title:", title)
24+
print("Issue Body:", body)
25+
26+
video_urls = re.findall(r'(https?://[^\s]+?\.(?:mp4|mov))', body)
27+
if not video_urls:
28+
print("No .mp4 or .mov files found in the issue body.")
29+
return
30+
31+
issue_id = str(issue.get('number') or issue.get('id', 'unknown'))
32+
destination_dir = os.path.join("issue_videos", issue_id)
33+
os.makedirs(destination_dir, exist_ok=True)
34+
35+
for url in video_urls:
36+
video_name = os.path.basename(url.split('?')[0])
37+
destination_path = os.path.join(destination_dir, video_name)
38+
print(f"Downloading {url} to {destination_path} ...")
39+
40+
try:
41+
video_response = requests.get(url, stream=True)
42+
video_response.raise_for_status()
43+
with open(destination_path, 'wb') as out_file:
44+
for chunk in video_response.iter_content(chunk_size=8192):
45+
if chunk:
46+
out_file.write(chunk)
47+
print(f"Downloaded {video_name} successfully.")
48+
except Exception as e:
49+
print(f"Error downloading {url}: {e}")
50+
51+
def fetch_and_download_issue_videos(issue_number):
52+
issue = fetch_issue(issue_number)
53+
if issue is not None:
54+
download_issue_videos(issue)
55+
56+
if __name__ == '__main__':
57+
import sys
58+
if len(sys.argv) < 2:
59+
print("Usage: python utils/download_videos.py <issue_number>")
60+
else:
61+
issue_number = sys.argv[1]
62+
fetch_and_download_issue_videos(issue_number)

0 commit comments

Comments
 (0)