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; }
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; }
<?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); });