Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multi-File Processing Support and added support for linux #303

Open
wants to merge 16 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
09b7598
## Summary of Improvements
devanshusanghani Oct 29, 2024
45388c5
updated readme file
devanshusanghani Oct 29, 2024
52c5af0
Merge pull request #1 from devanshusanghani/multiple-file-feature-branch
devanshusanghani Oct 29, 2024
0355486
updated .gitignore
devanshusanghani Oct 29, 2024
b185a8f
Merge pull request #2 from devanshusanghani/multiple-file-feature-branch
devanshusanghani Oct 29, 2024
37fba87
Merge pull request #3 from devanshusanghani/multiple-file-feature-branch
devanshusanghani Dec 5, 2024
a534aa3
Fix output file path in Application class to use the correct director…
devanshusanghani Dec 6, 2024
0ac9211
Merge pull request #4 from devanshusanghani/google-master-branch
devanshusanghani Dec 5, 2024
270f48d
Add build_executables.py script and requirements.txt
devanshusanghani Jan 14, 2025
17c1f4d
Merge pull request #5 from devanshusanghani:multiple-file-feature-branch
devanshusanghani Jan 14, 2025
5901832
Add initial project structure and CI/CD configuration
devanshusanghani Jan 14, 2025
9a93c33
Revert "Fix output file path in Application class to use the correct …
devanshusanghani Jan 14, 2025
72c0ff3
Fix output file path in Application class to use self.save_file direc…
devanshusanghani Jan 14, 2025
2d0a01e
Revert "Add initial project structure and CI/CD configuration"
devanshusanghani Jan 14, 2025
3369a4b
Enhance Linux executable handling in spatial_media_metadata_injector.…
devanshusanghani Jan 14, 2025
7738640
Merge pull request #6 from devanshusanghani:multiple-file-feature-branch
devanshusanghani Jan 14, 2025
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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
*.pyc
__pycache__
/.venv
/dist
/build

86 changes: 86 additions & 0 deletions build_executables.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
#!/usr/bin/env python3
import os
import sys
import time
import platform
import subprocess
import shutil

def get_platform_name():
"""Get standardized platform name"""
if sys.platform.startswith('win'):
return 'windows'
elif sys.platform.startswith('darwin'):
return 'macos'
elif sys.platform.startswith('linux'):
return 'linux'
return sys.platform

def retry_rmtree(directory_name, max_retries=3, delay=1):
"""Retry removing directory tree with multiple attempts"""
for attempt in range(max_retries):
try:
if os.path.exists(directory_name):
shutil.rmtree(directory_name)
return True
except PermissionError as error:
if attempt == max_retries - 1:
print(f"Warning: Could not remove {directory_name}: {error}")
return False
print(f"Retrying removal of {directory_name} in {delay} seconds...")
time.sleep(delay)
return False

def clean_build_directories():
"""Clean up build directories"""
directories_to_clean = ['build', 'dist']
for directory_name in directories_to_clean:
if not retry_rmtree(directory_name):
print(f"Warning: Proceeding without cleaning {directory_name}")

def get_executable_name():
"""Get platform-specific executable name"""
platform_name = get_platform_name()
if platform_name == 'windows':
return 'Spatial Media Metadata Injector.exe'
elif platform_name == 'macos':
return 'Spatial Media Metadata Injector.app'
else:
return 'Spatial Media Metadata Injector'

def build_executable():
"""Build the executable for the current platform"""
# Clean previous builds
try:
clean_build_directories()
except Exception as error:
print(f"Warning: Error during cleanup: {error}")
print("Attempting to continue with build...")

# Get the specification file path
specification_file = os.path.join('spatialmedia', 'spatial_media_metadata_injector.spec')

# Build command
command = ['pyinstaller', '--clean', specification_file]

try:
subprocess.check_call(command)
platform_name = get_platform_name()
exe_name = get_executable_name()
print(f"Successfully built executable for {platform_name}")

# Show output location
print(f"Output: ./dist/{exe_name}")

# Set executable permissions for Unix-like systems
if platform_name in ('linux', 'macos'):
output_path = os.path.join('dist', exe_name)
if os.path.exists(output_path):
os.chmod(output_path, 0o755)

except subprocess.CalledProcessError as error:
print(f"Error building executable: {error}")
sys.exit(1)

