-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathdiscrip.py
More file actions
executable file
·330 lines (275 loc) · 10.1 KB
/
Copy pathdiscrip.py
File metadata and controls
executable file
·330 lines (275 loc) · 10.1 KB
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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
#!/usr/bin/env python3
# discrip.py
# This is a CLI interface to the modules capable of ripping and converting data
# from defined media types. It can take a list of media samples to rip in batch
# and a configuration json to change some settings.
# Python System
import argparse
import csv
import json
import sys
import os
import shutil
from pprint import pprint
# External Modules
import asyncio
import signal
# Internal Modules
from handler.mediareader import MediaReader
from handler.media.manager import MediaHandlerManager
from handler.data.manager import DataHandlerManager
def rip_list_read(filepath=None):
""" Read a CSV with drive paths, BIN names, and full media_sample names
CSVs may optionally provide a `media_type` which will be used to bypass
automatic media type detection. If mixing known and unknown media types
you can set media_type to "auto" as well.
"""
# Open CSV with media samples to rip
media_samples=[]
with open(filepath, newline='') as csvfile:
reader = csv.DictReader(csvfile, skipinitialspace=True)
# Make all CSV headers lowercase
for index, name in enumerate(reader.fieldnames):
reader.fieldnames[index]=name.lower()
for row in reader:
# Convert media types to upper case if present
if "media_type" in row:
row["media_type"] = row["media_type"].upper()
media_samples.append(row)
# Return a dict of media_sample information to rip
return media_samples
def config_read(filepath=None):
""" Read a JSON with config parameters for media and data handlers
"""
# Veryfiy config file exists
if not os.path.exists(filepath):
config_local = os.path.realpath(__file__).replace(os.path.basename(__file__),"")+"config/"+filepath
# Check for config file next to script
if not os.path.exists(config_local):
# Check for config file next to script without extension
if not os.path.exists(config_local+".json"):
print(f"Config file \"{filepath}\" not found.")
sys.exit(1)
else:
filepath = config_local+".json"
else:
filepath = config_local
# Open JSON to read config data
config_data={}
with open(filepath, newline='') as jsonfile:
config_data = json.load(jsonfile)
# Return a dict of config data
return config_data
def config_dump(filename):
""" Save a JSON with all config parameter options for media and data handlers
"""
# Save config data to JSON
with open(filename, 'w') as f:
json.dump(MediaReader.getConfigOptions(), f, indent=4)
global loop_state
global server
loop_state = True
server = None
async def asyncLoop():
""" Blocking main loop to provide time for async tasks to run"""
print('Blocking main loop')
global loop_state
while loop_state:
await asyncio.sleep(1)
def exit_handler(sig, frame):
""" Handle CTRL-C to gracefully end program and API connections """
global loop_state
print('You pressed Ctrl+C!')
loop_state = False
server.stop()
async def startWeb(settings=None):
# Internal Modules
from web.web import WebInterface
global server
server = WebInterface(settings)
""" Start connections to async modules """
# Setup CTRL-C signal to end programm
signal.signal(signal.SIGINT, exit_handler)
print('Press Ctrl+C to exit program')
# Start async modules
L = await asyncio.gather(
server.start(),
asyncLoop()
)
def main():
""" Execute as a CLI and process parameters to rip and convert
"""
# Clean up old temp data
if os.path.exists("/tmp/discrip"):
shutil.rmtree("/tmp/discrip")
# Setup CLI arguments
parser = argparse.ArgumentParser(
prog="pyDiscRip",
description='Media ripping manager program',
epilog='By Shelby Jueden')
parser.add_argument('-c', '--csv', help="CSV file in `Drive,Name,Description` format", default=None)
parser.add_argument('-f', '--config', help="Config file for ripping", default=None)
parser.add_argument('-d', '--configdump', help="Dump all config options. Optional filename to output to.",
nargs='?', default=None, const='config_options.json')
parser.add_argument('-o', '--output', help="Directory to save data in", default="")
parser.add_argument('-j', '--json-watch', help="Directory to watch for JSON sample files", default=None)
parser.add_argument('-p', '--preserve-order', help="Maintain FIFO rip order for group ripping", action='store_true')
parser.add_argument('-w', '--web', help="Start web server (Clears watch folder on launch)", action='store_true')
parser.add_argument('-s', '--settings', help="Settings file for web", default=None)
args = parser.parse_args()
# Dump config options and exit
settings={
"drives": {
"Optical":[
{
"name":"Laptop CD/DVD",
"drive":"/dev/sr0",
"group":"CD-DVD",
"type":"OPTICAL",
}
],
"Greaseweazle": [
{
"name":"Floppy A",
"drive": "a@/dev/ttyACM0",
"group":"3.5in",
"type":"FLOPPY",
"controller_id":"gw1"
},
{
"name":"Floppy B",
"drive": "b@/dev/ttyACM0",
"group":"5.25in",
"type":"FLOPPY",
"controller_id":"gw1"
},
],
"Dummy": [
{
"name":"Random A",
"drive": "/dev/random1",
"group":"dummy",
"type":"DUMMY"
},
{
"name":"Random B",
"drive": "/dev/random2",
"group":"dummy",
"type":"DUMMY"
},
{
"name":"Random C",
"drive": "/dev/random3",
"group":"dummy",
"type":"DUMMY"
}
],
},
"controllers":[
{
"controller_type":"RoboRacerLS",
"id": "stacker",
"serial_port":"/dev/ttyUSB0"
},
{
"controller_type":"AutoPublisherLS",
"id": "apls",
"bin":1,
"serial_port":"/dev/ttyUSB1",
"drives":[], # media_name, open
"cal":
{
"BIN_1":637,
"BIN_2":1356,
"BIN_3":2106,
"BIN_5":-140,
"ARM_BOTTOM":1832,
"DRIVE_1":575,
"DRIVE_2":1050,
"DRIVE_3":1450,
"TRAY_SLIDE":50,
"TRAY_ANGLE":-125
}
},
{
"controller_type": "Greaseweazle",
"id": "gw1"
}
],
"web" : {
"port": 5000,
"ip": "0.0.0.0"
},
"media_handlers":
{
"CD":"cdrdao",
"DVD":"dvd_ddrescue",
"BD":"bd_redumper"
},
"output": "",
"watch": None,
"fifo": False
}
if args.settings is not None:
if args.settings == "":
print(json.dumps(settings, indent=4))
sys.exit(0)
else:
settings = config_read(args.settings)
# Output folder
if args.output != "":
settings["output"]=args.output
if args.preserve_order:
settings["fifo"]=args.preserve_order
if args.json_watch is not None:
settings["watch"]=args.json_watch
# Dump config options and exit
if args.configdump is not None:
config_dump(args.configdump)
sys.exit(0)
# If CSV is none exit
if args.csv == None and settings["watch"] is None:
parser.print_help()
sys.exit(0)
# If CSV is blank return only CSV header and exit
if args.csv == "":
print("Media_Type,Drive,Name,Description")
sys.exit(0)
# Load optional config file
if args.config is not None:
config_data = config_read(args.config)
else:
config_data = {}
# Pass settings
config_data["settings"] = settings
# Read media samples to rip from CSV file
media_samples =[]
if args.csv is not None:
media_samples = rip_list_read(args.csv)
MediaReader.rip_queue_drives(media_samples,config_data)
sys.exit(0)
# Watch folder
if settings["watch"] is not None:
if not args.web:
MediaReader.rip_queue_groups(media_samples,config_data)
sys.exit(0)
# Run web server
if args.web:
if settings["watch"] is None:
print("Must provide -j/--json-watch or settings file for rip watch folder")
sys.exit(1)
else:
if os.path.exists(settings["watch"]):
shutil.rmtree(settings["watch"])
asyncio.run(startWeb(settings))
sys.exit(0)
# Begin ripping all media samples provided
rip_count = 1
for media_sample in media_samples:
MediaReader.rip(media_sample,config_data)
# If there are more media samples to rip, wait while user changes samples
if rip_count < len(media_samples):
rip_count+=1
input("Change media_samples and press Enter to continue...")
if __name__ == "__main__":
main()