Completed
Push — master ( 6d2800...afd9a4 )
by Carlos
01:48
created

Downloader::onlyDownloadProvidedLessonsAndSeries()   B

Complexity

Conditions 5
Paths 9

Size

Total Lines 29
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 29
rs 8.439
cc 5
eloc 18
nc 9
nop 1
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
            $this->bench->end();
98
99
100
            if($this->_haveOptions()) {  //filter all online lessons to the selected ones
101
                $allLessonsOnline = $this->onlyDownloadProvidedLessonsAndSeries($allLessonsOnline);
102
            }
103
104
            Utils::box('Downloading');
105
            //Magic to get what to download
106
            $diff = Utils::resolveFaultyLessons($allLessonsOnline, $localLessons);
107
108
            $new_lessons = Utils::countLessons($diff);
109
            $new_episodes = Utils::countEpisodes($diff);
110
111
            Utils::write(sprintf("%d new lessons and %d episodes. %s elapsed with %s of memory usage.",
112
                    $new_lessons,
113
                    $new_episodes,
114
                    $this->bench->getTime(),
115
                    $this->bench->getMemoryUsage())
116
            );
117
118
119
            //Download Lessons
120
            if ($new_lessons > 0) {
121
                $this->downloadLessons($diff, $counter, $new_lessons);
122
            }
123
124
            //Donwload Episodes
125
            if ($new_episodes > 0) {
126
                $this->downloadEpisodes($diff, $counter, $new_episodes);
127
            }
128
129
            Utils::writeln(sprintf("Finished! Downloaded %d new lessons and %d new episodes. Failed: %d",
130
                $new_lessons - $counter['failed_lesson'],
131
                $new_episodes - $counter['failed_episode'],
132
                $counter['failed_lesson'] + $counter['failed_episode']
133
            ));
134
        } catch (LoginException $e) {
135
            Utils::write("Your login details are wrong!");
136
        } catch (SubscriptionNotActiveException $e) {
137
            Utils::write('Your subscription is not active!');
138
        }
139
    }
140
141
    /**
142
     * Tries to login.
143
     *
144
     * @param $options
145
     *
146
     * @throws \Exception
147
     */
148
    public function doAuth($options)
149
    {
150
        if (!$this->client->doAuth($options['email'], $options['password'])) {
151
            throw new LoginException("Can't do the login..");
152
        }
153
        Utils::write("Successfull!");
154
    }
155
156
    /**
157
     * Download Lessons
158
     * @param $diff
159
     * @param $counter
160
     * @param $new_lessons
161
     */
162
    public function downloadLessons(&$diff, &$counter, $new_lessons)
163
    {
164
        $this->system->createFolderIfNotExists(LESSONS_FOLDER);
165
        Utils::box('Downloading Lessons');
166 View Code Duplication
        foreach ($diff['lessons'] as $lesson) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
167
168
            if($this->client->downloadLesson($lesson) === false) {
169
                $counter['failed_lesson']++;
170
            }
171
172
            Utils::write(sprintf("Current: %d of %d total. Left: %d",
173
                $counter['lessons']++,
174
                $new_lessons,
175
                $new_lessons - $counter['lessons'] + 1
176
            ));
177
        }
178
    }
179
180
    /**
181
     * Download Episodes
182
     * @param $diff
183
     * @param $counter
184
     * @param $new_episodes
185
     */
186
    public function downloadEpisodes(&$diff, &$counter, $new_episodes)
187
    {
188
        $this->system->createFolderIfNotExists(SERIES_FOLDER);
189
        Utils::box('Downloading Series');
190
        foreach ($diff['series'] as $serie => $episodes) {
191
            $this->system->createSerieFolderIfNotExists($serie);
192 View Code Duplication
            foreach ($episodes as $episode) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
193
194
                if($this->client->downloadSerieEpisode($serie, $episode) === false) {
195
                    $counter['failed_episode'] = $counter['failed_episode'] +1;
196
                }
197
198
                Utils::write(sprintf("Current: %d of %d total. Left: %d",
199
                    $counter['series']++,
200
                    $new_episodes,
201
                    $new_episodes - $counter['series'] + 1
202
                ));
203
            }
204
        }
205
    }
206
207
    protected function _haveOptions()
208
    {
209
        $found = false;
210
211
        $short_options = "s:";
212
        $short_options .= "l:";
213
214
        $long_options  = array(
215
            "series-name:",
216
            "lesson-name:"
217
        );
218
        $options = getopt($short_options, $long_options);
219
220
        Utils::box(sprintf("Checking for options %s", json_encode($options)));
221
222
        if(count($options) == 0) {
223
            Utils::write('No options provided');
224
            return false;
225
        }
226
227
        $slugify = new Slugify();
228
        $slugify->addRule("'", '');
229
230 View Code Duplication
        if(isset($options['s']) || isset($options['series-name'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
231
            $series = isset($options['s']) ? $options['s'] : $options['series-name'];
232
            if(!is_array($series))
233
                $series = [$series];
234
235
            Utils::write(sprintf("Series names provided: %s", json_encode($series)));
236
237
238
            $this->wantSeries = array_map(function ($serie) use ($slugify) {
239
                return $slugify->slugify($serie);
240
            }, $series);
241
242
            Utils::write(sprintf("Series names provided: %s", json_encode($this->wantSeries)));
243
244
            $found = true;
245
        }
246
247 View Code Duplication
        if(isset($options['l']) || isset($options['lesson-name'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
248
            $lessons = isset($options['l']) ? $options['l'] : $options['lesson-name'];
249
250
            if(!is_array($lessons))
251
                $lessons = [$lessons];
252
253
            Utils::write(sprintf("Lesson names provided: %s", json_encode($lessons)));
254
255
            $this->wantLessons = array_map(function($lesson) use ($slugify) {
256
                return $slugify->slugify($lesson); },$lessons
257
            );
258
259
            Utils::write(sprintf("Lesson names provided: %s", json_encode($this->wantLessons)));
260
261
            $found = true;
262
        }
263
264
        return $found;
265
    }
266
267
    /**
268
     * Download selected Series and lessons
269
     * @param $allLessonsOnline
270
     * @return array
271
     */
272
    public function onlyDownloadProvidedLessonsAndSeries($allLessonsOnline)
273
    {
274
        Utils::box('Checking if series and lessons exists');
275
276
        $selectedLessonsOnline = [
277
            'lessons' => [],
278
            'series' => []
279
        ];
280
281
        foreach($this->wantSeries as $series) {
282
            if(isset($allLessonsOnline['series'][$series])) {
283
                Utils::write('Series "'.$series.'" found!');
284
                $selectedLessonsOnline['series'][$series] = $allLessonsOnline['series'][$series];
285
            } else {
286
                Utils::write("Series '".$series."' not found!");
287
            }
288
        }
289
290
        foreach($this->wantLessons as $lesson) {
291
            if(in_array($lesson, $allLessonsOnline['lessons'])) {
292
                Utils::write('Lesson "'.$lesson.'" found');
293
                $selectedLessonsOnline['lessons'][] = $allLessonsOnline['lessons'][array_search($lesson, $allLessonsOnline)];
294
            } else {
295
                Utils::write("Lesson '".$lesson."' not found!");
296
            }
297
        }
298
299
        return $selectedLessonsOnline;
300
    }
301
}
302