public static function getAchievementsDefinitions()
 {
     $dir = Config::$achievementsDefinitionsDirectory;
     $imgFiles = scandir(Config::$imageDirectory . DIRECTORY_SEPARATOR . 'achievement');
     $definitions = array_fill_keys(Media::getConstList(), []);
     foreach (glob($dir . DIRECTORY_SEPARATOR . '*.json') as $file) {
         $definition = TextHelper::loadJson($file);
         $prevAch = null;
         foreach ($definition->achievements as &$ach) {
             foreach ($imgFiles as $f) {
                 if (preg_match('/' . $ach->id . '[^0-9a-zA-Z_-]/', $f)) {
                     $ach->path = $f;
                 }
             }
             $ach->next = null;
         }
         foreach ($definition->achievements as &$ach) {
             if ($prevAch !== null) {
                 $prevAch->next = $ach;
             }
             $ach->prev = $prevAch;
             $prevAch =& $ach;
         }
         unset($ach);
         unset($prevAch);
         $definitions[$definition->media][] = $definition;
     }
     foreach (Media::getConstList() as $key) {
         uasort($definitions[$key], function ($a, $b) {
             return $a->order - $b->order;
         });
     }
     return $definitions;
 }
示例#2
0
 public static function parseRequest($url, &$controllerContext)
 {
     $userRegex = self::getUserRegex();
     $modulesRegex = self::getAvailableModulesRegex();
     $mediaParts = array_map(['Media', 'toString'], Media::getConstList());
     $mediaRegex = implode('|', $mediaParts);
     $regex = '^/?' . '(' . $userRegex . ')' . '(' . $modulesRegex . ')' . '(,(' . $mediaRegex . '))?' . '/?($|\\?)';
     if (!preg_match('#' . $regex . '#', $url, $matches)) {
         return false;
     }
     $controllerContext->userName = $matches[1];
     $media = !empty($matches[4]) ? $matches[4] : 'anime';
     switch ($media) {
         case 'anime':
             $controllerContext->media = Media::Anime;
             break;
         case 'manga':
             $controllerContext->media = Media::Manga;
             break;
         default:
             throw new BadMediaException();
     }
     $rawModule = ltrim($matches[2], '/') ?: 'profile';
     $controllerContext->rawModule = $rawModule;
     $controllerContext->module = self::getModuleByUrlPart($rawModule);
     assert(!empty($controllerContext->module));
     return true;
 }
 public static function work(&$controllerContext, &$viewContext)
 {
     $viewContext->viewName = 'user-profile';
     $viewContext->meta->title = $viewContext->user->name . '\'s profile — ' . Config::$title;
     $viewContext->meta->description = $viewContext->user->name . '\'s profile.';
     WebMediaHelper::addEntries($viewContext);
     WebMediaHelper::addMiniSections($viewContext);
     WebMediaHelper::addCustom($viewContext);
     $viewContext->yearsOnMal = null;
     if (intval($viewContext->user->join_date)) {
         list($year, $month, $day) = explode('-', $viewContext->user->join_date);
         $time = mktime(0, 0, 0, $month, $day, $year);
         $diff = time() - $time;
         $diff /= 3600 * 24;
         $viewContext->yearsOnMal = $diff / 361.25;
     }
     $viewContext->friends = $viewContext->user->getFriends();
     $viewContext->finished = [];
     $viewContext->meanUserScore = [];
     $viewContext->meanGlobalScore = [];
     $viewContext->franchiseCount = [];
     $viewContext->mismatchedCount = [];
     foreach (Media::getConstList() as $media) {
         $list = $viewContext->user->getMixedUserMedia($media);
         $listFinished = UserMediaFilter::doFilter($list, UserMediaFilter::finished());
         $viewContext->finished[$media] = count($listFinished);
         unset($listFinished);
         $listNonPlanned = UserMediaFilter::doFilter($list, UserMediaFilter::nonPlanned());
         $viewContext->meanUserScore[$media] = RatingDistribution::fromEntries($listNonPlanned)->getMeanScore();
         $franchises = Model_MixedUserMedia::getFranchises($listNonPlanned);
         $viewContext->franchiseCount[$media] = count(array_filter($franchises, function ($franchise) {
             return count($franchise->ownEntries) > 1;
         }));
         unset($franchises);
         unset($listNonPlanned);
         if ($media == Media::Anime) {
             $viewContext->episodes = array_sum(array_map(function ($mixedMediaEntry) {
                 return $mixedMediaEntry->finished_episodes;
             }, $list));
         } else {
             $viewContext->chapters = array_sum(array_map(function ($mixedMediaEntry) {
                 return $mixedMediaEntry->finished_chapters;
             }, $list));
         }
         $mismatched = $viewContext->user->getMismatchedUserMedia($list);
         $viewContext->mismatchedCount[$media] = count($mismatched);
         unset($mismatched);
         unset($list);
         $globalsCache = file_exists(Config::$globalsCachePath) ? TextHelper::loadJson(Config::$globalsCachePath, true) : [];
         $viewContext->meanGlobalScore[$media] = array_map(function ($v) {
             return RatingDistribution::fromArray($v);
         }, $globalsCache['rating-dist'])[$media]->getMeanScore();
     }
 }
 public static function work(&$controllerContext, &$viewContext)
 {
     $viewContext->viewName = 'user-profile';
     $viewContext->meta->title = 'MALgraph - ' . $viewContext->user->name . '’s profile';
     $viewContext->meta->description = $viewContext->user->name . '’s profile on MALgraph, an online tool that extends your MyAnimeList profile.';
     $viewContext->meta->keywords = array_merge($viewContext->meta->keywords, ['profile', 'list', 'achievements', 'ratings', 'history', 'favorites', 'suggestions', 'recommendations']);
     WebMediaHelper::addEntries($viewContext);
     WebMediaHelper::addMiniSections($viewContext);
     WebMediaHelper::addCustom($viewContext);
     $viewContext->yearsOnMal = null;
     if (intval($viewContext->user->join_date)) {
         list($year, $month, $day) = explode('-', $viewContext->user->join_date);
         $time = mktime(0, 0, 0, $month, $day, $year);
         $diff = time() - $time;
         $diff /= 3600 * 24;
         $viewContext->yearsOnMal = $diff / 361.25;
     }
     $viewContext->friends = $viewContext->user->getFriends();
     $viewContext->clubs = $viewContext->user->getClubs();
     $viewContext->finished = [];
     $viewContext->meanUserScore = [];
     $viewContext->meanGlobalScore = [];
     $viewContext->franchiseCount = [];
     $viewContext->mismatchedCount = [];
     foreach (Media::getConstList() as $media) {
         $list = $viewContext->user->getMixedUserMedia($media);
         $listFinished = UserMediaFilter::doFilter($list, UserMediaFilter::finished());
         $viewContext->finished[$media] = count($listFinished);
         unset($listFinished);
         $listNonPlanned = UserMediaFilter::doFilter($list, UserMediaFilter::nonPlanned());
         $viewContext->meanUserScore[$media] = RatingDistribution::fromEntries($listNonPlanned)->getMeanScore();
         $viewContext->meanGlobalScore[$media] = Model_MixedUserMedia::getRatingDistribution($media)->getMeanScore();
         $franchises = Model_MixedUserMedia::getFranchises($listNonPlanned);
         $viewContext->franchiseCount[$media] = count(array_filter($franchises, function ($franchise) {
             return count($franchise->ownEntries) > 1;
         }));
         unset($franchises);
         unset($listNonPlanned);
         if ($media == Media::Anime) {
             $viewContext->episodes = array_sum(array_map(function ($mixedMediaEntry) {
                 return $mixedMediaEntry->finished_episodes;
             }, $list));
         } else {
             $viewContext->chapters = array_sum(array_map(function ($mixedMediaEntry) {
                 return $mixedMediaEntry->finished_chapters;
             }, $list));
         }
         $mismatched = $viewContext->user->getMismatchedUserMedia($list);
         $viewContext->mismatchedCount[$media] = count($mismatched);
         unset($mismatched);
         unset($list);
     }
 }
 public function process(array $documents, &$context)
 {
     Database::delete('usermedia', ['user_id' => $context->user->id]);
     $context->user->cool = false;
     foreach (Media::getConstList() as $media) {
         $key = $media == Media::Anime ? self::URL_ANIMELIST : self::URL_MANGALIST;
         $isPrivate = strpos($documents[$key]->content, 'This list has been made private by the owner') !== false;
         $key = $media == Media::Anime ? self::URL_ANIMEINFO : self::URL_MANGAINFO;
         $doc = $documents[$key];
         $dom = self::getDOM($doc);
         $xpath = new DOMXPath($dom);
         if ($xpath->query('//myinfo')->length == 0) {
             throw new BadProcessorDocumentException($doc, 'myinfo block is missing');
         }
         if (strpos($doc->content, '</myanimelist>') === false) {
             throw new BadProcessorDocumentException($doc, 'list is only partially downloaded');
         }
         $nodes = $xpath->query('//anime | //manga');
         $data = [];
         foreach ($nodes as $root) {
             $mediaMalId = Strings::makeInteger(self::getNodeValue($xpath, 'series_animedb_id | series_mangadb_id', $root));
             $score = Strings::makeInteger(self::getNodeValue($xpath, 'my_score', $root));
             $startDate = Strings::makeDate(self::getNodeValue($xpath, 'my_start_date', $root));
             $finishDate = Strings::makeDate(self::getNodeValue($xpath, 'my_finish_date', $root));
             $status = Strings::makeEnum(self::getNodeValue($xpath, 'my_status', $root), [1 => UserListStatus::Completing, 2 => UserListStatus::Finished, 3 => UserListStatus::OnHold, 4 => UserListStatus::Dropped, 6 => UserListStatus::Planned], UserListStatus::Unknown);
             $finishedEpisodes = null;
             $finishedChapters = null;
             $finishedVolumes = null;
             switch ($media) {
                 case Media::Anime:
                     $finishedEpisodes = Strings::makeInteger(self::getNodeValue($xpath, 'my_watched_episodes', $root));
                     break;
                 case Media::Manga:
                     $finishedChapters = Strings::makeInteger(self::getNodeValue($xpath, 'my_read_chapters', $root));
                     $finishedVolumes = Strings::makeInteger(self::getNodeValue($xpath, 'my_read_volumes', $root));
                     break;
                 default:
                     throw new BadMediaException();
             }
             $data[] = ['user_id' => $context->user->id, 'mal_id' => $mediaMalId, 'media' => $media, 'score' => $score, 'start_date' => $startDate, 'end_date' => $finishDate, 'finished_episodes' => $finishedEpisodes, 'finished_chapters' => $finishedChapters, 'finished_volumes' => $finishedVolumes, 'status' => $status];
         }
         Database::insert('usermedia', $data);
         $dist = RatingDistribution::fromEntries(ReflectionHelper::arraysToClasses($data));
         $daysSpent = Strings::makeFloat(self::getNodeValue($xpath, '//user_days_spent_watching'));
         $user =& $context->user;
         $user->{Media::toString($media) . '_days_spent'} = $daysSpent;
         $user->{Media::toString($media) . '_private'} = $isPrivate;
         $user->cool |= ($dist->getRatedCount() >= 50 and $dist->getStandardDeviation() >= 1.5);
         R::store($user);
     }
 }
 public static function work(&$controllerContext, &$viewContext)
 {
     $ratingDistribution = [];
     foreach (Media::getConstList() as $media) {
         $entries = $viewContext->user->getMixedUserMedia($media);
         $entriesNonPlanned = UserMediaFilter::doFilter($entries, [UserMEdiaFilter::nonPlanned()]);
         $ratingDistribution[$media] = RatingDistribution::fromEntries($entries);
     }
     //get input data from GET
     $userSettings = !empty($_GET['settings']) ? json_decode(base64_decode($_GET['settings']), true) : [];
     $imageType = !empty($userSettings[0]) ? $userSettings[0] : null;
     if (!in_array($imageType, [self::IMAGE_TYPE_ANIME, self::IMAGE_TYPE_MANGA, self::IMAGE_TYPE_ANIME_MANGA])) {
         $imageType = self::IMAGE_TYPE_ANIME;
     }
     $settings = new StdClass();
     $settings->font = Config::$mediaDirectory . DIRECTORY_SEPARATOR . 'font' . DIRECTORY_SEPARATOR . 'OpenSans-Regular.ttf';
     $settings->fontSizeSmall = 7;
     $settings->fontSizeNormal = 9;
     $settings->fontSizeBig = 10.5;
     $settings->barWidth = 220;
     $settings->barHeight = 13;
     $settings->barPadding = 1;
     $settings->colors = [self::COLOR_BARS1 => '00a4c0f4', self::COLOR_BARS2 => '0013459a', self::COLOR_BAR_GUIDES1 => 'eea4c0f4', self::COLOR_BAR_GUIDES2 => 'ee13459a', self::COLOR_BACKGROUND => 'ffffffff', self::COLOR_FONT_DARK => '00000000', self::COLOR_FONT_LIGHT => 'aa000000', self::COLOR_TITLE => '00577fc2', self::COLOR_LOGO => '00577fc2'];
     foreach (array_keys($settings->colors) as $key) {
         if (isset($userSettings[$key])) {
             $value = $userSettings[$key];
             assert(in_array(strlen($value), [6, 8]));
             $settings->colors[$key] = $value;
         }
     }
     $settings->colors = array_map(function ($color) {
         $value = array_map('hexdec', str_split($color, 2));
         if (count($value) == 3) {
             array_unshift($value, 0);
         }
         $value[0] >>= 1;
         $c = 0;
         while (!empty($value)) {
             $c <<= 8;
             $c |= array_shift($value);
         }
         return $c;
     }, $settings->colors);
     $margin = 6;
     $iconImage = self::getIconImage($settings);
     if ($imageType == self::IMAGE_TYPE_ANIME or $imageType == self::IMAGE_TYPE_MANGA) {
         $media = $imageType == self::IMAGE_TYPE_ANIME ? Media::Anime : Media::Manga;
         $barsImage = self::getBarsImage($settings, $ratingDistribution[$media], false);
         $barsAxesImage = self::getBarsAxesImage($settings, false);
         $barsBandsImage = self::getBarsBandsImage($settings, $ratingDistribution[$media], false);
         $footerImage = self::getFooterImage($settings, $ratingDistribution[$media], $media, false);
         $w = imagesx($barsImage) + imagesx($barsAxesImage) + imagesx($barsBandsImage);
         $h = imagesy($barsImage) + $margin + imagesy($footerImage);
         $img = imagecreatetruecolor($w, $h);
         imagealphablending($img, false);
         imagefilledrectangle($img, 0, 0, $w, $h, $settings->colors[self::COLOR_BACKGROUND]);
         $x = 0;
         $y = imagesy($barsAxesImage) + $margin;
         self::drawCopy($img, $barsAxesImage, $x, 0);
         $x += imagesx($barsAxesImage);
         self::drawCopy($img, $barsImage, $x, 0);
         self::drawCopy($img, $footerImage, $x, $y);
         $x += imagesx($barsImage);
         self::drawCopy($img, $barsBandsImage, $x, 0);
         $x += imagesx($barsBandsImage);
         $x = imagesx($barsAxesImage) - imagesx($iconImage) >> 1;
         self::drawCopy($img, $iconImage, $x, $y);
     } else {
         $barsImage1 = self::getBarsImage($settings, $ratingDistribution[Media::Anime], true);
         $barsImage2 = self::getBarsImage($settings, $ratingDistribution[Media::Manga], false);
         $barsAxesImage = self::getBarsAxesImage($settings, true);
         $barsBandsImage1 = self::getBarsBandsImage($settings, $ratingDistribution[Media::Anime], true);
         $barsBandsImage2 = self::getBarsBandsImage($settings, $ratingDistribution[Media::Manga], false);
         $footerImage1 = self::getFooterImage($settings, $ratingDistribution[Media::Anime], Media::Anime, true);
         $footerImage2 = self::getFooterImage($settings, $ratingDistribution[Media::Manga], Media::Manga, false);
         $w = imagesx($barsImage1) + imagesx($barsImage2) + imagesx($barsAxesImage) + imagesx($barsBandsImage1) + imagesx($barsBandsImage2);
         $h = imagesy($barsImage1) + $margin + imagesy($footerImage1);
         $img = imagecreatetruecolor($w, $h);
         imagealphablending($img, false);
         imagefilledrectangle($img, 0, 0, $w, $h, $settings->colors[self::COLOR_BACKGROUND]);
         $x = 0;
         $y = imagesy($barsAxesImage) + $margin;
         self::drawCopy($img, $barsBandsImage1, $x, 0);
         $x += imagesx($barsBandsImage1);
         self::drawCopy($img, $barsImage1, $x, 0);
         self::drawCopy($img, $footerImage1, $x, $y);
         $x += imagesx($barsImage1);
         self::drawCopy($img, $barsAxesImage, $x, 0);
         $x += imagesx($barsAxesImage);
         self::drawCopy($img, $barsImage2, $x, 0);
         self::drawCopy($img, $footerImage2, $x, $y);
         $x += imagesx($barsImage2);
         self::drawCopy($img, $barsBandsImage2, $x, 0);
         $x = imagesx($barsBandsImage1) + imagesx($barsImage1) + (imagesx($barsAxesImage) - imagesx($iconImage) >> 1);
         self::drawCopy($img, $iconImage, $x, $y);
     }
     imagesavealpha($img, true);
     $viewContext->layoutName = null;
     HttpHeadersHelper::setCurrentHeader('Cache-Control', 'no-cache, must-revalidate');
     HttpHeadersHelper::setCurrentHeader('Expires', 'Sat, 26 Jul 1997 05:00:00 GMT');
     imagepng($img);
 }
 public static function work(&$controllerContext, &$viewContext)
 {
     $sender = $_GET['sender'];
     $filterParam = isset($_GET['filter-param']) ? $_GET['filter-param'] : null;
     if (isset($_GET['media']) and in_array($_GET['media'], Media::getConstList())) {
         $viewContext->media = $_GET['media'];
     }
     $viewContext->viewName = 'user-entries-' . $sender;
     $viewContext->layoutName = 'layout-ajax';
     $viewContext->filterParam = $filterParam;
     $list = $viewContext->user->getMixedUserMedia($viewContext->media);
     $computeMeanScore = null;
     switch ($sender) {
         case 'ratings':
             $filter = UserMediaFilter::combine(UserMediaFilter::nonPlanned(), UserMediaFilter::score($filterParam));
             break;
         case 'length':
             $filter = UserMediaFilter::combine(UserMediaFilter::nonPlanned(), UserMediaFilter::nonMovie(), UserMediaFilter::lengthGroup($filterParam));
             $computeMeanScore = true;
             break;
         case 'type':
             $filter = UserMediaFilter::combine(UserMediaFilter::nonPlanned(), UserMediaFilter::type($filterParam));
             $computeMeanScore = true;
             break;
         case 'year':
             $filter = UserMediaFilter::combine(UserMediaFilter::nonPlanned(), UserMediaFilter::publishedYear($filterParam));
             $computeMeanScore = true;
             break;
         case 'decade':
             $filter = UserMediaFilter::combine(UserMediaFilter::nonPlanned(), UserMediaFilter::publishedDecade($filterParam));
             $computeMeanScore = true;
             break;
         case 'creator':
             $filter = UserMediaFilter::combine(UserMediaFilter::nonPlanned(), UserMediaFilter::creator($filterParam, $list));
             switch ($viewContext->media) {
                 case Media::Anime:
                     $table = 'animeproducer';
                     break;
                 case Media::Manga:
                     $table = 'mangaauthor';
                     break;
                 default:
                     throw new BadMediaException();
             }
             $computeMeanScore = true;
             break;
         case 'genre':
             $filter = UserMediaFilter::combine(UserMediaFilter::nonPlanned(), UserMediaFilter::genre($filterParam, $list));
             $computeMeanScore = true;
             break;
         case 'franchises':
             $filter = UserMediaFilter::nonPlanned();
             break;
         case 'mismatches':
             $filter = null;
             break;
         case 'watched':
             $filterParam = explode(":", $filterParam);
             $filterParam[2] = boolval($filterParam[2]);
             if ($filterParam[2]) {
                 $yearOrDecade = UserMediaFilter::publishedDecade($filterParam[1]);
             } else {
                 $yearOrDecade = UserMediaFilter::publishedYear($filterParam[1]);
             }
             if ($filterParam[0] == 1) {
                 $filter = UserMediaFilter::combine(UserMediaFilter::nonPlanned(), UserMediaFilter::nonDropped(), UserMediaFilter::notOnHold(), $yearOrDecade, UserMediaFilter::type($filterParam[0]));
             } else {
                 if ($filterParam[0] == 2) {
                     $filter = UserMediaFilter::combine(UserMediaFilter::nonPlanned(), UserMediaFilter::nonDropped(), UserMediaFilter::notOnHold(), $yearOrDecade, UserMediaFilter::notType(1));
                 } else {
                     if ($filterParam[0] == 3) {
                         $filter = UserMediaFilter::combine(UserMediaFilter::nonPlanned(), UserMediaFilter::notCompleting(), UserMediaFilter::notFinished(), $yearOrDecade);
                     }
                 }
             }
             $computeMeanScore = true;
             $viewContext->filterParam = $filterParam;
             break;
         default:
             throw new Exception('Unknown sender (' . $sender . ')');
     }
     $list = UserMediaFilter::doFilter($list, $filter);
     $isPrivate = $viewContext->user->isUserMediaPrivate($viewContext->media);
     if (!$isPrivate) {
         if ($computeMeanScore) {
             $dist = RatingDistribution::fromEntries($list);
             $viewContext->meanScore = $dist->getMeanScore();
         }
         if ($sender == 'franchises') {
             $franchises = Model_MixedUserMedia::getFranchises($list);
             foreach ($franchises as &$franchise) {
                 $dist = RatingDistribution::fromEntries($franchise->ownEntries);
                 $franchise->meanScore = $dist->getMeanScore();
             }
             unset($franchise);
             DataSorter::sort($franchises, DataSorter::MeanScore);
             $viewContext->franchises = array_filter($franchises, function ($franchise) {
                 return count($franchise->ownEntries) > 1;
             });
         } elseif ($sender == 'mismatches') {
             $entries = $viewContext->user->getMismatchedUserMedia($list);
             DataSorter::sort($entries, DataSorter::Title);
             $viewContext->entries = $entries;
         } else {
             DataSorter::sort($list, DataSorter::Title);
             $viewContext->entries = $list;
         }
     }
     $viewContext->isPrivate = $isPrivate;
 }
示例#8
0
<?php

require_once __DIR__ . '/../src/core.php';
CronRunner::run(__FILE__, function ($logger) {
    $userCount = Model_User::getCount();
    $userCountActive = Model_User::getCountActive();
    $mediaCount = [];
    $distArr = [];
    foreach (Media::getConstList() as $media) {
        $distArr[$media] = [];
        $mediaCount[$media] = Model_Media::getCount($media);
    }
    foreach (Media::getConstList() as $media) {
        $localDist = Model_MixedUserMedia::getRatingDistribution($media);
        foreach ($localDist->getGroupsKeys() as $key) {
            if (!isset($distArr[$media][$key])) {
                $distArr[$media][$key] = 0;
            }
            $distArr[$media][$key] += $localDist->getGroupSize($key);
        }
    }
    $globalsCache = ['user-count' => $userCount, 'user-count-active' => $userCountActive, 'media-count' => $mediaCount, 'rating-dist' => $distArr];
    TextHelper::putJson(Config::$globalsCachePath, $globalsCache);
});