Advertisement
Guest User

Untitled

a guest
Oct 29th, 2024
1,180
0
Never
4
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.93 KB | None | 0 0
  1. import obspython as obs
  2. from shutil import move
  3. import os
  4. import time
  5. import logging
  6.  
  7. # Output paths and search strings
  8. output_paths = {
  9. "anythingelse": "D:/vods/anything-else",
  10. "bridges": "D:/vods/bridges",
  11. "destinystudio": "D:/vods/destiny-stream",
  12. "saturdaymorning": "D:/vods/saturday-morning"
  13. }
  14.  
  15. # Set up logging to a file
  16. log_file = "obs_recording_move.log"
  17. logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")
  18. file_handler = logging.FileHandler(log_file)
  19. file_handler.setLevel(logging.INFO)
  20. formatter = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s")
  21. file_handler.setFormatter(formatter)
  22. logger = logging.getLogger()
  23. logger.addHandler(file_handler)
  24.  
  25. # Description of the script for OBS
  26. def script_description():
  27. """Return the plugin description."""
  28. return "This plugin moves the recorded file to a specified folder after recording stops, based on keywords in the filename."
  29.  
  30. # Hook to connect recording stop signal
  31. def script_load(settings):
  32. """Hook stop recording signal on plugin load."""
  33. signal_handler = obs.obs_output_get_signal_handler(
  34. obs.obs_frontend_get_recording_output()
  35. )
  36. obs.signal_handler_connect(signal_handler, "stop", signal_handler_function)
  37.  
  38. # Update function to set output paths and search strings dynamically
  39. def script_update(settings):
  40. """Called when script settings are updated."""
  41. global output_paths
  42. output_paths = {
  43. "anythingelse": obs.obs_data_get_string(settings, "search_string1"),
  44. "bridges": obs.obs_data_get_string(settings, "search_string2"),
  45. "destinystudio": obs.obs_data_get_string(settings, "search_string3"),
  46. "saturdaymorning": obs.obs_data_get_string(settings, "search_string4")
  47. }
  48.  
  49. # Property panel for OBS interface configuration
  50. def script_properties():
  51. """Define properties for OBS interface configuration."""
  52. props = obs.obs_properties_create()
  53.  
  54. obs.obs_properties_add_text(props, "search_string1", "Keyword for Output 1", obs.OBS_TEXT_DEFAULT)
  55. obs.obs_properties_add_path(props, "output_path1", "Output Folder 1", obs.OBS_PATH_DIRECTORY, "", "")
  56.  
  57. obs.obs_properties_add_text(props, "search_string2", "Keyword for Output 2", obs.OBS_TEXT_DEFAULT)
  58. obs.obs_properties_add_path(props, "output_path2", "Output Folder 2", obs.OBS_PATH_DIRECTORY, "", "")
  59.  
  60. obs.obs_properties_add_text(props, "search_string3", "Keyword for Output 3", obs.OBS_TEXT_DEFAULT)
  61. obs.obs_properties_add_path(props, "output_path3", "Output Folder 3", obs.OBS_PATH_DIRECTORY, "", "")
  62.  
  63. obs.obs_properties_add_text(props, "search_string4", "Keyword for Output 4", obs.OBS_TEXT_DEFAULT)
  64. obs.obs_properties_add_path(props, "output_path4", "Output Folder 4", obs.OBS_PATH_DIRECTORY, "", "")
  65.  
  66. return props
  67.  
  68. # Signal handler for recording stop
  69. def signal_handler_function(calldata):
  70. """Handle the recording stop signal and move the file accordingly."""
  71. try:
  72. last_recording = obs.obs_frontend_get_last_recording()
  73.  
  74. # Wait for the file to be fully available
  75. time.sleep(5)
  76.  
  77. if not last_recording or not os.path.exists(last_recording):
  78. logger.error(f"Recording file not found: {last_recording}")
  79. return
  80.  
  81. # Move the file based on matching keyword
  82. for keyword, output_path in output_paths.items():
  83. if keyword.lower() in last_recording.lower():
  84. if os.path.exists(output_path):
  85. move(last_recording, output_path)
  86. logger.info(f"Moved file to: {output_path}")
  87. else:
  88. logger.error(f"Output path does not exist: {output_path}")
  89. break
  90. else:
  91. logger.warning(f"No keyword match found for recording: {last_recording}")
  92.  
  93. except Exception as e:
  94. logger.error(f"Error occurred during file move: {e}")
