From c004e8fdb5f4a903a53b6851eb2473eda2781a2c Mon Sep 17 00:00:00 2001 From: John-Mark Gurney Date: Thu, 1 Sep 2022 13:35:02 -0700 Subject: [PATCH] add support for torrents with a single file in them.. --- ui/medashare/btv/__init__.py | 48 +++++++++++++++++++-- ui/medashare/btv/fixtures/filed.txt.torrent | 1 + 2 files changed, 45 insertions(+), 4 deletions(-) create mode 100644 ui/medashare/btv/fixtures/filed.txt.torrent diff --git a/ui/medashare/btv/__init__.py b/ui/medashare/btv/__init__.py index c753345..208ba7c 100644 --- a/ui/medashare/btv/__init__.py +++ b/ui/medashare/btv/__init__.py @@ -21,6 +21,11 @@ _escapes = '*?[]' def glob_escape(s): return ''.join(x if x not in _escapes else '[%s]' % x for x in s) +def roundup(x, y): + '''Round up x to the next multiple of y.''' + + return (x + y - 1) // y + class Storage: '''A class to help read pieces of a torrent. ''' @@ -30,13 +35,21 @@ class Storage: rootpath - path to the dir of torrent files are in files - the files dictionary from the torrent info key piecelen - piece length from the torren info key + + If files is None, then rootpath points at the single file. ''' self._rootpath = pathlib.Path(rootpath) self._files = files self._piecelen = piecelen - self._buildindex() + if files is None: + # get length + sz = self._rootpath.stat().st_size + piececnt = roundup(sz, piecelen) + self._pieceindex = [ [ dict(file=self._rootpath, offset=x * piecelen, size=piecelen if x < piececnt - 1 else sz - piececnt * x) ] for x in range(piececnt) ] + else: + self._buildindex() def _filepaths(self): '''Iterates over all the files in the torrent. @@ -148,7 +161,8 @@ def validate(torrent, basedir): torrentdir = basedir / info['name'].decode(_encoding) - stor = Storage(torrentdir, info['files'], info['piece length']) + files = info.get('files', None) + stor = Storage(torrentdir, files, info['piece length']) pieces = info['pieces'] piecescnt = len(pieces) // 20 @@ -164,6 +178,15 @@ def validate(torrent, basedir): else: valid[num] = False + if files is None: + # single file + f, e = set([ torrentdir ]), set() + + if not all(valid): + f, e = e, f + + return f,e + # if any piece of a file is bad, it's bad allfiles = set(stor.allfiles()) @@ -197,11 +220,13 @@ class _TestCases(unittest.TestCase): self.basetempdir = d - tor = importlib.resources.files(__name__) - tor = tor / 'fixtures' / 'somedir.torrent' + fixtures = importlib.resources.files(__name__) / 'fixtures' + tor = fixtures / 'somedir.torrent' with tor.open('rb') as fp: self.torrent = bencode.bdecode(fp.read()) + self.fixtures = fixtures + self.oldcwd = os.getcwd() os.chdir(d) @@ -258,6 +283,21 @@ class _TestCases(unittest.TestCase): ]: self.assertTrue(fnmatch.fnmatch(i, glob_escape(i))) + def test_validate_file_single(self): + sd = self.basetempdir / 'anotherdir' + sd.mkdir() + + self.make_files(sd, self.origfiledata) + + shutil.copy(self.fixtures / 'filed.txt.torrent', self.basetempdir) + + tor = self.basetempdir / 'filed.txt.torrent' + + good, bad = validate_file(tor) + + self.assertFalse(bad) + self.assertEqual(good, { sd / 'filed.txt' }) + def test_verification(self): # Testing for "missing" files # piece size 2 (aka 4 bytes) diff --git a/ui/medashare/btv/fixtures/filed.txt.torrent b/ui/medashare/btv/fixtures/filed.txt.torrent new file mode 100644 index 0000000..5b3d1a5 --- /dev/null +++ b/ui/medashare/btv/fixtures/filed.txt.torrent @@ -0,0 +1 @@ +d13:creation datei1662063094e4:infod6:lengthi8e4:name9:filed.txt12:piece lengthi4e6:pieces40:ë‡X…'²,²·_™-ÿ­Á°\f]Fñýí÷íùÆw‚—‡ë ½¬e5:nodeslee \ No newline at end of file