Refresh and added usage tracking
This commit is contained in:
1 parent
8519d9f62e
commit
477b1bf985
45 files changed
+721
-161
No files matched your search
@@ -16,6 +16,8 @@ if [[ ! -d "$folder" ]]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
/home/honney/.bin/tracker.py add append
|
||||
|
||||
# Process files
|
||||
for file in "$folder"/*; do
|
||||
[[ -f "$file" ]] || continue # skip non-files
|
||||
|
||||
Executable
+112
@@ -0,0 +1,112 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Usage:
|
||||
python3 count_files (<number>) (<directory>)
|
||||
python3 count_files (<number>) (<directory>) --undo
|
||||
"""
|
||||
|
||||
import os
|
||||
from pathlib import Path
|
||||
import sys
|
||||
import re
|
||||
from termcolor import colored
|
||||
|
||||
|
||||
VIDEO_EXTENSIONS = {
|
||||
".mkv", ".mp4", ".avi", ".mov", ".wmv", ".flv", ".webm", ".m4v"
|
||||
}
|
||||
|
||||
|
||||
def main():
|
||||
args = sys.argv[1:]
|
||||
|
||||
undo = "--undo" in args
|
||||
if undo:
|
||||
args.remove("--undo")
|
||||
|
||||
if len(args) == 0:
|
||||
number = 0
|
||||
directory = Path(os.getcwd())
|
||||
elif len(args) == 1:
|
||||
try:
|
||||
number = int(args[0])
|
||||
directory = Path(os.getcwd())
|
||||
except:
|
||||
number = 0
|
||||
directory = Path(args[0])
|
||||
elif len(args) == 2:
|
||||
try:
|
||||
number = int(args[0])
|
||||
directory = Path(args[1])
|
||||
except:
|
||||
number = int(args[1])
|
||||
directory = Path(args[0])
|
||||
else:
|
||||
print("Usage: recount_videos.py (<directory>) [--undo]")
|
||||
sys.exit(1)
|
||||
|
||||
if not directory.exists():
|
||||
print(colored("Directory does not exist", "red"))
|
||||
sys.exit(1)
|
||||
|
||||
import subprocess
|
||||
subprocess.run(["python", "/home/honney/.bin/tracker.py", "add", "count_files"])
|
||||
|
||||
files = sorted(
|
||||
[f for f in directory.iterdir()
|
||||
if f.is_file() and f.suffix.lower() in VIDEO_EXTENSIONS],
|
||||
key=lambda f: f.name
|
||||
)
|
||||
|
||||
if not files:
|
||||
print(colored("No video files found", "yellow"))
|
||||
return
|
||||
|
||||
if undo:
|
||||
# detect prefix like "00", "001", etc.
|
||||
pattern = re.compile(r"^\d+")
|
||||
|
||||
for f in files:
|
||||
if not pattern.match(f.name):
|
||||
continue
|
||||
|
||||
new_name = Path(directory / pattern.sub("", f.name, count=1))
|
||||
|
||||
if new_name.exists():
|
||||
print(colored(f"Conflict exists: {new_name.name}", "red"))
|
||||
continue
|
||||
|
||||
print(
|
||||
colored("Restored: ", "green") +
|
||||
colored(f.name, "red") +
|
||||
colored(" -> ", "white") +
|
||||
colored(new_name.name, "green")
|
||||
)
|
||||
|
||||
f.rename(new_name)
|
||||
|
||||
else:
|
||||
max_len = max(len(str(len(files))), 2)
|
||||
|
||||
for i, f in enumerate(files):
|
||||
if number:
|
||||
new_name = Path(f"{f.parent}/{i+number:0{max_len}d}{f.name}")
|
||||
else:
|
||||
new_name = Path(f"{f.parent}/{i+1:0{max_len}d}{f.name}")
|
||||
|
||||
if new_name.exists():
|
||||
print(colored(f"Exists, skipping: {new_name.name}", "red"))
|
||||
continue
|
||||
|
||||
print(
|
||||
colored("Renamed: ", "green") +
|
||||
colored(f.name, "red") +
|
||||
colored(" -> ", "white") +
|
||||
colored(new_name.name, "green")
|
||||
)
|
||||
|
||||
f.rename(new_name)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -29,6 +29,8 @@ else
|
||||
SYMBOL="_" # Default separator is "_"
|
||||
fi
|
||||
|
||||
/home/honney/.bin/tracker.py add create_folder_counting
|
||||
|
||||
# Ensure the target directory exists
|
||||
mkdir -p "$TARGET_DIR"
|
||||
|
||||
|
||||
@@ -6,6 +6,8 @@ if [ "$#" -lt 2 ] || [ "$#" -gt 3 ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
/home/honney/.bin/tracker.py add create_folder_date
|
||||
|
||||
# Set folder path
|
||||
if [ "$#" -eq 3 ]; then
|
||||
TARGET_DIR="$1"
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
ff,2
|
||||
simple_ffprobe_script,1
|
||||
show_path,2
|
||||
append,15
|
||||
deappend,17
|
||||
rename_to_first_n,3
|
||||
count_files,4
|
||||
remove_fname_last_n,2
|
||||
|
@@ -63,6 +63,8 @@ def main():
|
||||
if len(sys.argv) < 3:
|
||||
print("Usage: deappend.py <mode> <string> [directory]")
|
||||
sys.exit(1)
|
||||
import subprocess
|
||||
subprocess.run(["python", "/home/honney/.bin/tracker.py", "add", "deappend"])
|
||||
|
||||
# Get arguments
|
||||
mode = sys.argv[1] # Mode: back, front, ext/extension
|
||||
|
||||
@@ -9,6 +9,8 @@ if [ ! -f "$INPUT" ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
/home/honney/.bin/tracker.py add deinterlace_cpu
|
||||
|
||||
# Step 1: Try runtime detection with idet
|
||||
ffmpeg -hide_banner -vstats -nostats \
|
||||
-i "$INPUT" \
|
||||
|
||||
@@ -4,6 +4,8 @@ INPUT="$HOME/mount/Ripping/Lutz/noch zu rendern/Brücke nach Terabithia/A1_t00.m
|
||||
OTPUT="${INPUT%.*}_deinterlaced_vaapi.mp4"
|
||||
TEMP_STATS=$(mktemp)
|
||||
|
||||
/home/honney/.bin/tracker.py add deinterlace_gpu
|
||||
|
||||
ffmpeg -filter:v idet -frames:v 5000 -an -f rawvideo -y /dev/null -i "$INPUT" 2> "$TEMP_STATS"
|
||||
|
||||
SUMMARY_LINE=$(grep "Multi frame detection" "$TEMP_STATS")
|
||||
|
||||
@@ -324,13 +324,64 @@ class subtitles:
|
||||
|
||||
return " ".join(parts)
|
||||
|
||||
# def get_media_info(file):
|
||||
# cmd = [
|
||||
# "ffprobe",
|
||||
# "-v", "error",
|
||||
# "-show_entries",
|
||||
# (
|
||||
# "format=duration:"
|
||||
# "stream=index,codec_type,codec_name,"
|
||||
# "width,height,r_frame_rate,bit_rate,duration,nb_frames,"
|
||||
# "pix_fmt,field_order,time_base,display_aspect_ratio,"
|
||||
# "color_space,color_transfer,color_primaries,bits_per_raw_sample,"
|
||||
# "sample_rate,channels,bits_per_sample,"
|
||||
# "stream_disposition=forced,default:"
|
||||
# "stream_tags=language,title"
|
||||
# ),
|
||||
# "-of", "json",
|
||||
# file
|
||||
# ]
|
||||
|
||||
# try:
|
||||
# result = subprocess.run(cmd, capture_output=True, text=True, check=True)
|
||||
# info = json.loads(result.stdout)
|
||||
# except subprocess.CalledProcessError as e:
|
||||
# print(f"Error running ffprobe: {e.stderr}")
|
||||
# return None, [], [], []
|
||||
|
||||
# # Container / file duration (string seconds, per ffprobe convention)
|
||||
# duration = None
|
||||
# if "format" in info:
|
||||
# duration = info["format"].get("duration")
|
||||
|
||||
# video_streams = []
|
||||
# audio_streams = []
|
||||
# subtitle_streams = []
|
||||
|
||||
# for stream in info.get("streams", []):
|
||||
# stream_type = stream.get("codec_type")
|
||||
# if stream_type == "video":
|
||||
# video_streams.append(stream)
|
||||
# elif stream_type == "audio":
|
||||
# audio_streams.append(stream)
|
||||
# elif stream_type == "subtitle":
|
||||
# subtitle_streams.append(stream)
|
||||
|
||||
# if duration is not None:
|
||||
# duration = float(duration)
|
||||
# else:
|
||||
# duration = float('nan')
|
||||
|
||||
# return duration, video_streams, audio_streams, subtitle_streams
|
||||
|
||||
def get_media_info(file):
|
||||
cmd = [
|
||||
"ffprobe",
|
||||
"-v", "error",
|
||||
"-show_entries",
|
||||
(
|
||||
"format=duration:"
|
||||
"format=duration:format_tags=title:"
|
||||
"stream=index,codec_type,codec_name,"
|
||||
"width,height,r_frame_rate,bit_rate,duration,nb_frames,"
|
||||
"pix_fmt,field_order,time_base,display_aspect_ratio,"
|
||||
@@ -348,13 +399,18 @@ def get_media_info(file):
|
||||
info = json.loads(result.stdout)
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(f"Error running ffprobe: {e.stderr}")
|
||||
return None, [], [], []
|
||||
return None, [], [], [], None
|
||||
|
||||
# Container / file duration (string seconds, per ffprobe convention)
|
||||
# Duration
|
||||
duration = None
|
||||
if "format" in info:
|
||||
duration = info["format"].get("duration")
|
||||
|
||||
# ✅ Extract container title
|
||||
title = None
|
||||
if "format" in info:
|
||||
title = info["format"].get("tags", {}).get("title")
|
||||
|
||||
video_streams = []
|
||||
audio_streams = []
|
||||
subtitle_streams = []
|
||||
@@ -368,16 +424,27 @@ def get_media_info(file):
|
||||
elif stream_type == "subtitle":
|
||||
subtitle_streams.append(stream)
|
||||
|
||||
return float(duration), video_streams, audio_streams, subtitle_streams
|
||||
if duration is not None:
|
||||
duration = float(duration)
|
||||
else:
|
||||
duration = float('nan')
|
||||
|
||||
return duration, video_streams, audio_streams, subtitle_streams, title
|
||||
|
||||
def seconds_to_hms(seconds):
|
||||
if type(seconds) is float:
|
||||
h = int(seconds // 3600)
|
||||
m = int((seconds % 3600) // 60)
|
||||
s = int(seconds % 60)
|
||||
return f"{h:02}:{m:02}:{s:02}"
|
||||
else:
|
||||
return "ERROR"
|
||||
|
||||
def get_stream_bitrate(file_size, duration):
|
||||
return int((file_size * 8)/duration/1000000) if duration > 0 else 0
|
||||
if type(duration) is float:
|
||||
if duration != float('nan'):
|
||||
return round(float((file_size * 8)/duration/1000000), 2) if duration > 0 else 0
|
||||
return float('nan')
|
||||
|
||||
class video_file:
|
||||
def __init__(self, path, base_tab=""):
|
||||
@@ -386,7 +453,7 @@ class video_file:
|
||||
self.name = os.path.basename(path) # 25.mkv
|
||||
self.size = os.path.getsize(path)
|
||||
|
||||
self.duration, videos, audios, subs = get_media_info(path)
|
||||
self.duration, videos, audios, subs, title = get_media_info(path)
|
||||
|
||||
self.sort_video_info(videos)
|
||||
self.sort_audio_info(audios)
|
||||
@@ -395,6 +462,7 @@ class video_file:
|
||||
self.bitrate = get_stream_bitrate(self.size, self.duration)
|
||||
self.size = human_readable_size(self.size) # 198MB
|
||||
self.duration = seconds_to_hms(self.duration)
|
||||
self.title = title
|
||||
|
||||
def sort_video_info(self, videos):
|
||||
self.videos = []
|
||||
@@ -422,6 +490,8 @@ class video_file:
|
||||
else:
|
||||
np(f"{os.path.dirname(self.path)}/", INFO_STYLE)
|
||||
np(f"\t{self.name} ({self.size}, {self.duration}, {self.bitrate} MB/s):", NORMAL_STYLE)
|
||||
if self.title:
|
||||
np(f"\t\tTitle: \"{self.title}\"", NORMAL_STYLE)
|
||||
for video in self.videos:
|
||||
np(f"\t\t{video}", NORMAL_STYLE)
|
||||
for audio in self.audios:
|
||||
@@ -484,14 +554,15 @@ def handle_folders(dirs, all_files):
|
||||
file = file.path
|
||||
if check_video_ext(os.path.splitext(file)[1]):
|
||||
dir_files.append(file)
|
||||
else:
|
||||
np(f"{file} is not a compatabile Video file", WARN_STYLE)
|
||||
# else:
|
||||
# np(f"{file} is not a compatabile Video file", WARN_STYLE)
|
||||
if(dir_files != []):
|
||||
dir_files.sort()
|
||||
all_files.append(dir_files)
|
||||
|
||||
if __name__ == "__main__":
|
||||
# print(sys.argv)
|
||||
subprocess.run(["python", "/home/honney/.bin/tracker.py", "add", "ff"])
|
||||
file_dir_array = []
|
||||
if len(sys.argv) == 0:
|
||||
print("Something went horribly wrong!")
|
||||
@@ -504,7 +575,10 @@ if __name__ == "__main__":
|
||||
dirs = []
|
||||
for argv in sys.argv[1:]:
|
||||
if os.path.isfile(argv):
|
||||
if check_video_ext(os.path.splitext(argv)[1]):
|
||||
files.append(os.path.abspath(argv))
|
||||
# else:
|
||||
# np(f"{os.path.abspath(argv)} is not a compatabile Video file", WARN_STYLE)
|
||||
elif os.path.isdir(argv):
|
||||
dirs.append(os.path.abspath(argv))
|
||||
else:
|
||||
|
||||
@@ -6,6 +6,8 @@ if [ -z "$1" ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
/home/honney/.bin/tracker.py add ffbitrate
|
||||
|
||||
# Get the video file path from the argument
|
||||
VIDEO_FILE="$1"
|
||||
|
||||
|
||||
@@ -11,6 +11,8 @@ if [ "$#" -lt 2 ]; then
|
||||
usage
|
||||
fi
|
||||
|
||||
/home/honney/.bin/tracker.py add ffsplit
|
||||
|
||||
# Get the input file and validate its existence
|
||||
input_file="$1"
|
||||
if [ ! -f "$input_file" ]; then
|
||||
|
||||
@@ -20,6 +20,8 @@ if [[ ! -d "$DIR" ]]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
/home/honney/.bin/tracker.py add ff_testing
|
||||
|
||||
echo "Scanning directory: $DIR"
|
||||
for ext in "${EXTENSIONS[@]}"; do
|
||||
# Find files with the current extension
|
||||
|
||||
@@ -47,3 +47,5 @@ for dir in */; do
|
||||
done
|
||||
fi
|
||||
done
|
||||
|
||||
/home/honney/.bin/tracker.py add filter_extra
|
||||
@@ -60,6 +60,7 @@ while IFS= read -r -d '' video; do
|
||||
rm -rf "$workdir" "$trimmed"
|
||||
done
|
||||
|
||||
/home/honney/.bin/tracker.py add generate-thumb
|
||||
|
||||
|
||||
########## Using full video duration ##########
|
||||
|
||||
@@ -49,3 +49,4 @@ list_non_empty_directories() {
|
||||
|
||||
# Start listing from the current directory
|
||||
list_non_empty_directories "."
|
||||
/home/honney/.bin/tracker.py add list_folder_empty
|
||||
@@ -1,16 +0,0 @@
|
||||
node:events:502
|
||||
throw er; // Unhandled 'error' event
|
||||
^
|
||||
|
||||
Error: EBADF: bad file descriptor, read
|
||||
Emitted 'error' event on ReadStream instance at:
|
||||
at emitErrorNT (node:internal/streams/destroy:169:8)
|
||||
at errorOrDestroy (node:internal/streams/destroy:238:7)
|
||||
at node:internal/fs/streams:272:9
|
||||
at FSReqCallback.wrapper [as oncomplete] (node:fs:683:5) {
|
||||
errno: -9,
|
||||
code: 'EBADF',
|
||||
syscall: 'read'
|
||||
}
|
||||
|
||||
Node.js v20.19.0
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Executable
+59
@@ -0,0 +1,59 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Usage:
|
||||
python3 recount_files.py <number> (<directory>)
|
||||
"""
|
||||
|
||||
import os
|
||||
from pathlib import Path
|
||||
import sys
|
||||
import re
|
||||
from termcolor import colored
|
||||
|
||||
def main():
|
||||
if len(sys.argv) == 2:
|
||||
dir = Path(os.getcwd())
|
||||
elif (len(sys.argv) == 3):
|
||||
dir = Path(sys.argv[2])
|
||||
else:
|
||||
print("Usage: recount_files.py <number> (<directory>)")
|
||||
sys.exit(1)
|
||||
import subprocess
|
||||
subprocess.run(["python", "/home/honney/.bin/tracker.py", "add", "recount_files"])
|
||||
|
||||
number = int(sys.argv[1])
|
||||
|
||||
pattern = re.compile(r'^\d+')
|
||||
|
||||
files = sorted(
|
||||
[f for f in dir.iterdir() if f.is_file() and pattern.match(f.name)],
|
||||
key=lambda f: float(f.stem)
|
||||
)
|
||||
|
||||
min_num = int(files[0].stem)
|
||||
max_len = max(len(files[-1].stem), 2)
|
||||
|
||||
for f in files:
|
||||
try:
|
||||
delta = int(f.stem)-min_num
|
||||
new_file_name = Path(f"{f.parent}/{delta+number:0{max_len}d}{f.suffix}")
|
||||
except:
|
||||
delta = float(f.stem)-min_num
|
||||
new_file_name = Path(f"{f.parent}/{delta+number:0{max_len+2}.1f}{f.suffix}")
|
||||
if not new_file_name.is_file():
|
||||
print(
|
||||
colored("Renamed: ", "green") +
|
||||
colored(str(f.parent), "cyan") +
|
||||
colored("[", "white") +
|
||||
colored(f.name, "red") +
|
||||
colored(" -> ", "white") +
|
||||
colored(new_file_name.name, "green") +
|
||||
colored("]", "white")
|
||||
)
|
||||
f.rename(new_file_name)
|
||||
else:
|
||||
print(colored(f"{new_file_name.name} already exists. Aborting", "red"))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Executable
+78
@@ -0,0 +1,78 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Usage:
|
||||
remove_fname_last_n <number> (<directory>)
|
||||
"""
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
import os
|
||||
from termcolor import colored
|
||||
|
||||
VIDEO_EXTENSIONS = {
|
||||
".mkv", ".mp4", ".avi", ".mov", ".wmv", ".flv", ".webm", ".m4v"
|
||||
}
|
||||
|
||||
def main():
|
||||
|
||||
args = sys.argv[1:]
|
||||
|
||||
undo = "--undo" in args
|
||||
if undo:
|
||||
args.remove("--undo")
|
||||
|
||||
if len(args) == 0:
|
||||
number = 0
|
||||
directory = Path(os.getcwd())
|
||||
elif len(args) == 1:
|
||||
try:
|
||||
number = int(args[0])
|
||||
directory = Path(os.getcwd())
|
||||
except:
|
||||
number = 0
|
||||
directory = Path(args[0])
|
||||
elif len(args) == 2:
|
||||
try:
|
||||
number = int(args[0])
|
||||
directory = Path(args[1])
|
||||
except:
|
||||
number = int(args[1])
|
||||
directory = Path(args[0])
|
||||
else:
|
||||
print("Usage: remove_fname_last_n <number> (<directory>)")
|
||||
sys.exit(1)
|
||||
|
||||
if not directory.exists():
|
||||
print(colored("Directory does not exist", "red"))
|
||||
sys.exit(1)
|
||||
|
||||
import subprocess
|
||||
subprocess.run(["python", "/home/honney/.bin/tracker.py", "add", "remove_fname_last_n"])
|
||||
|
||||
files = sorted(
|
||||
[f for f in directory.iterdir()
|
||||
if f.is_file() and f.suffix.lower() in VIDEO_EXTENSIONS],
|
||||
key=lambda f: f.name
|
||||
)
|
||||
|
||||
if not files:
|
||||
print(colored("No video files found", "yellow"))
|
||||
return
|
||||
|
||||
for f in files:
|
||||
new_name = f.parent/Path(f.stem[:-number]+f.suffix)
|
||||
if new_name.exists():
|
||||
print(colored(f"File {new_name.name} already exists", "red"))
|
||||
else:
|
||||
print(
|
||||
colored("Renamed: ", "green") +
|
||||
colored(f.name, "red") +
|
||||
colored(" -> ", "white") +
|
||||
colored(new_name.name, "green")
|
||||
)
|
||||
|
||||
f.rename(new_name)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
+84
-24
@@ -1,27 +1,87 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env python3
|
||||
import os
|
||||
import sys
|
||||
import glob
|
||||
|
||||
# Check if scheme is provided
|
||||
if [ -z "$1" ]; then
|
||||
echo "Usage: rename_filtered <scheme> [folder]"
|
||||
echo
|
||||
echo "Example:"
|
||||
echo " Files in folder:"
|
||||
echo " myfile_E123.txt"
|
||||
echo " myfile_E456.txt"
|
||||
echo " myfile_E789.txt"
|
||||
echo " myfile_E2468.txt"
|
||||
echo
|
||||
echo " Run:"
|
||||
echo " rename_filtered \"????????E!!!\" ./"
|
||||
echo
|
||||
echo " Result:"
|
||||
echo " myfile_E123.txt → 123.txt"
|
||||
echo " myfile_E456.txt → 456.txt"
|
||||
echo " myfile_E789.txt → 789.txt"
|
||||
echo " myfile_E2468.txt → myfile_2468.txt"
|
||||
def process_files(files, scheme):
|
||||
scheme_len = len(scheme)
|
||||
|
||||
exit 1
|
||||
fi
|
||||
for filename in files:
|
||||
print(f"Processing file: {filename}")
|
||||
print(f"Against scheme: {scheme}")
|
||||
|
||||
# Call the Python script with scheme and optional folder argument
|
||||
python3 /home/honney/.bin/rename_filtered.py "$@"
|
||||
# Get the actual filename without the directory path
|
||||
base = os.path.basename(filename)
|
||||
|
||||
name, ext = os.path.splitext(base)
|
||||
|
||||
if scheme_len == len(name):
|
||||
new_name = ""
|
||||
for i in range(scheme_len):
|
||||
current_letter = scheme[i]
|
||||
if current_letter == "?":
|
||||
pass
|
||||
elif current_letter == "!":
|
||||
new_name += name[i]
|
||||
elif current_letter == name[i]:
|
||||
new_name += current_letter
|
||||
else:
|
||||
print(f"Mismatch at position {i}, skipping {filename}")
|
||||
new_name = None
|
||||
break
|
||||
if new_name:
|
||||
rename_file(filename, new_name, ext)
|
||||
else:
|
||||
print("No new name Generated. It is not supposed to do that")
|
||||
return
|
||||
|
||||
def rename_file(file, new_name, ext):
|
||||
dirname = os.path.dirname(file) # correct: preserve folder
|
||||
old_base = os.path.basename(file)
|
||||
|
||||
if old_base != new_name:
|
||||
new_filepath = os.path.join(dirname, new_name + ext)
|
||||
os.rename(file, new_filepath)
|
||||
print(f"Renamed '{old_base}' → '{new_name + ext}'")
|
||||
else:
|
||||
print(f"No renaming needed for '{old_base}'.")
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) < 2:
|
||||
print("Usage: scheme.py <scheme> [folder]")
|
||||
sys.exit(1)
|
||||
else:
|
||||
print("Usage: rename_filtered <scheme> [folder]")
|
||||
print()
|
||||
print("Example:")
|
||||
print(" Files in folder:")
|
||||
print(" myfile_E123.txt")
|
||||
print(" myfile_E456.txt")
|
||||
print(" myfile_E789.txt")
|
||||
print(" myfile_E2468.txt")
|
||||
print()
|
||||
print(" Run:")
|
||||
print(" rename_filtered \"????????E!!!\" ./")
|
||||
print()
|
||||
print(" Result:")
|
||||
print(" myfile_E123.txt → 123.txt")
|
||||
print(" myfile_E456.txt → 456.txt")
|
||||
print(" myfile_E789.txt → 789.txt")
|
||||
print(" myfile_E2468.txt → myfile_2468.txt")
|
||||
|
||||
sys.exit(1)
|
||||
import subprocess
|
||||
subprocess.run(["python", "/home/honney/.bin/tracker.py", "add", "rename_filtered"])
|
||||
|
||||
scheme = sys.argv[1]
|
||||
folder = sys.argv[2] if len(sys.argv) > 2 else "."
|
||||
|
||||
# Get all files in the folder (assuming files are in the current directory by default)
|
||||
files = glob.glob(os.path.join(folder, "*"))
|
||||
|
||||
# Run the renaming logic
|
||||
process_files(files, scheme)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1,64 +0,0 @@
|
||||
import os
|
||||
import sys
|
||||
import glob
|
||||
|
||||
def process_files(files, scheme):
|
||||
scheme_len = len(scheme)
|
||||
|
||||
for filename in files:
|
||||
print(f"Processing file: {filename}")
|
||||
print(f"Against scheme: {scheme}")
|
||||
|
||||
# Get the actual filename without the directory path
|
||||
base = os.path.basename(filename)
|
||||
|
||||
name, ext = os.path.splitext(base)
|
||||
|
||||
if scheme_len == len(name):
|
||||
new_name = ""
|
||||
for i in range(scheme_len):
|
||||
current_letter = scheme[i]
|
||||
if current_letter == "?":
|
||||
pass
|
||||
elif current_letter == "!":
|
||||
new_name += name[i]
|
||||
elif current_letter == name[i]:
|
||||
new_name += current_letter
|
||||
else:
|
||||
print(f"Mismatch at position {i}, skipping {filename}")
|
||||
new_name = None
|
||||
break
|
||||
if new_name:
|
||||
rename_file(filename, new_name, ext)
|
||||
else:
|
||||
print("No new name Generated. It is not supposed to do that")
|
||||
return
|
||||
|
||||
def rename_file(file, new_name, ext):
|
||||
dirname = os.path.dirname(file) # correct: preserve folder
|
||||
old_base = os.path.basename(file)
|
||||
|
||||
if old_base != new_name:
|
||||
new_filepath = os.path.join(dirname, new_name + ext)
|
||||
os.rename(file, new_filepath)
|
||||
print(f"Renamed '{old_base}' → '{new_name + ext}'")
|
||||
else:
|
||||
print(f"No renaming needed for '{old_base}'.")
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) < 2:
|
||||
print("Usage: scheme.py <scheme> [folder]")
|
||||
sys.exit(1)
|
||||
|
||||
scheme = sys.argv[1]
|
||||
folder = sys.argv[2] if len(sys.argv) > 2 else "."
|
||||
|
||||
# Get all files in the folder (assuming files are in the current directory by default)
|
||||
files = glob.glob(os.path.join(folder, "*"))
|
||||
|
||||
# Run the renaming logic
|
||||
process_files(files, scheme)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1,47 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
rename_to_first4.py
|
||||
|
||||
Usage:
|
||||
python3 rename_to_first4.py <directory>
|
||||
|
||||
Renames each file in <directory> so its name becomes the first
|
||||
four characters of the original filename (before the extension).
|
||||
Keeps the file extension and avoids overwriting existing files.
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
def main():
|
||||
if len(sys.argv) != 2:
|
||||
print("Usage: rename_to_first4.py <directory>")
|
||||
sys.exit(1)
|
||||
|
||||
directory = Path(sys.argv[1])
|
||||
if not directory.is_dir():
|
||||
print(f"Error: '{directory}' is not a directory.")
|
||||
sys.exit(1)
|
||||
|
||||
for f in directory.iterdir():
|
||||
if not f.is_file():
|
||||
continue
|
||||
|
||||
stem = f.stem[:4] # first 4 letters of filename (no extension)
|
||||
new_name = f"{stem}{f.suffix}"
|
||||
new_path = directory / new_name
|
||||
|
||||
# avoid overwriting existing files
|
||||
counter = 1
|
||||
while new_path.exists():
|
||||
new_name = f"{stem}_{counter}{f.suffix}"
|
||||
new_path = directory / new_name
|
||||
counter += 1
|
||||
|
||||
print(f"Renaming: {f.name} -> {new_name}")
|
||||
f.rename(new_path)
|
||||
|
||||
print("✅ Done renaming all files.")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Executable
+57
@@ -0,0 +1,57 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
rename_to_first_n.py
|
||||
|
||||
Usage:
|
||||
python3 rename_to_first_n.py <number> <directory>
|
||||
|
||||
Renames each file in <directory> so its name becomes the first
|
||||
four characters of the original filename (before the extension).
|
||||
Keeps the file extension and avoids overwriting existing files.
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
def main():
|
||||
if len(sys.argv) < 2:
|
||||
print("Usage: rename_to_first4.py <number> <directory>")
|
||||
sys.exit(1)
|
||||
import subprocess
|
||||
subprocess.run(["python", "/home/honney/.bin/tracker.py", "add", "rename_to_first_n"])
|
||||
|
||||
try:
|
||||
length = int(sys.argv[1])
|
||||
except:
|
||||
raise ValueError(f"Error: '{sys.argv[1]}' is not a number.")
|
||||
try:
|
||||
directory = Path(sys.argv[2]) if len(sys.argv) > 2 else Path(os.getcwd())
|
||||
except:
|
||||
raise ValueError(f"Error: '{sys.argv[2] if len(sys.argv) > 2 else os.getcwd()}' is not a directory.")
|
||||
if not directory.is_dir():
|
||||
raise ValueError(f"Error: '{directory}' is not a directory.")
|
||||
|
||||
for f in directory.iterdir():
|
||||
if not f.is_file():
|
||||
continue
|
||||
|
||||
original_stem = f.stem
|
||||
|
||||
if len(original_stem) < length:
|
||||
print(f"Skipping {f.name} because it is less than {length} characters.")
|
||||
continue
|
||||
stem = original_stem[:length] # first n letters of filename (no extension)
|
||||
new_name = f"{stem}{f.suffix}"
|
||||
new_path = directory / new_name
|
||||
|
||||
# avoid overwriting existing files
|
||||
if new_path.exists():
|
||||
print(f"File {new_name} already exists. Skipping.")
|
||||
continue
|
||||
print(f"Renaming: {f.name} -> {new_name}")
|
||||
f.rename(new_path)
|
||||
|
||||
print("✅ Done renaming all files.")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -36,6 +36,7 @@ def main():
|
||||
else:
|
||||
targets = sys.argv[1:]
|
||||
lang = "German" # Hardcoded to German
|
||||
subprocess.run(["python", "/home/honney/.bin/tracker.py", "add", "set_1_ger"])
|
||||
|
||||
lang = normalize_language(lang)
|
||||
lang_code = normalize_lang_code(lang)
|
||||
|
||||
+2
-1
@@ -102,11 +102,12 @@ def main():
|
||||
else:
|
||||
targets = sys.argv[1:-1]
|
||||
lang = sys.argv[-1]
|
||||
|
||||
subprocess.run(["python", "/home/honney/.bin/tracker.py", "add", "set_audio_lang"])
|
||||
lang = normalize_language(lang)
|
||||
|
||||
for f in collect_files(targets):
|
||||
set_audio_lang(f, lang)
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
main()
|
||||
@@ -1,3 +1,3 @@
|
||||
#!/bin/bash
|
||||
|
||||
/home/honney/.bin/tracker.py add show_path
|
||||
echo $PATH | tr ":" "\n" | nl
|
||||
@@ -338,6 +338,7 @@ process_file() {
|
||||
echo -e "\t$subtitle_output"
|
||||
}
|
||||
|
||||
/home/honney/.bin/tracker.py add simple_ffprobe_script
|
||||
|
||||
# Main script logic
|
||||
if [ -z "$1" ]; then
|
||||
|
||||
@@ -115,6 +115,7 @@ if __name__ == "__main__":
|
||||
if len(sys.argv) < 3:
|
||||
print("Usage: python split_mkv_by_chapter.py <input_file> <timestamp1> <timestamp2> ...")
|
||||
sys.exit(1)
|
||||
subprocess.run(["python", "/home/honney/.bin/tracker.py", "add", "split_mkv_by_chapter"])
|
||||
|
||||
input_file = sys.argv[1]
|
||||
timestamps = sys.argv[2:]
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import sys
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
EP_REGEX = re.compile(r'(E)(\d{4})(.*)')
|
||||
|
||||
def main():
|
||||
args = sys.argv[1:]
|
||||
|
||||
dry_run = False
|
||||
if args and args[0] in ("--dry-run", "-n"):
|
||||
dry_run = True
|
||||
args = args[1:]
|
||||
|
||||
if len(args) != 3:
|
||||
print("Usage: script.py [--dry-run|-n] <directory> <threshold> <subtract>")
|
||||
sys.exit(1)
|
||||
|
||||
directory = Path(args[0])
|
||||
threshold = int(args[1])
|
||||
subtract = int(args[2])
|
||||
|
||||
if not directory.is_dir():
|
||||
print(f"Error: '{directory}' is not a directory.")
|
||||
sys.exit(1)
|
||||
|
||||
# Step 1: build array of original filenames and parsed numbers
|
||||
old_array = []
|
||||
for f in sorted(directory.iterdir()):
|
||||
if not f.is_file():
|
||||
continue
|
||||
m = EP_REGEX.match(f.name)
|
||||
if m:
|
||||
prefix, num_str, rest = m.groups()
|
||||
num = int(num_str)
|
||||
old_array.append([prefix, num, rest])
|
||||
|
||||
# Step 2: compute new filenames
|
||||
new_array = []
|
||||
for prefix, num, rest in old_array:
|
||||
if num >= threshold:
|
||||
new_num = num - subtract
|
||||
else:
|
||||
new_num = num
|
||||
if new_num < 0 or new_num > 9999:
|
||||
raise ValueError(f"Invalid resulting number for file: {prefix}{num:04d}{rest}")
|
||||
new_array.append([prefix, new_num, rest])
|
||||
|
||||
if subtract < 0:
|
||||
new_array.reverse()
|
||||
old_array.reverse()
|
||||
|
||||
# Step 3: sequential rename simulation / real rename
|
||||
for i in range(len(old_array)):
|
||||
old_name = f"{old_array[i][0]}{old_array[i][1]:04d}{old_array[i][2]}"
|
||||
new_name = f"{new_array[i][0]}{new_array[i][1]:04d}{new_array[i][2]}"
|
||||
|
||||
for j in range(i):
|
||||
if old_array[j][0] == new_array[i][0] and old_array[j][1] == new_array[i][1] and old_array[j][2] == new_array[i][2]:
|
||||
raise RuntimeError(
|
||||
f"Rename conflict in simulation:\n Source: {old_name}\n Target: {new_name}\n Conflicts with: {old_array[j][0]}{old_array[j][1]:04d}{old_array[j][2]}"
|
||||
)
|
||||
if old_array[j][1] > new_array[i][1]:
|
||||
break
|
||||
|
||||
print(f"\"{old_name}\" -> \"{new_name}\"", end=" ")
|
||||
|
||||
if old_name == new_name:
|
||||
print("Skipped")
|
||||
continue
|
||||
else:
|
||||
print()
|
||||
|
||||
# Update simulated old_array to reflect that this file has been "renamed"
|
||||
old_array[i][1] = new_array[i][1]
|
||||
|
||||
# Actually rename unless dry-run
|
||||
if not dry_run:
|
||||
target_path = directory / new_name
|
||||
if target_path.exists():
|
||||
raise RuntimeError(f"Rename would overwrite existing file on disk:\n Source: {old_name}\n Target: {new_name}")
|
||||
(directory / old_name).rename(target_path)
|
||||
|
||||
if dry_run:
|
||||
print("Dry-run complete. No files were renamed.")
|
||||
else:
|
||||
print("Done.")
|
||||
|
||||
if __name__ == "__main__":
|
||||
import subprocess
|
||||
subprocess.run(["python", "/home/honney/.bin/tracker.py", "add", "substract_episode_num"])
|
||||
main()
|
||||
@@ -16,6 +16,8 @@ if [ "$#" -ne 2 ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
/home/honney/.bin/tracker.py add sync_delete
|
||||
|
||||
TARGET_DIR="$1"
|
||||
REFERENCE_DIR="$2"
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import re
|
||||
from datetime import timedelta
|
||||
import subprocess
|
||||
|
||||
def parse_timecode(timecode):
|
||||
parts = list(map(int, timecode.split(':')))
|
||||
@@ -18,6 +19,7 @@ def add_timecodes(*timecodes):
|
||||
return f"{hours:02}:{minutes:02}:{seconds:02}"
|
||||
|
||||
if __name__ == "__main__":
|
||||
subprocess.run(["python", "/home/honney/.bin/tracker.py", "add", "time_add"])
|
||||
timecodes = input("Enter timecodes separated by spaces: ").split()
|
||||
total = add_timecodes(*timecodes)
|
||||
print("Total time:", total)
|
||||
Executable
+115
@@ -0,0 +1,115 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# Python: subprocess.run(["python", "/home/honney/.bin/tracker.py", "add", "name"])
|
||||
# Bash: /home/honney/.bin/tracker.py add my_script
|
||||
#
|
||||
|
||||
import sys
|
||||
import csv
|
||||
import os
|
||||
|
||||
DB_FILE = "/home/honney/.bin/data/tracker.csv"
|
||||
|
||||
|
||||
def load_data():
|
||||
data = {}
|
||||
if not os.path.exists(DB_FILE):
|
||||
return data
|
||||
|
||||
with open(DB_FILE, newline="") as f:
|
||||
reader = csv.reader(f)
|
||||
for row in reader:
|
||||
if len(row) != 2:
|
||||
continue
|
||||
name, count = row
|
||||
data[name] = int(count)
|
||||
return data
|
||||
|
||||
|
||||
def save_data(data):
|
||||
with open(DB_FILE, "w", newline="") as f:
|
||||
writer = csv.writer(f)
|
||||
for name, count in data.items():
|
||||
writer.writerow([name, count])
|
||||
|
||||
|
||||
def add_entry(name):
|
||||
data = load_data()
|
||||
data[name] = data.get(name, 0) + 1
|
||||
save_data(data)
|
||||
# print(f"{name}: {data[name]}")
|
||||
|
||||
def sub_entry(name, amount=1):
|
||||
data = load_data()
|
||||
|
||||
if name not in data:
|
||||
print(f"{name} not found.")
|
||||
return
|
||||
|
||||
data[name] -= amount
|
||||
|
||||
if data[name] <= 0:
|
||||
del data[name] # remove entry completely
|
||||
# alternatively: data[name] = 0
|
||||
save_data(data)
|
||||
|
||||
def show_ranking():
|
||||
data = load_data()
|
||||
if not data:
|
||||
print("No data yet.")
|
||||
return
|
||||
|
||||
sorted_data = sorted(data.items(), key=lambda x: x[1], reverse=True)
|
||||
|
||||
print("Ranking:")
|
||||
for i, (name, count) in enumerate(sorted_data, start=1):
|
||||
print(f"{i}. {name} - {count}")
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) < 2:
|
||||
print("Usage:")
|
||||
print(" tracker.py add <name>")
|
||||
print(" tracker.py sub <name> (<amount>)")
|
||||
print(" tracker.py ranking")
|
||||
sys.exit(1)
|
||||
|
||||
mode = sys.argv[1]
|
||||
|
||||
if mode == "add":
|
||||
if len(sys.argv) < 3:
|
||||
print("Error: Missing name")
|
||||
sys.exit(1)
|
||||
name = sys.argv[2]
|
||||
add_entry(name)
|
||||
|
||||
elif mode == "sub":
|
||||
if len(sys.argv) < 3:
|
||||
print("Error: Missing name")
|
||||
sys.exit(1)
|
||||
|
||||
name = sys.argv[2]
|
||||
amount = 1
|
||||
|
||||
if len(sys.argv) >= 4:
|
||||
try:
|
||||
amount = int(sys.argv[3])
|
||||
except ValueError:
|
||||
print("Error: amount must be a number")
|
||||
sys.exit(1)
|
||||
|
||||
sub_entry(name, amount)
|
||||
|
||||
elif mode == "ranking":
|
||||
show_ranking()
|
||||
|
||||
else:
|
||||
print(f"Unknown mode: {mode}")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in new issue
Block a user