Completed
Push — master ( 3e36aa...af59c2 )
by Stanislav
02:21
created

TransmissionClient   B

Complexity

Total Complexity 39

Size/Duplication

Total Lines 205
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Importance

Changes 12
Bugs 5 Features 3
Metric Value
wmc 39
c 12
b 5
f 3
lcom 1
cbo 3
dl 0
loc 205
rs 8.2857

13 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A createSession() 0 4 1
A getSessionId() 0 11 2
A getTorrentData() 0 19 2
A getTorrentsSize() 0 8 2
A getTorrentsField() 0 8 2
B filterTorrents() 0 22 6
B parseAgeFilter() 0 18 5
B getTorrentAgeInDays() 0 7 5
A printTorrentsTable() 0 15 2
B getObsoleteTorrents() 0 24 5
A removeTorrents() 0 17 3
A detectObsoleteTorrent() 0 9 3
1
<?php
2
3
namespace Popstas\Transmission\Console;
4
5
use Martial\Transmission\API;
6
use Martial\Transmission\API\Argument\Torrent;
7
use Symfony\Component\Console\Helper\Table;
8
use Symfony\Component\Console\Output\OutputInterface;
9
10
class TransmissionClient
11
{
12
    private $api;
13
    private $sessionId;
14
15
    public function __construct(API\TransmissionAPI $api)
16
    {
17
        $this->api = $api;
18
    }
19
20
    public function createSession()
21
    {
22
        $this->sessionId = $this->getSessionId($this->sessionId);
23
    }
24
25
    private function getSessionId($sessionId)
26
    {
27
        try {
28
            $this->api->sessionGet($sessionId);
29
        } catch (API\CSRFException $e) {
30
            // The session has been reinitialized. Fetch the new session ID with the method getSessionId().
31
            $sessionId = $e->getSessionId();
32
        }
33
34
        return $sessionId;
35
    }
36
37
    public function getTorrentData(array $ids = [], $fields = [])
38
    {
39
        if (empty($fields)) {
40
            $fields = [
41
                Torrent\Get::ID,
42
                Torrent\Get::NAME,
43
                Torrent\Get::TOTAL_SIZE,
44
                Torrent\Get::DOWNLOAD_DIR,
45
                Torrent\Get::UPLOAD_EVER,
46
                Torrent\Get::DOWNLOAD_EVER,
47
                Torrent\Get::DONE_DATE,
48
                Torrent\Get::ADDED_DATE,
49
            ];
50
        }
51
52
        $this->createSession();
53
        $torrentList = $this->api->torrentGet($this->sessionId, $ids, $fields);
54
        return $torrentList;
55
    }
56
57
    public function getTorrentsSize(array $torrentList, $fieldName = Torrent\Get::TOTAL_SIZE)
58
    {
59
        $torrentSize = 0;
60
        foreach ($torrentList as $torrent) {
61
            $torrentSize += $torrent[$fieldName];
62
        }
63
        return $torrentSize;
64
    }
65
66
    public function getTorrentsField(array $torrentList, $fieldName)
67
    {
68
        $fields = [];
69
        foreach ($torrentList as $torrent) {
70
            $fields[] = $torrent[$fieldName];
71
        }
72
        return $fields;
73
    }
74
75
    /**
76
     * @param array $torrentList
77
     *
78
     * @param array $filters
79
     * filters[
80
     * - age
81
     * - age_min
82
     * - age_max
83
     * ]
84
     *
85
     * @return array
86
     */
87
    public function filterTorrents(array $torrentList, array $filters)
88
    {
89
        $filters += ['age_min' => 0, 'age_max' => 99999, 'name' => ''];
90
        $filters['name'] = str_replace(['/', '.', '*'], ['\/', '\.', '.*?'], $filters['name']);
91
92
        if (isset($filters['age'])) {
93
            $filters = $this->parseAgeFilter($filters['age']) + $filters;
94
        }
95
96
        return array_filter($torrentList, function ($torrent) use ($filters) {
97
            $age = $this->getTorrentAgeInDays($torrent);
98
            if ($age < $filters['age_min'] || $age > $filters['age_max']) {
99
                return false;
100
            }
101
            if (isset($torrent[Torrent\Get::NAME])
102
                && !preg_match('/' . $filters['name'] . '/i', $torrent[Torrent\Get::NAME])
103
            ) {
104
                return false;
105
            }
106
            return true;
107
        });
108
    }
109
110
    private function parseAgeFilter($age)
111
    {
112
        $filters = [];
113
        preg_match_all('/([<>])\s?(\d+)/', $age, $results, PREG_SET_ORDER);
114
        if (count($results)) {
115
            foreach ($results as $result) {
0 ignored issues
show
Bug introduced by
The expression $results of type null|array<integer,array<integer,string>> is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
116
                $ageOperator = $result[1];
117
                $ageValue = $result[2];
118
                if ($ageOperator == '<') {
119
                    $filters['age_max'] = $ageValue - 1;
120
                }
121
                if ($ageOperator == '>') {
122
                    $filters['age_min'] = $ageValue + 1;
123
                }
124
            }
125
        }
126
        return $filters;
127
    }
128
129
    /**
130
     * @param $torrent
131
     * @return int days from torrent finish download
132
     */
133
    public function getTorrentAgeInDays($torrent)
134
    {
135
        $date = isset($torrent[Torrent\Get::DONE_DATE]) && $torrent[Torrent\Get::DONE_DATE] ?
136
            $torrent[Torrent\Get::DONE_DATE] :
137
            (isset($torrent[Torrent\Get::ADDED_DATE]) ? $torrent[Torrent\Get::ADDED_DATE] : 0);
138
        return $date ? round((time() - $date) / 86400) : 0;
139
    }
140
141
    public function printTorrentsTable(array $torrentList, OutputInterface $output)
142
    {
143
        $table = new Table($output);
144
        $table->setHeaders(['Name', 'Id', 'Size']);
145
146
        foreach ($torrentList as $torrent) {
147
            $table->addRow([
148
                $torrent[Torrent\Get::NAME],
149
                $torrent[Torrent\Get::ID],
150
                round($torrent[Torrent\Get::TOTAL_SIZE] / 1024 / 1000 / 1000, 2),
151
            ]);
152
        }
153
154
        $table->render();
155
    }
156
157
    public function getObsoleteTorrents()
158
    {
159
        $torrentList = $this->getTorrentData();
160
        $all = [];
161
        $obsolete = [];
162
163
        foreach ($torrentList as $torrent) {
164
            $name = $torrent[Torrent\Get::NAME];
165
            if (!isset($all[$name])) {
166
                $all[$name] = $torrent;
167
                continue;
168
            }
169
170
            $obs = $this->detectObsoleteTorrent($all[$name], $torrent);
171
            if ($obs) {
172
                $obsolete[] = $obs;
173
                if ($obs[Torrent\Get::ID] !== $torrent[Torrent\Get::ID]) {
174
                    $all[$name] = $torrent;
175
                }
176
            }
177
        }
178
179
        return $obsolete;
180
    }
181
182
    /**
183
     * @param array $torrentList Array of Torrent data or torrent_ids
184
     * @param bool $deleteLocalData
185
     * @return bool
186
     */
187
    public function removeTorrents(array $torrentList, $deleteLocalData = false)
188
    {
189
        if (empty($torrentList)) {
190
            return false;
191
        }
192
193
        $torrentIds = [];
194
195
        foreach ($torrentList as $torrent) {
196
            $torrentIds[] = $torrent[Torrent\Get::ID];
197
        }
198
199
        $this->createSession();
200
        $this->api->torrentRemove($this->sessionId, $torrentIds, $deleteLocalData);
201
202
        return true;
203
    }
204
205
    private function detectObsoleteTorrent($torrentInList, $torrentNotInList)
206
    {
207
        if ($torrentInList[Torrent\Get::DOWNLOAD_DIR] !== $torrentNotInList[Torrent\Get::DOWNLOAD_DIR]) {
208
            return false;
209
        }
210
211
        return $torrentInList[Torrent\Get::TOTAL_SIZE] < $torrentNotInList[Torrent\Get::TOTAL_SIZE] ?
212
            $torrentInList : $torrentNotInList;
213
    }
214
}
215