Downloader   A
last analyzed

Complexity

Total Complexity 33

Size/Duplication

Total Lines 291
Duplicated Lines 19.24 %

Coupling/Cohesion

Components 1
Dependencies 6

Importance

Changes 7
Bugs 0 Features 0
Metric Value
wmc 33
c 7
b 0
f 0
lcom 1
cbo 6
dl 56
loc 291
rs 9.3999

8 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
B start() 0 67 6
A doAuth() 0 7 2
A downloadLessons() 12 17 3
A downloadEpisodes() 12 20 4
C _haveOptions() 32 59 10
B onlyDownloadProvidedLessonsAndSeries() 0 29 5
A sortSeries() 0 6 2

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
/**
3
 * Main cycle of the app
4
 */
5
namespace App;
6
7
use App\Exceptions\LoginException;
8
use App\Exceptions\SubscriptionNotActiveException;
9
use App\Http\Resolver;
10
use App\System\Controller;
11
use App\Utils\Utils;
12
use Cocur\Slugify\Slugify;
13
use GuzzleHttp\Client;
14
use League\Flysystem\Filesystem;
15
use Ubench;
16
17
/**
18
 * Class Downloader
19
 * @package App
20
 */
21
class Downloader
22
{
23
    /**
24
     * Http resolver object
25
     * @var Resolver
26
     */
27
    private $client;
28
29
    /**
30
     * System object
31
     * @var Controller
32
     */
33
    private $system;
34
35
    /**
36
     * Ubench lib
37
     * @var Ubench
38
     */
39
    private $bench;
40
41
    /**
42
     * Number of local lessons
43
     * @var int
44
     */
45
    public static $totalLocalLessons;
46
47
    /**
48
     * Current lesson number
49
     * @var int
50
     */
51
    public static $currentLessonNumber;
52
53
    private $wantSeries = [];
54
    private $wantLessons = [];
55
56
    /**
57
     * Receives dependencies
58
     *
59
     * @param Client $client
60
     * @param Filesystem $system
61
     * @param Ubench $bench
62
     * @param bool $retryDownload
63
     */
64
    public function __construct(Client $client, Filesystem $system, Ubench $bench, $retryDownload = false)
65
    {
66
        $this->client = new Resolver($client, $bench, $retryDownload);
67
        $this->system = new Controller($system);
68
        $this->bench = $bench;
69
    }
70
71
    /**
72
     * All the logic
73
     *
74
     * @param $options
75
     */
76
    public function start($options)
77
    {
78
        try {
79
            $counter = [
80
                'series'  => 1,
81
                'lessons' => 1,
82
                'failed_episode' => 0,
83
                'failed_lesson' => 0
84
            ];
85
86
            Utils::box('Authenticating');
87
88
            $this->doAuth($options);
89
90
            Utils::box('Starting Collecting the data');
91
92
            $this->bench->start();
93
94
            $localLessons = $this->system->getAllLessons();
95
            $allLessonsOnline = $this->client->getAllLessons();
96
97
            // Sort series episodes from low to high (download order)
98
            $this->sortSeries($allLessonsOnline);
99
100
            $this->bench->end();
101
102
103
            if($this->_haveOptions()) {  //filter all online lessons to the selected ones
104
                $allLessonsOnline = $this->onlyDownloadProvidedLessonsAndSeries($allLessonsOnline);
105
            }
106
107
            Utils::box('Downloading');
108
            //Magic to get what to download
109
            $diff = Utils::resolveFaultyLessons($allLessonsOnline, $localLessons);
110
111
            $new_lessons = Utils::countLessons($diff);
112
            $new_episodes = Utils::countEpisodes($diff);
113
114
            Utils::write(sprintf("%d new lessons and %d episodes. %s elapsed with %s of memory usage.",
115
                    $new_lessons,
116
                    $new_episodes,
117
                    $this->bench->getTime(),
118
                    $this->bench->getMemoryUsage())
119
            );
120
121
122
            //Download Lessons
123
            if ($new_lessons > 0) {
124
                $this->downloadLessons($diff, $counter, $new_lessons);
125
            }
126
127
            //Donwload Episodes
128
            if ($new_episodes > 0) {
129
                $this->downloadEpisodes($diff, $counter, $new_episodes);
130
            }
131
132
            Utils::writeln(sprintf("Finished! Downloaded %d new lessons and %d new episodes. Failed: %d",
133
                $new_lessons - $counter['failed_lesson'],
134
                $new_episodes - $counter['failed_episode'],
135
                $counter['failed_lesson'] + $counter['failed_episode']
136
            ));
137
        } catch (LoginException $e) {
138
            Utils::write("Your login details are wrong!");
139
        } catch (SubscriptionNotActiveException $e) {
140
            Utils::write('Your subscription is not active!');
141
        }
142
    }
143
144
    /**
145
     * Tries to login.
146
     *
147
     * @param $options
148
     *
149
     * @throws \Exception
150
     */
151
    public function doAuth($options)
152
    {
153
        if (!$this->client->doAuth($options['email'], $options['password'])) {
154
            throw new LoginException("Can't do the login..");
155
        }
156
        Utils::write("Successfull!");
157
    }
158
159
    /**
160
     * Download Lessons
161
     * @param $diff
162
     * @param $counter
163
     * @param $new_lessons
164
     */
165
    public function downloadLessons(&$diff, &$counter, $new_lessons)
166
    {
167
        $this->system->createFolderIfNotExists(LESSONS_FOLDER);
168
        Utils::box('Downloading Lessons');
169 View Code Duplication
        foreach ($diff['lessons'] as $lesson) {
170
171
            if($this->client->downloadLesson($lesson) === false) {
172
                $counter['failed_lesson']++;
173
            }
174
175
            Utils::write(sprintf("Current: %d of %d total. Left: %d",
176
                $counter['lessons']++,
177
                $new_lessons,
178
                $new_lessons - $counter['lessons'] + 1
179
            ));
180
        }
181
    }
182
183
    /**
184
     * Download Episodes
185
     * @param $diff
186
     * @param $counter
187
     * @param $new_episodes
188
     */
189
    public function downloadEpisodes(&$diff, &$counter, $new_episodes)
190
    {
191
        $this->system->createFolderIfNotExists(SERIES_FOLDER);
192
        Utils::box('Downloading Series');
193
        foreach ($diff['series'] as $serie => $episodes) {
194
            $this->system->createSerieFolderIfNotExists($serie);
195 View Code Duplication
            foreach ($episodes as $episode) {
196
197
                if($this->client->downloadSerieEpisode($serie, $episode) === false) {
198
                    $counter['failed_episode'] = $counter['failed_episode'] +1;
199
                }
200
201
                Utils::write(sprintf("Current: %d of %d total. Left: %d",
202
                    $counter['series']++,
203
                    $new_episodes,
204
                    $new_episodes - $counter['series'] + 1
205
                ));
206
            }
207
        }
208
    }
209
210
    protected function _haveOptions()
211
    {
212
        $found = false;
213
214
        $short_options = "s:";
215
        $short_options .= "l:";
216
217
        $long_options  = array(
218
            "series-name:",
219
            "lesson-name:"
220
        );
221
        $options = getopt($short_options, $long_options);
222
223
        Utils::box(sprintf("Checking for options %s", json_encode($options)));
224
225
        if(count($options) == 0) {
226
            Utils::write('No options provided');
227
            return false;
228
        }
229
230
        $slugify = new Slugify();
231
        $slugify->addRule("'", '');
232
233 View Code Duplication
        if(isset($options['s']) || isset($options['series-name'])) {
234
            $series = isset($options['s']) ? $options['s'] : $options['series-name'];
235
            if(!is_array($series))
236
                $series = [$series];
237
238
            Utils::write(sprintf("Series names provided: %s", json_encode($series)));
239
240
241
            $this->wantSeries = array_map(function ($serie) use ($slugify) {
242
                return $slugify->slugify($serie);
243
            }, $series);
244
245
            Utils::write(sprintf("Series names provided: %s", json_encode($this->wantSeries)));
246
247
            $found = true;
248
        }
249
250 View Code Duplication
        if(isset($options['l']) || isset($options['lesson-name'])) {
251
            $lessons = isset($options['l']) ? $options['l'] : $options['lesson-name'];
252
253
            if(!is_array($lessons))
254
                $lessons = [$lessons];
255
256
            Utils::write(sprintf("Lesson names provided: %s", json_encode($lessons)));
257
258
            $this->wantLessons = array_map(function($lesson) use ($slugify) {
259
                return $slugify->slugify($lesson); },$lessons
260
            );
261
262
            Utils::write(sprintf("Lesson names provided: %s", json_encode($this->wantLessons)));
263
264
            $found = true;
265
        }
266
267
        return $found;
268
    }
269
270
    /**
271
     * Download selected Series and lessons
272
     * @param $allLessonsOnline
273
     * @return array
274
     */
275
    public function onlyDownloadProvidedLessonsAndSeries($allLessonsOnline)
276
    {
277
        Utils::box('Checking if series and lessons exists');
278
279
        $selectedLessonsOnline = [
280
            'lessons' => [],
281
            'series' => []
282
        ];
283
284
        foreach($this->wantSeries as $series) {
285
            if(isset($allLessonsOnline['series'][$series])) {
286
                Utils::write('Series "'.$series.'" found!');
287
                $selectedLessonsOnline['series'][$series] = $allLessonsOnline['series'][$series];
288
            } else {
289
                Utils::write("Series '".$series."' not found!");
290
            }
291
        }
292
293
        foreach($this->wantLessons as $lesson) {
294
            if(in_array($lesson, $allLessonsOnline['lessons'])) {
295
                Utils::write('Lesson "'.$lesson.'" found');
296
                $selectedLessonsOnline['lessons'][] = $lesson;
297
            } else {
298
                Utils::write("Lesson '".$lesson."' not found!");
299
            }
300
        }
301
302
        return $selectedLessonsOnline;
303
    }
304
305
    public function sortSeries(&$allLessons) {
306
        foreach ($allLessons['series'] as $k => $v) {
307
308
            sort($allLessons['series'][$k], SORT_NUMERIC);
309
        }
310
    }
311
}
312