Video2Crops/v2cmodules/toolbox.py

186 lines
6.8 KiB
Python

import re, os, urllib.request
import tkinter as tk
from datetime import datetime
from bs4 import BeautifulSoup
from tkinter import filedialog, simpledialog, messagebox, scrolledtext
from v2cmodules.common import *
def extract_version(title):
# Use regular expressions to extract the version number from the title
match = re.search(r'(\d+\.\d+\.\d+)', title)
if match:
return match.group(1)
return None
def fetch_ini():
global INVALID_INI
try:
with open(CONFIG_FILE, 'w') as file:
config_url = 'https://git.rolfsvaag.no/frarol96/Video2Crops/raw/branch/main/config.ini'
with urllib.request.urlopen(config_url) as config_template:
config_template = config_template.read().decode("utf-8")
file.write(config_template)
tk.messagebox.showinfo("Reset config file", f"Config file has been reset")
debug('DEBUG', f"Config file was reset to default")
INVALID_INI = False
except:
print(f"[ERROR] Unable to fetch the missing config.ini file!\nCheck directory permissions and network connectivity!")
exit
# Debug function
def debug(state, message):
if DEBUG:
allowed_states = ['LOG EVENT', 'DEBUG', 'ERROR', 'INFO']
if state in allowed_states:
debug_message = f"[{state}] {message}"
print(f"{debug_message}")
debugfile_path = os.path.join(os.getcwd(), 'debugfile.txt')
with open(debugfile_path, 'a') as debugfile:
log_debug_message = f"{datetime.now().strftime('%m-%d_%H:%M:%S')} | [{state}] {message}\n"
debugfile.write(log_debug_message)
else:
raise ValueError(f"Invalid state '{state}'. Please choose from {', '.join(allowed_states)}.")
def checkinifile():
global INVALID_INI
# Check for the presence of sections and keys
expected_sections = ['settings', 'debug']
expected_settings_keys = {
'frame_step': int,
'contrast_threshold': float,
'duplicate_threshold': int,
'save_output': bool,
'show_playback': bool,
'roi_size': int,
'window_size': str,
'user_defined_output_dir': str
}
expected_debug_keys = {
'debug_output': bool
}
CHECK_SECTIONS = True
CHECK_KEYS = True
CHECK_VALUES = False
# Check for the presence of sections
if CHECK_SECTIONS:
for section in expected_sections:
if section not in config.sections():
INVALID_INI = True
print(f"Missing section: [{section}]")
# Check for the presence of keys and their types in the 'settings' section
if 'settings' in config.sections():
for key, expected_type in expected_settings_keys.items():
if key not in config['settings']:
if CHECK_KEYS:
INVALID_INI = True
print(f"Missing key '{key}' in [settings] section")
else:
value = config.get('settings', key)
if not isinstance(value, expected_type):
if CHECK_VALUES:
INVALID_INI = True
print(f"Value of '{key}' in [settings] section is not of expected type {expected_type}")
# Check for the presence of keys and their types in the 'debug' section
if 'debug' in config.sections():
for key, expected_type in expected_debug_keys.items():
if key not in config['debug']:
if CHECK_KEYS:
INVALID_INI = True
print(f"Missing key '{key}' in [debug] section")
else:
value = config.get('debug', key)
if not isinstance(value, expected_type):
if CHECK_VALUES:
INVALID_INI = True
print(f"Value of '{key}' in [debug] section is not of expected type {expected_type}")
if INVALID_INI:
fetch_ini()
def write2ini(section, variable, value):
config.set(section, str(variable), str(value))
# Save the changes to the INI file
with open(CONFIG_FILE, 'w') as configfile:
config.write(configfile)
def extract_changelog(description):
# Parse the HTML content using BeautifulSoup
soup = BeautifulSoup(description, 'html.parser')
# Find all changelog sections
changelog_sections = soup.find_all('h3', id='user-content-changelog')
changelogs = []
for changelog_section in changelog_sections:
# Extract the changelog text as plain text
changelog_text = changelog_section.find_next('ul').get_text()
changelogs.append(changelog_text.strip())
# Join the changelogs into a single string
changelog_str = '\n'.join(changelogs)
return changelog_str if changelog_str else None
def toggle_save():
if not processing:
global SAVE
SAVE = not SAVE
write2ini('settings', 'save_output', SAVE)
debug('DEBUG', f"Saving output: {SAVE}")
else:
messagebox.showinfo("Info", "Video2Crops is currently processing files!")
def toggle_show():
if not processing:
global SHOW
SHOW = not SHOW
write2ini('settings', 'show_playback', SHOW)
debug('DEBUG', f"Displaying output: {SHOW}")
else:
messagebox.showinfo("Info", "Video2Crops is currently processing files!")
# Function to create the output directory and return its path
def create_output_directory(video_filename):
debug('DEBUG', f"Creating output directory")
base_directory = user_defined_output_dir
video_filename_base, _ = os.path.splitext(os.path.basename(video_filename))
output_folder_path = os.path.join(base_directory, video_filename_base)
# Create the output directory if it doesn't exist
if not os.path.exists(output_folder_path):
os.makedirs(output_folder_path)
debug('DEBUG', f"Processing file: {video_filename}")
debug('DEBUG', f"Created output directory at: {output_folder_path}")
return output_folder_path
def truncate_path(path, pre_max=None, post_max=None):
# Split the path into components
path_components = os.path.normpath(path).split(os.path.sep)
# Ensure the first two components are displayed in full
pre_part = os.path.sep.join(path_components[:2])
# Ensure the last two components are displayed in full
post_part = os.path.sep.join(path_components[-2:])
# Truncate the pre-portion if pre_max is specified
if pre_max is not None:
pre_part = pre_part[:pre_max]
# Truncate the post-portion if post_max is specified
if post_max is not None:
post_part = post_part[-post_max:]
# Combine the parts with ellipsis in between
truncated_path = f"{pre_part}...{post_part}"
debug('DEBUG', f"Truncated the path \'{path}\' to \'{truncated_path}\'")
return truncated_path