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
|
|
|
|
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.