-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmove_nas_videos.py
89 lines (80 loc) · 3.61 KB
/
move_nas_videos.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#!/usr/bin/env python3
import os
import time
import shutil
import logging
import errno
from logging.handlers import RotatingFileHandler
from datetime import datetime
# ---------------------------------------------------------------------------
# 1. Logging Setup
# ---------------------------------------------------------------------------
logger = logging.getLogger("Mover")
logger.setLevel(logging.INFO)
# Console handler
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.INFO)
formatter = logging.Formatter("%(asctime)s - %(levelname)s - [Mover] %(message)s")
console_handler.setFormatter(formatter)
logger.addHandler(console_handler)
# File handler with rotation
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
log_file = f"/logs/move_nas_videos_{timestamp}.log" # Change this to your desired log file path
file_handler = RotatingFileHandler(log_file, maxBytes=10*1024*1024, backupCount=5)
file_handler.setLevel(logging.INFO)
file_handler.setFormatter(formatter)
logger.addHandler(file_handler)
# ---------------------------------------------------------------------------
# 2. Configuration (via environment variables, or defaults)
# ---------------------------------------------------------------------------
NAS_DIR = os.environ.get("NAS_DIR", "/nas") # Path where NAS share is mounted (inside container)
LOCAL_DIR = os.environ.get("LOCAL_DIR", "/videos") # Local folder to move files to
MOVE_INTERVAL = int(os.environ.get("MOVE_INTERVAL", "60")) # How often to poll (seconds)
# ---------------------------------------------------------------------------
# 3. Function to handle cross-device move
# ---------------------------------------------------------------------------
def cross_device_move(source, dest):
"""
Moves a file even if source and dest are on different devices
by doing a copy + remove fallback upon EXDEV.
"""
try:
shutil.move(source, dest)
except OSError as e:
# If the error is EXDEV, it means "Invalid cross-device link" (can't do a simple rename).
if e.errno == errno.EXDEV:
logger.info(f"[CrossDevice] Using copy+remove for {source} -> {dest}")
shutil.copy2(source, dest)
os.remove(source)
else:
raise
# ---------------------------------------------------------------------------
# 4. Logic: Move .MOV files from NAS_DIR to LOCAL_DIR
# ---------------------------------------------------------------------------
def move_new_videos():
"""
Moves all .MOV files from NAS_DIR to LOCAL_DIR (if they don't already exist).
Skips hidden files and uses cross_device_move() to handle potential EXDEV errors.
"""
for entry in os.scandir(NAS_DIR):
# Skip directories and hidden files
if entry.is_file() and not entry.name.startswith('.') and entry.name.lower().endswith('.mov'):
source = os.path.join(NAS_DIR, entry.name)
dest = os.path.join(LOCAL_DIR, entry.name)
# Only move if the file doesn't already exist at dest
if not os.path.exists(dest):
logger.info(f"Moving {source} -> {dest}")
try:
cross_device_move(source, dest)
except Exception as err:
logger.error(f"Error moving {source}: {err}")
else:
if entry.name.startswith('.'):
logger.info(f"Skipped hidden file: {entry.name}")
def main():
logger.info(f"Starting poll loop. NAS: {NAS_DIR}, Local: {LOCAL_DIR}, Interval: {MOVE_INTERVAL}s")
while True:
move_new_videos()
time.sleep(MOVE_INTERVAL)
if __name__ == "__main__":
main()