Skip to content

Commit eb2a4d3

Browse files
committed
Started changing compression script to python. Added new functions to disk stats.
1 parent 1c6e4b9 commit eb2a4d3

File tree

6 files changed

+110
-14
lines changed

6 files changed

+110
-14
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ config.local.json
55
.local.env
66
*.log
77
input*.json
8+
*.flag
89

910
# Byte-compiled / optimized / DLL files
1011
__pycache__/

README.md

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
# shipper
22
**shipper** is a utility with the purpose of making re-encoding and compressing of movies and TV shows easier. While it is built with Plex in mind, it can be used for anything. It is comprised of a daemon which can be run in the background and also acts as a dashboard for current jobs as well as a input script to safely add new jobs to the queue.
33

4+
5+
> [!WARNING]
6+
> This repository is very much **work in progress**. Most commits will break previous versions. It is likely that many features will only partly work or not work at all.
7+
48
Requirements
59
---
6-
- ffmpeg
10+
- FFmpeg
711

812

913
Installation & Usage
@@ -60,25 +64,31 @@ Features
6064
Todo
6165
---
6266
<details>
63-
<summary>4/21 Complete</summary>
67+
<summary>4/27 Complete</summary>
6468

69+
- [ ] Change flags (stop, unstop) to use .flag suffix to avoid committing.
6570
- [ ] Reorganise file structure to move functions to their own files.
6671
- [ ] daemon
6772
- [ ] input
6873
- [ ] status
6974

7075
- [ ] input.py
71-
- [x] Input directory
72-
- [x] Output directory
7376
- [ ] Allow custom output file name formats
7477
- [ ] Fix ctrl+c throwing 20 lines of error
75-
- [x] daemon.py
76-
- [x] Change daemon printing to log file.
78+
- [ ] Potentially make part of status.py TUI
7779
- [ ] status.py
7880
- [ ] Consider moving to TUI frontend such as textualize which would allow it to run as webpage.
7981
- [ ] Running status or input should trigger daemon to start.
8082
- [ ] compress_file.sh
8183
- [ ] Turn into python script.
84+
- [x] Checks if file exists
85+
- [x] Checks valid preset & gets preset values
86+
- [x] Check enough disk space
87+
- [x] Fail job if output already exists
88+
- [ ] If english audio exists, use it
89+
- [ ] If english subs exist, use them
90+
- [ ] Run ffmpeg
91+
- [ ] Warn if output > input
8292

8393
- [ ] Prompt user for missing config.json & .env values when initially running input.py.
8494
- [ ] Allow editing of current jobs.

functions/compressor.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# == PLAN ==
2+
# [x] Checks if input and output files exists
3+
# [x] Checks valid preset & gets preset values
4+
# [x] Check enough disk space
5+
# [ ] If english audio exists, use it
6+
# [ ] If english subs exist, use them
7+
# [ ] Run ffmpeg
8+
# [ ] Warn if output > input
9+
from pathlib import Path
10+
11+
from config import load_config
12+
import disk_stats as ds
13+
14+
CONFIG = load_config()
15+
16+
17+
def create_ffmpeg_cmd(input_path: str, output_path: str, quality_key: str):
18+
"""
19+
Function to start compression of a video.
20+
Returns a process when working.
21+
Returns a string if error.
22+
"""
23+
# Check input exists and output does not
24+
if not Path(input_path).exists():
25+
error_message = "Input file does not exist (compressor)"
26+
print(error_message)
27+
return error_message
28+
if Path(output_path).exists():
29+
error_message = "Output file already exists (compressor)"
30+
print(error_message)
31+
return error_message
32+
33+
# Safely load quality config
34+
try:
35+
quality = CONFIG.quality_presets[quality_key]
36+
except Exception as e:
37+
error_message = f"Failed to get quality (compressor): {e}"
38+
print(error_message)
39+
return error_message
40+
41+
# Check free space
42+
buffer = ds.gib_to_bytes(CONFIG.buffer)
43+
if not ds.check_enough_space(input_path, buffer):
44+
error_message = f"Not enough free space on disk (compressor)"
45+
print(error_message)
46+
return error_message
47+
48+
49+
if __name__ == '__main__':
50+
pass

functions/config.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ def __init__(self, raw_config: Dict[str, Any]):
4242

4343
# --- 4. Paths (Added default paths if you introduce them) ---
4444
self.input_dir: Path = Path(raw_config.get('input_dir', '.'))
45-
print(raw_config.get('input_dir'))
4645
self.output_dir: Path = Path(
4746
raw_config.get('output_dir', './Encoded'))
4847

functions/disk_stats.py

Lines changed: 43 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,65 @@
11
import shutil
2+
from pathlib import Path
3+
4+
5+
def bytes_to_gib(no_of_bytes: float) -> float:
6+
"""
7+
Function to convert bytes to gigibytes.
8+
"""
9+
return no_of_bytes / 2**30
10+
11+
12+
def gib_to_bytes(no_of_gib: float) -> float:
13+
"""
14+
Function to convert gigibytes to bytes.
15+
"""
16+
return no_of_gib * 2**30
17+
18+
19+
def get_file_size(path: str) -> float:
20+
"""
21+
Function to get size of a file.
22+
Returns answer in bytes.
23+
"""
24+
return Path(path).stat().st_size
225

326

427
def get_disk_metrics(path: str = "/") -> tuple[float, float, float]:
528
"""
6-
Calculates and returns total GiB, used GiB, and decimal usage ratio.
29+
Calculates and returns total bytes, used bytes, and decimal usage ratio.
730
"""
831
total_bytes, used_bytes, _ = shutil.disk_usage(path)
932

10-
gib_divisor = 2**30
11-
total_gib = total_bytes / gib_divisor
12-
used_gib = used_bytes / gib_divisor
1333
disk_decimal = used_bytes / total_bytes
1434

15-
return total_gib, used_gib, disk_decimal
35+
return total_bytes, used_bytes, disk_decimal
36+
37+
38+
def check_enough_space(path: str, buffer: float = 0) -> bool:
39+
"""
40+
Function to check if duplicating a file will exceed the disk space.
41+
Buffer should be in bytes.
42+
Buffer is first removed from disk space.
43+
Returns boolean (true if there is enough space).
44+
"""
45+
file_size = get_file_size(path)
46+
disk_space, used_disk, _ = get_disk_metrics()
47+
final_disk_space = disk_space - used_disk - buffer - file_size
48+
return final_disk_space > 0
1649

1750

1851
def print_disk_usage(
19-
total_gib: float,
20-
used_gib: float,
52+
total_bytes: float,
53+
used_bytes: float,
2154
disk_decimal: float,
2255
bar_length: int = 50
2356
):
2457
"""
2558
Formats and prints the disk usage progress bar.
2659
"""
60+
total_gib = bytes_to_gib(total_bytes)
61+
used_gib = bytes_to_gib(used_bytes)
62+
2763
used_disk_count = int(disk_decimal * bar_length)
2864

2965
used_disk_str = '#' * used_disk_count

stop

Whitespace-only changes.

0 commit comments

Comments
 (0)