-
Notifications
You must be signed in to change notification settings - Fork 0
/
pfl4.py
129 lines (109 loc) · 3.69 KB
/
pfl4.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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#!/usr/bin/env python
__author__ = "Michael Heise"
__copyright__ = "Copyright (C) 2023 by Michael Heise"
__license__ = "LGPL"
__version__ = "0.2.0"
__date__ = "07/15/2023"
"""List mp4 files in a directory and its sub-directories,
and print results including mp4 tags to stdout or save as a CSV file
"""
# standard imports
import os
from datetime import datetime
# 3rd party imports
from tinytag import TinyTag
# local imports
import pfllib.pflargparse as pflargparse
import pfllib.pflparams as pflparams
import pfllib.pflrun as pflrun
class PFLParamsMP4(pflparams.PFLParams):
"""Class with fixed search pattern '*.mp4'."""
def __init__(self, args):
super().__init__(args, fixpattern="*.mp4")
class PFLRunMP4(pflrun.PFLRun):
"""Derived class for scanning and storage of mp4 file and tag information."""
def __init__(self, params):
super().__init__(params)
self.Columns = [
"path",
"filename",
"ctime",
"wtime",
"length",
"bitrate",
"artist",
"title",
"year",
]
self._fileDateTimeFormat = "%Y-%m-%d %H:%M:%S"
def getMatchDataList(self, match):
"""Return list with data from the match."""
try:
tag = TinyTag.get(match)
return [
match.parent,
match.name,
datetime.fromtimestamp(os.path.getctime(match)),
datetime.fromtimestamp(os.path.getmtime(match)),
round(tag.duration, 3),
round(tag.bitrate, 0),
"" if tag.artist is None else tag.artist.strip(),
tag.title,
tag.year,
]
except (Exception):
return [match.parent, match.name, None, None, 0, 0, "", "", "-1"]
def formatListStrings(self, dataList):
"""Return all elements in the list formatted as strings."""
return [
str(dataList[0]),
str(dataList[1]),
dataList[2].strftime(self._fileDateTimeFormat)
if dataList[2] is not None
else "",
dataList[3].strftime(self._fileDateTimeFormat)
if dataList[3] is not None
else "",
str(dataList[4]),
str(dataList[5]),
dataList[6],
dataList[7],
dataList[8],
]
def formatListDatabase(self, dataList):
"""Return all elements in the list converted to types suitable for database."""
return [
str(dataList[0]),
str(dataList[1]),
dataList[2],
dataList[3],
dataList[4],
dataList[5],
dataList[6],
dataList[7],
int((dataList[8].strip() or -1) if dataList[8] is not None else -1),
]
# define and collect commandline arguments
# (kept outside try-catch block to leave exception messages untouched)
parser = pflargparse.PFLArgParseFixedPattern(
description="List mp4 files in a directory and its sub-directories\n"
+ "and print results including mp4 tags to stdout,\n"
+ "or save as a CSV or database file."
)
args = parser.parse_args()
try:
# create parameter object
params = PFLParamsMP4(args)
print("Search for mp4 files in directory '{}'...".format(params.ScanPath))
run = PFLRunMP4(params)
run.Run()
except (ValueError) as e:
print(f"Invalid parameter: {e.args[0]}")
except (FileNotFoundError) as e:
print(f"Directory not found: {e.args[0]}")
except (NotADirectoryError) as e:
print(f"Error: {e.args[0]}")
except (KeyboardInterrupt):
print("Cancelled by user!")
except (Exception) as e:
print("Unhandled error:", e.args[0])