|
| 1 | +import os |
| 2 | +import requests |
| 3 | +import xml.etree.ElementTree as ET |
| 4 | +from watchdog.observers import Observer |
| 5 | +from watchdog.events import FileSystemEventHandler |
| 6 | + |
| 7 | +# Constants |
| 8 | +access_token = '{TOKEN}' # Replace with your actual access token |
| 9 | +folder_to_monitor = '{PATH}' |
| 10 | + |
| 11 | +# Set to track processed file pairs |
| 12 | +processed_pairs = set() |
| 13 | + |
| 14 | +class UploadHandler(FileSystemEventHandler): |
| 15 | + def on_created(self, event): |
| 16 | + if event.event_type == 'created': |
| 17 | + file_path = event.src_path |
| 18 | + if file_path.endswith('.mp4'): |
| 19 | + self.process_mp4(file_path) |
| 20 | + elif file_path.endswith('.xml'): |
| 21 | + self.process_xml(file_path) |
| 22 | + |
| 23 | + def process_mp4(self, video_path): |
| 24 | + xml_path = os.path.splitext(video_path)[0] + '.xml' |
| 25 | + if os.path.exists(xml_path): |
| 26 | + pair = (video_path, xml_path) |
| 27 | + if pair not in processed_pairs: |
| 28 | + self.process_files(video_path, xml_path) |
| 29 | + processed_pairs.add(pair) |
| 30 | + |
| 31 | + def process_xml(self, xml_path): |
| 32 | + video_path = os.path.splitext(xml_path)[0] + '.mp4' |
| 33 | + if os.path.exists(video_path): |
| 34 | + pair = (video_path, xml_path) |
| 35 | + if pair not in processed_pairs: |
| 36 | + self.process_files(video_path, xml_path) |
| 37 | + processed_pairs.add(pair) |
| 38 | + |
| 39 | + def process_files(self, video_path, xml_path): |
| 40 | + if (video_path, xml_path) in processed_pairs: |
| 41 | + return |
| 42 | + try: |
| 43 | + metadata = extract_metadata(xml_path) |
| 44 | + upload_file(video_path, metadata) |
| 45 | + except Exception as e: |
| 46 | + print(f"Failed to process files {video_path} and {xml_path}: {e}") |
| 47 | + |
| 48 | +def extract_metadata(xml_path): |
| 49 | + metadata = {'title': '', 'description': '', 'tags': []} |
| 50 | + try: |
| 51 | + tree = ET.parse(xml_path) |
| 52 | + root = tree.getroot() |
| 53 | + for child in root: |
| 54 | + if child.tag == 'title': |
| 55 | + metadata['title'] = child.text |
| 56 | + elif child.tag == 'description': |
| 57 | + metadata['description'] = child.text |
| 58 | + elif child.tag == 'tags': |
| 59 | + metadata['tags'] = [tag.strip() for tag in child.text.split(',')] |
| 60 | + except Exception as e: |
| 61 | + print(f"Error parsing XML metadata for {xml_path}: {e}") |
| 62 | + return metadata |
| 63 | + |
| 64 | +def upload_file(video_path, metadata): |
| 65 | + try: |
| 66 | + filename_without_extension = os.path.splitext(os.path.basename(video_path))[0] |
| 67 | + |
| 68 | + title = metadata.get('title', filename_without_extension) |
| 69 | + description = metadata.get('description', '') |
| 70 | + tags = metadata.get('tags', []) |
| 71 | + |
| 72 | + headers = { |
| 73 | + 'Authorization': f'Bearer {access_token}', |
| 74 | + 'Content-Type': 'application/json', |
| 75 | + 'Accept': 'application/vnd.vimeo.*+json;version=3.4' |
| 76 | + } |
| 77 | + params = { |
| 78 | + 'upload': { |
| 79 | + 'approach': 'tus', |
| 80 | + 'size': os.path.getsize(video_path), |
| 81 | + }, |
| 82 | + 'name': title, |
| 83 | + 'description': description, |
| 84 | + } |
| 85 | + response = requests.post('https://api.vimeo.com/me/videos', headers=headers, json=params) |
| 86 | + video_data = response.json() |
| 87 | + upload_link = video_data.get('upload', {}).get('upload_link') |
| 88 | + |
| 89 | + chunk_size = 256 * 1024 * 1024 |
| 90 | + |
| 91 | + with open(video_path, 'rb') as f: |
| 92 | + headers = { |
| 93 | + 'Tus-Resumable': '1.0.0', |
| 94 | + 'Upload-Offset': '0', |
| 95 | + 'Content-Type': 'application/offset+octet-stream' |
| 96 | + } |
| 97 | + while True: |
| 98 | + data = f.read(chunk_size) |
| 99 | + if not data: |
| 100 | + break |
| 101 | + response = requests.patch(upload_link, headers=headers, data=data) |
| 102 | + upload_offset = int(response.headers.get('Upload-Offset', 0)) |
| 103 | + if upload_offset == os.path.getsize(video_path): |
| 104 | + print(f"Upload of {video_path} complete!") |
| 105 | + break |
| 106 | + |
| 107 | + response = requests.head(upload_link, headers={'Tus-Resumable': '1.0.0', 'Accept': 'application/vnd.vimeo.*+json;version=3.4'}) |
| 108 | + upload_length = int(response.headers.get('Upload-Length', 0)) |
| 109 | + upload_offset = int(response.headers.get('Upload-Offset', 0)) |
| 110 | + if upload_length == upload_offset: |
| 111 | + print(f"Upload of {video_path} verified: Video file received completely.") |
| 112 | + else: |
| 113 | + print(f"Upload of {video_path} verification failed: Video file upload incomplete.") |
| 114 | + |
| 115 | + video_id = video_data.get('uri').split('/')[-1] |
| 116 | + add_tags_to_video(video_id, tags) |
| 117 | + |
| 118 | + except Exception as e: |
| 119 | + print(f"Failed to upload {video_path} to Vimeo: {e}") |
| 120 | + |
| 121 | +def add_tags_to_video(video_id, tags): |
| 122 | + try: |
| 123 | + headers = { |
| 124 | + 'Authorization': f'Bearer {access_token}', |
| 125 | + 'Content-Type': 'application/json', |
| 126 | + 'Accept': 'application/vnd.vimeo.*+json;version=3.4' |
| 127 | + } |
| 128 | + for tag in tags: |
| 129 | + url = f'https://api.vimeo.com/videos/{video_id}/tags/{tag}' |
| 130 | + response = requests.put(url, headers=headers) |
| 131 | + if response.status_code == 200: |
| 132 | + print(f"Tag '{tag}' added to the video.") |
| 133 | + else: |
| 134 | + print(f"Trouble adding '{tag}' to the video. Status code: {response.status_code}") |
| 135 | + except Exception as e: |
| 136 | + print(f"Failed to add tags to the video: {e}") |
| 137 | + |
| 138 | +if __name__ == "__main__": |
| 139 | + observer = Observer() |
| 140 | + observer.schedule(UploadHandler(), folder_to_monitor, recursive=True) |
| 141 | + observer.start() |
| 142 | + try: |
| 143 | + print(f"Watching folder: {folder_to_monitor}") |
| 144 | + observer.join() |
| 145 | + except KeyboardInterrupt: |
| 146 | + observer.stop() |
| 147 | + observer.join() |
0 commit comments