示例#1
0
 public function testMalXml()
 {
     $manga = new Manga();
     $items = array();
     $output = "<?xml version=\"1.0\"?>\n<entry><chapter>7</chapter><volume>7</volume><status>1</status><score>9</score><downloaded_chapters>8</downloaded_chapters><times_reread>1</times_reread><reread_value>4</reread_value><date_start>01012015</date_start><date_finish>01022015</date_finish><priority>0</priority><comments>This is a comment.</comments><tags>one,two,three</tags></entry>\n";
     $manga->setId(1);
     $manga->setChaptersRead(7);
     $items[] = 'chapters';
     $manga->setVolumesRead(7);
     $items[] = 'volumes';
     $manga->setReadStatus(1);
     $items[] = 'status';
     $manga->setScore(9);
     $items[] = 'score';
     $manga->setChapDownloaded(8);
     $items[] = 'downloaded';
     $manga->setRereadCount(1);
     $items[] = 'rereadCount';
     $manga->setRereadValue(4);
     $items[] = 'rereadValue';
     $manga->setReadingStart(new \DateTime('20150101'));
     $items[] = 'start';
     $manga->setReadingEnd(new \DateTime('20150102'));
     $items[] = 'end';
     $manga->setPriority(6);
     $items[] = 'priority';
     $manga->setPersonalComments('This is a comment.');
     $items[] = 'comments';
     $manga->setPersonalTags('one,two,three');
     $items[] = 'tags';
     $this->assertEquals($output, $manga->MALApiXml($items));
 }
 /**
  * Update a manga on a user's list.
  *
  * Uses the contents of the HTTP Request to get the needed data for updating the
  * requested title. The user must have passed the basic authentication needs and the
  * PHP_AUTH_USER and PHP_AUTH_PW variables must be set. If so, the get variables of
  * "status", "chapters", "volumes", and "score" are checked and used in the creation
  * of a manga object. The object is used to make an XML document that is then posted
  * to MyAnimeList.
  *
  * @param Request $request Contains all the needed information to update the title.
  * @param int     $id      ID of the manga.
  *
  * @return View
  */
 public function updateAction(Request $request, $id, $apiVersion)
 {
     // http://mymangalist.net/api/mangalist/update/#{id}.xml
     //get the credentials we received
     $username = $this->getRequest()->server->get('PHP_AUTH_USER');
     $password = $this->getRequest()->server->get('PHP_AUTH_PW');
     //Don't bother making a request if the user didn't send any authentication
     if ($username === null) {
         $view = $this->view(array('error' => 'unauthorized'), 401);
         $view->setHeader('WWW-Authenticate', 'Basic realm="myanimelist.net"');
         return $view;
     }
     $manga = new Manga();
     $manga->setId($id);
     //Only use values we were sent for the Update XML
     $update_items = array();
     try {
         if ($request->request->get('status') !== null) {
             $manga->setReadStatus($request->request->get('status'));
             $update_items[] = 'status';
         }
         if ($request->request->get('chapters') !== null) {
             $manga->setChaptersRead($request->request->get('chapters'));
             $update_items[] = 'chapters';
         }
         if ($request->request->get('volumes') !== null) {
             $manga->setVolumesRead($request->request->get('volumes'));
             $update_items[] = 'volumes';
         }
         if ($request->request->get('score') !== null) {
             $manga->setScore($request->request->get('score'));
             $update_items[] = 'score';
         }
         //API 2 Items
         if ($apiVersion >= 2.0) {
             if ($request->request->get('downloaded_chap') !== null) {
                 $manga->setChapDownloaded($request->request->get('downloaded_chap'));
                 //Int
                 $update_items[] = 'downloaded';
             }
             if ($request->request->get('reread_count') !== null) {
                 $manga->setRereadCount($request->request->get('reread_count'));
                 //Int
                 $update_items[] = 'rereadCount';
             }
             if ($request->request->get('reread_value') !== null) {
                 $manga->setRereadValue($request->request->get('reread_value'));
                 //Int
                 $update_items[] = 'rereadValue';
             }
             if ($request->request->get('start') !== null) {
                 $manga->setReadingStart(DateTime::createFromFormat('Y-m-d', $request->request->get('start')));
                 //Needs to be DT!
                 $update_items[] = 'start';
             }
             if ($request->request->get('end') !== null) {
                 $manga->setReadingEnd(DateTime::createFromFormat('Y-m-d', $request->request->get('end')));
                 //Needs to be DT!
                 $update_items[] = 'end';
             }
             if ($request->request->get('priority') !== null) {
                 $manga->setPriority($request->request->get('priority'));
                 $update_items[] = 'priority';
             }
             if ($request->request->get('is_rereading') !== null) {
                 $manga->setRereading($request->request->get('is_rereading'));
                 //Bool - 0 = no, 1 = yes
                 $update_items[] = 'isRereading';
             }
             if ($request->request->get('comments') !== null) {
                 $manga->setPersonalComments($request->request->get('comments'));
                 //Plain text string. No HTML.
                 $update_items[] = 'comments';
             }
             if ($request->request->get('tags') !== null) {
                 $manga->setPersonalTags($request->request->get('tags'));
                 //Comma-separated string
                 $update_items[] = 'tags';
             }
         }
     } catch (\Exception $e) {
         return $this->view(array('error' => $e->getMessage()), 500);
     }
     $xmlcontent = $manga->MALApiXml($update_items);
     $connection = $this->get('atarashii_api.communicator');
     try {
         $connection->sendXML('/api/mangalist/update/' . $manga->getId() . '.xml', $xmlcontent, $username, $password);
         return $this->view('ok', 200);
     } catch (Exception\ClientErrorResponseException $e) {
         $view = $this->view(array('error' => 'unauthorized'), 401);
         $view->setHeader('WWW-Authenticate', 'Basic realm="myanimelist.net"');
         return $view;
     } catch (Exception\ServerErrorResponseException $e) {
         //MAL broke API responses, so we have to check the content on the response to make sure
         //it actually was an error.
         $response = $e->getResponse()->getBody(true);
         if (stripos($response, 'Updated') === 0) {
             return $this->view('ok', 200);
         }
         return $this->view(array('error' => 'not-found'), 404);
     } catch (Exception\CurlException $e) {
         return $this->view(array('error' => 'network-error'), 500);
     }
 }
 public static function parse($contents, $mine = false)
 {
     $crawler = new Crawler();
     $crawler->addHTMLContent($contents, 'UTF-8');
     $mangarecord = new Manga();
     # Manga ID.
     # Example:
     # <input type="hidden" value="104" name="mid" />
     $mangarecord->setId((int) $crawler->filter('input[name="mid"]')->attr('value'));
     # Title and rank.
     # Example:
     # <h1>
     #     <div style="float: right; font-size: 13px;">Ranked #22</div>
     #     <span itemprop="name">One Punch-Man</span> <span style="font-weight: normal;"><small>(Manga)</small></span>
     # </h1>
     $mangarecord->setTitle(trim($crawler->filter('span[itemprop="name"]')->text()));
     $rank = $crawler->filterXPath('//span[contains(@class, "ranked")]');
     if (count($rank) > 0) {
         $mangarecord->setRank((int) str_replace('Ranked #', '', $rank->text()));
     }
     # Title Image
     # Example:
     # <a href="http://myanimelist.net/manga/104/Yotsubato!/pic&pid=90029"><img src="http://cdn.myanimelist.net/images/manga/4/90029.jpg" alt="Yotsubato!" align="center"></a>
     $mangarecord->setImageUrl(str_replace('t.jpg', '.jpg', $crawler->filter('div#content tr td div img')->attr('src')));
     // Left Column - Alt titles, info, stats, tags
     $leftcolumn = $crawler->filterXPath('//div[@id="content"]/table/tr/td[@class="borderClass"]');
     # Alternative Titles section.
     # Example:
     # <h2>Alternative Titles</h2>
     # <div class="spaceit_pad"><span class="dark_text">English:</span> Yotsuba&!</div>
     # <div class="spaceit_pad"><span class="dark_text">Synonyms:</span> Yotsubato!, Yotsuba and !, Yotsuba!, Yotsubato, Yotsuba and!</div>
     # <div class="spaceit_pad"><span class="dark_text">Japanese:</span> よつばと!</div>
     # English:
     $extracted = $leftcolumn->filterXPath('//span[text()="English:"]');
     if ($extracted->count() > 0) {
         $text = trim(str_replace($extracted->text(), '', $extracted->parents()->text()));
         $setother_titles['english'] = explode(', ', $text);
         $mangarecord->setOtherTitles($setother_titles);
     }
     # Synonyms:
     $extracted = $leftcolumn->filterXPath('//span[text()="Synonyms:"]');
     if ($extracted->count() > 0) {
         $text = trim(str_replace($extracted->text(), '', $extracted->parents()->text()));
         $setother_titles['synonyms'] = explode(', ', $text);
         $mangarecord->setOtherTitles($setother_titles);
     }
     # Japanese:
     $extracted = $leftcolumn->filterXPath('//span[text()="Japanese:"]');
     if ($extracted->count() > 0) {
         $text = trim(str_replace($extracted->text(), '', $extracted->parents()->text()));
         $setother_titles['japanese'] = explode(', ', $text);
         $mangarecord->setOtherTitles($setother_titles);
     }
     # Information section.
     # Example:
     # <h2>Information</h2>
     # <div><span class="dark_text">Type:</span> Manga</div>
     # <div class="spaceit"><span class="dark_text">Volumes:</span> Unknown</div>
     # <div><span class="dark_text">Chapters:</span> Unknown</div>
     # <div class="spaceit"><span class="dark_text">Status:</span> Publishing</div>
     # <div><span class="dark_text">Published:</span> Mar  21, 2003 to ?</div>
     # <div class="spaceit"><span class="dark_text">Genres:</span>
     #   <a href="http://myanimelist.net/manga.php?genre[]=4">Comedy</a>,
     #   <a href="http://myanimelist.net/manga.php?genre[]=36">Slice of Life</a>
     # </div>
     # <div><span class="dark_text">Authors:</span>
     #   <a href="http://myanimelist.net/people/1939/Kiyohiko_Azuma">Azuma, Kiyohiko</a> (Story & Art)
     # </div>
     # <div class="spaceit"><span class="dark_text">Serialization:</span>
     #   <a href="http://myanimelist.net/manga.php?mid=23">Dengeki Daioh (Monthly)</a>
     # </div>
     # Type:
     $extracted = $leftcolumn->filterXPath('//span[text()="Type:"]');
     if ($extracted->count() > 0) {
         $mangarecord->setType(trim(str_replace($extracted->text(), '', $extracted->parents()->text())));
     }
     # Volumes:
     $extracted = $leftcolumn->filterXPath('//span[text()="Volumes:"]');
     $mangarecord->setVolumes(null);
     if ($extracted->count() > 0) {
         $data = trim(str_replace($extracted->text(), '', $extracted->parents()->text()));
         if ($data != 'Unknown') {
             $mangarecord->setVolumes((int) $data);
         } else {
             $mangarecord->setVolumes(null);
         }
     }
     # Chapters:
     $extracted = $leftcolumn->filterXPath('//span[text()="Chapters:"]');
     $mangarecord->setChapters(null);
     if ($extracted->count() > 0) {
         $data = trim(str_replace($extracted->text(), '', $extracted->parents()->text()));
         if ($data != 'Unknown') {
             $mangarecord->setChapters((int) $data);
         } else {
             $mangarecord->setChapters(null);
         }
     }
     # Status:
     $extracted = $leftcolumn->filterXPath('//span[text()="Status:"]');
     if ($extracted->count() > 0) {
         $mangarecord->setStatus(strtolower(trim(str_replace($extracted->text(), '', $extracted->parents()->text()))));
     }
     # Genres:
     $extracted = $leftcolumn->filterXPath('//span[text()="Genres:"]');
     if ($extracted->count() > 0) {
         $mangarecord->setGenres(explode(', ', trim(str_replace($extracted->text(), '', $extracted->parents()->text()))));
     }
     # Statistics
     # Example:
     # <h2>Statistics</h2>
     # <div><span class="dark_text">Score:</span> 8.90<sup><small>1</small></sup> <small>(scored by 4899 users)</small>
     # </div>
     # <div class="spaceit"><span class="dark_text">Ranked:</span> #8<sup><small>2</small></sup></div>
     # <div><span class="dark_text">Popularity:</span> #32</div>
     # <div class="spaceit"><span class="dark_text">Members:</span> 8,344</div>
     # <div><span class="dark_text">Favorites:</span> 1,700</div>
     //TODO: Rewrite to properly clean up excess tags.
     # Score:
     $extracted = $leftcolumn->filterXPath('//span[text()="Score:"]');
     if ($extracted->count() > 0) {
         $extracted = str_replace($extracted->text(), '', $extracted->parents()->text());
         //Remove the parenthetical at the end of the string
         $extracted = trim(str_replace(strstr($extracted, '('), '', $extracted));
         //Sometimes there is a superscript number at the end from a note.
         //Scores are only two decimals, so number_format should chop off the excess, hopefully.
         $mangarecord->setMembersScore((double) number_format($extracted, 2));
     }
     # Popularity:
     $extracted = $leftcolumn->filterXPath('//span[text()="Popularity:"]');
     if ($extracted->count() > 0) {
         $extracted = str_replace($extracted->text(), '', $extracted->parents()->text());
         //Remove the hash at the front of the string and trim whitespace. Needed so we can cast to an int.
         $extracted = trim(str_replace('#', '', $extracted));
         $mangarecord->setPopularityRank((int) $extracted);
     }
     # Members:
     $extracted = $leftcolumn->filterXPath('//span[text()="Members:"]');
     if ($extracted->count() > 0) {
         $extracted = str_replace($extracted->text(), '', $extracted->parents()->text());
         //PHP doesn't like commas in integers. Remove it.
         $extracted = trim(str_replace(',', '', $extracted));
         $mangarecord->setMembersCount((int) $extracted);
     }
     # Members:
     $extracted = $leftcolumn->filterXPath('//span[text()="Favorites:"]');
     if ($extracted->count() > 0) {
         $extracted = str_replace($extracted->text(), '', $extracted->parents()->text());
         //PHP doesn't like commas in integers. Remove it.
         $extracted = trim(str_replace(',', '', $extracted));
         $mangarecord->setFavoritedCount((int) $extracted);
     }
     # -
     # Extract from sections on the right column: Synopsis, Related Manga
     # -
     $rightcolumn = $crawler->filterXPath('//div[@id="content"]/table/tr/td[2]');
     # Synopsis
     # Example:
     # <h2>Synopsis</h2>
     # Yotsuba's daily life is full of adventure. She is energetic, curious, and a bit odd &ndash; odd enough to be called strange by her father as well as ignorant of many things that even a five-year-old should know. Because of this, the most ordinary experience can become an adventure for her. As the days progress, she makes new friends and shows those around her that every day can be enjoyable.<br />
     # <br />
     # [Written by MAL Rewrite]
     $extracted = $crawler->filterXPath('//span[@itemprop="description"]');
     //Compatibility Note: We don't convert extended characters to HTML entities, we just
     //use the output directly from MAL. This should be okay as our return charset is UTF-8.
     $mangarecord->setSynopsis('There is currently no synopsis for this title.');
     if ($extracted->count() > 0) {
         $mangarecord->setSynopsis($extracted->html());
     }
     # Related Manga
     # Example:
     #<table class="anime_detail_related_anime" style="border-spacing:0px;">
     #  <tr>
     #    <td class="ar fw-n borderClass" nowrap="" valign="top">Side story:</td>
     #    <td class="borderClass" width="100%"><a href="/manga/13992/Azumanga_Daioh:_Hoshuu-hen">Azumanga Daioh: Hoshuu-hen</a></td>
     #  </tr>
     #  <tr>
     #    <td class="ar fw-n borderClass" nowrap="" valign="top">Other:</td>
     #    <td class="borderClass" width="100%"><a href="/manga/29937/Bara_Manga_Daioh">Bara Manga Daioh</a>, <a href="/manga/59917/Osaka_Banpaku">Osaka Banpaku</a></td>
     #  </tr>
     #</table>
     $related = $rightcolumn->filter('table.anime_detail_related_anime');
     //NOTE: Not all relations are currently supported.
     if (iterator_count($related)) {
         $rows = $related->children();
         foreach ($rows as $row) {
             $rowItem = $row->firstChild;
             $relationType = rtrim($rowItem->nodeValue, ':');
             //This gets the next td containing the items
             $relatedItem = $rowItem->nextSibling->firstChild;
             do {
                 if ($relatedItem->nodeType !== XML_TEXT_NODE && $relatedItem->tagName == 'a') {
                     $url = $relatedItem->attributes->getNamedItem('href')->nodeValue;
                     $id = preg_match('/\\/(anime|manga)\\/(\\d+)\\/.*?/', $url, $urlParts);
                     if (count($urlParts) > 2) {
                         if ($id !== false || $id !== 0) {
                             $itemId = (int) $urlParts[2];
                             $itemTitle = $relatedItem->textContent;
                             $itemUrl = $url;
                         }
                         $itemArray = array();
                         if ($urlParts[1] == 'anime') {
                             $itemArray['anime_id'] = $itemId;
                         } else {
                             $itemArray['manga_id'] = $itemId;
                         }
                         $itemArray['title'] = $itemTitle;
                         $itemArray['url'] = 'https://myanimelist.net' . $itemUrl;
                         switch ($relationType) {
                             case 'Adaptation':
                                 $mangarecord->setAnimeAdaptations($itemArray);
                                 break;
                             case 'Alternative version':
                                 $mangarecord->setAlternativeVersions($itemArray);
                                 break;
                             case 'Other':
                             default:
                                 $mangarecord->setRelatedManga($itemArray);
                                 break;
                         }
                     }
                 }
                 //Grab next item
                 $relatedItem = $relatedItem->nextSibling;
             } while ($relatedItem !== null);
         }
     }
     # Personal Info
     $userPersonalInfo = $crawler->filterXPath('//h2[text()="Edit Status"]');
     // Only try to parse personal info if the box is there
     if ($userPersonalInfo->count() > 0) {
         #Read Status - Only available when user is authenticated
         $my_data = $crawler->filter('select#myinfo_status');
         if (iterator_count($my_data) && iterator_count($my_data->filter('option[selected="selected"]'))) {
             $mangarecord->setReadStatus($my_data->filter('option[selected="selected"]')->attr('value'));
         }
         #Read Chapters - Only available when user is authenticated
         $my_data = $crawler->filter('input#myinfo_chapters');
         if (iterator_count($my_data)) {
             $mangarecord->setChaptersRead((int) $my_data->attr('value'));
         }
         #Read Volumes - Only available when user is authenticated
         $my_data = $crawler->filter('input#myinfo_volumes');
         if (iterator_count($my_data)) {
             $mangarecord->setVolumesRead((int) $my_data->attr('value'));
         }
         #User's Score - Only available when user is authenticated
         $my_data = $crawler->filter('select#myinfo_score');
         if (iterator_count($my_data) && iterator_count($my_data->filter('option[selected="selected"]'))) {
             $mangarecord->setScore((int) $my_data->filter('option[selected="selected"]')->attr('value'));
         }
         #Listed ID (?) - Only available when user is authenticated
         $my_data = $crawler->filterXPath('//a[text()="Edit Details"]');
         if (iterator_count($my_data)) {
             if (preg_match('/id=(\\d+)/', $my_data->attr('href'), $my_data)) {
                 $mangarecord->setListedMangaId((int) $my_data[1]);
             }
         }
     }
     return $mangarecord;
 }