This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | /** |
||
3 | * AnimeDb package. |
||
4 | * |
||
5 | * @author Peter Gribanov <[email protected]> |
||
6 | * @copyright Copyright (c) 2011, Peter Gribanov |
||
7 | * @license http://opensource.org/licenses/GPL-3.0 GPL v3 |
||
8 | */ |
||
9 | |||
10 | namespace AnimeDb\Bundle\WorldArtFillerBundle\Service; |
||
11 | |||
12 | use AnimeDb\Bundle\AppBundle\Service\Downloader; |
||
13 | use AnimeDb\Bundle\AppBundle\Service\Downloader\Entity\EntityInterface; |
||
14 | use AnimeDb\Bundle\CatalogBundle\Entity\Image; |
||
15 | use AnimeDb\Bundle\CatalogBundle\Entity\Item; |
||
16 | use AnimeDb\Bundle\CatalogBundle\Entity\Name; |
||
17 | use AnimeDb\Bundle\CatalogBundle\Entity\Source; |
||
18 | use AnimeDb\Bundle\CatalogBundle\Plugin\Fill\Filler\Filler as FillerPlugin; |
||
19 | use AnimeDb\Bundle\WorldArtFillerBundle\Form\Type\Filler as FillerForm; |
||
20 | use Doctrine\Bundle\DoctrineBundle\Registry; |
||
21 | use Knp\Menu\ItemInterface; |
||
22 | |||
23 | class Filler extends FillerPlugin |
||
24 | { |
||
25 | /** |
||
26 | * Name. |
||
27 | * |
||
28 | * @var string |
||
29 | */ |
||
30 | const NAME = 'world-art'; |
||
31 | |||
32 | /** |
||
33 | * Title. |
||
34 | * |
||
35 | * @var string |
||
36 | */ |
||
37 | const TITLE = 'World-Art.ru'; |
||
38 | |||
39 | /** |
||
40 | * XPath for fill item. |
||
41 | * |
||
42 | * @var string |
||
43 | */ |
||
44 | const XPATH_FOR_FILL = '//center/table[@height="58%"]/tr/td/table[1]/tr/td'; |
||
45 | |||
46 | /** |
||
47 | * Item type animation. |
||
48 | * |
||
49 | * @var string |
||
50 | */ |
||
51 | const ITEM_TYPE_ANIMATION = 'animation'; |
||
52 | |||
53 | /** |
||
54 | * Item type cinema. |
||
55 | * |
||
56 | * @var string |
||
57 | */ |
||
58 | const ITEM_TYPE_CINEMA = 'cinema'; |
||
59 | |||
60 | /** |
||
61 | * Browser. |
||
62 | * |
||
63 | * @var \AnimeDb\Bundle\WorldArtFillerBundle\Service\Browser |
||
64 | */ |
||
65 | protected $browser; |
||
66 | |||
67 | /** |
||
68 | * Doctrine. |
||
69 | * |
||
70 | * @var \Doctrine\Bundle\DoctrineBundle\Registry |
||
71 | */ |
||
72 | protected $doctrine; |
||
73 | |||
74 | /** |
||
75 | * Downloader. |
||
76 | * |
||
77 | * @var \AnimeDb\Bundle\AppBundle\Service\Downloader |
||
78 | */ |
||
79 | protected $downloader; |
||
80 | |||
81 | /** |
||
82 | * World-Art genres. |
||
83 | * |
||
84 | * @var array |
||
85 | */ |
||
86 | protected $genres = [ |
||
87 | 'боевик' => 'Action', |
||
88 | 'фильм действия' => 'Action', |
||
89 | 'боевые искусства' => 'Martial arts', |
||
90 | 'вампиры' => 'Vampire', |
||
91 | 'война' => 'War', |
||
92 | 'детектив' => 'Detective', |
||
93 | 'для детей' => 'Kids', |
||
94 | 'дзёсэй' => 'Josei', |
||
95 | 'драма' => 'Drama', |
||
96 | 'история' => 'History', |
||
97 | 'киберпанк' => 'Cyberpunk', |
||
98 | 'комедия' => 'Comedy', |
||
99 | 'махо-сёдзё' => 'Mahoe shoujo', |
||
100 | 'меха' => 'Mecha', |
||
101 | 'мистерия' => 'Mystery', |
||
102 | 'мистика' => 'Mystery', |
||
103 | 'музыкальный' => 'Music', |
||
104 | 'образовательный' => 'Educational', |
||
105 | 'пародия' => 'Parody', |
||
106 | 'cтимпанк' => 'Steampunk', |
||
107 | 'паропанк' => 'Steampunk', |
||
108 | 'повседневность' => 'Slice of life', |
||
109 | 'полиция' => 'Police', |
||
110 | 'постапокалиптика' => 'Apocalyptic fiction', |
||
111 | 'приключения' => 'Adventure', |
||
112 | 'приключенческий фильм' => 'Adventure', |
||
113 | 'психология' => 'Psychological', |
||
114 | 'романтика' => 'Romance', |
||
115 | 'самурайский боевик' => 'Samurai', |
||
116 | 'сёдзё' => 'Shoujo', |
||
117 | 'сёдзё-ай' => 'Shoujo-ai', |
||
118 | 'сёнэн' => 'Shounen', |
||
119 | 'сёнэн-ай' => 'Shounen-ai', |
||
120 | 'сказка' => 'Fable', |
||
121 | 'спорт' => 'Sport', |
||
122 | 'сэйнэн' => 'Senen', |
||
123 | 'триллер' => 'Thriller', |
||
124 | 'школа' => 'School', |
||
125 | 'фантастика' => 'Sci-fi', |
||
126 | 'кинофантазия' => 'Fantastic', |
||
127 | 'фэнтези' => 'Fantasy', |
||
128 | 'эротика' => 'Erotica', |
||
129 | 'этти' => 'Ecchi', |
||
130 | 'ужасы' => 'Horror', |
||
131 | 'хентай' => 'Hentai', |
||
132 | 'юри' => 'Yuri', |
||
133 | 'яой' => 'Yaoi', |
||
134 | ]; |
||
135 | |||
136 | /** |
||
137 | * World-Art types. |
||
138 | * |
||
139 | * @var array |
||
140 | */ |
||
141 | protected $types = [ |
||
142 | 'ТВ' => 'tv', |
||
143 | 'ТВ-спэшл' => 'special', |
||
144 | 'OVA' => 'ova', |
||
145 | 'ONA' => 'ona', |
||
146 | 'OAV' => 'ova', |
||
147 | 'полнометражный фильм' => 'feature', |
||
148 | 'короткометражный фильм' => 'featurette', |
||
149 | 'музыкальное видео' => 'music', |
||
150 | 'рекламный ролик' => 'commercial', |
||
151 | ]; |
||
152 | |||
153 | /** |
||
154 | * World-Art studios. |
||
155 | * |
||
156 | * @var array |
||
157 | */ |
||
158 | protected $studios = [ |
||
159 | 1 => 'Studio Ghibli', |
||
160 | 3 => 'Gainax', |
||
161 | 4 => 'AIC', |
||
162 | 6 => 'KSS', |
||
163 | 14 => 'TMS Entertainment', |
||
164 | 20 => 'Bones', |
||
165 | 21 => 'Clamp', |
||
166 | 22 => 'Studio DEEN', |
||
167 | 24 => 'J.C.Staff', |
||
168 | 25 => 'Madhouse', |
||
169 | 26 => 'animate', |
||
170 | 29 => 'OLM, Inc.', |
||
171 | 30 => 'Tezuka Productions', |
||
172 | 31 => 'Production I.G', |
||
173 | 32 => 'Gonzo', |
||
174 | 34 => 'Sunrise', |
||
175 | 37 => 'Agent 21', |
||
176 | 41 => 'Toei Animation', |
||
177 | 44 => 'APPP', |
||
178 | 54 => 'Radix', |
||
179 | 56 => 'Pierrot', |
||
180 | 59 => 'XEBEC', |
||
181 | 64 => 'Satelight', |
||
182 | 74 => 'Oh! Production', |
||
183 | 78 => 'Triangle Staff', |
||
184 | 82 => 'Bee Train', |
||
185 | 84 => 'Animax', |
||
186 | 87 => 'Daume', |
||
187 | 89 => 'Kitty Films', |
||
188 | 92 => 'Ajia-do', |
||
189 | 96 => 'Studio 4°C', |
||
190 | 106 => 'CoMix Wave Inc.', |
||
191 | 116 => 'Fox Animation Studios', |
||
192 | 117 => 'Blue Sky Studios', |
||
193 | 118 => 'Pacific Data Images', |
||
194 | 120 => 'Pixar', |
||
195 | 152 => 'Mushi Production', |
||
196 | 154 => 'Aardman Animations', |
||
197 | 159 => 'DR Movie', |
||
198 | 171 => 'Tatsunoko Productions', |
||
199 | 178 => 'Paramount Animation', |
||
200 | 193 => 'Hal Film Maker', |
||
201 | 198 => 'Studio Fantasia', |
||
202 | 210 => 'Arms Corporation', |
||
203 | 212 => 'Green Bunny', |
||
204 | 236 => 'Pink Pineapple', |
||
205 | 244 => 'Production Reed', |
||
206 | // reverse links |
||
207 | 250 => 'Melnitsa Animation Studio', |
||
208 | 252 => 'Nippon Animation', |
||
209 | 255 => 'Artland', |
||
210 | 267 => 'SHAFT', |
||
211 | 278 => 'March Entertainment', |
||
212 | 296 => 'Gallop', |
||
213 | 315 => 'DreamWorks Animation', |
||
214 | 351 => 'TNK', |
||
215 | 398 => 'A.C.G.T.', |
||
216 | 436 => 'Kyoto Animation', |
||
217 | 439 => 'Studio Comet', |
||
218 | 463 => 'Magic Bus', |
||
219 | 639 => 'Industrial Light & Magic', |
||
220 | 689 => 'ZEXCS', |
||
221 | 724 => 'Six Point Harness', |
||
222 | 753 => 'Pentamedia Graphics', |
||
223 | 795 => 'Rough Draft Studios', |
||
224 | 802 => 'Shin-Ei Animation', |
||
225 | 821 => 'Warner Bros. Animation', |
||
226 | 1066 => 'Animal Logic', |
||
227 | 1161 => 'Marvel Animation Studios', |
||
228 | 1168 => 'Klasky Csupo', |
||
229 | 1654 => 'Digital Frontier', |
||
230 | 1663 => 'Mac Guff', |
||
231 | 1689 => 'Manglobe', |
||
232 | 1778 => 'CinéGroupe', |
||
233 | 1889 => 'Film Roman, Inc.', |
||
234 | 1890 => 'AKOM', |
||
235 | 1901 => 'Brain\'s Base', |
||
236 | 1961 => 'feel.', |
||
237 | 2058 => 'Eiken', |
||
238 | 2229 => 'Studio Hibari', |
||
239 | 2370 => 'IMAGIN', |
||
240 | 2379 => 'Folimage', |
||
241 | 2381 => 'DisneyToon Studios', |
||
242 | 2491 => 'ufotable', |
||
243 | 3058 => 'Asahi Production', |
||
244 | 3096 => 'Mook Animation', |
||
245 | 3113 => 'Walt Disney Television Animation', |
||
246 | 3420 => 'Metro-Goldwyn-Mayer Animation', |
||
247 | 3530 => 'Seven Arcs', |
||
248 | 3742 => 'Nomad', |
||
249 | 3748 => 'Dygra Films', |
||
250 | 3773 => 'Dogakobo', |
||
251 | 3816 => 'EMation', |
||
252 | 4013 => 'Toon City', |
||
253 | 5423 => 'O Entertainment/Omation Animation Studio', |
||
254 | 6081 => 'Sony Pictures Animation', |
||
255 | 6474 => 'Wang Film Productions', |
||
256 | 6475 => 'Creative Capers Entertainment', |
||
257 | 6701 => 'Arc Productions', |
||
258 | 7092 => 'Millimages', |
||
259 | 7194 => 'Mondo TV', |
||
260 | 7298 => 'A-1 Pictures Inc.', |
||
261 | 7372 => 'Diomedea', |
||
262 | 7388 => 'Williams Street Studios', |
||
263 | 7801 => 'National Film Board of Canada', |
||
264 | 7933 => 'Titmouse', |
||
265 | 8590 => 'Rhythm and Hues Studios', |
||
266 | 8639 => 'Bagdasarian Productions', |
||
267 | 9298 => 'Toonz', |
||
268 | 9900 => 'Savage Studios Ltd.', |
||
269 | 10664 => 'A. Film', |
||
270 | 11077 => 'Vanguard Animation', |
||
271 | 11213 => 'bolexbrothers', |
||
272 | 11827 => 'Zinkia Entertainment', |
||
273 | 12209 => 'P.A. Works', |
||
274 | 12268 => 'Universal Animation Studios', |
||
275 | 12280 => 'Reel FX', |
||
276 | 12281 => 'Walt Disney Animation Studios', |
||
277 | 12299 => 'LAIKA', |
||
278 | 12825 => 'White Fox', |
||
279 | 13269 => 'David Production', |
||
280 | 13301 => 'Silver Link', |
||
281 | 13329 => 'Kinema Citrus', |
||
282 | 13906 => 'GoHands', |
||
283 | 13957 => 'Khara', |
||
284 | 14617 => 'Ordet', |
||
285 | 15102 => 'TYO Animations', |
||
286 | 15334 => 'Dong Woo Animation', |
||
287 | 16112 => 'Studio Gokumi', |
||
288 | 16433 => 'Nickelodeon Animation Studios', |
||
289 | 16961 => 'Renegade Animation', |
||
290 | 17049 => 'Curious Pictures', |
||
291 | 17235 => 'Trigger', |
||
292 | 17322 => 'Wit Studio', |
||
293 | ]; |
||
294 | |||
295 | /** |
||
296 | * Construct. |
||
297 | * |
||
298 | * @param \AnimeDb\Bundle\WorldArtFillerBundle\Service\Browser $browser |
||
299 | * @param \Doctrine\Bundle\DoctrineBundle\Registry $doctrine |
||
300 | * @param \AnimeDb\Bundle\AppBundle\Service\Downloader $downloader |
||
301 | */ |
||
302 | public function __construct(Browser $browser, Registry $doctrine, Downloader $downloader) |
||
303 | { |
||
304 | $this->browser = $browser; |
||
305 | $this->doctrine = $doctrine; |
||
306 | $this->downloader = $downloader; |
||
307 | } |
||
308 | |||
309 | /** |
||
310 | * Get name. |
||
311 | * |
||
312 | * @return string |
||
313 | */ |
||
314 | public function getName() |
||
315 | { |
||
316 | return self::NAME; |
||
317 | } |
||
318 | |||
319 | /** |
||
320 | * Get title. |
||
321 | * |
||
322 | * @return string |
||
323 | */ |
||
324 | public function getTitle() |
||
325 | { |
||
326 | return self::TITLE; |
||
327 | } |
||
328 | |||
329 | /** |
||
330 | * Get form. |
||
331 | * |
||
332 | * @return \AnimeDb\Bundle\WorldArtFillerBundle\Form\Type\Filler |
||
333 | */ |
||
334 | public function getForm() |
||
335 | { |
||
336 | return new FillerForm($this->browser->getHost()); |
||
337 | } |
||
338 | |||
339 | /** |
||
340 | * Build menu for plugin. |
||
341 | * |
||
342 | * @param \Knp\Menu\ItemInterface $item |
||
343 | * |
||
344 | * @return \Knp\Menu\ItemInterface |
||
345 | */ |
||
346 | public function buildMenu(ItemInterface $item) |
||
347 | { |
||
348 | return parent::buildMenu($item) |
||
349 | ->setLinkAttribute('class', 'icon-label icon-label-plugin-world-art'); |
||
350 | } |
||
351 | |||
352 | /** |
||
353 | * Fill item from source. |
||
354 | * |
||
355 | * @param array $data |
||
356 | * |
||
357 | * @return \AnimeDb\Bundle\CatalogBundle\Entity\Item|null |
||
358 | */ |
||
359 | public function fill(array $data) |
||
360 | { |
||
361 | if (empty($data['url']) || !is_string($data['url']) || strpos($data['url'], $this->browser->getHost()) !== 0) { |
||
362 | return; |
||
363 | } |
||
364 | |||
365 | $dom = $this->browser->getDom(substr($data['url'], strlen($this->browser->getHost()))); |
||
366 | if (!($dom instanceof \DOMDocument)) { |
||
367 | return; |
||
368 | } |
||
369 | $xpath = new \DOMXPath($dom); |
||
370 | $nodes = $xpath->query(self::XPATH_FOR_FILL); |
||
371 | |||
372 | // get item type |
||
373 | if (!($type = $this->getItemType($data['url']))) { |
||
374 | return; |
||
375 | } |
||
376 | |||
377 | /* @var $body \DOMElement */ |
||
378 | if (!($body = $nodes->item(5))) { |
||
379 | throw new \LogicException('Incorrect data structure at source'); |
||
380 | } |
||
381 | |||
382 | // item id from source |
||
383 | $id = 0; |
||
384 | if (preg_match('/id=(?<id>\d+)/', $data['url'], $mat)) { |
||
385 | $id = (int) $mat['id']; |
||
386 | } |
||
387 | |||
388 | $item = new Item(); |
||
389 | |||
390 | // add source link on world-art |
||
391 | $item->addSource((new Source())->setUrl($data['url'])); |
||
392 | |||
393 | // add other source links |
||
394 | /* @var $links \DOMNodeList */ |
||
395 | $links = $xpath->query('a', $nodes->item(1)); |
||
396 | for ($i = 0; $i < $links->length; ++$i) { |
||
397 | $link = $this->getAttrAsArray($links->item($i)); |
||
0 ignored issues
–
show
|
|||
398 | if (strpos($link['href'], 'http://') !== false && |
||
399 | strpos($link['href'], $this->browser->getHost()) === false |
||
400 | ) { |
||
401 | $item->addSource((new Source())->setUrl($link['href'])); |
||
402 | } |
||
403 | } |
||
404 | |||
405 | // add cover |
||
406 | $this->setCover($item, $id, $type); |
||
407 | |||
408 | // fill item studio |
||
409 | if ($studio = $this->getStudio($xpath, $body)) { |
||
410 | $item->setStudio($studio); |
||
411 | } |
||
412 | |||
413 | // fill main data |
||
414 | if ($type == self::ITEM_TYPE_ANIMATION) { |
||
415 | $head = $xpath->query('table[3]/tr[2]/td[3]', $body); |
||
416 | if (!$head->length) { |
||
417 | $head = $xpath->query('table[2]/tr[1]/td[3]', $body); |
||
418 | } |
||
419 | } else { |
||
420 | $head = $xpath->query('table[3]/tr[1]/td[3]', $body); |
||
421 | } |
||
422 | |||
423 | if ($head->length) { |
||
424 | switch ($type) { |
||
425 | case self::ITEM_TYPE_ANIMATION: |
||
426 | $this->fillAnimationNames($item, $xpath, $head->item(0)); |
||
0 ignored issues
–
show
$head->item(0) of type object<DOMNode> is not a sub-type of object<DOMElement> . It seems like you assume a child class of the class DOMNode to be always present.
This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass. Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type. ![]() |
|||
427 | break; |
||
428 | default: |
||
429 | $this->fillCinemaNames($item, $xpath, $head->item(0)); |
||
0 ignored issues
–
show
$head->item(0) of type object<DOMNode> is not a sub-type of object<DOMElement> . It seems like you assume a child class of the class DOMNode to be always present.
This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass. Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type. ![]() |
|||
430 | } |
||
431 | } |
||
432 | $this->fillHeadData($item, $xpath, $head->item(0)); |
||
0 ignored issues
–
show
$head->item(0) of type object<DOMNode> is not a sub-type of object<DOMElement> . It seems like you assume a child class of the class DOMNode to be always present.
This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass. Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type. ![]() |
|||
433 | |||
434 | // fill body data |
||
435 | $this->fillBodyData($item, $xpath, $body, $id, !empty($data['frames']), $type); |
||
0 ignored issues
–
show
$body of type object<DOMNode> is not a sub-type of object<DOMElement> . It seems like you assume a child class of the class DOMNode to be always present.
This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass. Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type. ![]() |
|||
436 | |||
437 | return $item; |
||
438 | } |
||
439 | |||
440 | /** |
||
441 | * Get element attributes as array. |
||
442 | * |
||
443 | * @param \DOMElement $element |
||
444 | * |
||
445 | * @return array |
||
446 | */ |
||
447 | private function getAttrAsArray(\DOMElement $element) |
||
448 | { |
||
449 | $return = []; |
||
450 | for ($i = 0; $i < $element->attributes->length; ++$i) { |
||
0 ignored issues
–
show
The property
length does not seem to exist in DOMNamedNodeMap .
An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name. If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading. ![]() |
|||
451 | $return[$element->attributes->item($i)->nodeName] = $element->attributes->item($i)->nodeValue; |
||
452 | } |
||
453 | |||
454 | return $return; |
||
455 | } |
||
456 | |||
457 | /** |
||
458 | * Get cover from source id. |
||
459 | * |
||
460 | * @param \AnimeDb\Bundle\CatalogBundle\Entity\Item $item |
||
461 | * @param string $id |
||
462 | * @param string $type |
||
463 | * |
||
464 | * @return bool |
||
465 | */ |
||
466 | private function setCover(Item $item, $id, $type) |
||
467 | { |
||
468 | $item->setCover(self::NAME.'/'.$id.'/1.jpg'); |
||
469 | |||
470 | return $this->uploadImage($this->getCoverUrl($id, $type), $item); |
||
471 | } |
||
472 | |||
473 | /** |
||
474 | * Fill head data. |
||
475 | * |
||
476 | * @param \AnimeDb\Bundle\CatalogBundle\Entity\Item $item |
||
477 | * @param \DOMXPath $xpath |
||
478 | * @param \DOMElement $head |
||
479 | * |
||
480 | * @return \AnimeDb\Bundle\CatalogBundle\Entity\Item |
||
481 | */ |
||
482 | private function fillHeadData(Item $item, \DOMXPath $xpath, \DOMElement $head) |
||
483 | { |
||
484 | /* @var $data \DOMElement */ |
||
485 | $data = $xpath->query('font', $head)->item(0); |
||
486 | $length = $data->childNodes->length; |
||
487 | for ($i = 0; $i < $length; ++$i) { |
||
488 | if ($data->childNodes->item($i)->nodeName == 'b') { |
||
489 | switch ($data->childNodes->item($i)->nodeValue) { |
||
490 | // set country |
||
491 | case 'Производство': |
||
492 | $j = 1; |
||
493 | do { |
||
494 | if ($data->childNodes->item($i + $j)->nodeName == 'a') { |
||
495 | $country_name = trim($data->childNodes->item($i + $j)->nodeValue); |
||
496 | if ($country_name && $country = $this->getCountryByName($country_name)) { |
||
497 | $item->setCountry($country); |
||
498 | } |
||
499 | break; |
||
500 | } |
||
501 | ++$j; |
||
502 | } while ($data->childNodes->item($i + $j)->nodeName != 'br'); |
||
503 | $i += $j; |
||
504 | break; |
||
505 | // add genre |
||
506 | case 'Жанр': |
||
507 | $j = 2; |
||
508 | do { |
||
509 | if ($data->childNodes->item($i + $j)->nodeName == 'a' && |
||
510 | ($genre = $this->getGenreByName($data->childNodes->item($i + $j)->nodeValue)) |
||
511 | ) { |
||
512 | $item->addGenre($genre); |
||
513 | } |
||
514 | ++$j; |
||
515 | } while ($data->childNodes->item($i + $j)->nodeName != 'br'); |
||
516 | $i += $j; |
||
517 | break; |
||
518 | // set type and add file info |
||
519 | case 'Тип': |
||
520 | $type = $data->childNodes->item($i + 1)->nodeValue; |
||
521 | if (preg_match('/(?<type>[\w\s]+)(?: \((?:(?<episodes_number>>?\d+) эп.)?(?<file_info>.*)\))?(, (?<duration>\d{1,3}) мин\.)?$/u', $type, $match)) { |
||
522 | // add type |
||
523 | if ($type = $this->getTypeByName(trim($match['type']))) { |
||
524 | $item->setType($type); |
||
525 | } |
||
526 | // add duration |
||
527 | if (!empty($match['duration'])) { |
||
528 | $item->setDuration((int) $match['duration']); |
||
529 | } |
||
530 | // add number of episodes |
||
531 | if (!empty($match['episodes_number'])) { |
||
532 | if ($match['episodes_number'][0] == '>') { |
||
533 | $item->setEpisodesNumber(substr($match['episodes_number'], 1).'+'); |
||
534 | } else { |
||
535 | $item->setEpisodesNumber((int) $match['episodes_number']); |
||
536 | } |
||
537 | } elseif ($item->getType()->getId() != 'tv') { |
||
538 | // everything except the TV series consist of a single episode |
||
539 | $item->setEpisodesNumber(1); |
||
540 | } |
||
541 | // add file info |
||
542 | if (!empty($match['file_info'])) { |
||
543 | $file_info = $item->getFileInfo(); |
||
544 | $item->setFileInfo(($file_info ? $file_info."\n" : '').trim($match['file_info'])); |
||
545 | } |
||
546 | } |
||
547 | ++$i; |
||
548 | break; |
||
549 | // set date premiere and date end if exists |
||
550 | case 'Премьера': |
||
551 | case 'Выпуск': |
||
552 | $j = 1; |
||
553 | $date = ''; |
||
554 | do { |
||
555 | $date .= $data->childNodes->item($i + $j)->nodeValue; |
||
556 | ++$j; |
||
557 | } while ($length > $i + $j && $data->childNodes->item($i + $j)->nodeName != 'br'); |
||
558 | $i += $j; |
||
559 | |||
560 | $reg = '/(?<start>(?:(?:\d{2})|(?:\?\?)).\d{2}.\d{4})'. |
||
561 | '(?:.*(?<end>(?:(?:\d{2})|(?:\?\?)).\d{2}.\d{4}))?/'; |
||
562 | if (preg_match($reg, $date, $match)) { |
||
563 | $item->setDatePremiere(new \DateTime(str_replace('??', '01', $match['start']))); |
||
564 | if (isset($match['end'])) { |
||
565 | $item->setDateEnd(new \DateTime($match['end'])); |
||
566 | } |
||
567 | } |
||
568 | break; |
||
569 | case 'Хронометраж': |
||
570 | if (preg_match('/(?<duration>\d+)/', $data->childNodes->item($i + 1)->nodeValue, $match)) { |
||
571 | $item->setDuration((int) $match['duration']); |
||
572 | } |
||
573 | break; |
||
574 | case 'Кол-во серий': |
||
575 | $number = trim($data->childNodes->item($i + 1)->nodeValue, ' :'); |
||
576 | if (strpos($number, '>') !== false) { |
||
577 | $number = str_replace('>', '', $number).'+'; |
||
578 | } |
||
579 | $item->setEpisodesNumber($number); |
||
580 | break; |
||
581 | } |
||
582 | } |
||
583 | } |
||
584 | } |
||
585 | |||
586 | /** |
||
587 | * Fill body data. |
||
588 | * |
||
589 | * @param \AnimeDb\Bundle\CatalogBundle\Entity\Item $item |
||
590 | * @param \DOMXPath $xpath |
||
591 | * @param \DOMElement $body |
||
592 | * @param int $id |
||
593 | * @param bool $frames |
||
594 | * @param string $type |
||
595 | * |
||
596 | * @return \AnimeDb\Bundle\CatalogBundle\Entity\Item |
||
597 | */ |
||
598 | private function fillBodyData(Item $item, \DOMXPath $xpath, \DOMElement $body, $id, $frames, $type) |
||
599 | { |
||
600 | for ($i = 0; $i < $body->childNodes->length; ++$i) { |
||
601 | if ($value = trim($body->childNodes->item($i)->nodeValue)) { |
||
602 | switch ($value) { |
||
603 | // get summary |
||
604 | case 'Краткое содержание:': |
||
605 | $summary = $xpath->query('tr/td/p[1]', $body->childNodes->item($i + 2)); |
||
606 | if ($summary->length) { |
||
607 | $item->setSummary($this->getNodeValueAsText($summary->item(0))); |
||
608 | } |
||
609 | $i += 2; |
||
610 | break; |
||
611 | // get episodes |
||
612 | case 'Эпизоды:': |
||
613 | if (!trim($body->childNodes->item($i + 1)->nodeValue)) { // simple list |
||
614 | $item->setEpisodes($this->getNodeValueAsText($body->childNodes->item($i + 2))); |
||
615 | $i += 2; |
||
616 | } else { // episodes in table |
||
617 | $rows = $xpath->query('tr/td[2]', $body->childNodes->item($i + 1)); |
||
618 | $episodes = ''; |
||
619 | for ($j = 1; $j < $rows->length; ++$j) { |
||
620 | $episode = $xpath->query('font', $rows->item($j)); |
||
621 | $episodes .= $j.'. '.$episode->item(0)->nodeValue; |
||
622 | if ($rows->length > 1) { |
||
623 | $episodes .= ' ('.$episode->item(1)->nodeValue.')'; |
||
624 | } |
||
625 | $episodes .= "\n"; |
||
626 | } |
||
627 | $item->setEpisodes($episodes); |
||
628 | ++$i; |
||
629 | } |
||
630 | break; |
||
631 | // get date premiere |
||
632 | case 'Даты премьер и релизов': |
||
633 | $rows = $xpath->query('tr/td/table/tr/td[3]', $body->childNodes->item($i + 1)); |
||
634 | foreach ($rows as $row) { |
||
635 | if (preg_match('/\d{4}\.\d{2}\.\d{2}/', $row->nodeValue, $match)) { |
||
636 | $date = new \DateTime(str_replace('.', '-', $match[0])); |
||
637 | if (!$item->getDatePremiere() || $item->getDatePremiere() > $date) { |
||
638 | $item->setDatePremiere($date); |
||
639 | } |
||
640 | } |
||
641 | } |
||
642 | break; |
||
643 | default: |
||
644 | // get frames |
||
645 | if ( |
||
646 | ( |
||
647 | strpos($value, 'кадры из аниме') !== false || |
||
648 | strpos($value, 'Кадры из фильма') !== false |
||
649 | ) && $id && $frames |
||
650 | ) { |
||
651 | foreach ($this->getFrames($id, $type) as $frame) { |
||
652 | $item->addImage($frame); |
||
653 | } |
||
654 | } |
||
655 | } |
||
656 | } |
||
657 | } |
||
658 | } |
||
659 | |||
660 | /** |
||
661 | * Upload image from url. |
||
662 | * |
||
663 | * @param string $url |
||
664 | * @param \AnimeDb\Bundle\AppBundle\Service\Downloader\Entity\EntityInterface $entity |
||
665 | * |
||
666 | * @return bool |
||
667 | */ |
||
668 | public function uploadImage($url, EntityInterface $entity) |
||
669 | { |
||
670 | return $this->downloader->image($url, $this->downloader->getRoot().$entity->getWebPath()); |
||
671 | } |
||
672 | |||
673 | /** |
||
674 | * Get real country by name. |
||
675 | * |
||
676 | * @param string $name |
||
677 | * |
||
678 | * @return \AnimeDb\Bundle\CatalogBundle\Entity\Country|null |
||
679 | */ |
||
680 | private function getCountryByName($name) |
||
681 | { |
||
682 | $name = str_replace('Южная Корея', 'Республика Корея', $name); |
||
683 | $rep = $this->doctrine->getRepository('AnimeDbCatalogBundle:CountryTranslation'); |
||
684 | if ($country = $rep->findOneBy(['locale' => 'ru', 'content' => $name])) { |
||
685 | return $country->getObject(); |
||
686 | } |
||
687 | } |
||
688 | |||
689 | /** |
||
690 | * Get real genre by name. |
||
691 | * |
||
692 | * @param string $name |
||
693 | * |
||
694 | * @return \AnimeDb\Bundle\CatalogBundle\Entity\Genre|null |
||
695 | */ |
||
696 | private function getGenreByName($name) |
||
697 | { |
||
698 | if (isset($this->genres[$name])) { |
||
699 | return $this->doctrine |
||
700 | ->getRepository('AnimeDbCatalogBundle:Genre') |
||
701 | ->findOneByName($this->genres[$name]); |
||
702 | } |
||
703 | } |
||
704 | |||
705 | /** |
||
706 | * Get real type by name. |
||
707 | * |
||
708 | * @param string $name |
||
709 | * |
||
710 | * @return \AnimeDb\Bundle\CatalogBundle\Entity\Type|null |
||
711 | */ |
||
712 | private function getTypeByName($name) |
||
713 | { |
||
714 | if (isset($this->types[$name])) { |
||
715 | return $this->doctrine |
||
716 | ->getRepository('AnimeDbCatalogBundle:Type') |
||
717 | ->find($this->types[$name]); |
||
718 | } |
||
719 | } |
||
720 | |||
721 | /** |
||
722 | * Get item frames. |
||
723 | * |
||
724 | * @param int $id |
||
725 | * @param string $type |
||
726 | * |
||
727 | * @return array |
||
728 | */ |
||
729 | public function getFrames($id, $type) |
||
730 | { |
||
731 | $dom = $this->browser->getDom('/'.$type.'/'.$type.'_photos.php?id='.$id); |
||
732 | if (!$dom) { |
||
733 | return []; |
||
734 | } |
||
735 | $images = (new \DOMXPath($dom))->query('//table//table//table//img'); |
||
736 | $frames = []; |
||
737 | foreach ($images as $image) { |
||
738 | $src = $this->getAttrAsArray($image)['src']; |
||
739 | $entity = new Image(); |
||
740 | if ($type == self::ITEM_TYPE_ANIMATION) { |
||
741 | $src = str_replace('optimize_b', 'optimize_d', $src); |
||
742 | if (strpos($src, 'http://') === false) { |
||
743 | $src = $this->browser->getHost().'/'.$type.'/'.$src; |
||
744 | } |
||
745 | if (preg_match('/\-(?<image>\d+)\-optimize_d(?<ext>\.jpe?g|png|gif)/', $src, $mat)) { |
||
746 | $entity->setSource(self::NAME.'/'.$id.'/'.$mat['image'].$mat['ext']); |
||
747 | if ($this->uploadImage($src, $entity)) { |
||
748 | $frames[] = $entity; |
||
749 | } |
||
750 | } |
||
751 | } elseif (preg_match('/_(?<round>\d+)\/.+\/(?<id>\d+)-(?<image>\d+)-.+(?<ext>\.jpe?g|png|gif)/', $src, $mat)) { |
||
752 | $src = $this->browser->getHost().'/'.$type.'/img/'.$mat['round'].'/'.$mat['id'].'/'.$mat['image'].$mat['ext']; |
||
753 | $entity->setSource(self::NAME.'/'.$id.'/'.$mat['image'].$mat['ext']); |
||
754 | if ($this->uploadImage($src, $entity)) { |
||
755 | $frames[] = $entity; |
||
756 | } |
||
757 | } |
||
758 | } |
||
759 | |||
760 | return $frames; |
||
761 | } |
||
762 | |||
763 | /** |
||
764 | * Get node value as text. |
||
765 | * |
||
766 | * @param \DOMNode $node |
||
767 | * |
||
768 | * @return string |
||
769 | */ |
||
770 | private function getNodeValueAsText(\DOMNode $node) |
||
771 | { |
||
772 | $text = $node->ownerDocument->saveHTML($node); |
||
773 | $text = str_replace(["<br>\n", "\n", '<br>'], ['<br>', ' ', "\n"], $text); |
||
774 | |||
775 | return trim(strip_tags($text)); |
||
776 | } |
||
777 | |||
778 | /** |
||
779 | * Get item studio. |
||
780 | * |
||
781 | * @param \DOMXPath $xpath |
||
782 | * @param \DOMNode $body |
||
783 | * |
||
784 | * @return \AnimeDb\Bundle\CatalogBundle\Entity\Studio|null |
||
785 | */ |
||
786 | private function getStudio(\DOMXPath $xpath, \DOMNode $body) |
||
787 | { |
||
788 | $studios = $xpath->query('//img[starts-with(@src,"http://www.world-art.ru/img/company_new/")]', $body); |
||
789 | if ($studios->length) { |
||
790 | foreach ($studios as $studio) { |
||
791 | $url = $studio->attributes->getNamedItem('src')->nodeValue; |
||
792 | if (preg_match('/\/(\d+)\./', $url, $mat) && isset($this->studios[$mat[1]])) { |
||
793 | return $this->doctrine |
||
794 | ->getRepository('AnimeDbCatalogBundle:Studio') |
||
795 | ->findOneByName($this->studios[$mat[1]]); |
||
796 | } |
||
797 | } |
||
798 | } |
||
799 | } |
||
800 | |||
801 | /** |
||
802 | * Get item type by URL. |
||
803 | * |
||
804 | * @param string $url |
||
805 | * |
||
806 | * @return string |
||
807 | */ |
||
808 | public function getItemType($url) |
||
809 | { |
||
810 | if (strpos($url, self::ITEM_TYPE_ANIMATION.'/'.self::ITEM_TYPE_ANIMATION) !== false) { |
||
811 | return self::ITEM_TYPE_ANIMATION; |
||
812 | } elseif (strpos($url, self::ITEM_TYPE_CINEMA.'/'.self::ITEM_TYPE_CINEMA) !== false) { |
||
813 | return self::ITEM_TYPE_CINEMA; |
||
814 | } else { |
||
815 | return; |
||
816 | } |
||
817 | } |
||
818 | |||
819 | /** |
||
820 | * Fill names for Animation type. |
||
821 | * |
||
822 | * @param \AnimeDb\Bundle\CatalogBundle\Entity\Item $item |
||
823 | * @param \DOMXPath $xpath |
||
824 | * @param \DOMElement $head |
||
825 | * |
||
826 | * @return \AnimeDb\Bundle\CatalogBundle\Entity\Item |
||
827 | */ |
||
828 | protected function fillAnimationNames(Item $item, \DOMXPath $xpath, \DOMElement $head) |
||
829 | { |
||
830 | // add main name |
||
831 | $names = $xpath->query('table[1]/tr/td', $head)->item(0)->nodeValue; |
||
832 | $names = explode("\n", trim($names)); |
||
833 | |||
834 | // clear |
||
835 | $name = preg_replace('/\[\d{4}\]/', '', array_shift($names)); // example: [2011] |
||
836 | $name = preg_replace('/\[?(ТВ|OVA|ONA)(\-\d)?\]?/', '', $name); // example: [TV-1] |
||
837 | $name = preg_replace('/\(фильм \w+\)/u', '', $name); // example: (фильм седьмой) |
||
838 | $name = preg_replace('/ - Фильм$/iu', '', $name); // example: - Фильм |
||
839 | $item->setName(trim($name)); |
||
840 | |||
841 | // add other names |
||
842 | View Code Duplication | foreach ($names as $name) { |
|
0 ignored issues
–
show
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. ![]() |
|||
843 | $name = trim(preg_replace('/(\(\d+\))?/', '', $name)); |
||
844 | $item->addName((new Name())->setName($name)); |
||
845 | } |
||
846 | |||
847 | return $item; |
||
848 | } |
||
849 | |||
850 | /** |
||
851 | * Fill names for Cinema type. |
||
852 | * |
||
853 | * @param \AnimeDb\Bundle\CatalogBundle\Entity\Item $item |
||
854 | * @param \DOMXPath $xpath |
||
855 | * @param \DOMElement $head |
||
856 | * |
||
857 | * @return \AnimeDb\Bundle\CatalogBundle\Entity\Item |
||
858 | */ |
||
859 | protected function fillCinemaNames(Item $item, \DOMXPath $xpath, \DOMElement $head) |
||
860 | { |
||
861 | // get list names |
||
862 | $names = []; |
||
863 | foreach ($xpath->query('table[1]/tr/td/table/tr/td', $head) as $name) { |
||
864 | $names[] = $name->nodeValue; |
||
865 | } |
||
866 | |||
867 | // clear |
||
868 | $name = preg_replace('/\[\d{4}\]/', '', array_shift($names)); // example: [2011] |
||
869 | $name = preg_replace('/\[?(ТВ|OVA|ONA)(\-\d)?\]?/', '', $name); // example: [TV-1] |
||
870 | $name = preg_replace('/\(фильм \w+\)/u', '', $name); // example: (фильм седьмой) |
||
871 | $item->setName(trim($name)); |
||
872 | |||
873 | // add other names |
||
874 | View Code Duplication | foreach ($names as $name) { |
|
0 ignored issues
–
show
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. ![]() |
|||
875 | $name = trim(preg_replace('/(\(\d+\))/', '', $name)); |
||
876 | $item->addName((new Name())->setName($name)); |
||
877 | } |
||
878 | |||
879 | return $item; |
||
880 | } |
||
881 | |||
882 | /** |
||
883 | * Get cover URL. |
||
884 | * |
||
885 | * @param string $id |
||
886 | * @param string $type |
||
887 | * |
||
888 | * @return string|null |
||
889 | */ |
||
890 | public function getCoverUrl($id, $type) |
||
891 | { |
||
892 | switch ($type) { |
||
893 | View Code Duplication | case self::ITEM_TYPE_ANIMATION: |
|
0 ignored issues
–
show
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. ![]() |
|||
894 | return $this->browser->getHost().'/'.$type.'/img/'.(ceil($id / 1000) * 1000).'/'.$id.'/1.jpg'; |
||
895 | View Code Duplication | case self::ITEM_TYPE_CINEMA: |
|
0 ignored issues
–
show
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. ![]() |
|||
896 | return $this->browser->getHost().'/'.$type.'/img/'.(ceil($id / 10000) * 10000).'/'.$id.'/1.jpg'; |
||
897 | default: |
||
898 | return; |
||
899 | } |
||
900 | } |
||
901 | |||
902 | /** |
||
903 | * Is supported URL. |
||
904 | * |
||
905 | * @param string $url |
||
906 | * |
||
907 | * @return bool |
||
908 | */ |
||
909 | public function isSupportedUrl($url) |
||
910 | { |
||
911 | return strpos($url, $this->browser->getHost()) === 0; |
||
912 | } |
||
913 | } |
||
914 |
This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.
Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.