Add support for Join sets where the parity protects the split files master
authorIra W. Snyder <devel@irasnyder.com>
Wed, 7 May 2014 01:08:09 +0000 (18:08 -0700)
committerIra W. Snyder <devel@irasnyder.com>
Wed, 7 May 2014 01:08:09 +0000 (18:08 -0700)
These sorts of sets are sometimes created by people who do not know
exactly what they are doing. It is beneficial to be able to extract
these sets appropriately.

PAR2Set/JoinProtected.py [new file with mode: 0644]
PAR2Set/__init__.py
rarslave.py

diff --git a/PAR2Set/JoinProtected.py b/PAR2Set/JoinProtected.py
new file mode 100644 (file)
index 0000000..dc70007
--- /dev/null
@@ -0,0 +1,116 @@
+#!/usr/bin/env python
+# vim: set ts=4 sts=4 sw=4 textwidth=92:
+
+"""
+Holds the JoinProtected class.
+
+This module works with joined sets where the joined files are
+protected directly by the PAR2 files.
+
+It will detect sets like the following:
+X.par2
+X.vol0+1.par2
+...
+
+X.001
+X.002
+...
+
+Where the PAR2 files protect a file named X.001, etc. It works in the case
+that the PAR2 files are protecting the X.001, etc. files directly.
+
+It currently whitelists a number of media formats that can be protected.
+"""
+
+__author__    = "Ira W. Snyder (devel@irasnyder.com)"
+__copyright__ = "Copyright (c) 2014 Ira W. Snyder (devel@irasnyder.com)"
+__license__   = "GNU GPL v2 (or, at your option, any later version)"
+
+#    JoinProtected.py
+#
+#    Copyright (C) 2014  Ira W. Snyder (devel@irasnyder.com)
+#
+#    This program is free software; you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation; either version 2 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program; if not, write to the Free Software
+#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+import os, re, logging
+from PAR2Set import Base, utils
+
+class JoinProtected(Base):
+
+    ############################################################################
+
+    # find all prefixes in the protected set by stripping the extension off
+    # of each file
+    def getPrefixes(self):
+
+        prefixes = set()
+        for f in self.protectedFiles:
+            prefix, extension = os.path.splitext(f)
+            prefixes.add(prefix)
+
+        return list(prefixes)
+
+
+    ############################################################################
+
+    def detect(self):
+
+        # check to see that there are joined files in the set
+        regex = r'^.*\.\d\d\d$'
+        if not utils.hasAMatch(regex, self.protectedFiles):
+            raise TypeError
+
+        # This is a good match if this criteria is met
+        prefixes = self.getPrefixes()
+        if len(prefixes) == 1:
+            return
+
+        raise TypeError
+
+    ############################################################################
+
+    def repair(self):
+
+        regex = r'^.*\.\d\d\d$'
+        files = utils.findMatches(regex, self.protectedFiles)
+        utils.runCommand(['par2repair'] + self.PAR2Files + files, self.directory)
+
+    ############################################################################
+
+    def extract(self):
+
+        # we guaranteed there is exactly one prefix during detection
+        filename = self.getPrefixes()[0]
+
+        regex = r'^.*\.\d\d\d$'
+        files = utils.findMatches(regex, self.protectedFiles)
+
+        # concatenate all '.001' files into a single output file
+        with open(filename, 'wb') as f:
+            utils.runCommand(['cat'] + files, self.directory, stdout=f)
+
+    ############################################################################
+
+    def findDeletableFiles(self):
+
+        prefixes = self.getPrefixes()
+
+        files = Base.findDeletableFiles(self)
+        files = [f for f in files if f not in prefixes]
+
+        return files
+
+    ############################################################################
+
index aa57931..6ad1000 100644 (file)
@@ -22,6 +22,7 @@ from CompareSet import CompareSet
 from Base import Base
 from NewRAR import NewRAR
 from OldRAR import OldRAR
 from Base import Base
 from NewRAR import NewRAR
 from OldRAR import OldRAR
+from JoinProtected import JoinProtected
 from Join import Join
 from NoExtract import NoExtract
 from ZIP import ZIP
 from Join import Join
 from NoExtract import NoExtract
 from ZIP import ZIP
@@ -30,6 +31,6 @@ from ExtractFirstNewRAR import ExtractFirstNewRAR
 from ExtractFirstOldRAR import ExtractFirstOldRAR
 
 __all__ = ['utils', 'par2parser', 'CompareSet', 'Base', 'ExtractFirstBase',
 from ExtractFirstOldRAR import ExtractFirstOldRAR
 
 __all__ = ['utils', 'par2parser', 'CompareSet', 'Base', 'ExtractFirstBase',
-           'ExtractFirstNewRAR', 'ExtractFirstOldRAR', 'Join', 'NewRAR',
-           'NoExtract', 'OldRAR', 'ZIP']
+           'ExtractFirstNewRAR', 'ExtractFirstOldRAR', 'JoinProtected', 'Join',
+           'NewRAR', 'NoExtract', 'OldRAR', 'ZIP']
 
 
index 001bf0f..20c0288 100755 (executable)
@@ -269,6 +269,7 @@ def findUniqueSets(directory, files):
 def runEachType(cs, options):
 
     types = (
 def runEachType(cs, options):
 
     types = (
+        PAR2Set.JoinProtected,
         PAR2Set.Join,
         PAR2Set.ZIP,
         PAR2Set.OldRAR,
         PAR2Set.Join,
         PAR2Set.ZIP,
         PAR2Set.OldRAR,