if __name__ == "__main__":
build_executable()
4 changes: 4 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
PyInstaller
tk
pillow
packaging
61 changes: 42 additions & 19 deletions spatialmedia/gui.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,14 +62,17 @@ def append(self, text):

class Application(tk.Frame):
def action_open(self):
"""Triggers open file diaglog, reading a new file's metadata."""
tmp_in_file = filedialog.askopenfilename(**self.open_options)
if not tmp_in_file:
"""Triggers open file dialog, reading new files' metadata."""
tmp_in_files = filedialog.askopenfilenames(**self.open_options)
if not tmp_in_files:
return
self.in_file = tmp_in_file

self.set_message("Current 360 video: %s" % ntpath.basename(self.in_file))


# Process first file to show in the UI
self.in_file = tmp_in_files[0]
self.all_files = tmp_in_files # Store all selected files

self.set_message(f"Selected {len(tmp_in_files)} files. Current file: {ntpath.basename(self.in_file)}")

console = Console()
parsed_metadata = metadata_utils.parse_metadata(self.in_file, console.append)

Expand Down Expand Up @@ -125,6 +128,7 @@ def action_open(self):
self.update_state()

def action_inject_delay(self):
"""Process all selected files for injection."""
stereo = None
if self.var_3d.get():
stereo = "top-bottom"
Expand All @@ -139,28 +143,45 @@ def action_inject_delay(self):
)

console = Console()
metadata_utils.inject_metadata(
self.in_file, self.save_file, metadata, console.append
)
success_count = 0

for input_file in self.all_files:
split_filename = os.path.splitext(ntpath.basename(input_file))
base_filename = split_filename[0]
extension = split_filename[1]

# Create output filename for each file
# Fix: Use self.save_file directly as it's already the correct directory path
output_file = os.path.join(
#os.path.dirname(self.save_file), # Remove os.path.dirname() call to fix directory path issue
self.save_file, # Remove os.path.dirname() call
f"{base_filename}_injected{extension}"
)

try:
metadata_utils.inject_metadata(
input_file, output_file, metadata, console.append
)
success_count += 1
except Exception as e:
console.append(f"Error processing {ntpath.basename(input_file)}: {str(e)}")

self.set_message(
"Successfully saved file to %s\n" % ntpath.basename(self.save_file)
f"Successfully processed {success_count} out of {len(self.all_files)} files"
)
self.button_open.configure(state="normal")
self.update_state()

def action_inject(self):
"""Inject metadata into a new save file."""
split_filename = os.path.splitext(ntpath.basename(self.in_file))
base_filename = split_filename[0]
extension = split_filename[1]
self.save_options["initialfile"] = base_filename + "_injected" + extension
self.save_file = filedialog.asksaveasfilename(**self.save_options)
"""Inject metadata into new save files."""
# Ask for output directory instead of single file
self.save_file = filedialog.askdirectory(title="Select Output Directory")
if not self.save_file:
return

self.set_message("Saving file to %s" % ntpath.basename(self.save_file))
self.set_message(f"Processing {len(self.all_files)} files...")

# Launch injection on a separate thread after disabling buttons.
# Launch injection on a separate thread after disabling buttons
self.disable_state()
self.master.after(100, self.action_inject_delay)

Expand Down Expand Up @@ -310,6 +331,7 @@ def __init__(self, master=None):
self.title = "Spatial Media Metadata Injector"
self.open_options = {}
self.open_options["filetypes"] = [("Videos", ("*.mov", "*.mp4"))]
self.open_options["multiple"] = True # Enable multiple file selection

self.save_options = {}

Expand All @@ -318,6 +340,7 @@ def __init__(self, master=None):
self.pack()

self.in_file = None
self.all_files = [] # Store all selected files
self.disable_state()
self.enable_state()
master.attributes("-topmost", True)
Expand Down
11 changes: 11 additions & 0 deletions spatialmedia/spatial_media_metadata_injector.spec
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,14 @@ if sys.platform == 'darwin':
icon=None,
bundle_identifier=None,
info_plist={'NSHighResolutionCapable': 'True'})
if sys.platform.startswith('linux'):
exe = EXE(pyz,
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
name='Spatial Media Metadata Injector',
debug=False,
strip=False,
upx=True,
console=False)