Advertisement
Comments
  • lildazeez
    231 days
    # text 5.76 KB | 1 0
    1. import obspython as obs
    2. from shutil import move
    3. import os
    4. import time
    5. import logging
    6. from typing import Dict, Optional
    7. import re
    8.  
    9. class VODMover:
    10. def __init__(self):
    11. # Output paths and search strings with default values
    12. self.output_paths: Dict[str, str] = {
    13. "anythingelse": "D:/vods/anything-else",
    14. "bridges": "D:/vods/bridges",
    15. "destinystudio": "D:/vods/destiny-stream",
    16. "saturdaymorning": "D:/vods/saturday-morning"
    17. }
    18.  
    19. # Initialize logging
    20. self.setup_logging()
    21.  
    22. def setup_logging(self) -> None:
    23. """Set up logging configuration"""
    24. log_file = "obs_recording_move.log"
    25. logging.basicConfig(
    26. level=logging.INFO,
    27. format="%(asctime)s - %(levelname)s - %(message)s",
    28. handlers=[
    29. logging.FileHandler(log_file),
    30. logging.StreamHandler() # Also log to console
    31. ]
    32. )
    33. self.logger = logging.getLogger(__name__)
    34.  
    35. def move_recording(self, recording_path: str) -> None:
    36. """
    37. Move recording to appropriate folder based on filename patterns
    38. """
    39. if not recording_path or not os.path.exists(recording_path):
    40. self.logger.error(f"Invalid recording path: {recording_path}")
    41. return
    42.  
    43. try:
    44. filename = os.path.basename(recording_path).lower()
    45. destination = self._get_destination_folder(filename)
    46.  
    47. if destination:
    48. self._perform_move(recording_path, destination)
    49. else:
    50. self.logger.warning(f"No matching folder found for: {filename}")
    51. # Move to anything-else folder as fallback
    52. self._perform_move(recording_path, self.output_paths["anythingelse"])
    53.  
    54. except Exception as e:
    55. self.logger.error(f"Error processing recording {recording_path}: {str(e)}")
    56.  
    57. def _get_destination_folder(self, filename: str) -> Optional[str]:
    58. """
    59. Determine destination folder based on filename patterns
    60. """
    61. patterns = {
    62. "bridges": r"bridge|bridges",
    63. "destinystudio": r"destiny|studio",
    64. "saturdaymorning": r"saturday|morning|weekend"
    65. }
    66.  
    67. for key, pattern in patterns.items():
    68. if re.search(pattern, filename, re.IGNORECASE):
    69. return self.output_paths[key]
    70.  
    71. return None
    72.  
    73. def _perform_move(self, source: str, destination: str) -> None:
    74. """
    75. Perform the actual file move operation
    76. """
    77. if not os.path.exists(destination):
    78. os.makedirs(destination, exist_ok=True)
    79. self.logger.info(f"Created destination directory: {destination}")
    80.  
    81. try:
    82. # Wait for file to be fully written
    83. time.sleep(5)
    84.  
    85. # Get destination filepath
    86. dest_path = os.path.join(destination, os.path.basename(source))
    87.  
    88. # Handle existing files
    89. if os.path.exists(dest_path):
    90. base, ext = os.path.splitext(dest_path)
    91. counter = 1
    92. while os.path.exists(f"{base}_{counter}{ext}"):
    93. counter += 1
    94. dest_path = f"{base}_{counter}{ext}"
    95.  
    96. move(source, dest_path)
    97. self.logger.info(f"Successfully moved {source} to {dest_path}")
    98.  
    99. except Exception as e:
    100. self.logger.error(f"Failed to move file {source}: {str(e)}")
    101.  
    102. # Global instance of VODMover
    103. vod_mover = VODMover()
    104.  
    105. def script_description():
    106. """Return the script description for OBS"""
    107. return "Automatically moves VOD recordings to categorized folders based on filename patterns"
    108.  
    109. def script_load(settings):
    110. """Hook stop recording signal on script load"""
    111. signal_handler = obs.obs_output_get_signal_handler(
    112. obs.obs_frontend_get_recording_output()
    113. )
    114. obs.signal_handler_connect(signal_handler, "stop", on_recording_stop)
    115.  
    116. def script_update(settings):
    117. """Update paths when settings are changed"""
    118. global vod_mover
    119.  
    120. # Update paths from OBS settings
    121. vod_mover.output_paths = {
    122. "anythingelse": obs.obs_data_get_string(settings, "anything_else_path"),
    123. "bridges": obs.obs_data_get_string(settings, "bridges_path"),
    124. "destinystudio": obs.obs_data_get_string(settings, "destiny_path"),
    125. "saturdaymorning": obs.obs_data_get_string(settings, "saturday_path")
    126. }
    127.  
    128. def script_properties():
    129. """Define properties for OBS interface"""
    130. props = obs.obs_properties_create()
    131.  
    132. # Add path properties for each category
    133. obs.obs_properties_add_path(
    134. props, "anything_else_path",
    135. "Anything Else Path",
    136. obs.OBS_PATH_DIRECTORY,
    137. "", "D:/vods/anything-else"
    138. )
    139. obs.obs_properties_add_path(
    140. props, "bridges_path",
    141. "Bridges Path",
    142. obs.OBS_PATH_DIRECTORY,
    143. "", "D:/vods/bridges"
    144. )
    145. obs.obs_properties_add_path(
    146. props, "destiny_path",
    147. "Destiny Studio Path",
    148. obs.OBS_PATH_DIRECTORY,
    149. "", "D:/vods/destiny-stream"
    150. )
    151. obs.obs_properties_add_path(
    152. props, "saturday_path",
    153. "Saturday Morning Path",
    154. obs.OBS_PATH_DIRECTORY,
    155. "", "D:/vods/saturday-morning"
    156. )
    157.  
    158. return props
    159.  
    160. def on_recording_stop(calldata):
    161. """Handle recording stop event"""
    162. try:
    163. recording_path = obs.obs_frontend_get_last_recording()
    164. vod_mover.move_recording(recording_path)
    165. except Exception as e:
    166. logging.error(f"Error in recording stop handler: {str(e)}")
  • Thuggernaut58
    231 days
    # text 3.51 KB | 0 0
    1. import obspython as obs
    2. from shutil import move
    3. import os
    4. import time
    5. import logging
    6.  
    7. # Change the log file location to a user-writable directory
    8. log_file = os.path.join(os.path.expanduser("~"), "obs_recording_move.log")
    9.  
    10. # Output paths and search strings (set dynamically)
    11. output_paths = {}
    12.  
    13. # Set up logging to a file
    14. logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")
    15. logger = logging.getLogger(__name__)
    16.  
    17. # Ensure logging to a file as well
    18. file_handler = logging.FileHandler(log_file)
    19. file_handler.setFormatter(logging.Formatter("%(asctime)s - %(levelname)s - %(message)s"))
    20. logger.addHandler(file_handler)
    21.  
    22. # Description of the script for OBS
    23. def script_description():
    24. """Return the plugin description."""
    25. return "This plugin moves the recorded file to a specified folder after recording stops, based on keywords in the filename."
    26.  
    27. # Hook to connect recording stop signal
    28. def script_load(settings):
    29. """Hook the recording stop signal when the plugin loads."""
    30. signal_handler = obs.obs_output_get_signal_handler(
    31. obs.obs_frontend_get_recording_output()
    32. )
    33. obs.signal_handler_connect(signal_handler, "stop", signal_handler_function)
    34.  
    35. # Update function to set output paths and search strings dynamically
    36. def script_update(settings):
    37. """Called when script settings are updated."""
    38. global output_paths
    39. output_paths.clear()
    40.  
    41. # Retrieve settings from the OBS properties panel
    42. for i in range(1, 5):
    43. keyword = obs.obs_data_get_string(settings, f"search_string{i}")
    44. output_path = obs.obs_data_get_string(settings, f"output_path{i}")
    45.  
    46. if keyword and output_path:
    47. output_paths[keyword] = output_path
    48.  
    49. # Property panel for OBS interface configuration
    50. def script_properties():
    51. """Define properties for OBS interface configuration."""
    52. props = obs.obs_properties_create()
    53.  
    54. # Add fields for up to 4 keyword-folder pairs
    55. for i in range(1, 5):
    56. obs.obs_properties_add_text(
    57. props, f"search_string{i}", f"Keyword for Output {i}", obs.OBS_TEXT_DEFAULT
    58. )
    59. obs.obs_properties_add_path(
    60. props, f"output_path{i}", f"Output Folder {i}", obs.OBS_PATH_DIRECTORY, "", ""
    61. )
    62.  
    63. return props
    64.  
    65. # Signal handler for recording stop
    66. def signal_handler_function(calldata):
    67. """Handle the recording stop signal and move the file accordingly."""
    68. try:
    69. last_recording = obs.obs_frontend_get_last_recording()
    70.  
    71. # Wait a bit to ensure the file is available
    72. time.sleep(5)
    73.  
    74. if not last_recording or not os.path.exists(last_recording):
    75. logger.error(f"Recording file not found: {last_recording}")
    76. return
    77.  
    78. # Move the file based on keyword matching
    79. for keyword, output_path in output_paths.items():
    80. if keyword.lower() in os.path.basename(last_recording).lower():
    81. # Ensure the output path exists
    82. os.makedirs(output_path, exist_ok=True)
    83.  
    84. destination = os.path.join(output_path, os.path.basename(last_recording))
    85. move(last_recording, destination)
    86.  
    87. logger.info(f"Moved file to: {destination}")
    88. return # Exit once the file is moved successfully
    89.  
    90. # If no matching keyword was found
    91. logger.warning(f"No keyword match found for recording: {last_recording}")
    92.  
    93. except Exception as e:
    94. logger.error(f"Error occurred during file move: {e}")
    95.  
  • KRACK_BIT
    231 days
    Comment was deleted
  • # Python 7.05 KB | 0 0
    1. #!/usr/bin/env python3
    2. # Original: <https://pastebin.com/xsUhLTtH>
    3. """
    4. Moves a recording file when filename matches match_keyword X to output_folder Y
    5.  
    6. Created by `Sateviss` :chatting:
    7. Refactored and cleaned by `JohnSmith`
    8. """
    9.  
    10. import logging
    11. from pathlib import Path
    12. from time import sleep
    13. from typing import NamedTuple
    14.  
    15. import obspython as obs
    16.  
    17. # Configuration constants
    18. NUM_OF_MATCHES = 4
    19. """Number of match strings to be configurable in OBS"""
    20.  
    21. NUM_OF_POLL_TRIES = 15
    22. """Num of polls to try between OBS signal and moving the file."""
    23. POLL_WAIT_TIME = 1
    24. """Seconds to wait between each file poll."""
    25.  
    26. LOG_FORMAT = "%(asctime)s | %(name)s | %(levelname)s | %(message)s"
    27. """Logging format for the script."""
    28. LOG_LEVEL = logging.INFO
    29. """Logging level for stdout."""
    30. LOG_FILEPATH = Path.home() / "obs_recording_migration_script.log"
    31. """Logging file path for the script."""
    32.  
    33.  
    34. # Data classes
    35. class RecordingMatchCase(NamedTuple):
    36.     """Entry type to encode a match case for recording migration."""
    37.  
    38.     match_keyword: str
    39.     """Keyword to match against the recording filename."""
    40.  
    41.     output_folder: Path
    42.     """Output folder to move the recording file to."""
    43.  
    44.  
    45. # Initialisation functions
    46. def init_logger() -> logging.Logger:
    47.     """Initialises a logger object for the script."""
    48.  
    49.     print("Initialising logger object...")
    50.  
    51.     # Setup logging to stdout
    52.     logging.basicConfig(level=LOG_LEVEL, format=LOG_FORMAT)
    53.     logger = logging.getLogger(__name__)
    54.  
    55.     # Setup logging to logfile
    56.     file_handler = logging.FileHandler(LOG_FILEPATH)
    57.     file_handler.setFormatter(logging.Formatter(LOG_FORMAT))
    58.  
    59.     # Join logging handlers together
    60.     logger.addHandler(file_handler)
    61.  
    62.     logger.info(f"Logger initialized! {LOG_FILEPATH=}")
    63.     return logger
    64.  
    65.  
    66. # Global mutable variables
    67. script_logger = init_logger()
    68. """Logger object for the script."""
    69. recording_migrate_mappings: set[RecordingMatchCase] = set()
    70. """Mapping of match strings to output paths."""
    71.  
    72.  
    73. # ================================
    74. # OBS invocation hooks
    75. # ================================
    76. def script_description() -> str:
    77.     """Return the plugin description string."""
    78.     # Just re-using the script docstring; see top of file
    79.     return __doc__ if __doc__ is not None else ""
    80.  
    81.  
    82. def script_load(settings) -> None:
    83.     """Initialises hook for stop recording signal during plugin load."""
    84.  
    85.     script_logger.debug("Attaching handler...")
    86.  
    87.     try:
    88.         obs_frontend = obs.obs_frontend_get_recording_output()
    89.         signal_handler = obs.obs_output_get_signal_handler(obs_frontend)
    90.  
    91.         obs.signal_handler_connect(signal_handler, "stop", signal_handler_function)
    92.  
    93.     except Exception as err:
    94.         script_logger.error(f"Error occurred during handler attachment: {err}")
    95.         raise err
    96.  
    97.     script_logger.info("Script handler hook was successfully attached!")
    98.  
    99.  
    100. def script_properties():
    101.     """Hook to setup initial OBS properties for the script."""
    102.  
    103.     script_logger.info("Setting up OBS properties...")
    104.  
    105.     # global NUM_OF_MATCHES
    106.     props = obs.obs_properties_create()
    107.  
    108.     for i in range(NUM_OF_MATCHES):
    109.  
    110.         obs.obs_properties_add_text(
    111.             props, f"match{i}", f"Match {i + 1}", obs.OBS_TEXT_DEFAULT
    112.         )
    113.         obs.obs_properties_add_path(
    114.             props, f"path{i}", f"Path {i + 1}", obs.OBS_PATH_DIRECTORY, None, None
    115.         )
    116.  
    117.     return props
    118.  
    119.  
    120. def script_update(settings) -> None:
    121.     """Hook to update recording patterns"""
    122.  
    123.     # global NUM_OF_MATCHES
    124.     global recording_migrate_mappings
    125.  
    126.     for i in range(NUM_OF_MATCHES):
    127.  
    128.         new_match_entry = RecordingMatchCase(
    129.             match_keyword=obs.obs_data_get_string(settings, f"match{i}"),
    130.             output_folder=Path(obs.obs_data_get_string(settings, f"path{i}")),
    131.         )
    132.  
    133.         recording_migrate_mappings.add(new_match_entry)
    134.         script_logger.debug(f"Loaded matcher {i}:", new_match_entry)
    135.  
    136.  
    137. def signal_handler_function(calldata) -> None:
    138.     """Handles the recording stop signal and moves the file accordingly."""
    139.     # global recording_migrate_mappings
    140.  
    141.     script_logger.info("Handler triggered! Running recording migration hook...")
    142.  
    143.     try:
    144.  
    145.         # Get the last recording file path
    146.         orig_recording_raw: str = obs.obs_frontend_get_last_recording()
    147.         if not orig_recording_raw:
    148.             script_logger.error(
    149.                 f"No recording file path was returned by OBS: {orig_recording_raw=}",
    150.             )
    151.             return
    152.         orig_recording: Path = Path(orig_recording_raw)
    153.         script_logger.debug(f"Recording file path: {orig_recording=}")
    154.  
    155.         # Wait for the file to be fully available
    156.         for poll_i in range(NUM_OF_POLL_TRIES):
    157.             sleep(POLL_WAIT_TIME)
    158.             if orig_recording.exists():
    159.                 break
    160.             script_logger.debug(f"Recording file not found yet: {poll_i=}")
    161.         else:
    162.             script_logger.error(f"Recording file cannot be found: {orig_recording=}")
    163.             # TODO: turn these returns into error raises?
    164.             return
    165.  
    166.         script_logger.info(f"Valid initial recording file given! {orig_recording=}")
    167.         script_logger.debug("Trying to match file...")
    168.  
    169.         # Find matching file migration mapping
    170.         for mapping in recording_migrate_mappings:
    171.  
    172.             # Checking if the current match is valid...
    173.             if mapping.match_keyword.casefold() not in orig_recording.name.casefold():
    174.                 script_logger.debug(f"Not a match! {mapping=}")
    175.                 continue
    176.  
    177.             script_logger.info(f"Suitable match found: matcher={mapping}")
    178.  
    179.             # Checking if the matching output folder is currently valid
    180.             # NOTE: if this gets race conditioned somehow, just throw everything below into a retry loop
    181.             if not mapping.output_folder.exists():
    182.                 script_logger.error(
    183.                     f"Output path does not exist: {mapping.output_folder=}"
    184.                 )
    185.                 break
    186.  
    187.             if not mapping.output_folder.is_dir():
    188.                 script_logger.error(
    189.                     f"Output Path is not actually a directory: {mapping.output_folder=}"
    190.                 )
    191.                 break
    192.  
    193.             # Constructing the new recording path
    194.             new_recording_path = mapping.output_folder / orig_recording.name
    195.             script_logger.debug(
    196.                 f"Valid resulting recording path constructed: {new_recording_path}"
    197.             )
    198.  
    199.             script_logger.debug("Attempting file migration...")
    200.             orig_recording.rename(new_recording_path)
    201.             script_logger.info(
    202.                 f"Recording file has been migrated to: {new_recording_path}"
    203.             )
    204.             break
    205.  
    206.         else:
    207.             script_logger.error(
    208.                 f"No keyword match found for recording: {orig_recording}"
    209.             )
    210.  
    211.     except Exception as err:
    212.         script_logger.error(f"Error occurred during file migration hook: {err}")
    213.         # TODO: should error messages be chained up to OBS itself?
    214.         # raise err
    215.  
Add Comment
Please, Sign In to add comment
Advertisement