Refresh and added usage tracking
This commit is contained in:
@@ -16,6 +16,8 @@ if [[ ! -d "$folder" ]]; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
/home/honney/.bin/tracker.py add append
|
||||||
|
|
||||||
# Process files
|
# Process files
|
||||||
for file in "$folder"/*; do
|
for file in "$folder"/*; do
|
||||||
[[ -f "$file" ]] || continue # skip non-files
|
[[ -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 "_"
|
SYMBOL="_" # Default separator is "_"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
/home/honney/.bin/tracker.py add create_folder_counting
|
||||||
|
|
||||||
# Ensure the target directory exists
|
# Ensure the target directory exists
|
||||||
mkdir -p "$TARGET_DIR"
|
mkdir -p "$TARGET_DIR"
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ if [ "$#" -lt 2 ] || [ "$#" -gt 3 ]; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
/home/honney/.bin/tracker.py add create_folder_date
|
||||||
|
|
||||||
# Set folder path
|
# Set folder path
|
||||||
if [ "$#" -eq 3 ]; then
|
if [ "$#" -eq 3 ]; then
|
||||||
TARGET_DIR="$1"
|
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:
|
if len(sys.argv) < 3:
|
||||||
print("Usage: deappend.py <mode> <string> [directory]")
|
print("Usage: deappend.py <mode> <string> [directory]")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
import subprocess
|
||||||
|
subprocess.run(["python", "/home/honney/.bin/tracker.py", "add", "deappend"])
|
||||||
|
|
||||||
# Get arguments
|
# Get arguments
|
||||||
mode = sys.argv[1] # Mode: back, front, ext/extension
|
mode = sys.argv[1] # Mode: back, front, ext/extension
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ if [ ! -f "$INPUT" ]; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
/home/honney/.bin/tracker.py add deinterlace_cpu
|
||||||
|
|
||||||
# Step 1: Try runtime detection with idet
|
# Step 1: Try runtime detection with idet
|
||||||
ffmpeg -hide_banner -vstats -nostats \
|
ffmpeg -hide_banner -vstats -nostats \
|
||||||
-i "$INPUT" \
|
-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"
|
OTPUT="${INPUT%.*}_deinterlaced_vaapi.mp4"
|
||||||
TEMP_STATS=$(mktemp)
|
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"
|
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")
|
SUMMARY_LINE=$(grep "Multi frame detection" "$TEMP_STATS")
|
||||||
|
|||||||
@@ -324,13 +324,64 @@ class subtitles:
|
|||||||
|
|
||||||
return " ".join(parts)
|
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):
|
def get_media_info(file):
|
||||||
cmd = [
|
cmd = [
|
||||||
"ffprobe",
|
"ffprobe",
|
||||||
"-v", "error",
|
"-v", "error",
|
||||||
"-show_entries",
|
"-show_entries",
|
||||||
(
|
(
|
||||||
"format=duration:"
|
"format=duration:format_tags=title:"
|
||||||
"stream=index,codec_type,codec_name,"
|
"stream=index,codec_type,codec_name,"
|
||||||
"width,height,r_frame_rate,bit_rate,duration,nb_frames,"
|
"width,height,r_frame_rate,bit_rate,duration,nb_frames,"
|
||||||
"pix_fmt,field_order,time_base,display_aspect_ratio,"
|
"pix_fmt,field_order,time_base,display_aspect_ratio,"
|
||||||
@@ -348,13 +399,18 @@ def get_media_info(file):
|
|||||||
info = json.loads(result.stdout)
|
info = json.loads(result.stdout)
|
||||||
except subprocess.CalledProcessError as e:
|
except subprocess.CalledProcessError as e:
|
||||||
print(f"Error running ffprobe: {e.stderr}")
|
print(f"Error running ffprobe: {e.stderr}")
|
||||||
return None, [], [], []
|
return None, [], [], [], None
|
||||||
|
|
||||||
# Container / file duration (string seconds, per ffprobe convention)
|
# Duration
|
||||||
duration = None
|
duration = None
|
||||||
if "format" in info:
|
if "format" in info:
|
||||||
duration = info["format"].get("duration")
|
duration = info["format"].get("duration")
|
||||||
|
|
||||||
|
# ✅ Extract container title
|
||||||
|
title = None
|
||||||
|
if "format" in info:
|
||||||
|
title = info["format"].get("tags", {}).get("title")
|
||||||
|
|
||||||
video_streams = []
|
video_streams = []
|
||||||
audio_streams = []
|
audio_streams = []
|
||||||
subtitle_streams = []
|
subtitle_streams = []
|
||||||
@@ -368,16 +424,27 @@ def get_media_info(file):
|
|||||||
elif stream_type == "subtitle":
|
elif stream_type == "subtitle":
|
||||||
subtitle_streams.append(stream)
|
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):
|
def seconds_to_hms(seconds):
|
||||||
|
if type(seconds) is float:
|
||||||
h = int(seconds // 3600)
|
h = int(seconds // 3600)
|
||||||
m = int((seconds % 3600) // 60)
|
m = int((seconds % 3600) // 60)
|
||||||
s = int(seconds % 60)
|
s = int(seconds % 60)
|
||||||
return f"{h:02}:{m:02}:{s:02}"
|
return f"{h:02}:{m:02}:{s:02}"
|
||||||
|
else:
|
||||||
|
return "ERROR"
|
||||||
|
|
||||||
def get_stream_bitrate(file_size, duration):
|
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:
|
class video_file:
|
||||||
def __init__(self, path, base_tab=""):
|
def __init__(self, path, base_tab=""):
|
||||||
@@ -386,7 +453,7 @@ class video_file:
|
|||||||
self.name = os.path.basename(path) # 25.mkv
|
self.name = os.path.basename(path) # 25.mkv
|
||||||
self.size = os.path.getsize(path)
|
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_video_info(videos)
|
||||||
self.sort_audio_info(audios)
|
self.sort_audio_info(audios)
|
||||||
@@ -395,6 +462,7 @@ class video_file:
|
|||||||
self.bitrate = get_stream_bitrate(self.size, self.duration)
|
self.bitrate = get_stream_bitrate(self.size, self.duration)
|
||||||
self.size = human_readable_size(self.size) # 198MB
|
self.size = human_readable_size(self.size) # 198MB
|
||||||
self.duration = seconds_to_hms(self.duration)
|
self.duration = seconds_to_hms(self.duration)
|
||||||
|
self.title = title
|
||||||
|
|
||||||
def sort_video_info(self, videos):
|
def sort_video_info(self, videos):
|
||||||
self.videos = []
|
self.videos = []
|
||||||
@@ -422,6 +490,8 @@ class video_file:
|
|||||||
else:
|
else:
|
||||||
np(f"{os.path.dirname(self.path)}/", INFO_STYLE)
|
np(f"{os.path.dirname(self.path)}/", INFO_STYLE)
|
||||||
np(f"\t{self.name} ({self.size}, {self.duration}, {self.bitrate} MB/s):", NORMAL_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:
|
for video in self.videos:
|
||||||
np(f"\t\t{video}", NORMAL_STYLE)
|
np(f"\t\t{video}", NORMAL_STYLE)
|
||||||
for audio in self.audios:
|
for audio in self.audios:
|
||||||
@@ -484,14 +554,15 @@ def handle_folders(dirs, all_files):
|
|||||||
file = file.path
|
file = file.path
|
||||||
if check_video_ext(os.path.splitext(file)[1]):
|
if check_video_ext(os.path.splitext(file)[1]):
|
||||||
dir_files.append(file)
|
dir_files.append(file)
|
||||||
else:
|
# else:
|
||||||
np(f"{file} is not a compatabile Video file", WARN_STYLE)
|
# np(f"{file} is not a compatabile Video file", WARN_STYLE)
|
||||||
if(dir_files != []):
|
if(dir_files != []):
|
||||||
dir_files.sort()
|
dir_files.sort()
|
||||||
all_files.append(dir_files)
|
all_files.append(dir_files)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
# print(sys.argv)
|
# print(sys.argv)
|
||||||
|
subprocess.run(["python", "/home/honney/.bin/tracker.py", "add", "ff"])
|
||||||
file_dir_array = []
|
file_dir_array = []
|
||||||
if len(sys.argv) == 0:
|
if len(sys.argv) == 0:
|
||||||
print("Something went horribly wrong!")
|
print("Something went horribly wrong!")
|
||||||
@@ -504,7 +575,10 @@ if __name__ == "__main__":
|
|||||||
dirs = []
|
dirs = []
|
||||||
for argv in sys.argv[1:]:
|
for argv in sys.argv[1:]:
|
||||||
if os.path.isfile(argv):
|
if os.path.isfile(argv):
|
||||||
|
if check_video_ext(os.path.splitext(argv)[1]):
|
||||||
files.append(os.path.abspath(argv))
|
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):
|
elif os.path.isdir(argv):
|
||||||
dirs.append(os.path.abspath(argv))
|
dirs.append(os.path.abspath(argv))
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ if [ -z "$1" ]; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
/home/honney/.bin/tracker.py add ffbitrate
|
||||||
|
|
||||||
# Get the video file path from the argument
|
# Get the video file path from the argument
|
||||||
VIDEO_FILE="$1"
|
VIDEO_FILE="$1"
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ if [ "$#" -lt 2 ]; then
|
|||||||
usage
|
usage
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
/home/honney/.bin/tracker.py add ffsplit
|
||||||
|
|
||||||
# Get the input file and validate its existence
|
# Get the input file and validate its existence
|
||||||
input_file="$1"
|
input_file="$1"
|
||||||
if [ ! -f "$input_file" ]; then
|
if [ ! -f "$input_file" ]; then
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ if [[ ! -d "$DIR" ]]; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
/home/honney/.bin/tracker.py add ff_testing
|
||||||
|
|
||||||
echo "Scanning directory: $DIR"
|
echo "Scanning directory: $DIR"
|
||||||
for ext in "${EXTENSIONS[@]}"; do
|
for ext in "${EXTENSIONS[@]}"; do
|
||||||
# Find files with the current extension
|
# Find files with the current extension
|
||||||
|
|||||||
@@ -47,3 +47,5 @@ for dir in */; do
|
|||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
|
/home/honney/.bin/tracker.py add filter_extra
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ while IFS= read -r -d '' video; do
|
|||||||
rm -rf "$workdir" "$trimmed"
|
rm -rf "$workdir" "$trimmed"
|
||||||
done
|
done
|
||||||
|
|
||||||
|
/home/honney/.bin/tracker.py add generate-thumb
|
||||||
|
|
||||||
|
|
||||||
########## Using full video duration ##########
|
########## Using full video duration ##########
|
||||||
|
|||||||
@@ -49,3 +49,4 @@ list_non_empty_directories() {
|
|||||||
|
|
||||||
# Start listing from the current directory
|
# Start listing from the current directory
|
||||||
list_non_empty_directories "."
|
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
|
|
||||||
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
|
def process_files(files, scheme):
|
||||||
if [ -z "$1" ]; then
|
scheme_len = len(scheme)
|
||||||
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"
|
|
||||||
|
|
||||||
exit 1
|
for filename in files:
|
||||||
fi
|
print(f"Processing file: {filename}")
|
||||||
|
print(f"Against scheme: {scheme}")
|
||||||
|
|
||||||
# Call the Python script with scheme and optional folder argument
|
# Get the actual filename without the directory path
|
||||||
python3 /home/honney/.bin/rename_filtered.py "$@"
|
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:
|
else:
|
||||||
targets = sys.argv[1:]
|
targets = sys.argv[1:]
|
||||||
lang = "German" # Hardcoded to German
|
lang = "German" # Hardcoded to German
|
||||||
|
subprocess.run(["python", "/home/honney/.bin/tracker.py", "add", "set_1_ger"])
|
||||||
|
|
||||||
lang = normalize_language(lang)
|
lang = normalize_language(lang)
|
||||||
lang_code = normalize_lang_code(lang)
|
lang_code = normalize_lang_code(lang)
|
||||||
|
|||||||
+2
-1
@@ -102,11 +102,12 @@ def main():
|
|||||||
else:
|
else:
|
||||||
targets = sys.argv[1:-1]
|
targets = sys.argv[1:-1]
|
||||||
lang = sys.argv[-1]
|
lang = sys.argv[-1]
|
||||||
|
subprocess.run(["python", "/home/honney/.bin/tracker.py", "add", "set_audio_lang"])
|
||||||
lang = normalize_language(lang)
|
lang = normalize_language(lang)
|
||||||
|
|
||||||
for f in collect_files(targets):
|
for f in collect_files(targets):
|
||||||
set_audio_lang(f, lang)
|
set_audio_lang(f, lang)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
||||||
main()
|
main()
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
/home/honney/.bin/tracker.py add show_path
|
||||||
echo $PATH | tr ":" "\n" | nl
|
echo $PATH | tr ":" "\n" | nl
|
||||||
|
|||||||
@@ -338,6 +338,7 @@ process_file() {
|
|||||||
echo -e "\t$subtitle_output"
|
echo -e "\t$subtitle_output"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/home/honney/.bin/tracker.py add simple_ffprobe_script
|
||||||
|
|
||||||
# Main script logic
|
# Main script logic
|
||||||
if [ -z "$1" ]; then
|
if [ -z "$1" ]; then
|
||||||
|
|||||||
@@ -115,6 +115,7 @@ if __name__ == "__main__":
|
|||||||
if len(sys.argv) < 3:
|
if len(sys.argv) < 3:
|
||||||
print("Usage: python split_mkv_by_chapter.py <input_file> <timestamp1> <timestamp2> ...")
|
print("Usage: python split_mkv_by_chapter.py <input_file> <timestamp1> <timestamp2> ...")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
subprocess.run(["python", "/home/honney/.bin/tracker.py", "add", "split_mkv_by_chapter"])
|
||||||
|
|
||||||
input_file = sys.argv[1]
|
input_file = sys.argv[1]
|
||||||
timestamps = sys.argv[2:]
|
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
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
/home/honney/.bin/tracker.py add sync_delete
|
||||||
|
|
||||||
TARGET_DIR="$1"
|
TARGET_DIR="$1"
|
||||||
REFERENCE_DIR="$2"
|
REFERENCE_DIR="$2"
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import re
|
import re
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
|
import subprocess
|
||||||
|
|
||||||
def parse_timecode(timecode):
|
def parse_timecode(timecode):
|
||||||
parts = list(map(int, timecode.split(':')))
|
parts = list(map(int, timecode.split(':')))
|
||||||
@@ -18,6 +19,7 @@ def add_timecodes(*timecodes):
|
|||||||
return f"{hours:02}:{minutes:02}:{seconds:02}"
|
return f"{hours:02}:{minutes:02}:{seconds:02}"
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
subprocess.run(["python", "/home/honney/.bin/tracker.py", "add", "time_add"])
|
||||||
timecodes = input("Enter timecodes separated by spaces: ").split()
|
timecodes = input("Enter timecodes separated by spaces: ").split()
|
||||||
total = add_timecodes(*timecodes)
|
total = add_timecodes(*timecodes)
|
||||||
print("Total time:", total)
|
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