forked from Github/Axter-Stash
Added additional fields
Added fields resolution, width, and galleries. Fixed bug with studio. Modified GUI option to simplify. Added postfix styles option to advance renamefile_settings.py file. Added logic to avoid running rename logic twice for the same file. Implemented code to limit max logging file size.
This commit is contained in:
2
plugins/RenameFile/.gitignore
vendored
2
plugins/RenameFile/.gitignore
vendored
@@ -9,6 +9,8 @@ desktop.ini
|
|||||||
*.ipch
|
*.ipch
|
||||||
*.lib
|
*.lib
|
||||||
*.log
|
*.log
|
||||||
|
*.log.1
|
||||||
|
*.log.2
|
||||||
*.manifest
|
*.manifest
|
||||||
*.obj
|
*.obj
|
||||||
*.pch
|
*.pch
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# RenameFile: Ver 0.2.5
|
# RenameFile: Ver 0.3.1
|
||||||
RenameFile is a [Stash](https://github.com/stashapp/stash) plugin which performs the following two main task.
|
RenameFile is a [Stash](https://github.com/stashapp/stash) plugin which performs the following two main task.
|
||||||
- **Rename Scene File Name** (On-The-Fly)
|
- **Rename Scene File Name** (On-The-Fly)
|
||||||
- **Append tag names** to file name
|
- **Append tag names** to file name
|
||||||
|
|||||||
14
plugins/RenameFile/manifest
Normal file
14
plugins/RenameFile/manifest
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
id: renamefile
|
||||||
|
name: RenameFile
|
||||||
|
metadata:
|
||||||
|
description: Renames video (scene) file names when the user edits the [Title] field located in the scene [Edit] tab.
|
||||||
|
version: 0.4.1
|
||||||
|
date: "2024-07-26 08:00:00"
|
||||||
|
requires: [pip install stashapp-tools, pip install pyYAML]
|
||||||
|
source_repository: https://github.com/David-Maisonave/Axter-Stash/tree/main/plugins/RenameFile
|
||||||
|
files:
|
||||||
|
- README.md
|
||||||
|
- renamefile.yml
|
||||||
|
- renamefile.py
|
||||||
|
- renamefile_settings.py
|
||||||
|
- requirements.txt
|
||||||
@@ -1,18 +1,19 @@
|
|||||||
|
# This is a Stash plugin which allows users to rename the video (scene) file name by editing the [Title] field located in the scene [Edit] tab.
|
||||||
|
# By David Maisonave (aka Axter) 2024
|
||||||
|
# Get the latest developers version from following link: https://github.com/David-Maisonave/Axter-Stash/tree/main/plugins/RenameFile
|
||||||
|
# Based on source code from https://github.com/Serechops/Serechops-Stash/tree/main/plugins/Renamer
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
import os
|
import os
|
||||||
import logging
|
import logging
|
||||||
|
import stashapi.log as log # Importing stashapi.log as log for critical events ONLY
|
||||||
import shutil
|
import shutil
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import hashlib
|
import hashlib
|
||||||
import json
|
import json
|
||||||
import sys
|
import sys
|
||||||
from stashapi.stashapp import StashInterface
|
from stashapi.stashapp import StashInterface
|
||||||
|
from logging.handlers import RotatingFileHandler
|
||||||
# This is a Stash plugin which allows users to rename the video (scene) file name by editing the [Title] field located in the scene [Edit] tab.
|
|
||||||
|
|
||||||
# Importing stashapi.log as log for critical events
|
|
||||||
import stashapi.log as log
|
|
||||||
|
|
||||||
# Import settings from renamefile_settings.py
|
# Import settings from renamefile_settings.py
|
||||||
from renamefile_settings import config
|
from renamefile_settings import config
|
||||||
|
|
||||||
@@ -21,14 +22,24 @@ script_dir = Path(__file__).resolve().parent
|
|||||||
|
|
||||||
# Configure logging for your script
|
# Configure logging for your script
|
||||||
log_file_path = script_dir / 'renamefile.log'
|
log_file_path = script_dir / 'renamefile.log'
|
||||||
|
rfh = RotatingFileHandler(
|
||||||
|
filename=log_file_path,
|
||||||
|
mode='a',
|
||||||
|
maxBytes=2*1024*1024,
|
||||||
|
backupCount=2,
|
||||||
|
encoding=None,
|
||||||
|
delay=0
|
||||||
|
)
|
||||||
FORMAT = "[%(asctime)s - LN:%(lineno)s] %(message)s"
|
FORMAT = "[%(asctime)s - LN:%(lineno)s] %(message)s"
|
||||||
logging.basicConfig(filename=log_file_path, level=logging.INFO, format=FORMAT)
|
logging.basicConfig(level=logging.INFO, format=FORMAT, datefmt="%y%m%d %H:%M:%S", handlers=[rfh])
|
||||||
logger = logging.getLogger('renamefile')
|
logger = logging.getLogger('renamefile')
|
||||||
DEFAULT_ENDPOINT = "http://localhost:9999/graphql" # Default GraphQL endpoint
|
DEFAULT_ENDPOINT = "http://localhost:9999/graphql" # Default GraphQL endpoint
|
||||||
DEFAULT_FIELD_KEY_LIST = "title,performers,studio,tags" # Default Field Key List with the desired order
|
DEFAULT_FIELD_KEY_LIST = "title,performers,studio,tags" # Default Field Key List with the desired order
|
||||||
DEFAULT_SEPERATOR = "-"
|
DEFAULT_SEPERATOR = "-"
|
||||||
PLUGIN_ARGS = False
|
PLUGIN_ARGS = False
|
||||||
|
errOccurred = False
|
||||||
|
inputToUpdateScenePost = False
|
||||||
|
exitMsg = "Change success!!"
|
||||||
|
|
||||||
|
|
||||||
# ------------------------------------------
|
# ------------------------------------------
|
||||||
@@ -65,7 +76,11 @@ try:
|
|||||||
PLUGIN_ARGS = json_input['args']["mode"]
|
PLUGIN_ARGS = json_input['args']["mode"]
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
logger.info(f"\nStarting (debugTracing={debugTracing}) (dry_run={dry_run}) (PLUGIN_ARGS={PLUGIN_ARGS})************************************************")
|
try:
|
||||||
|
if json_input['args']['hookContext']['input']: inputToUpdateScenePost = True # This avoid calling rename logic twice
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
logger.info(f"\nStarting (debugTracing={debugTracing}) (dry_run={dry_run}) (PLUGIN_ARGS={PLUGIN_ARGS}) (inputToUpdateScenePost={inputToUpdateScenePost})************************************************")
|
||||||
if debugTracing: logger.info("settings: %s " % (settings,))
|
if debugTracing: logger.info("settings: %s " % (settings,))
|
||||||
if dry_run:
|
if dry_run:
|
||||||
logger.info("Dry run mode is enabled.")
|
logger.info("Dry run mode is enabled.")
|
||||||
@@ -102,7 +117,14 @@ separator = settings["zseparators"]
|
|||||||
# ------------------------------------------
|
# ------------------------------------------
|
||||||
double_separator = separator + separator
|
double_separator = separator + separator
|
||||||
|
|
||||||
|
# Extract styles from config
|
||||||
|
wrapper_styles = config["wrapper_styles"]
|
||||||
|
postfix_styles = config["postfix_styles"]
|
||||||
|
|
||||||
|
try:
|
||||||
|
if debugTracing: logger.info(f"Debug Tracing (json_input['args']={json_input['args']})................")
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
# GraphQL query to fetch all scenes
|
# GraphQL query to fetch all scenes
|
||||||
query_all_scenes = """
|
query_all_scenes = """
|
||||||
@@ -142,7 +164,7 @@ def should_exclude_path(scene_details):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
# Function to form the new filename based on scene details and user settings
|
# Function to form the new filename based on scene details and user settings
|
||||||
def form_filename(original_file_stem, scene_details, wrapper_styles):
|
def form_filename(original_file_stem, scene_details):
|
||||||
if debugTracing: logger.info("Debug Tracing................")
|
if debugTracing: logger.info("Debug Tracing................")
|
||||||
filename_parts = []
|
filename_parts = []
|
||||||
tag_keys_added = 0
|
tag_keys_added = 0
|
||||||
@@ -165,7 +187,6 @@ def form_filename(original_file_stem, scene_details, wrapper_styles):
|
|||||||
def add_tag(tag_name):
|
def add_tag(tag_name):
|
||||||
nonlocal tag_keys_added
|
nonlocal tag_keys_added
|
||||||
nonlocal filename_parts
|
nonlocal filename_parts
|
||||||
nonlocal wrapper_styles
|
|
||||||
if debugTracing: logger.info(f"Debug Tracing (tag_name={tag_name})................")
|
if debugTracing: logger.info(f"Debug Tracing (tag_name={tag_name})................")
|
||||||
if max_tag_keys == -1 or (max_tag_keys is not None and tag_keys_added >= int(max_tag_keys)):
|
if max_tag_keys == -1 or (max_tag_keys is not None and tag_keys_added >= int(max_tag_keys)):
|
||||||
return # Skip adding more tags if the maximum limit is reached
|
return # Skip adding more tags if the maximum limit is reached
|
||||||
@@ -194,6 +215,7 @@ def form_filename(original_file_stem, scene_details, wrapper_styles):
|
|||||||
studio_name = scene_details.get('studio', {}).get('name', '')
|
studio_name = scene_details.get('studio', {}).get('name', '')
|
||||||
if debugTracing: logger.info(f"Debug Tracing (studio_name={studio_name})................")
|
if debugTracing: logger.info(f"Debug Tracing (studio_name={studio_name})................")
|
||||||
if studio_name:
|
if studio_name:
|
||||||
|
studio_name += postfix_styles.get('studio')
|
||||||
if debugTracing: logger.info("Debug Tracing................")
|
if debugTracing: logger.info("Debug Tracing................")
|
||||||
if include_keyField_if_in_name or studio_name.lower() not in title.lower():
|
if include_keyField_if_in_name or studio_name.lower() not in title.lower():
|
||||||
if wrapper_styles.get('studio'):
|
if wrapper_styles.get('studio'):
|
||||||
@@ -202,6 +224,7 @@ def form_filename(original_file_stem, scene_details, wrapper_styles):
|
|||||||
filename_parts.append(studio_name)
|
filename_parts.append(studio_name)
|
||||||
elif key == 'title':
|
elif key == 'title':
|
||||||
if title: # This value has already been fetch in start of function because it needs to be defined before tags and performers
|
if title: # This value has already been fetch in start of function because it needs to be defined before tags and performers
|
||||||
|
title += postfix_styles.get('title')
|
||||||
if wrapper_styles.get('title'):
|
if wrapper_styles.get('title'):
|
||||||
filename_parts.append(f"{wrapper_styles['title'][0]}{title}{wrapper_styles['title'][1]}")
|
filename_parts.append(f"{wrapper_styles['title'][0]}{title}{wrapper_styles['title'][1]}")
|
||||||
else:
|
else:
|
||||||
@@ -210,6 +233,7 @@ def form_filename(original_file_stem, scene_details, wrapper_styles):
|
|||||||
if settings["performerAppend"]:
|
if settings["performerAppend"]:
|
||||||
performers = '-'.join([performer.get('name', '') for performer in scene_details.get('performers', [])])
|
performers = '-'.join([performer.get('name', '') for performer in scene_details.get('performers', [])])
|
||||||
if performers:
|
if performers:
|
||||||
|
performers += postfix_styles.get('performers')
|
||||||
if debugTracing: logger.info(f"Debug Tracing (include_keyField_if_in_name={include_keyField_if_in_name})................")
|
if debugTracing: logger.info(f"Debug Tracing (include_keyField_if_in_name={include_keyField_if_in_name})................")
|
||||||
if include_keyField_if_in_name or performers.lower() not in title.lower():
|
if include_keyField_if_in_name or performers.lower() not in title.lower():
|
||||||
if debugTracing: logger.info(f"Debug Tracing (performers={performers})................")
|
if debugTracing: logger.info(f"Debug Tracing (performers={performers})................")
|
||||||
@@ -221,15 +245,33 @@ def form_filename(original_file_stem, scene_details, wrapper_styles):
|
|||||||
scene_date = scene_details.get('date', '')
|
scene_date = scene_details.get('date', '')
|
||||||
if debugTracing: logger.info("Debug Tracing................")
|
if debugTracing: logger.info("Debug Tracing................")
|
||||||
if scene_date:
|
if scene_date:
|
||||||
|
scene_date += postfix_styles.get('date')
|
||||||
if debugTracing: logger.info("Debug Tracing................")
|
if debugTracing: logger.info("Debug Tracing................")
|
||||||
if wrapper_styles.get('date'):
|
if wrapper_styles.get('date'):
|
||||||
filename_parts.append(f"{wrapper_styles['date'][0]}{scene_date}{wrapper_styles['date'][1]}")
|
filename_parts.append(f"{wrapper_styles['date'][0]}{scene_date}{wrapper_styles['date'][1]}")
|
||||||
else:
|
else:
|
||||||
filename_parts.append(scene_date)
|
filename_parts.append(scene_date)
|
||||||
|
elif key == 'resolution':
|
||||||
|
width = str(scene_details.get('files', [{}])[0].get('width', '')) # Convert width to string
|
||||||
|
height = str(scene_details.get('files', [{}])[0].get('height', '')) # Convert height to string
|
||||||
|
if width and height:
|
||||||
|
resolution = width + postfix_styles.get('width_height_seperator') + height + postfix_styles.get('resolution')
|
||||||
|
if wrapper_styles.get('resolution'):
|
||||||
|
filename_parts.append(f"{wrapper_styles['resolution'][0]}{resolution}{wrapper_styles['width'][1]}")
|
||||||
|
else:
|
||||||
|
filename_parts.append(resolution)
|
||||||
|
elif key == 'width':
|
||||||
|
width = str(scene_details.get('files', [{}])[0].get('width', '')) # Convert width to string
|
||||||
|
if width:
|
||||||
|
width += postfix_styles.get('width')
|
||||||
|
if wrapper_styles.get('width'):
|
||||||
|
filename_parts.append(f"{wrapper_styles['width'][0]}{width}{wrapper_styles['width'][1]}")
|
||||||
|
else:
|
||||||
|
filename_parts.append(width)
|
||||||
elif key == 'height':
|
elif key == 'height':
|
||||||
height = str(scene_details.get('files', [{}])[0].get('height', '')) # Convert height to string
|
height = str(scene_details.get('files', [{}])[0].get('height', '')) # Convert height to string
|
||||||
if height:
|
if height:
|
||||||
height += 'p'
|
height += postfix_styles.get('height')
|
||||||
if wrapper_styles.get('height'):
|
if wrapper_styles.get('height'):
|
||||||
filename_parts.append(f"{wrapper_styles['height'][0]}{height}{wrapper_styles['height'][1]}")
|
filename_parts.append(f"{wrapper_styles['height'][0]}{height}{wrapper_styles['height'][1]}")
|
||||||
else:
|
else:
|
||||||
@@ -237,6 +279,7 @@ def form_filename(original_file_stem, scene_details, wrapper_styles):
|
|||||||
elif key == 'video_codec':
|
elif key == 'video_codec':
|
||||||
video_codec = scene_details.get('files', [{}])[0].get('video_codec', '').upper() # Convert to uppercase
|
video_codec = scene_details.get('files', [{}])[0].get('video_codec', '').upper() # Convert to uppercase
|
||||||
if video_codec:
|
if video_codec:
|
||||||
|
video_codec += postfix_styles.get('video_codec')
|
||||||
if wrapper_styles.get('video_codec'):
|
if wrapper_styles.get('video_codec'):
|
||||||
filename_parts.append(f"{wrapper_styles['video_codec'][0]}{video_codec}{wrapper_styles['video_codec'][1]}")
|
filename_parts.append(f"{wrapper_styles['video_codec'][0]}{video_codec}{wrapper_styles['video_codec'][1]}")
|
||||||
else:
|
else:
|
||||||
@@ -244,6 +287,7 @@ def form_filename(original_file_stem, scene_details, wrapper_styles):
|
|||||||
elif key == 'frame_rate':
|
elif key == 'frame_rate':
|
||||||
frame_rate = str(scene_details.get('files', [{}])[0].get('frame_rate', '')) + 'FPS' # Convert to string and append ' FPS'
|
frame_rate = str(scene_details.get('files', [{}])[0].get('frame_rate', '')) + 'FPS' # Convert to string and append ' FPS'
|
||||||
if frame_rate:
|
if frame_rate:
|
||||||
|
frame_rate += postfix_styles.get('frame_rate')
|
||||||
if wrapper_styles.get('frame_rate'):
|
if wrapper_styles.get('frame_rate'):
|
||||||
filename_parts.append(f"{wrapper_styles['frame_rate'][0]}{frame_rate}{wrapper_styles['frame_rate'][1]}")
|
filename_parts.append(f"{wrapper_styles['frame_rate'][0]}{frame_rate}{wrapper_styles['frame_rate'][1]}")
|
||||||
else:
|
else:
|
||||||
@@ -254,6 +298,7 @@ def form_filename(original_file_stem, scene_details, wrapper_styles):
|
|||||||
for gallery_name in galleries:
|
for gallery_name in galleries:
|
||||||
if debugTracing: logger.info(f"Debug Tracing (include_keyField_if_in_name={include_keyField_if_in_name}) (gallery_name={gallery_name})................")
|
if debugTracing: logger.info(f"Debug Tracing (include_keyField_if_in_name={include_keyField_if_in_name}) (gallery_name={gallery_name})................")
|
||||||
if include_keyField_if_in_name or gallery_name.lower() not in title.lower():
|
if include_keyField_if_in_name or gallery_name.lower() not in title.lower():
|
||||||
|
gallery_name += postfix_styles.get('galleries')
|
||||||
if wrapper_styles.get('galleries'):
|
if wrapper_styles.get('galleries'):
|
||||||
filename_parts.append(f"{wrapper_styles['galleries'][0]}{gallery_name}{wrapper_styles['galleries'][1]}")
|
filename_parts.append(f"{wrapper_styles['galleries'][0]}{gallery_name}{wrapper_styles['galleries'][1]}")
|
||||||
if debugTracing: logger.info("Debug Tracing................")
|
if debugTracing: logger.info("Debug Tracing................")
|
||||||
@@ -269,11 +314,11 @@ def form_filename(original_file_stem, scene_details, wrapper_styles):
|
|||||||
for tag_name in tags:
|
for tag_name in tags:
|
||||||
if debugTracing: logger.info(f"Debug Tracing (include_keyField_if_in_name={include_keyField_if_in_name}) (tag_name={tag_name})................")
|
if debugTracing: logger.info(f"Debug Tracing (include_keyField_if_in_name={include_keyField_if_in_name}) (tag_name={tag_name})................")
|
||||||
if include_keyField_if_in_name or tag_name.lower() not in title.lower():
|
if include_keyField_if_in_name or tag_name.lower() not in title.lower():
|
||||||
add_tag(tag_name)
|
add_tag(tag_name + postfix_styles.get('tag'))
|
||||||
if debugTracing: logger.info(f"Debug Tracing (tag_name={tag_name})................")
|
if debugTracing: logger.info(f"Debug Tracing (tag_name={tag_name})................")
|
||||||
if debugTracing: logger.info("Debug Tracing................")
|
if debugTracing: logger.info("Debug Tracing................")
|
||||||
|
|
||||||
if debugTracing: logger.info("Debug Tracing................")
|
if debugTracing: logger.info(f"Debug Tracing (filename_parts={filename_parts})................")
|
||||||
new_filename = separator.join(filename_parts).replace(double_separator, separator)
|
new_filename = separator.join(filename_parts).replace(double_separator, separator)
|
||||||
if debugTracing: logger.info(f"Debug Tracing (new_filename={new_filename})................")
|
if debugTracing: logger.info(f"Debug Tracing (new_filename={new_filename})................")
|
||||||
|
|
||||||
@@ -293,6 +338,7 @@ def find_scene_by_id(scene_id):
|
|||||||
date
|
date
|
||||||
files {
|
files {
|
||||||
path
|
path
|
||||||
|
width
|
||||||
height
|
height
|
||||||
video_codec
|
video_codec
|
||||||
frame_rate
|
frame_rate
|
||||||
@@ -316,6 +362,7 @@ def find_scene_by_id(scene_id):
|
|||||||
return scene_result.get('data', {}).get('findScene')
|
return scene_result.get('data', {}).get('findScene')
|
||||||
|
|
||||||
def move_or_rename_files(scene_details, new_filename, original_parent_directory):
|
def move_or_rename_files(scene_details, new_filename, original_parent_directory):
|
||||||
|
global exitMsg
|
||||||
studio_directory = None
|
studio_directory = None
|
||||||
for file_info in scene_details['files']:
|
for file_info in scene_details['files']:
|
||||||
path = file_info['path']
|
path = file_info['path']
|
||||||
@@ -354,10 +401,12 @@ def move_or_rename_files(scene_details, new_filename, original_parent_directory)
|
|||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
log.error(f"File not found: {path}. Skipping...")
|
log.error(f"File not found: {path}. Skipping...")
|
||||||
logger.error(f"File not found: {path}. Skipping...")
|
logger.error(f"File not found: {path}. Skipping...")
|
||||||
|
exitMsg = "File not found"
|
||||||
continue
|
continue
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
log.error(f"Failed to move or rename file: {path}. Error: {e}")
|
log.error(f"Failed to move or rename file: {path}. Error: {e}")
|
||||||
logger.error(f"Failed to move or rename file: {path}. Error: {e}")
|
logger.error(f"Failed to move or rename file: {path}. Error: {e}")
|
||||||
|
exitMsg = "Failed to move or rename file"
|
||||||
continue
|
continue
|
||||||
|
|
||||||
return new_path # Return the new_path variable after the loop
|
return new_path # Return the new_path variable after the loop
|
||||||
@@ -374,7 +423,8 @@ def perform_metadata_scan(metadata_scan_path):
|
|||||||
logger.info(f"Mutation string: {mutation_metadata_scan}")
|
logger.info(f"Mutation string: {mutation_metadata_scan}")
|
||||||
graphql_request(mutation_metadata_scan)
|
graphql_request(mutation_metadata_scan)
|
||||||
|
|
||||||
def rename_scene(scene_id, wrapper_styles, stash_directory):
|
def rename_scene(scene_id, stash_directory):
|
||||||
|
global exitMsg
|
||||||
scene_details = find_scene_by_id(scene_id)
|
scene_details = find_scene_by_id(scene_id)
|
||||||
if debugTracing: logger.info(f"Debug Tracing (scene_details={scene_details})................")
|
if debugTracing: logger.info(f"Debug Tracing (scene_details={scene_details})................")
|
||||||
if not scene_details:
|
if not scene_details:
|
||||||
@@ -401,7 +451,7 @@ def rename_scene(scene_id, wrapper_styles, stash_directory):
|
|||||||
|
|
||||||
original_file_stem = Path(original_file_path).stem
|
original_file_stem = Path(original_file_path).stem
|
||||||
original_file_name = Path(original_file_path).name
|
original_file_name = Path(original_file_path).name
|
||||||
new_filename = form_filename(original_file_stem, scene_details, wrapper_styles)
|
new_filename = form_filename(original_file_stem, scene_details)
|
||||||
newFilenameWithExt = new_filename + Path(original_file_path).suffix
|
newFilenameWithExt = new_filename + Path(original_file_path).suffix
|
||||||
if debugTracing: logger.info(f"Debug Tracing (original_file_name={original_file_name})(newFilenameWithExt={newFilenameWithExt})................")
|
if debugTracing: logger.info(f"Debug Tracing (original_file_name={original_file_name})(newFilenameWithExt={newFilenameWithExt})................")
|
||||||
if original_file_name == newFilenameWithExt:
|
if original_file_name == newFilenameWithExt:
|
||||||
@@ -429,6 +479,7 @@ def rename_scene(scene_id, wrapper_styles, stash_directory):
|
|||||||
os.rename(original_file_path, new_file_path)
|
os.rename(original_file_path, new_file_path)
|
||||||
logger.info(f"{dry_run_prefix}Renamed file: {original_file_path} -> {new_file_path}")
|
logger.info(f"{dry_run_prefix}Renamed file: {original_file_path} -> {new_file_path}")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
exitMsg = "Failed to rename file"
|
||||||
log.error(f"Failed to rename file: {original_file_path}. Error: {e}")
|
log.error(f"Failed to rename file: {original_file_path}. Error: {e}")
|
||||||
logger.error(f"Failed to rename file: {original_file_path}. Error: {e}")
|
logger.error(f"Failed to rename file: {original_file_path}. Error: {e}")
|
||||||
|
|
||||||
@@ -443,10 +494,12 @@ def rename_scene(scene_id, wrapper_styles, stash_directory):
|
|||||||
hash_suffix = hashlib.md5(new_filename.encode()).hexdigest()
|
hash_suffix = hashlib.md5(new_filename.encode()).hexdigest()
|
||||||
new_filename = truncated_filename + '_' + hash_suffix + Path(original_file_path).suffix
|
new_filename = truncated_filename + '_' + hash_suffix + Path(original_file_path).suffix
|
||||||
|
|
||||||
|
if debugTracing: logger.info(f"Debug Tracing (exitMsg={exitMsg})................")
|
||||||
return new_filename, original_path_info, new_path_info
|
return new_filename, original_path_info, new_path_info
|
||||||
|
|
||||||
# Main default function for rename scene
|
# Main default function for rename scene
|
||||||
def rename_files_task():
|
def rename_files_task():
|
||||||
|
global exitMsg
|
||||||
if debugTracing: logger.info("Debug Tracing................")
|
if debugTracing: logger.info("Debug Tracing................")
|
||||||
# Execute the GraphQL query to fetch all scenes
|
# Execute the GraphQL query to fetch all scenes
|
||||||
scene_result = graphql_request(query_all_scenes)
|
scene_result = graphql_request(query_all_scenes)
|
||||||
@@ -466,10 +519,6 @@ def rename_files_task():
|
|||||||
# Extract the ID of the latest scene
|
# Extract the ID of the latest scene
|
||||||
latest_scene_id = latest_scene.get('id')
|
latest_scene_id = latest_scene.get('id')
|
||||||
|
|
||||||
|
|
||||||
# Extract wrapper styles
|
|
||||||
wrapper_styles = config["wrapper_styles"]
|
|
||||||
|
|
||||||
# Read stash directory from renamefile_settings.py
|
# Read stash directory from renamefile_settings.py
|
||||||
stash_directory = config.get('stash_directory', '')
|
stash_directory = config.get('stash_directory', '')
|
||||||
if debugTracing: logger.info("Debug Tracing................")
|
if debugTracing: logger.info("Debug Tracing................")
|
||||||
@@ -477,8 +526,8 @@ def rename_files_task():
|
|||||||
if debugTracing: logger.info("Debug Tracing................")
|
if debugTracing: logger.info("Debug Tracing................")
|
||||||
|
|
||||||
# Rename the latest scene and trigger metadata scan
|
# Rename the latest scene and trigger metadata scan
|
||||||
new_filename = rename_scene(latest_scene_id, wrapper_styles, stash_directory)
|
new_filename = rename_scene(latest_scene_id, stash_directory)
|
||||||
if debugTracing: logger.info("Debug Tracing................")
|
if debugTracing: logger.info(f"Debug Tracing (exitMsg={exitMsg})................")
|
||||||
|
|
||||||
# Log dry run state and indicate if no changes were made
|
# Log dry run state and indicate if no changes were made
|
||||||
if dry_run:
|
if dry_run:
|
||||||
@@ -487,7 +536,7 @@ def rename_files_task():
|
|||||||
elif not new_filename:
|
elif not new_filename:
|
||||||
logger.info("No changes were made.")
|
logger.info("No changes were made.")
|
||||||
else:
|
else:
|
||||||
logger.info("Change success!")
|
logger.info(f"{exitMsg}")
|
||||||
return
|
return
|
||||||
|
|
||||||
def fetch_dup_filename_tags(): # Place holder for new implementation
|
def fetch_dup_filename_tags(): # Place holder for new implementation
|
||||||
@@ -497,7 +546,7 @@ if PLUGIN_ARGS == "fetch_dup_filename_tags":
|
|||||||
fetch_dup_filename_tags()
|
fetch_dup_filename_tags()
|
||||||
elif PLUGIN_ARGS == "rename_files_task":
|
elif PLUGIN_ARGS == "rename_files_task":
|
||||||
rename_files_task()
|
rename_files_task()
|
||||||
else:
|
elif inputToUpdateScenePost:
|
||||||
rename_files_task()
|
rename_files_task()
|
||||||
|
|
||||||
if debugTracing: logger.info("\n*********************************\nEXITING ***********************\n*********************************")
|
if debugTracing: logger.info("\n*********************************\nEXITING ***********************\n*********************************")
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
name: RenameFile
|
name: RenameFile
|
||||||
description: Renames video (scene) file names when the user edits the [Title] field located in the scene [Edit] tab.
|
description: Renames video (scene) file names when the user edits the [Title] field located in the scene [Edit] tab.
|
||||||
version: 0.3.0
|
# By David Maisonave (aka Axter) 2024
|
||||||
|
version: 0.4.0
|
||||||
url: https://github.com/David-Maisonave/Axter-Stash/tree/main/plugins/RenameFile
|
url: https://github.com/David-Maisonave/Axter-Stash/tree/main/plugins/RenameFile
|
||||||
settings:
|
settings:
|
||||||
performerAppend:
|
performerAppend:
|
||||||
@@ -25,7 +26,7 @@ settings:
|
|||||||
type: BOOLEAN
|
type: BOOLEAN
|
||||||
zfieldKeyList:
|
zfieldKeyList:
|
||||||
displayName: Key Fields
|
displayName: Key Fields
|
||||||
description: '(Default=title,performers,studio,tags) Define key fields to use to format the file name. This is a comma seperated list, and the list should be in the desired format order. For example, if the user wants the performers name before the title, set the performers name first. Example:"performers,title,tags". This is an example of user adding height:"title,performers,tags,height" Here''s an example using all of the supported fields: "title,performers,tags,studio,galleries,date,height,video_codec,frame_rate".'
|
description: '(Default=title,performers,studio,tags) Define key fields to use to format the file name. This is a comma seperated list, and the list should be in the desired format order. For example, if the user wants the performers name before the title, set the performers name first. Example:"performers,title,tags". This is an example of user adding height:"title,performers,tags,height" Here''s an example using all of the supported fields: "title,performers,tags,studio,galleries,resolution,width,height,video_codec,frame_rate,date".'
|
||||||
type: STRING
|
type: STRING
|
||||||
zgraphqlEndpoint:
|
zgraphqlEndpoint:
|
||||||
displayName: GraphQL Endpoint
|
displayName: GraphQL Endpoint
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# Importing config dictionary
|
# By David Maisonave (aka Axter) 2024
|
||||||
# RenameFile plugin main configuration options are available on the Stash GUI under Settings->Plugins->Plugins->[RenameFile].
|
# RenameFile plugin main configuration options are available on the Stash GUI under Settings->Plugins->Plugins->[RenameFile].
|
||||||
# Most users should only use the GUI options.
|
# Most users should only use the GUI options.
|
||||||
# The configuration options in this file are for advanced users ONLY!!!
|
# The configuration options in this file are for advanced users ONLY!!!
|
||||||
@@ -9,16 +9,33 @@
|
|||||||
config = {
|
config = {
|
||||||
# Define wrapper styles for different parts of the filename.
|
# Define wrapper styles for different parts of the filename.
|
||||||
# Use '[]' for square brackets, '{}' for curly brackets, '()' for parentheses, or an empty string for None.
|
# Use '[]' for square brackets, '{}' for curly brackets, '()' for parentheses, or an empty string for None.
|
||||||
"wrapper_styles": {
|
"wrapper_styles": { # Modify these values to change how each part of the filename is wrapped.
|
||||||
"studio": '{}', # Modify these values to change how each part of the filename is wrapped.
|
"title": '',
|
||||||
"title": '', # Use '[]' for square brackets, '{}' for curly brackets, '()' for parentheses, or an empty string for None.
|
|
||||||
"performers": '()',
|
"performers": '()',
|
||||||
|
"tag": '[]',
|
||||||
|
"studio": '{}',
|
||||||
"galleries": '()',
|
"galleries": '()',
|
||||||
"date": '()',
|
"resolution": '', # Contains both WITH and HEIGHT
|
||||||
|
"width": '',
|
||||||
"height": '',
|
"height": '',
|
||||||
"video_codec": '',
|
"video_codec": '',
|
||||||
"frame_rate": '',
|
"frame_rate": '',
|
||||||
"tag": '[]'
|
"date": '()', # This field is not populated in the DB by default. It's usually empty.
|
||||||
|
},
|
||||||
|
# Define the field postfix
|
||||||
|
"postfix_styles": {
|
||||||
|
"title": '',
|
||||||
|
"performers": '',
|
||||||
|
"tag": '',
|
||||||
|
"studio": '',
|
||||||
|
"galleries": '',
|
||||||
|
"resolution": 'P', # Contains both WITH and HEIGHT
|
||||||
|
"width": 'W',
|
||||||
|
"height": 'P',
|
||||||
|
"width_height_seperator": 'x', # Used in RESOLUTION field as the string seperating WITH and HEIGHT. Example: 720x480 or 1280X720
|
||||||
|
"video_codec": '',
|
||||||
|
"frame_rate": 'FR',
|
||||||
|
"date": '',
|
||||||
},
|
},
|
||||||
# Define whether files should be renamed when moved
|
# Define whether files should be renamed when moved
|
||||||
"rename_files": True,
|
"rename_files": True,
|
||||||
|
|||||||
Reference in New Issue
Block a user