Skip to content

Commit

Permalink
feat: support sort in TorrentFile::getFileTree
Browse files Browse the repository at this point in the history
closed: #16, #17
  • Loading branch information
Rhilip committed Nov 4, 2023
1 parent ab58de2 commit f1fac92
Show file tree
Hide file tree
Showing 5 changed files with 159 additions and 4 deletions.
33 changes: 32 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -188,8 +188,39 @@ $torrent->parse(); // ['total_size' => $totalSize, 'count' => $count, 'files' =
*/
$size = $torrent->getSize();
$count = $torrent->getFileCount();

/**
* Return a list like:
* [
* ["path" => "filename1", "size" => 123], // 123 is file size
* ["path" => "directory/filename2", "size" => 2345]
* ]
*
*/
$fileList = $torrent->getFileList();
$fileTree = $torrent->getFileTree();


/**
* Return a dict like:
* [
* "torrentname" => [
* "directory" => [
* "filename2" => 2345
* ],
* "filename1" => 123
* ]
* ]
*
* > Add in v2.4.0
* You can now pass argument to control the fileTree sort type. By default, this argument is TorrentFile::FILETREE_SORT_NORMAL.
* Control Const (see different in `tests/TorrentFileTreeSortTest.php` file):
* - TorrentFile::FILETREE_SORT_NORMAL : not sort, also means sort by torrent file parsed order
* - TorrentFile::FILETREE_SORT_STRING : sort by filename ASC ("natural ordering" and "case-insensitively")
* - TorrentFile::FILETREE_SORT_FOLDER : sort by filetype (first folder, then file)
* - TorrentFile::FILETREE_SORT_NATURAL: sort by both filetype and filename ( same as `TorrentFile::FILETREE_SORT_NAME | TorrentFile::FILETREE_SORT_FOLDER` )
*
*/
$fileTree = $torrent->getFileTree(?$sortType = self::FILETREE_SORT_NORMAL);

// 6. Other method
$torrent->cleanCache();
Expand Down
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"php": "^7.3|^8.0"
},
"require-dev": {
"ext-json": "*",
"phpunit/phpunit": "^9.0"
},
"autoload": {
Expand Down
41 changes: 38 additions & 3 deletions src/TorrentFile.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,20 @@ class TorrentFile
public const PROTOCOL_V2 = 'v2'; // Version 2 of the BitTorrent protocol, using SHA-256 hashes
public const PROTOCOL_HYBRID = 'hybrid'; // Torrent with both v1 and v2 support

// BitTorrent File Mode
public const FILEMODE_SINGLE = 'single';
public const FILEMODE_MULTI = 'multi';

// Control for ->getFileTree() output, by default it is normal as parsed order
public const FILETREE_SORT_NORMAL = 0x00;
public const FILETREE_SORT_STRING = 0x01;
public const FILETREE_SORT_FOLDER = 0x10;
public const FILETREE_SORT_NATURAL = 0x11; // same as self::FILETREE_SORT_NAME | self::FILETREE_SORT_FOLDER

// store torrent dict
private $data;

// we may have some tmp data when parse, so we store here to avoid regenerate
// we may have some tmp data when parsed, so we store here to avoid regenerate
private $cache = [];

// Custom validator for parse torrent
Expand Down Expand Up @@ -693,6 +700,25 @@ public function getFileList()
return $this->parse()['files'];
}

private static function sortFileTreeRecursive(array &$fileTree, $sortByName = false, $sortByFolder = false): array
{
if ($sortByName) {
ksort($fileTree, SORT_NATURAL | SORT_FLAG_CASE);
}

$isoFile = [];
foreach ($fileTree as $key => &$item) {
if (is_array($item)) {
$fileTree[$key] = self::sortFileTreeRecursive($item, $sortByName, $sortByFolder);
} else if ($sortByFolder) {
$isoFile[$key] = $item;
unset($fileTree[$key]);
}
}
$fileTree = array_merge($fileTree, $isoFile);
return $fileTree;
}

/**
* Return a dict like:
* [
Expand All @@ -704,9 +730,18 @@ public function getFileList()
* ]
* ]
*/
public function getFileTree()
public function getFileTree($sortType = self::FILETREE_SORT_NORMAL)
{
return $this->parse()['fileTree'];
$fileTree = $this->parse()['fileTree'];

$sortByName = ($sortType & self::FILETREE_SORT_STRING) === self::FILETREE_SORT_STRING;
$sortByFolder = ($sortType & self::FILETREE_SORT_FOLDER) === self::FILETREE_SORT_FOLDER;

if ($sortByName || $sortByFolder) {
self::sortFileTreeRecursive($fileTree, $sortByName, $sortByFolder);
}

return $fileTree;
}

public function cleanCache()
Expand Down
87 changes: 87 additions & 0 deletions tests/TorrentFileTreeSortTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
<?php


use Rhilip\Bencode\TorrentFile;
use PHPUnit\Framework\TestCase;

class TorrentFileTreeSortTest extends TestCase
{

protected function setUp(): void
{
$this->torrent = TorrentFile::load("tests/asserts/test_tree_sort.torrent");
$this->torrent->parse();
}

public function testGetFileTreeByParse()
{
$this->assertEquals(
json_encode([
'test_tree_sort' => [
'file.txt' => 1048576,
'z' => [
'c.txt' => 1048576,
],
'a' => [
'd.txt' => 1048576,
'c.txt' => 1048576
]
]
]),
json_encode($this->torrent->getFileTree()));
}

public function testGetFileTreeByString()
{
$this->assertEquals(
json_encode([
'test_tree_sort' => [
'a' => [
'c.txt' => 1048576,
'd.txt' => 1048576
],
'file.txt' => 1048576,
'z' => [
'c.txt' => 1048576,
],
]
]),
json_encode($this->torrent->getFileTree(TorrentFile::FILETREE_SORT_STRING)));
}

public function testGetFileTreeByFolder()
{
$this->assertEquals(
json_encode([
'test_tree_sort' => [
'z' => [
'c.txt' => 1048576,
],
'a' => [
'd.txt' => 1048576,
'c.txt' => 1048576
],
'file.txt' => 1048576
]
]),
json_encode($this->torrent->getFileTree(TorrentFile::FILETREE_SORT_FOLDER)));
}

public function testGetFileTreeByNatural()
{
$this->assertEquals(
json_encode([
'test_tree_sort' => [
'a' => [
'c.txt' => 1048576,
'd.txt' => 1048576
],
'z' => [
'c.txt' => 1048576,
],
'file.txt' => 1048576
]
]),
json_encode($this->torrent->getFileTree(TorrentFile::FILETREE_SORT_NATURAL)));
}
}
1 change: 1 addition & 0 deletions tests/asserts/test_tree_sort.torrent
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
d4:infod5:filesld6:lengthi1048576e4:pathl8:file.txteed6:lengthi1048576e4:pathl1:z5:c.txteed6:lengthi1048576e4:pathl1:a5:d.txteed6:lengthi1048576e4:pathl1:a5:c.txteee4:name14:test_tree_sort12:piece lengthi524288e6:pieces160:��=1! ���$�ad�����g����f1|�5�6zV�{-SF0�Rk�\-�r���2j��[���9�l2UH�ox�|ASF0�Rk�\-�r���2j��[���9�l2UH�ox�|ASF0�Rk�\-�r���2j��[���9�l2UH�ox�|Aee

0 comments on commit f1fac92

Please sign in to comment.