├── DiskFormatID └── __init__.py ├── README.md ├── attic └── settings.json ├── chooseFormats.py ├── chooseFormatsGUI.py ├── diskIDMain ├── diskIDMainGUI.py ├── setup.py └── ui_files ├── chooseFormatsGUI.ui └── diskIDMainGUI.ui /DiskFormatID/__init__.py: -------------------------------------------------------------------------------- 1 | # Minimal init for DiskFormatID. Update for future releases. 2 | __license__ = "GPL 3.0" 3 | __version__ = "1.0.0" 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DiskFormatID 2 | 3 | More information is available in this blog post: http://digitalcontinuity.org/post/144268258748/floppy-disk-format-identifer-tool 4 | 5 | 6 | This program is intended to help to identify floppy disk formats. It takes a folder of http://www.Kryoflux.com stream files as input. It only works with linux and requires 7 | 8 | python 2.7 9 | 10 | pyqt4 11 | 12 | mount 13 | 14 | Kam Woods packaged it with setuptools, (https://twitter.com/kamwoods) thanks Kam! You will need the python-setuptools package installed on your system to install it. 15 | 16 | 17 | Please support http://kryoflux.com/ ! 18 | 19 | To use: 20 | Clone the repository or download all the files using the download zip button and extract them to a folder (not all are actually needed). 21 | 22 | In the DiskFormatID directory, build and install the program for all users as follows: 23 | 24 | python setup.py build 25 | sudo python setup.py install 26 | 27 | Now, you can run the program as root from any location with: 28 | 29 | "sudo diskIDMain" 30 | 31 | (If you properly install DTC according to the instructions in the Kryoflux documentation then you may not need to run it as root). 32 | 33 | The first time you start the program, you will see a warning that informs you a new settings file is being created. This settings file is located in the .diskFormatID directory within your home directory. 34 | 35 | Click "choose formats" to select disk image formats to be created 36 | Select input and output folders and specify the directory containing the Kryoflux DTC application. These settings (including selected formats) will be saved in "settings.json" 37 | 38 | NB: the program license must already have been agreed to by navigating to the dtc directory in a terminal window and running the GUI with: 39 | 40 | java -jar kryoflux-ui.jar 41 | 42 | Then accepting the prompt. 43 | 44 | Choose how many concurrent dtc instances you want to run to create the disk images. 45 | Click "create images" to use a local copy of the Kryoflux DTC program to create the image files from a folder containing folders of raw Kryoflux stream files. NB: the interface may lock up and not update the results for a indeterminate period of time. 46 | 47 | Click a button to mount the disk image files and get feedback on which files could be mounted. Check "delete unmountable" to delete the image files that couldn't be mounted. 48 | 49 | Click either of the "save results" buttons to save the results from the corresponding window to a file (extension will be added automatically). 50 | 51 | All created disk images will be have root permissions assigned, you may need to change that after using the program. 52 | -------------------------------------------------------------------------------- /attic/settings.json: -------------------------------------------------------------------------------- 1 | {"outputFormats": [{"Image type": "-i4"}, {"Image type": "-i10"}, {"Image type": "-i9"}], "mainSettings": [{"Output directory": "/home/euan/kryo/output/", "DTC directory": "/home/euan/kryo/kryoflux_2.6_linux/dtc/", "Input directory": "/home/euan/kryo/smallTest/", "Delete unmountable": "TRUE"}]} -------------------------------------------------------------------------------- /chooseFormats.py: -------------------------------------------------------------------------------- 1 | from PyQt4 import QtGui 2 | import sys 3 | import os 4 | import json 5 | import chooseFormatsGUI 6 | 7 | 8 | imageTypes = {"CT Raw":"-i2","FM Sector":"-i3","FM XFD":"-i3a","MFM":"-i4","Amiga DOS":"-i5","CBM DOS":"-i6","CBM DOS ErrMap":"-i7","Apple DOS 3.2":"-i8","Apple DOS 3.3":"-i8a","DSK":"-i9","Apple DOS 400/800K":"-i10","EMU":"-i11","EMU2":"-i12","Amiga Disk Spare":"-i13","DEC RX01":"-i14","DEC RX02":"-i15","CBM Micro Prose":"-i16","CBM RapidLok":"-i17","CBM Datasoft":"-i18","CBM Vorpal":"-i19","CBM V-MAX":"-i20","CBM Teque":"-i21","CBM TDP":"-i22","CBM GCR":"-i22a","CBM Big5":"-i23","CBM DOS":"-i24","CBM OziSoft":"-i25"} 9 | imageFmts = {'-i3a': 'FM XFD', '-i24': 'CBM DOS', '-i25': 'CBM OziSoft', '-i20': 'CBM V-MAX', '-i21': 'CBM Teque', '-i22': 'CBM TDP', '-i23': 'CBM Big5', '-i22a': 'CBM GCR', '-i9': 'DSK', '-i8': 'Apple DOS 3.2', '-i3': 'FM Sector', '-i2': 'CT Raw', '-i5': 'Amiga DOS', '-i4': 'MFM', '-i7': 'CBMDOS ErrMap', '-i15': 'DEC RX02', '-i14': 'DEC RX01', '-i17': 'CBM RapidLok', '-i16': 'CBM MicroProse', '-i11': 'EMU', '-i10': 'Apple DOS 400/800K', '-i13': 'Amiga Disk Spare', '-i12': 'EMU2', '-i19': 'CBM Vorpal', '-i18': 'CBM Datasoft', '-i8a': 'AppleDOS3.3'} 10 | 11 | endTracks = ("x","-e73","-e72","-e79","-e39","-e34","-e76","-e81") 12 | 13 | sideModes = {"Both sides":"-g2","Side 0":"-g0","Side 1":"-g1"} 14 | sideModesRv = {'-g2': 'Both sides', '-g1': 'Side 1', '-g0': 'Side 0'} 15 | 16 | sectorSizes = {"128":"-z0","256":"-z1","512":"-z3","1024":"-z2"} 17 | sectorSizesRv = {'-z0': '128', '-z1': '256', '-z2': '1024', '-z3': '512'} 18 | 19 | sectorCounts = {"Exactly":"+","At most":"-"} 20 | sectorCountsRv = {'+': 'Exactly', '-': 'At most'} 21 | 22 | trackDistances = {"80":"-k1","40":"-k2"} 23 | trackDistancesRv = {"-k1":"80","-k2":"40"} 24 | 25 | targetRPMsBasic = {"300":"-v300","288":"-v288","360":"-v360","150":"-v150"} 26 | targetRPMsBasicRv = {'-v150': '150', '-v288': '288', '-v300': '300', '-v360': '360'} 27 | 28 | driveDensities = {"High":"-dd0","Low":"-dd1"} 29 | driveDensitiesRv = {"-dd0":"High","-dd1":"Low"} 30 | 31 | outputTrackOrders = {"Side 0 descending":"-oo1","Side 1 descending":"-oo2","Side 1 then side 0":"-oo4","Side oriented":"-oo8"} 32 | outputTrackOrdersRv = {'-oo1': 'Side 0 descending', '-oo8': 'Side oriented', '-oo2': 'Side 1 descending', '-oo4': 'Side 1 then side 0'} 33 | 34 | global spath 35 | spath = os.getenv("HOME") + '/.diskFormatID/settings.json' 36 | 37 | class addTypes(QtGui.QMainWindow, chooseFormatsGUI.Ui_addTypes): 38 | def __init__(self, parent=None): 39 | global spath 40 | super(addTypes, self).__init__(parent) 41 | self.setupUi(self) 42 | self.imageTypeCB.clear() 43 | # populate the combo box with the keys in the image variables defined above 44 | self.imageTypeCB.addItems(imageTypes.keys()) 45 | #set the default value actual defaults 46 | #set most of the combo boxes to not editable/greyed out by default (that will be changed if the check box is unchecked 47 | self.imageTypeCB.setCurrentIndex(self.imageTypeCB.findText('MFM')) 48 | self.trackDistanceCB.addItems(trackDistances.keys()) 49 | self.trackDistanceCB.setCurrentIndex(self.trackDistanceCB.findText('40')) 50 | 51 | self.trackDistanceCB.setEnabled(False) 52 | 53 | self.sectorCountCB.addItems(sectorCounts.keys()) 54 | self.sectorCountCB.setEnabled(False) 55 | 56 | self.sideModeCB.addItems(sideModes.keys()) 57 | self.sideModeCB.setCurrentIndex(self.sideModeCB.findText('Both sides')) 58 | self.sideModeCB.setEnabled(False) 59 | 60 | self.sectorSizeCB.addItems(sectorSizes.keys()) 61 | self.sectorSizeCB.setCurrentIndex(self.sectorSizeCB.findText('512')) 62 | self.sectorSizeCB.setEnabled(False) 63 | 64 | self.startTrack.setEnabled(False) 65 | self.endTrack.setEnabled(False) 66 | self.sectorCount.setEnabled(False) 67 | 68 | self.targetRPMCB.addItems(targetRPMsBasic.keys()) 69 | self.targetRPMCB.setEnabled(False) 70 | 71 | 72 | # if the reset all button is clicked launch that function 73 | self.resetTypes.clicked.connect(self.reset_types) 74 | 75 | 76 | #open the spath file for reading 77 | if os.stat(spath).st_size != 0: 78 | self.updateTextBrowserFromJSON() 79 | else: 80 | #pass if file is empty 81 | pass 82 | 83 | def reset_types(self): 84 | global spath 85 | #open the json file and get the contents 86 | 87 | with open(spath ,'r') as settings_file: 88 | 89 | settings = json.load(settings_file) 90 | # try deleting the outputFormats element/key 91 | try: 92 | del settings['outputFormats'] 93 | except KeyError: 94 | pass 95 | #write back the remaining json 96 | jsoutput = json.dumps(settings) 97 | outfile = open(spath, 'w') 98 | outfile.write(jsoutput) 99 | outfile.close() 100 | 101 | # clear what is in the text browser in the gui 102 | self.settingsDisplay.clear() 103 | # process that clearance event 104 | QtGui.QApplication.processEvents() 105 | 106 | def save_and_add(self): 107 | # this function adds what is in each setting to the json file 108 | global spath 109 | 110 | #check to see if the spath file is empty 111 | 112 | if os.stat(spath).st_size != 0: 113 | # if it is not empty open it for reading 114 | with open(spath,'r') as settings_file: 115 | settings = json.load(settings_file) 116 | #create a variable to store the current input in the image type comobo box 117 | imgType = imageTypes[str(self.imageTypeCB.currentText())] 118 | #print imgType 119 | #create a dictionary to store the set of settings for one disk (if needed) 120 | diskSetting = {} 121 | diskSetting.update({"Image type":imgType}) 122 | #Check to see if the side mode combo box is set to default 123 | if not self.sideModeDefault.isChecked(): 124 | # if the side mode combo box is not set to default add the contents of it to the diskSetting dictionary 125 | diskSetting.update({"Side mode":sideModes[str(self.sideModeCB.currentText())]}) 126 | if self.flippyMode.isChecked(): 127 | diskSetting.update({"Flippy mode":"-y"}) 128 | 129 | if not self.sectorSizeDefault.isChecked(): 130 | # if the sector size combo box is not set to default add the contents of it to the diskSetting dictionary 131 | diskSetting.update({"Sector size":sectorSizes[str(self.sectorSizeCB.currentText())]}) 132 | 133 | if not self.sectorCountDefault.isChecked(): 134 | # if the sector count combo box is not set to default add the contents of it to the diskSetting dictionary 135 | diskSetting.update({"Sector count":sectorCounts[str(self.sectorCountCB.currentText())] + str(self.sectorCount.text())}) 136 | 137 | if not self.trackDistanceDefault.isChecked(): 138 | # if the track distance combo box is not set to default add the contents of it to the diskSetting dictionary 139 | diskSetting.update({"Track Distance":trackDistances[str(self.trackDistanceCB.currentText())]}) 140 | 141 | if not self.tracksDefault.isChecked(): 142 | starttr = "-os" + str(self.startTrack.text()) 143 | endtr = "-oe" + str(self.endTrack.text()) 144 | diskSetting.update({"Start track":str(starttr)}) 145 | diskSetting.update({"End track":str(endtr)}) 146 | 147 | if not self.targetRPMDefault.isChecked(): 148 | # if the target RPM combo box is not set to default add the contents of it to the diskSetting dictionary 149 | diskSetting.update({"Target RPM":targetRPMsBasic[str(self.targetRPMCB.currentText())]}) 150 | 151 | # append the contents of disk settings to the format json element 152 | if "outputFormats" in settings: 153 | settings["outputFormats"].append(diskSetting) 154 | else: 155 | settings["outputFormats"] = [diskSetting] 156 | #Clear the json file and write back the updated json 157 | jsoutput = json.dumps(settings) 158 | outfile = open(spath, 'w') 159 | outfile.write(jsoutput) 160 | outfile.close() 161 | self.settingsDisplay.clear() 162 | #clear the settings text browser in the GUI 163 | #open the spath file and print the contents to the text browser in the gui, one per format instance 164 | 165 | self.updateTextBrowserFromJSON() 166 | 167 | else: 168 | #if the spath file is empty you should put something into it 169 | 170 | #this is a hangover from earlier versions where I needed to id/process the imagetype ina a unique way 171 | imgType = imageTypes[str(self.imageTypeCB.currentText())] 172 | #print imgType 173 | #create a dictionary to store the set of settings for one disk (if needed) 174 | diskSetting = {} 175 | diskSetting.update({"Image type":imgType}) 176 | #Check to see if the side mode combo box is set to default 177 | if not self.sideModeDefault.isChecked(): 178 | # if the side mode combo box is not set to default add the contents of it to the diskSetting dictionary 179 | diskSetting.update({"Side mode":sideModes[str(self.sideModeCB.currentText())]}) 180 | 181 | if not self.sectorSizeDefault.isChecked(): 182 | # if the sector size combo box is not set to default add the contents of it to the diskSetting dictionary 183 | diskSetting.update({"Sector size":sectorSizes[str(self.sectorSizeCB.currentText())]}) 184 | if self.flippyMode.isChecked(): 185 | diskSetting.update({"Flippy mode":"-y"}) 186 | 187 | if not self.sectorCountDefault.isChecked(): 188 | # if the sector count combo box is not set to default add the contents of it to the diskSetting dictionary 189 | diskSetting.update({"Sector count":sectorCounts[str(self.sectorCountCB.currentText())] + str(self.sectorCount.text())}) 190 | 191 | if not self.trackDistanceDefault.isChecked(): 192 | # if the track distance combo box is not set to default add the contents of it to the diskSetting dictionary 193 | diskSetting.update({"Track Distance":trackDistances[str(self.trackDistanceCB.currentText())]}) 194 | 195 | if not self.tracksDefault.isChecked(): 196 | starttr = "-os" + str(self.startTrack.text()) 197 | endtr = "-oe" + str(self.endTrack.text()) 198 | diskSetting.update({"Start track":starttr}) 199 | diskSetting.update({"End track":endtr}) 200 | 201 | 202 | if not self.targetRPMDefault.isChecked(): 203 | # if the target RPM combo box is not set to default add the contents of it to the diskSetting dictionary 204 | diskSetting.update({"Target RPM":targetRPMsBasic[str(self.targetRPMCB.currentText())]}) 205 | 206 | #now write this all back 207 | settings = {"outputFormats":[diskSetting]} 208 | jsoutput = json.dumps(settings) 209 | outfile = open(spath, 'w') 210 | outfile.write(jsoutput) 211 | outfile.close() 212 | self.settingsDisplay.clear() 213 | self.updateTextBrowserFromJSON() 214 | 215 | def updateTextBrowserFromJSON(self): 216 | 217 | global spath 218 | #used to update what is in the textbrowser box in the GUI from the JSON file 219 | with open(spath) as settings_file: 220 | num = 0 221 | settings = json.load(settings_file) 222 | # get all the formats already stored in the file 223 | if "outputFormats" in settings: 224 | for format in settings["outputFormats"]: 225 | num = num + 1 226 | #create a variable to add content to be put into the text browser in the gui 227 | setting = "" 228 | 229 | for x in format: 230 | #For each format add the information to the setting variable, starting with Image type 231 | if x == "Image type": 232 | setting = x + ": " + imageFmts[str(format[x])] + setting 233 | elif x == "Sector size": 234 | setting = setting + ", " + x + ": " + sectorSizesRv[str(format[x])] 235 | 236 | elif x == "Side mode": 237 | setting = setting + ", " + x + ": " + sideModesRv[str(format[x])] 238 | 239 | elif x == "Sector count": 240 | setting = setting + ", " + x + ": " + sectorCountsRv[str(format[x])[0]] + str(self.sectorCount.text()) 241 | 242 | elif x == "Track distance": 243 | setting = setting + ", " + x + ": " + trackDistancesRv[str(format[x])] 244 | 245 | elif x == "Target RPM": 246 | setting = setting + ", " + x + ": " + targetRPMsBasicRv[str(format[x])] 247 | 248 | elif x == "Flippy mode": 249 | setting = setting + ", " + x + ": " + str(format[x]) 250 | 251 | elif x == "Start track": 252 | setting = setting + ", " + x + ": " + str(format[x])[2:] 253 | 254 | elif x == "End track": 255 | setting = setting + ", " + x + ": " + str(format[x])[2:] 256 | 257 | #update the text browser with the information in each format 258 | self.settingsDisplay.append("Image " + str(num) + ": " + setting) 259 | # process the update 260 | QtGui.QApplication.processEvents() 261 | 262 | 263 | settings_file.close() 264 | 265 | 266 | # set up functions to change the editablility of the various widgets when the checkboxes change to unchecked 267 | def tracks_default_change(self): 268 | if self.tracksDefault.isChecked(): 269 | self.startTrack.setEnabled(False) 270 | self.endTrack.setEnabled(False) 271 | else: 272 | self.startTrack.setEnabled(True) 273 | self.endTrack.setEnabled(True) 274 | 275 | 276 | def side_mode_default_change(self): 277 | 278 | if self.sideModeDefault.isChecked(): 279 | self.sideModeCB.setEnabled(False) 280 | else: 281 | self.sideModeCB.setEnabled(True) 282 | 283 | def sector_count_default_change(self): 284 | 285 | if self.sectorCountDefault.isChecked(): 286 | self.sectorCountCB.setEnabled(False) 287 | self.sectorCount.setEnabled(False) 288 | else: 289 | self.sectorCountCB.setEnabled(True) 290 | self.sectorCount.setEnabled(True) 291 | 292 | def sector_size_default_change(self): 293 | 294 | if self.sectorSizeDefault.isChecked(): 295 | self.sectorSizeCB.setEnabled(False) 296 | else: 297 | self.sectorSizeCB.setEnabled(True) 298 | 299 | def track_distance_default_change(self): 300 | 301 | if self.trackDistanceDefault.isChecked(): 302 | self.trackDistanceCB.setEnabled(False) 303 | else: 304 | self.trackDistanceCB.setEnabled(True) 305 | 306 | def target_RPM_default_change(self): 307 | if self.targetRPMDefault.isChecked(): 308 | self.targetRPMCB.setEnabled(False) 309 | else: 310 | self.targetRPMCB.setEnabled(True) 311 | 312 | # Don't think I strictly need this one 313 | def flippy_change(self): 314 | if self.flippyMode.isChecked(): 315 | True 316 | else: 317 | False 318 | 319 | 320 | def main(): 321 | app = QtGui.QApplication(sys.argv) 322 | form = addTypes() 323 | form.show() 324 | app.exec_() 325 | 326 | 327 | 328 | 329 | if __name__ == '__main__': 330 | main() 331 | -------------------------------------------------------------------------------- /chooseFormatsGUI.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Form implementation generated from reading ui file 'chooseFormatsGUI.ui' 4 | # 5 | # Created by: PyQt4 UI code generator 4.11.4 6 | # 7 | # WARNING! All changes made in this file will be lost! 8 | 9 | from PyQt4 import QtCore, QtGui 10 | 11 | try: 12 | _fromUtf8 = QtCore.QString.fromUtf8 13 | except AttributeError: 14 | def _fromUtf8(s): 15 | return s 16 | 17 | try: 18 | _encoding = QtGui.QApplication.UnicodeUTF8 19 | def _translate(context, text, disambig): 20 | return QtGui.QApplication.translate(context, text, disambig, _encoding) 21 | except AttributeError: 22 | def _translate(context, text, disambig): 23 | return QtGui.QApplication.translate(context, text, disambig) 24 | 25 | class Ui_addTypes(object): 26 | def setupUi(self, addTypes): 27 | addTypes.setObjectName(_fromUtf8("addTypes")) 28 | addTypes.resize(439, 587) 29 | self.centralwidget = QtGui.QWidget(addTypes) 30 | self.centralwidget.setObjectName(_fromUtf8("centralwidget")) 31 | self.imageTypeCB = QtGui.QComboBox(self.centralwidget) 32 | self.imageTypeCB.setGeometry(QtCore.QRect(118, 10, 221, 27)) 33 | self.imageTypeCB.setObjectName(_fromUtf8("imageTypeCB")) 34 | self.startTrack = QtGui.QLineEdit(self.centralwidget) 35 | self.startTrack.setGeometry(QtCore.QRect(118, 60, 61, 27)) 36 | self.startTrack.setObjectName(_fromUtf8("startTrack")) 37 | self.endTrack = QtGui.QLineEdit(self.centralwidget) 38 | self.endTrack.setGeometry(QtCore.QRect(277, 59, 61, 27)) 39 | self.endTrack.setObjectName(_fromUtf8("endTrack")) 40 | self.sideModeCB = QtGui.QComboBox(self.centralwidget) 41 | self.sideModeCB.setGeometry(QtCore.QRect(118, 100, 221, 27)) 42 | self.sideModeCB.setObjectName(_fromUtf8("sideModeCB")) 43 | self.sectorSizeCB = QtGui.QComboBox(self.centralwidget) 44 | self.sectorSizeCB.setGeometry(QtCore.QRect(118, 140, 221, 27)) 45 | self.sectorSizeCB.setObjectName(_fromUtf8("sectorSizeCB")) 46 | self.sectorCountCB = QtGui.QComboBox(self.centralwidget) 47 | self.sectorCountCB.setGeometry(QtCore.QRect(118, 177, 101, 27)) 48 | self.sectorCountCB.setObjectName(_fromUtf8("sectorCountCB")) 49 | self.sectorCount = QtGui.QLineEdit(self.centralwidget) 50 | self.sectorCount.setGeometry(QtCore.QRect(248, 177, 41, 27)) 51 | self.sectorCount.setObjectName(_fromUtf8("sectorCount")) 52 | self.trackDistanceCB = QtGui.QComboBox(self.centralwidget) 53 | self.trackDistanceCB.setGeometry(QtCore.QRect(118, 217, 221, 27)) 54 | self.trackDistanceCB.setObjectName(_fromUtf8("trackDistanceCB")) 55 | self.flippyMode = QtGui.QCheckBox(self.centralwidget) 56 | self.flippyMode.setGeometry(QtCore.QRect(131, 295, 121, 22)) 57 | self.flippyMode.setObjectName(_fromUtf8("flippyMode")) 58 | self.tracksDefault = QtGui.QCheckBox(self.centralwidget) 59 | self.tracksDefault.setEnabled(True) 60 | self.tracksDefault.setGeometry(QtCore.QRect(350, 62, 99, 22)) 61 | self.tracksDefault.setChecked(True) 62 | self.tracksDefault.setObjectName(_fromUtf8("tracksDefault")) 63 | self.sideModeDefault = QtGui.QCheckBox(self.centralwidget) 64 | self.sideModeDefault.setGeometry(QtCore.QRect(350, 103, 99, 22)) 65 | self.sideModeDefault.setChecked(True) 66 | self.sideModeDefault.setObjectName(_fromUtf8("sideModeDefault")) 67 | self.sectorSizeDefault = QtGui.QCheckBox(self.centralwidget) 68 | self.sectorSizeDefault.setGeometry(QtCore.QRect(349, 143, 99, 22)) 69 | self.sectorSizeDefault.setChecked(True) 70 | self.sectorSizeDefault.setObjectName(_fromUtf8("sectorSizeDefault")) 71 | self.sectorCountDefault = QtGui.QCheckBox(self.centralwidget) 72 | self.sectorCountDefault.setGeometry(QtCore.QRect(349, 180, 99, 22)) 73 | self.sectorCountDefault.setChecked(True) 74 | self.sectorCountDefault.setObjectName(_fromUtf8("sectorCountDefault")) 75 | self.trackDistanceDefault = QtGui.QCheckBox(self.centralwidget) 76 | self.trackDistanceDefault.setGeometry(QtCore.QRect(349, 217, 99, 22)) 77 | self.trackDistanceDefault.setChecked(True) 78 | self.trackDistanceDefault.setObjectName(_fromUtf8("trackDistanceDefault")) 79 | self.addType = QtGui.QPushButton(self.centralwidget) 80 | self.addType.setGeometry(QtCore.QRect(259, 290, 171, 31)) 81 | self.addType.setObjectName(_fromUtf8("addType")) 82 | self.label = QtGui.QLabel(self.centralwidget) 83 | self.label.setGeometry(QtCore.QRect(29, 12, 81, 20)) 84 | self.label.setObjectName(_fromUtf8("label")) 85 | self.label_2 = QtGui.QLabel(self.centralwidget) 86 | self.label_2.setGeometry(QtCore.QRect(29, 62, 81, 20)) 87 | self.label_2.setObjectName(_fromUtf8("label_2")) 88 | self.label_3 = QtGui.QLabel(self.centralwidget) 89 | self.label_3.setGeometry(QtCore.QRect(205, 62, 71, 20)) 90 | self.label_3.setObjectName(_fromUtf8("label_3")) 91 | self.label_4 = QtGui.QLabel(self.centralwidget) 92 | self.label_4.setGeometry(QtCore.QRect(31, 104, 81, 20)) 93 | self.label_4.setObjectName(_fromUtf8("label_4")) 94 | self.label_5 = QtGui.QLabel(self.centralwidget) 95 | self.label_5.setGeometry(QtCore.QRect(29, 143, 81, 20)) 96 | self.label_5.setObjectName(_fromUtf8("label_5")) 97 | self.label_6 = QtGui.QLabel(self.centralwidget) 98 | self.label_6.setGeometry(QtCore.QRect(19, 180, 91, 20)) 99 | self.label_6.setObjectName(_fromUtf8("label_6")) 100 | self.label_7 = QtGui.QLabel(self.centralwidget) 101 | self.label_7.setGeometry(QtCore.QRect(9, 220, 101, 20)) 102 | self.label_7.setObjectName(_fromUtf8("label_7")) 103 | self.label_8 = QtGui.QLabel(self.centralwidget) 104 | self.label_8.setGeometry(QtCore.QRect(24, 260, 81, 20)) 105 | self.label_8.setObjectName(_fromUtf8("label_8")) 106 | self.targetRPMDefault = QtGui.QCheckBox(self.centralwidget) 107 | self.targetRPMDefault.setGeometry(QtCore.QRect(350, 258, 99, 22)) 108 | self.targetRPMDefault.setChecked(True) 109 | self.targetRPMDefault.setObjectName(_fromUtf8("targetRPMDefault")) 110 | self.settingsDisplay = QtGui.QTextBrowser(self.centralwidget) 111 | self.settingsDisplay.setGeometry(QtCore.QRect(10, 370, 421, 171)) 112 | self.settingsDisplay.setObjectName(_fromUtf8("settingsDisplay")) 113 | self.resetTypes = QtGui.QPushButton(self.centralwidget) 114 | self.resetTypes.setGeometry(QtCore.QRect(330, 338, 99, 27)) 115 | self.resetTypes.setObjectName(_fromUtf8("resetTypes")) 116 | self.label_9 = QtGui.QLabel(self.centralwidget) 117 | self.label_9.setGeometry(QtCore.QRect(12, 350, 181, 17)) 118 | font = QtGui.QFont() 119 | font.setBold(True) 120 | font.setWeight(75) 121 | self.label_9.setFont(font) 122 | self.label_9.setObjectName(_fromUtf8("label_9")) 123 | self.targetRPMCB = QtGui.QComboBox(self.centralwidget) 124 | self.targetRPMCB.setGeometry(QtCore.QRect(118, 255, 221, 27)) 125 | self.targetRPMCB.setObjectName(_fromUtf8("targetRPMCB")) 126 | addTypes.setCentralWidget(self.centralwidget) 127 | self.menubar = QtGui.QMenuBar(addTypes) 128 | self.menubar.setGeometry(QtCore.QRect(0, 0, 439, 25)) 129 | self.menubar.setObjectName(_fromUtf8("menubar")) 130 | addTypes.setMenuBar(self.menubar) 131 | self.statusbar = QtGui.QStatusBar(addTypes) 132 | self.statusbar.setObjectName(_fromUtf8("statusbar")) 133 | addTypes.setStatusBar(self.statusbar) 134 | 135 | self.retranslateUi(addTypes) 136 | QtCore.QObject.connect(self.resetTypes, QtCore.SIGNAL(_fromUtf8("clicked()")), addTypes.reset_types) 137 | QtCore.QObject.connect(self.addType, QtCore.SIGNAL(_fromUtf8("clicked()")), addTypes.save_and_add) 138 | QtCore.QObject.connect(self.tracksDefault, QtCore.SIGNAL(_fromUtf8("stateChanged(int)")), addTypes.tracks_default_change) 139 | QtCore.QObject.connect(self.sideModeDefault, QtCore.SIGNAL(_fromUtf8("stateChanged(int)")), addTypes.side_mode_default_change) 140 | QtCore.QObject.connect(self.sectorSizeDefault, QtCore.SIGNAL(_fromUtf8("stateChanged(int)")), addTypes.sector_size_default_change) 141 | QtCore.QObject.connect(self.sectorCountDefault, QtCore.SIGNAL(_fromUtf8("stateChanged(int)")), addTypes.sector_count_default_change) 142 | QtCore.QObject.connect(self.trackDistanceDefault, QtCore.SIGNAL(_fromUtf8("stateChanged(int)")), addTypes.track_distance_default_change) 143 | QtCore.QObject.connect(self.targetRPMDefault, QtCore.SIGNAL(_fromUtf8("stateChanged(int)")), addTypes.target_RPM_default_change) 144 | QtCore.QObject.connect(self.flippyMode, QtCore.SIGNAL(_fromUtf8("stateChanged(int)")), addTypes.flippy_change) 145 | QtCore.QMetaObject.connectSlotsByName(addTypes) 146 | 147 | def retranslateUi(self, addTypes): 148 | addTypes.setWindowTitle(_translate("addTypes", "Add Disk Types", None)) 149 | self.flippyMode.setText(_translate("addTypes", "Flippy Mode", None)) 150 | self.tracksDefault.setText(_translate("addTypes", "Default", None)) 151 | self.sideModeDefault.setText(_translate("addTypes", "Default", None)) 152 | self.sectorSizeDefault.setText(_translate("addTypes", "Default", None)) 153 | self.sectorCountDefault.setText(_translate("addTypes", "Default", None)) 154 | self.trackDistanceDefault.setText(_translate("addTypes", "Default", None)) 155 | self.addType.setText(_translate("addTypes", "Save (and add another)", None)) 156 | self.label.setText(_translate("addTypes", "Image Type", None)) 157 | self.label_2.setText(_translate("addTypes", "Start Track", None)) 158 | self.label_3.setText(_translate("addTypes", "End Track", None)) 159 | self.label_4.setText(_translate("addTypes", "Side Mode", None)) 160 | self.label_5.setText(_translate("addTypes", "Sector Size", None)) 161 | self.label_6.setText(_translate("addTypes", "Sector Count", None)) 162 | self.label_7.setText(_translate("addTypes", "Track distance", None)) 163 | self.label_8.setText(_translate("addTypes", "Target RPM", None)) 164 | self.targetRPMDefault.setText(_translate("addTypes", "Default", None)) 165 | self.resetTypes.setText(_translate("addTypes", "Reset all", None)) 166 | self.label_9.setText(_translate("addTypes", "Configured image types:", None)) 167 | 168 | -------------------------------------------------------------------------------- /diskIDMain: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2 2 | from PyQt4 import QtGui, QtCore 3 | from distutils.dir_util import copy_tree 4 | import sys 5 | import os 6 | import diskIDMainGUI 7 | import chooseFormats 8 | import subprocess 9 | import json 10 | import shutil 11 | import sys 12 | import getpass 13 | from subprocess import Popen 14 | from subprocess import check_output 15 | from itertools import islice 16 | 17 | 18 | global inpDirLoc 19 | global outDirLoc 20 | global dtcDirloc 21 | 22 | 23 | impDirLoc = "" 24 | outDirLoc = "" 25 | dtcDirLoc = "" 26 | 27 | spath = os.getenv("HOME") + '/.diskFormatID/settings.json' 28 | 29 | class kryoMain(QtGui.QMainWindow, diskIDMainGUI.Ui_kryoMain): 30 | def __init__(self, parent=None): 31 | #don't really understand global variables well enough, but I think I need to put these here 32 | global inpDirLoc 33 | 34 | global outDirLoc 35 | 36 | global dtcDirLoc 37 | # start the whole gui thing 38 | super(kryoMain, self).__init__(parent) 39 | self.setupUi(self) 40 | 41 | # set the dtc max concurrent isntances box to default to 1 42 | self.DTCInstances.setText("1") 43 | 44 | # Check for existence of settings file for local user. If it doesn't 45 | # exist (e.g. on first use) warn and create) 46 | 47 | if not os.path.exists(spath): 48 | 49 | QtGui.QMessageBox.warning(self, "First run notice", 50 | "It looks like you're running the program for the first time as this user. I'm creating a new default settings file for you in " + spath, 51 | QtGui.QMessageBox.Ok, QtGui.QMessageBox.NoButton, 52 | QtGui.QMessageBox.NoButton) 53 | 54 | os.mkdir(os.getenv("HOME") + '/.diskFormatID') 55 | sfile = open(spath, 'w+') 56 | sfile.write('{"outputFormats": [{"Image type": "-i4"}, {"Image type": "-i10"}, {"Image type": "-i9"}], "mainSettings": [{"Output directory": "/home/euan/kryo/output/", "DTC directory": "/home/euan/kryo/kryoflux_2.6_linux/dtc/", "Input directory": "/home/euan/kryo/smallTest/", "Delete unmountable": "TRUE"}]}') 57 | sfile.close() 58 | 59 | # Probably need to change ownership settings if this program 60 | # is being run as root, and the user later decides to run it 61 | # as themselves. Fix this ina future version. Right now, 62 | # the settings directory and file installed in the dot-directory 63 | # will be root-owned if run as sudo. 64 | 65 | #open the settings.json file for reading 66 | if os.stat(spath).st_size != 0: 67 | with open(spath) as settings_file: 68 | 69 | #set main settings to values from settings json file 70 | settings = json.load(settings_file) 71 | if "mainSettings" in settings: 72 | for setting in settings["mainSettings"]: 73 | self.inputDir.setText(setting["Input directory"]) 74 | dtcDirLoc = str(setting["DTC directory"]) 75 | self.DTCDir.setText(setting["DTC directory"]) 76 | inpDirLoc = str(setting["Input directory"]) 77 | self.outputDir.setText(setting["Output directory"]) 78 | outDirLoc = str(setting["Output directory"]) 79 | if setting == "Delete unmountable": 80 | if setting["Delete unmountable"] == "TRUE": 81 | self.deleteUnmountable.setChecked(true) 82 | else: 83 | self.deleteUnmountable.setChecked(true) 84 | 85 | 86 | 87 | # initiate sub program to choose formats when button is clicked 88 | 89 | def choose_formats(self): 90 | 91 | self.addTypes = chooseFormats.addTypes() 92 | self.addTypes.show() 93 | 94 | 95 | # function below takes input from create images button and creates the images 96 | 97 | 98 | def create_images(self): 99 | global inpDirLoc 100 | 101 | global outDirLoc 102 | 103 | global dtcDirLoc 104 | 105 | with open(spath) as data_file: 106 | data = json.load(data_file) 107 | 108 | # set input variables for the source and destination file directories and dtc directory 109 | 110 | source_dirname= inpDirLoc 111 | dest_dir = outDirLoc 112 | dtc_dir = dtcDirLoc 113 | commands = [] 114 | 115 | outdir = () 116 | 117 | # check the input folder and find all sub directories 118 | for dirname, dirnames, filenames in os.walk(source_dirname): 119 | 120 | # get the folder names for each sub directory 121 | for subdirname in dirnames: 122 | 123 | # create a variable to use for the sub directory paths 124 | indirname = os.path.join(dirname, subdirname) 125 | #print str(indirname) 126 | 127 | 128 | # check each sub directory to see if it has a stream file in it 129 | if os.path.isfile(os.path.join(indirname, "track00.0.raw")) == True: 130 | 131 | # create directories to copy the streamfiles to, as the directories have to have no spaces in them, then copy the files to those directories 132 | 133 | outTrackDir = os.path.join(dest_dir,subdirname.replace(" ","_"),"track") 134 | if not os.path.exists(outTrackDir): 135 | os.makedirs(outTrackDir) 136 | outdir = os.path.join(dest_dir, subdirname.replace(" ","_")) 137 | 138 | for trackFile in os.listdir(indirname): 139 | if not os.path.isfile(os.path.join(outTrackDir,trackFile)): 140 | self.imageCreationResults.append("copying track " + str(os.path.join(indirname,trackFile))) 141 | QtGui.QApplication.processEvents() 142 | shutil.copyfile(os.path.join(indirname,trackFile),os.path.join(outTrackDir,trackFile)) 143 | 144 | 145 | 146 | 147 | #setup a variable to form each command into 148 | for format in data["outputFormats"]: 149 | command = set() 150 | 151 | filepath = os.path.join(outdir, subdirname.replace(" ","_")) 152 | #print str(trackPath) 153 | 154 | for param in format: 155 | if command != "": 156 | command.add(format[param]) 157 | filepath = filepath + format[param] 158 | 159 | else: 160 | command = format[param] 161 | filepath = filepath + format[param] 162 | 163 | commands.append((dtc_dir + "./dtc", "-f" + str(filepath) + ".img", "-m1", ", ".join([str(x) for x in command]), "-f" + outTrackDir + "/track","-i0")) 164 | 165 | 166 | 167 | # Now run the commands in paralell 168 | # set max concurrent instances from feild in gui 169 | max_workers = int(self.DTCInstances.text()) 170 | processes = (Popen(cmd, cwd=dtc_dir,stdout=subprocess.PIPE,stderr=subprocess.PIPE) for cmd in commands) 171 | 172 | running_processes = list(islice(processes, max_workers)) 173 | while running_processes: 174 | results = [] 175 | for i, process in enumerate(running_processes): 176 | out, err = process.communicate() 177 | 178 | #update the text browser with the status 179 | 180 | 181 | results.append(str(out) + str(err)) 182 | # process the update to the gui 183 | QtGui.QApplication.processEvents() 184 | if process.poll() is not None: # the process has finished 185 | running_processes[i] = next(processes, None) # start new process 186 | if running_processes[i] is None: # no new processes 187 | del running_processes[i] 188 | break 189 | for result in results: 190 | self.imageCreationResults.append(result) 191 | self.imageCreationResults.append(" ") 192 | self.imageCreationResults.append("------------------------------------------------") 193 | self.imageCreationResults.append("Creation of images complete") 194 | self.imageCreationResults.append("------------------------------------------------") 195 | 196 | 197 | def try_mounting(self): 198 | global outDirLoc 199 | dest_dir = outDirLoc 200 | 201 | # now try mounting the files you created and delete the ones that don't mount 202 | 203 | #select all directories in the destination directory 204 | for dirname, dirnames, filenames in os.walk(dest_dir): 205 | 206 | # for each of those find the files in them 207 | for subdirname in dirnames: 208 | indirname = os.path.join(dirname,subdirname) 209 | 210 | 211 | #for each disk image file in that directory 212 | for dirname2, dirnames2, filenames2 in os.walk(indirname): 213 | for filenm in filenames2: 214 | if not "track" in str(os.path.join(dest_dir, indirname, filenm)): 215 | # for each file, mount it and put the resulting errors into a variable p.stderr 216 | #update the text browser with the status 217 | self.MountingResults.append("Trying to mount " + str(filenm)) 218 | # process the update to the gui 219 | QtGui.QApplication.processEvents() 220 | p = subprocess.Popen(["mount", "-O loop", os.path.join(dest_dir, indirname, filenm), "/mnt"], stderr=subprocess.PIPE) 221 | 222 | # if there is no error then umount the disk image 223 | if p.stderr.readline() == "": 224 | #update the text browser with the status 225 | self.MountingResults.append(str(filenm) + " mounted successfully") 226 | # process the update to the gui 227 | QtGui.QApplication.processEvents() 228 | subprocess.call(["umount", "/mnt"]) 229 | self.MountingResults.append(" ") 230 | self.MountingResults.append("------------------------------------------------") 231 | self.MountingResults.append(" ") 232 | 233 | 234 | else: 235 | #update the text browser with the status 236 | self.MountingResults.append(str(filenm) + " mounting failed") 237 | 238 | # process the update to the gui 239 | QtGui.QApplication.processEvents() 240 | if self.deleteUnmountable.isChecked(): 241 | #update the text browser with the status 242 | self.MountingResults.append("Deleting " + str(filenm)) 243 | self.MountingResults.append(" ") 244 | self.MountingResults.append("------------------------------------------------") 245 | self.MountingResults.append(" ") 246 | # process the update to the gui 247 | QtGui.QApplication.processEvents() 248 | subprocess.call(["rm", os.path.join(dest_dir, indirname, filenm)]) 249 | else: 250 | 251 | self.MountingResults.append(" ") 252 | self.MountingResults.append("------------------------------------------------") 253 | self.MountingResults.append(" ") 254 | self.MountingResults.append 255 | self.MountingResults.append("Mounting process complete") 256 | self.MountingResults.append(" ") 257 | self.MountingResults.append("------------------------------------------------") 258 | 259 | def delete_unmountable_change(self): 260 | 261 | if os.stat(spath).st_size != 0: 262 | # if it is not empty open it for reading 263 | with open(spath,'r') as settings_file: 264 | settings = json.load(settings_file) 265 | if self.deleteUnmountable.isChecked(): 266 | for setting in settings["mainSettings"]: 267 | setting["Delete unmountable"] = "TRUE" 268 | 269 | else: 270 | for setting in settings["mainSettings"]: 271 | setting["Delete unmountable"] = "FALSE" 272 | jsoutput = json.dumps(settings) 273 | outfile = open(spath, 'w') 274 | outfile.write(jsoutput) 275 | outfile.close() 276 | 277 | def browse_dtc_dir(self): 278 | 279 | global dtcDirLoc 280 | dtcDirLoc = QtGui.QFileDialog.getExistingDirectory(self, 281 | "Select a folder") + "/" 282 | dtcDirLoc = str(dtcDirLoc) 283 | self.DTCDir.setText(dtcDirLoc) 284 | 285 | if os.stat(spath).st_size != 0: 286 | # if it is not empty open it for reading 287 | with open(spath,'r') as settings_file: 288 | settings = json.load(settings_file) 289 | for setting in settings["mainSettings"]: 290 | setting["DTC directory"] = str(dtcDirLoc) 291 | 292 | jsoutput = json.dumps(settings) 293 | outfile = open(spath, 'w') 294 | outfile.write(jsoutput) 295 | outfile.close() 296 | 297 | #This function processes the browse input directory button press 298 | def browse_inp_dir(self): 299 | global inpDirLoc 300 | 301 | inpDirLoc = QtGui.QFileDialog.getExistingDirectory(self, 302 | "Select a folder") + "/" 303 | inpDirLoc = str(inpDirLoc) 304 | self.inputDir.setText(inpDirLoc) 305 | 306 | if os.stat(spath).st_size != 0: 307 | # if it is not empty open it for reading 308 | with open(spath,'r') as settings_file: 309 | settings = json.load(settings_file) 310 | for setting in settings["mainSettings"]: 311 | setting["Input directory"] = str(inpDirLoc) 312 | 313 | jsoutput = json.dumps(settings) 314 | outfile = open(spath, 'w') 315 | outfile.write(jsoutput) 316 | outfile.close() 317 | 318 | def save_mounting_results(self): 319 | # get file path from user input browsing 320 | saveFilePath = QtGui.QFileDialog.getSaveFileName(self,'Choose save file location',str(outDirLoc),selectedFilter='*.txt') 321 | #make file extension .txt if not already 322 | if str(saveFilePath)[-4:] != '.txt': 323 | saveFilePath = saveFilePath + ".txt" 324 | #assing textbrowser contents to a variable and write it to the file selected above 325 | mountingResultsDialog = self.MountingResults.toPlainText() 326 | outfile = open(saveFilePath, 'w') 327 | outfile.write(mountingResultsDialog) 328 | outfile.close() 329 | 330 | 331 | 332 | 333 | def save_dtc_results(self): 334 | # get file path from user input browsing 335 | saveDTCPath = QtGui.QFileDialog.getSaveFileName(self,'Choose save file location',str(outDirLoc),selectedFilter='*.txt') 336 | #make file extension .txt if not already 337 | if str(saveDTCPath)[-4:] != '.txt': 338 | saveDTCPath = saveDTCPath + ".txt" 339 | #assing textbrowser contents to a variable and write it to the file selected above 340 | imageCreationResultsDialog = self.imageCreationResults.toPlainText() 341 | outfile = open(saveDTCPath, 'w') 342 | outfile.write(imageCreationResultsDialog) 343 | outfile.close() 344 | 345 | 346 | def browse_output_dir(self): 347 | global outDirLoc 348 | 349 | outDirLoc = QtGui.QFileDialog.getExistingDirectory(self, 350 | "Select a folder") + "/" 351 | outDirLoc = str(outDirLoc) 352 | self.outputDir.setText(outDirLoc) 353 | 354 | if os.stat(spath).st_size != 0: 355 | # if it is not empty open it for reading 356 | with open(spath,'r') as settings_file: 357 | settings = json.load(settings_file) 358 | for setting in settings["mainSettings"]: 359 | setting["Output directory"] = str(outDirLoc) 360 | 361 | jsoutput = json.dumps(settings) 362 | outfile = open(spath, 'w') 363 | outfile.write(jsoutput) 364 | outfile.close() 365 | 366 | def main(): 367 | app = QtGui.QApplication(sys.argv) 368 | form = kryoMain() 369 | form.show() 370 | app.exec_() 371 | 372 | 373 | 374 | 375 | if __name__ == '__main__': 376 | main() 377 | -------------------------------------------------------------------------------- /diskIDMainGUI.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Form implementation generated from reading ui file 'diskIDMainGUI.ui' 4 | # 5 | # Created by: PyQt4 UI code generator 4.11.4 6 | # 7 | # WARNING! All changes made in this file will be lost! 8 | 9 | from PyQt4 import QtCore, QtGui 10 | 11 | try: 12 | _fromUtf8 = QtCore.QString.fromUtf8 13 | except AttributeError: 14 | def _fromUtf8(s): 15 | return s 16 | 17 | try: 18 | _encoding = QtGui.QApplication.UnicodeUTF8 19 | def _translate(context, text, disambig): 20 | return QtGui.QApplication.translate(context, text, disambig, _encoding) 21 | except AttributeError: 22 | def _translate(context, text, disambig): 23 | return QtGui.QApplication.translate(context, text, disambig) 24 | 25 | class Ui_kryoMain(object): 26 | def setupUi(self, kryoMain): 27 | kryoMain.setObjectName(_fromUtf8("kryoMain")) 28 | kryoMain.resize(770, 600) 29 | self.centralwidget = QtGui.QWidget(kryoMain) 30 | self.centralwidget.setObjectName(_fromUtf8("centralwidget")) 31 | self.chooseFormats = QtGui.QPushButton(self.centralwidget) 32 | self.chooseFormats.setGeometry(QtCore.QRect(30, 10, 201, 27)) 33 | self.chooseFormats.setObjectName(_fromUtf8("chooseFormats")) 34 | self.createImages = QtGui.QPushButton(self.centralwidget) 35 | self.createImages.setGeometry(QtCore.QRect(30, 50, 201, 71)) 36 | self.createImages.setObjectName(_fromUtf8("createImages")) 37 | self.tryMounting = QtGui.QPushButton(self.centralwidget) 38 | self.tryMounting.setGeometry(QtCore.QRect(30, 330, 191, 27)) 39 | self.tryMounting.setObjectName(_fromUtf8("tryMounting")) 40 | self.imageCreationResults = QtGui.QTextBrowser(self.centralwidget) 41 | self.imageCreationResults.setGeometry(QtCore.QRect(30, 140, 711, 181)) 42 | self.imageCreationResults.setObjectName(_fromUtf8("imageCreationResults")) 43 | self.MountingResults = QtGui.QTextBrowser(self.centralwidget) 44 | self.MountingResults.setGeometry(QtCore.QRect(31, 360, 711, 192)) 45 | self.MountingResults.setObjectName(_fromUtf8("MountingResults")) 46 | self.deleteUnmountable = QtGui.QCheckBox(self.centralwidget) 47 | self.deleteUnmountable.setGeometry(QtCore.QRect(225, 333, 171, 22)) 48 | self.deleteUnmountable.setChecked(False) 49 | self.deleteUnmountable.setObjectName(_fromUtf8("deleteUnmountable")) 50 | self.browseOutputDir = QtGui.QPushButton(self.centralwidget) 51 | self.browseOutputDir.setGeometry(QtCore.QRect(250, 80, 141, 27)) 52 | self.browseOutputDir.setObjectName(_fromUtf8("browseOutputDir")) 53 | self.browseInpDir = QtGui.QPushButton(self.centralwidget) 54 | self.browseInpDir.setGeometry(QtCore.QRect(250, 46, 141, 27)) 55 | self.browseInpDir.setObjectName(_fromUtf8("browseInpDir")) 56 | self.browseDTCDir = QtGui.QPushButton(self.centralwidget) 57 | self.browseDTCDir.setGeometry(QtCore.QRect(250, 10, 141, 27)) 58 | self.browseDTCDir.setObjectName(_fromUtf8("browseDTCDir")) 59 | self.inputDir = QtGui.QLineEdit(self.centralwidget) 60 | self.inputDir.setGeometry(QtCore.QRect(410, 46, 331, 27)) 61 | self.inputDir.setObjectName(_fromUtf8("inputDir")) 62 | self.outputDir = QtGui.QLineEdit(self.centralwidget) 63 | self.outputDir.setGeometry(QtCore.QRect(410, 80, 331, 27)) 64 | self.outputDir.setObjectName(_fromUtf8("outputDir")) 65 | self.DTCDir = QtGui.QLineEdit(self.centralwidget) 66 | self.DTCDir.setGeometry(QtCore.QRect(410, 11, 331, 27)) 67 | self.DTCDir.setObjectName(_fromUtf8("DTCDir")) 68 | self.saveMountingResults = QtGui.QPushButton(self.centralwidget) 69 | self.saveMountingResults.setGeometry(QtCore.QRect(601, 330, 141, 27)) 70 | self.saveMountingResults.setObjectName(_fromUtf8("saveMountingResults")) 71 | self.line = QtGui.QFrame(self.centralwidget) 72 | self.line.setGeometry(QtCore.QRect(30, 319, 711, 16)) 73 | self.line.setFrameShape(QtGui.QFrame.HLine) 74 | self.line.setFrameShadow(QtGui.QFrame.Sunken) 75 | self.line.setObjectName(_fromUtf8("line")) 76 | self.saveDTCResults = QtGui.QPushButton(self.centralwidget) 77 | self.saveDTCResults.setGeometry(QtCore.QRect(601, 109, 141, 27)) 78 | self.saveDTCResults.setObjectName(_fromUtf8("saveDTCResults")) 79 | self.DTCInstances = QtGui.QLineEdit(self.centralwidget) 80 | self.DTCInstances.setGeometry(QtCore.QRect(503, 109, 41, 27)) 81 | self.DTCInstances.setObjectName(_fromUtf8("DTCInstances")) 82 | self.label = QtGui.QLabel(self.centralwidget) 83 | self.label.setGeometry(QtCore.QRect(253, 115, 261, 17)) 84 | self.label.setObjectName(_fromUtf8("label")) 85 | kryoMain.setCentralWidget(self.centralwidget) 86 | self.menubar = QtGui.QMenuBar(kryoMain) 87 | self.menubar.setGeometry(QtCore.QRect(0, 0, 770, 25)) 88 | self.menubar.setObjectName(_fromUtf8("menubar")) 89 | kryoMain.setMenuBar(self.menubar) 90 | self.statusbar = QtGui.QStatusBar(kryoMain) 91 | self.statusbar.setObjectName(_fromUtf8("statusbar")) 92 | kryoMain.setStatusBar(self.statusbar) 93 | 94 | self.retranslateUi(kryoMain) 95 | QtCore.QObject.connect(self.chooseFormats, QtCore.SIGNAL(_fromUtf8("clicked()")), kryoMain.choose_formats) 96 | QtCore.QObject.connect(self.createImages, QtCore.SIGNAL(_fromUtf8("clicked()")), kryoMain.create_images) 97 | QtCore.QObject.connect(self.tryMounting, QtCore.SIGNAL(_fromUtf8("clicked()")), kryoMain.try_mounting) 98 | QtCore.QObject.connect(self.browseDTCDir, QtCore.SIGNAL(_fromUtf8("clicked()")), kryoMain.browse_dtc_dir) 99 | QtCore.QObject.connect(self.browseInpDir, QtCore.SIGNAL(_fromUtf8("clicked()")), kryoMain.browse_inp_dir) 100 | QtCore.QObject.connect(self.browseOutputDir, QtCore.SIGNAL(_fromUtf8("clicked()")), kryoMain.browse_output_dir) 101 | QtCore.QObject.connect(self.deleteUnmountable, QtCore.SIGNAL(_fromUtf8("stateChanged(int)")), kryoMain.delete_unmountable_change) 102 | QtCore.QObject.connect(self.saveMountingResults, QtCore.SIGNAL(_fromUtf8("clicked()")), kryoMain.save_mounting_results) 103 | QtCore.QObject.connect(self.saveDTCResults, QtCore.SIGNAL(_fromUtf8("clicked()")), kryoMain.save_dtc_results) 104 | QtCore.QMetaObject.connectSlotsByName(kryoMain) 105 | 106 | def retranslateUi(self, kryoMain): 107 | kryoMain.setWindowTitle(_translate("kryoMain", "Disk format identifier", None)) 108 | self.chooseFormats.setText(_translate("kryoMain", "Choose formats to create", None)) 109 | self.createImages.setText(_translate("kryoMain", "Create images", None)) 110 | self.tryMounting.setText(_translate("kryoMain", "Try mounting", None)) 111 | self.deleteUnmountable.setText(_translate("kryoMain", "Delete unmountable", None)) 112 | self.browseOutputDir.setText(_translate("kryoMain", "Output Directory", None)) 113 | self.browseInpDir.setText(_translate("kryoMain", "Input Directory", None)) 114 | self.browseDTCDir.setText(_translate("kryoMain", "DTC Directory", None)) 115 | self.saveMountingResults.setText(_translate("kryoMain", "Save Results", None)) 116 | self.saveDTCResults.setText(_translate("kryoMain", "Save Results", None)) 117 | self.label.setText(_translate("kryoMain", "Maximum concurrent DTC instances:", None)) 118 | 119 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import os 2 | import warnings 3 | 4 | from setuptools import setup 5 | 6 | with open(os.path.join('DiskFormatID', '__init__.py')) as init_: 7 | for line in init_: 8 | if '__version__' in line: 9 | version = line.split('=')[-1].strip().replace('"','') 10 | break 11 | else: 12 | version = 'unknown' 13 | warnings.warn('Unable to find version, using "%s"' % version) 14 | input("Continue?") 15 | 16 | 17 | setup(name='DiskFormatID', 18 | version=version, 19 | description='Disk Format Identification for KryoFlux', 20 | author='Euan Cochrane', 21 | author_email='euanc@foobar.com', 22 | maintainer = "Euan Cochrane", 23 | maintainer_email = "euanc@foobar.com", 24 | url="https://github.com/euanc/DiskFormatID", 25 | 26 | py_modules = ['chooseFormatsGUI', 'chooseFormats', 'diskIDMainGUI'], 27 | 28 | scripts = ['diskIDMain'], 29 | 30 | classifiers = ['Development Status :: 2 - Pre-Alpha' 31 | "Intended Audience :: Developers", 32 | "License :: OSI Approved :: GNU General Public License v3 (GPLv3)", 33 | "Programming Language :: Python", 34 | 'Programming Language :: Python :: 2', 35 | 'Programming Language :: Python :: 2.7' 36 | "Operating System :: OS Independent", 37 | "Topic :: Software Development :: Libraries :: Python Modules"], 38 | keywords="DiskFormatID") 39 | 40 | -------------------------------------------------------------------------------- /ui_files/chooseFormatsGUI.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | addTypes 4 | 5 | 6 | 7 | 0 8 | 0 9 | 439 10 | 587 11 | 12 | 13 | 14 | Add Disk Types 15 | 16 | 17 | 18 | 19 | 20 | 118 21 | 10 22 | 221 23 | 27 24 | 25 | 26 | 27 | 28 | 29 | 30 | 118 31 | 60 32 | 61 33 | 27 34 | 35 | 36 | 37 | 38 | 39 | 40 | 277 41 | 59 42 | 61 43 | 27 44 | 45 | 46 | 47 | 48 | 49 | 50 | 118 51 | 100 52 | 221 53 | 27 54 | 55 | 56 | 57 | 58 | 59 | 60 | 118 61 | 140 62 | 221 63 | 27 64 | 65 | 66 | 67 | 68 | 69 | 70 | 118 71 | 177 72 | 101 73 | 27 74 | 75 | 76 | 77 | 78 | 79 | 80 | 248 81 | 177 82 | 41 83 | 27 84 | 85 | 86 | 87 | 88 | 89 | 90 | 118 91 | 217 92 | 221 93 | 27 94 | 95 | 96 | 97 | 98 | 99 | 100 | 131 101 | 295 102 | 121 103 | 22 104 | 105 | 106 | 107 | Flippy Mode 108 | 109 | 110 | 111 | 112 | true 113 | 114 | 115 | 116 | 350 117 | 62 118 | 99 119 | 22 120 | 121 | 122 | 123 | Default 124 | 125 | 126 | true 127 | 128 | 129 | 130 | 131 | 132 | 350 133 | 103 134 | 99 135 | 22 136 | 137 | 138 | 139 | Default 140 | 141 | 142 | true 143 | 144 | 145 | 146 | 147 | 148 | 349 149 | 143 150 | 99 151 | 22 152 | 153 | 154 | 155 | Default 156 | 157 | 158 | true 159 | 160 | 161 | 162 | 163 | 164 | 349 165 | 180 166 | 99 167 | 22 168 | 169 | 170 | 171 | Default 172 | 173 | 174 | true 175 | 176 | 177 | 178 | 179 | 180 | 349 181 | 217 182 | 99 183 | 22 184 | 185 | 186 | 187 | Default 188 | 189 | 190 | true 191 | 192 | 193 | 194 | 195 | 196 | 259 197 | 290 198 | 171 199 | 31 200 | 201 | 202 | 203 | Save (and add another) 204 | 205 | 206 | 207 | 208 | 209 | 29 210 | 12 211 | 81 212 | 20 213 | 214 | 215 | 216 | Image Type 217 | 218 | 219 | 220 | 221 | 222 | 29 223 | 62 224 | 81 225 | 20 226 | 227 | 228 | 229 | Start Track 230 | 231 | 232 | 233 | 234 | 235 | 205 236 | 62 237 | 71 238 | 20 239 | 240 | 241 | 242 | End Track 243 | 244 | 245 | 246 | 247 | 248 | 31 249 | 104 250 | 81 251 | 20 252 | 253 | 254 | 255 | Side Mode 256 | 257 | 258 | 259 | 260 | 261 | 29 262 | 143 263 | 81 264 | 20 265 | 266 | 267 | 268 | Sector Size 269 | 270 | 271 | 272 | 273 | 274 | 19 275 | 180 276 | 91 277 | 20 278 | 279 | 280 | 281 | Sector Count 282 | 283 | 284 | 285 | 286 | 287 | 9 288 | 220 289 | 101 290 | 20 291 | 292 | 293 | 294 | Track distance 295 | 296 | 297 | 298 | 299 | 300 | 24 301 | 260 302 | 81 303 | 20 304 | 305 | 306 | 307 | Target RPM 308 | 309 | 310 | 311 | 312 | 313 | 350 314 | 258 315 | 99 316 | 22 317 | 318 | 319 | 320 | Default 321 | 322 | 323 | true 324 | 325 | 326 | 327 | 328 | 329 | 10 330 | 370 331 | 421 332 | 171 333 | 334 | 335 | 336 | 337 | 338 | 339 | 330 340 | 338 341 | 99 342 | 27 343 | 344 | 345 | 346 | Reset all 347 | 348 | 349 | 350 | 351 | 352 | 12 353 | 350 354 | 181 355 | 17 356 | 357 | 358 | 359 | 360 | 75 361 | true 362 | 363 | 364 | 365 | Configured image types: 366 | 367 | 368 | 369 | 370 | 371 | 118 372 | 255 373 | 221 374 | 27 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 0 383 | 0 384 | 439 385 | 25 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | resetTypes 395 | clicked() 396 | addTypes 397 | reset_types() 398 | 399 | 400 | 378 401 | 383 402 | 403 | 404 | 95 405 | 352 406 | 407 | 408 | 409 | 410 | addType 411 | clicked() 412 | addTypes 413 | save_and_add() 414 | 415 | 416 | 381 417 | 335 418 | 419 | 420 | 413 421 | 44 422 | 423 | 424 | 425 | 426 | tracksDefault 427 | stateChanged(int) 428 | addTypes 429 | tracks_default_change() 430 | 431 | 432 | 396 433 | 100 434 | 435 | 436 | 367 437 | 74 438 | 439 | 440 | 441 | 442 | sideModeDefault 443 | stateChanged(int) 444 | addTypes 445 | side_mode_default_change() 446 | 447 | 448 | 359 449 | 141 450 | 451 | 452 | 349 453 | 122 454 | 455 | 456 | 457 | 458 | sectorSizeDefault 459 | stateChanged(int) 460 | addTypes 461 | sector_size_default_change() 462 | 463 | 464 | 379 465 | 171 466 | 467 | 468 | 340 469 | 157 470 | 471 | 472 | 473 | 474 | sectorCountDefault 475 | stateChanged(int) 476 | addTypes 477 | sector_count_default_change() 478 | 479 | 480 | 379 481 | 218 482 | 483 | 484 | 336 485 | 208 486 | 487 | 488 | 489 | 490 | trackDistanceDefault 491 | stateChanged(int) 492 | addTypes 493 | track_distance_default_change() 494 | 495 | 496 | 380 497 | 254 498 | 499 | 500 | 336 501 | 228 502 | 503 | 504 | 505 | 506 | targetRPMDefault 507 | stateChanged(int) 508 | addTypes 509 | target_RPM_default_change() 510 | 511 | 512 | 408 513 | 288 514 | 515 | 516 | 350 517 | 268 518 | 519 | 520 | 521 | 522 | flippyMode 523 | stateChanged(int) 524 | addTypes 525 | flippy_change() 526 | 527 | 528 | 177 529 | 325 530 | 531 | 532 | 99 533 | 316 534 | 535 | 536 | 537 | 538 | 539 | reset_types() 540 | save_and_add() 541 | side_mode_default_change() 542 | tracks_default_change() 543 | sector_size_default_change() 544 | sector_count_default_change() 545 | track_distance_default_change() 546 | target_RPM_default_change() 547 | flippy_change() 548 | 549 | 550 | -------------------------------------------------------------------------------- /ui_files/diskIDMainGUI.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | kryoMain 4 | 5 | 6 | 7 | 0 8 | 0 9 | 770 10 | 600 11 | 12 | 13 | 14 | Disk format identifier 15 | 16 | 17 | 18 | 19 | 20 | 30 21 | 10 22 | 201 23 | 27 24 | 25 | 26 | 27 | Choose formats to create 28 | 29 | 30 | 31 | 32 | 33 | 30 34 | 50 35 | 201 36 | 71 37 | 38 | 39 | 40 | Create images 41 | 42 | 43 | 44 | 45 | 46 | 30 47 | 330 48 | 191 49 | 27 50 | 51 | 52 | 53 | Try mounting 54 | 55 | 56 | 57 | 58 | 59 | 30 60 | 140 61 | 711 62 | 181 63 | 64 | 65 | 66 | 67 | 68 | 69 | 31 70 | 360 71 | 711 72 | 192 73 | 74 | 75 | 76 | 77 | 78 | 79 | 225 80 | 333 81 | 171 82 | 22 83 | 84 | 85 | 86 | Delete unmountable 87 | 88 | 89 | false 90 | 91 | 92 | 93 | 94 | 95 | 250 96 | 80 97 | 141 98 | 27 99 | 100 | 101 | 102 | Output Directory 103 | 104 | 105 | 106 | 107 | 108 | 250 109 | 46 110 | 141 111 | 27 112 | 113 | 114 | 115 | Input Directory 116 | 117 | 118 | 119 | 120 | 121 | 250 122 | 10 123 | 141 124 | 27 125 | 126 | 127 | 128 | DTC Directory 129 | 130 | 131 | 132 | 133 | 134 | 410 135 | 46 136 | 331 137 | 27 138 | 139 | 140 | 141 | 142 | 143 | 144 | 410 145 | 80 146 | 331 147 | 27 148 | 149 | 150 | 151 | 152 | 153 | 154 | 410 155 | 11 156 | 331 157 | 27 158 | 159 | 160 | 161 | 162 | 163 | 164 | 601 165 | 330 166 | 141 167 | 27 168 | 169 | 170 | 171 | Save Results 172 | 173 | 174 | 175 | 176 | 177 | 30 178 | 319 179 | 711 180 | 16 181 | 182 | 183 | 184 | Qt::Horizontal 185 | 186 | 187 | 188 | 189 | 190 | 601 191 | 109 192 | 141 193 | 27 194 | 195 | 196 | 197 | Save Results 198 | 199 | 200 | 201 | 202 | 203 | 503 204 | 109 205 | 41 206 | 27 207 | 208 | 209 | 210 | 211 | 212 | 213 | 253 214 | 115 215 | 261 216 | 17 217 | 218 | 219 | 220 | Maximum concurrent DTC instances: 221 | 222 | 223 | 224 | 225 | 226 | 227 | 0 228 | 0 229 | 770 230 | 25 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | chooseFormats 240 | clicked() 241 | kryoMain 242 | choose_formats() 243 | 244 | 245 | 173 246 | 61 247 | 248 | 249 | 295 250 | 72 251 | 252 | 253 | 254 | 255 | createImages 256 | clicked() 257 | kryoMain 258 | create_images() 259 | 260 | 261 | 183 262 | 109 263 | 264 | 265 | 253 266 | 85 267 | 268 | 269 | 270 | 271 | tryMounting 272 | clicked() 273 | kryoMain 274 | try_mounting() 275 | 276 | 277 | 170 278 | 369 279 | 280 | 281 | 9 282 | 332 283 | 284 | 285 | 286 | 287 | browseDTCDir 288 | clicked() 289 | kryoMain 290 | browse_dtc_dir() 291 | 292 | 293 | 349 294 | 49 295 | 296 | 297 | 17 298 | 77 299 | 300 | 301 | 302 | 303 | browseInpDir 304 | clicked() 305 | kryoMain 306 | browse_inp_dir() 307 | 308 | 309 | 383 310 | 92 311 | 312 | 313 | 397 314 | 94 315 | 316 | 317 | 318 | 319 | browseOutputDir 320 | clicked() 321 | kryoMain 322 | browse_output_dir() 323 | 324 | 325 | 350 326 | 121 327 | 328 | 329 | 401 330 | 121 331 | 332 | 333 | 334 | 335 | deleteUnmountable 336 | stateChanged(int) 337 | kryoMain 338 | delete_unmountable_change() 339 | 340 | 341 | 354 342 | 361 343 | 344 | 345 | 486 346 | 335 347 | 348 | 349 | 350 | 351 | saveMountingResults 352 | clicked() 353 | kryoMain 354 | save_mounting_results() 355 | 356 | 357 | 649 358 | 366 359 | 360 | 361 | 762 362 | 363 363 | 364 | 365 | 366 | 367 | saveDTCResults 368 | clicked() 369 | kryoMain 370 | save_dtc_results() 371 | 372 | 373 | 717 374 | 331 375 | 376 | 377 | 757 378 | 219 379 | 380 | 381 | 382 | 383 | 384 | choose_formats() 385 | create_images() 386 | try_mounting() 387 | delete_unmountable_change() 388 | browse_dtc_dir() 389 | browse_inp_dir() 390 | browse_output_dir() 391 | save_dtc_results() 392 | save_mounting_results() 393 | 394 | 395 | --------------------------------------------------------------------------------