diff options
| author | horus | 2020-03-05 16:02:10 +0100 |
|---|---|---|
| committer | horus | 2020-03-05 16:02:10 +0100 |
| commit | 5dda561d73c9a5698386d643d56a142aa4bbdeec (patch) | |
| tree | 55afe2db98d0fa15fc845cc3da3afe6b517bbd3d | |
| parent | 420e44e0fe4623a439e26dfd0526ee5ef606a170 (diff) | |
| download | senpai-5dda561d73c9a5698386d643d56a142aa4bbdeec.tar.gz | |
Committing intermediate state.
25 files changed, 1097 insertions, 109 deletions
diff --git a/app/Airing.php b/app/Airing.php new file mode 100644 index 0000000..9e14571 --- /dev/null +++ b/app/Airing.php @@ -0,0 +1,16 @@ +<?php + +namespace App; + +use Illuminate\Database\Eloquent\Model; + +class Airing extends Model +{ + protected $table = 'airing'; + protected $fillable = [ + 'mal_id', + 'episode', + 'aired_at', + 'duration' + ]; +} diff --git a/app/Anime.php b/app/Anime.php index ac5c650..7971430 100644 --- a/app/Anime.php +++ b/app/Anime.php @@ -10,30 +10,28 @@ use Jikan\MyAnimeList\MalClient; class Anime extends Model { - /* - public $id; - public $mal_id; - - public $url; - public $image_url; - - public $title_eng; - public $title_rom; - public $title_nat; - public $title_pref; - - public $type; - */ - - private $animeInfo; - /** * Eloquent ORM */ + #protected $primarykey = 'mal_id'; protected $table = 'anime'; - protected $fillable = ['mal_id','url','image_url','title_eng','title_rom','title_nat','title_pref','type',]; + protected $fillable = [ + 'mal_id', + 'url', + 'image_url', + 'title_eng', + 'title_rom', + 'title_nat', + 'title_pref', + 'anime_type', + 'broadcasted', + 'episodes' + ]; + + public function __construct() { + } - public function __construct( $id, $parse_info = true ) { + public function fill( $id, $parse_info = true ) { $this->mal_id = $id; if ( $parse_info ) { @@ -51,18 +49,74 @@ class Anime extends Model { $this->title_nat = $this->animeInfo->getTitleJapanese(); $this->title_pref = $this->animeInfo->getTitle(); - $this->type = $this->animeInfo->getType(); + $this->anime_type = $this->animeInfo->getType(); + $this->broadcasted = $this->animeInfo->getBroadcast(); + + $this->episodes = $this->animeInfo->getEpisodes(); } } - /* public function getStats() { - return $this->hasMany('App\AnimeStats'); + return $this->hasMany('App\AnimeStats', 'mal_id', 'mal_id'); } -*/ + + public function getAiring() { + return $this->hasMany('App\Airing', 'mal_id', 'mal_id'); + } protected function getInfo() { return $this->animeInfo; } + public function user() { + return $this->belongsToMany('App\MALUser', 'is_watching', 'mal_id', 'user_id') + ->as('anime') + ->withPivot('episodes_watched', 'score_user') + ->withTimestamps(); + } + + public function getDataFromAnilist() { + $query = ' + query($id: Int!) { + Media(idMal: $id, type: ANIME) { + title { + romaji + english + native + userPreferred + } + nextAiringEpisode { + airingAt + timeUntilAiring + episode + } + episodes + duration + } + } + '; + + // Define our query variables and values that will be used in the query request + $variables = [ + "id" => $this->mal_id, + ]; + + // Make the HTTP Api request + try { + $http = new \GuzzleHttp\Client; + $response = $http->post('https://graphql.anilist.co', [ + 'json' => [ + 'query' => $query, + 'variables' => $variables, + ] + ]); + + $data = json_decode( $response->getBody() )->data->Media; + } catch (\Exception $e) { + echo "Problem with Guzzle connecting to Anilist on anime: (" . $this->mal_id . ")\n"; + return ""; + } + return $data; + } + } diff --git a/app/AnimeStats.php b/app/AnimeStats.php index 3bc6d25..827032c 100644 --- a/app/AnimeStats.php +++ b/app/AnimeStats.php @@ -5,54 +5,83 @@ use Illuminate\Database\Eloquent\Model; use Jikan\MyAnimeList\MalClient; -#class AnimeStats extends Anime { class AnimeStats extends Model { /* - public $mal_id; - - public $season_year; - public $season_name; - - public $score; - public $scored_by; - public $rank; - public $popularity; - public $members; - public $favorites; - - public $watching; - public $completed; - public $onhold; - public $dropped; - public $plan_to_watch; - - public $score_1; - public $score_2; - public $score_3; - public $score_4; - public $score_5; - public $score_6; - public $score_7; - public $score_8; - public $score_9; - public $score_10; + private $mal_id; + + private $season_year; + private $season_name; + + private $score; + private $scored_by; + private $rank; + private $popularity; + private $members; + private $favorites; + + private $watching; + private $completed; + private $onhold; + private $dropped; + private $plan_to_watch; + + private $score_1; + private $score_2; + private $score_3; + private $score_4; + private $score_5; + private $score_6; + private $score_7; + private $score_8; + private $score_9; + private $score_10; */ /** * Eloquent ORM */ protected $table = 'stats'; - protected $fillable = ['mal_id','season_year','season_name','score','scored_by','rank','popularity','members','favorites', 'watching','completed','onhold','dropped','plan_to_watch', 'score_1','score_2','score_3','score_4','score_5','score_6','score_7','score_8','score_9','score_10']; + protected $fillable = [ + 'mal_id', + + 'season_year', + 'season_name', + + 'score', + 'scored_by', + 'rank', + 'popularity', + 'members', + 'favorites', + + 'watching', + 'completed', + 'onhold', + 'dropped', + 'plan_to_watch', + + 'score_1', + 'score_2', + 'score_3', + 'score_4', + 'score_5', + 'score_6', + 'score_7', + 'score_8', + 'score_9', + 'score_10' + ]; + + public function __construct() { + } - public function __construct( $id, $season_year = 0, $season_name = "" ) { + public function fill( $id, $season_year = 0, $season_name = "" ) { $this->mal_id = $id; - #parent::__construct($this->mal_id); - $jikan = new Malclient; -# if ( 0 == $season_year || "" == $season_name ) { + if ( 0 == $season_year || "" == $season_name ) { $season = $jikan->getSeasonal( (new \Jikan\Request\Seasonal\SeasonalRequest( )) @@ -60,12 +89,10 @@ class AnimeStats extends Model { $this->season_year = $season->seasonYear; $this->season_name= $season->seasonName; - /* } else { $this->season_year = $season_year; $this->season_name= $season_name; } -*/ #$animeInfo = $this->getInfo(); $animeInfo = $jikan->getAnime( @@ -90,16 +117,60 @@ class AnimeStats extends Model { $scores = $animeStats->getScores(); - $this->score_1 = $scores[1]->getVotes(); - $this->score_2 = $scores[2]->getVotes(); - $this->score_3 = $scores[3]->getVotes(); - $this->score_4 = $scores[4]->getVotes(); - $this->score_5 = $scores[5]->getVotes(); - $this->score_6 = $scores[6]->getVotes(); - $this->score_7 = $scores[7]->getVotes(); - $this->score_8 = $scores[8]->getVotes(); - $this->score_9 = $scores[9]->getVotes(); - $this->score_10 = $scores[10]->getVotes(); + if ( isset($scores[1] )) { + $this->score_1 = $scores[1]->getVotes(); + } else { + $this->score_1 = 0; + } + if ( isset($scores[2]) ) { + $this->score_2 = $scores[2]->getVotes(); + } else { + $this->score_2 = 0; + } + if ( isset($scores[3]) ) { + $this->score_3 = $scores[3]->getVotes(); + } else { + $this->score_3 = 0; + } + if ( isset($scores[4]) ) { + $this->score_4 = $scores[4]->getVotes(); + } else { + $this->score_4 = 0; + } + if ( isset($scores[5]) ) { + $this->score_5 = $scores[5]->getVotes(); + } else { + $this->score_5 = 0; + } + if ( isset($scores[6]) ) { + $this->score_6 = $scores[6]->getVotes(); + } else { + $this->score_6 = 0; + } + if ( isset($scores[7]) ) { + $this->score_7 = $scores[7]->getVotes(); + } else { + $this->score_7 = 0; + } + if ( isset($scores[8]) ) { + $this->score_8 = $scores[8]->getVotes(); + } else { + $this->score_8 = 0; + } + if ( isset($scores[9]) ) { + $this->score_9 = $scores[9]->getVotes(); + } else { + $this->score_9 = 0; + } + if ( isset($scores[10]) ) { + $this->score_10 = $scores[10]->getVotes(); + } else { + $this->score_10 = 0; + } + } + + public function anime() { + return $this->belongsTo('App\Anime', 'mal_id', 'mal_id'); } } diff --git a/app/Calendar.php b/app/Calendar.php new file mode 100644 index 0000000..a42e190 --- /dev/null +++ b/app/Calendar.php @@ -0,0 +1,33 @@ +<?php + +namespace App; + +use Illuminate\Database\Eloquent\Model; + +class Calendar extends Model +{ + protected $table = 'calendar'; + + protected $fillable = [ + 'mal_id', + 'user_id', + 'airing_at', + 'duration', + 'episode', + 'episode_watched', + 'episode_complete', + 'score', + 'score_user', + ]; + + public function __construct() { + } + + public function user() { + return $this->belongsTo('App\MALUser', 'user_id', 'id'); + } + + public function anime() { + return $this->belongsTo('App\Anime', 'mal_id', 'mal_id'); + } +} diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index a8c5158..fa58874 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -5,6 +5,9 @@ namespace App\Console; use Illuminate\Console\Scheduling\Schedule; use Illuminate\Foundation\Console\Kernel as ConsoleKernel; +use App\Libraries\AnimeSeason; +use App\Libraries\Helper; + class Kernel extends ConsoleKernel { /** @@ -26,6 +29,13 @@ class Kernel extends ConsoleKernel { // $schedule->command('inspire') // ->hourly(); + $schedule->call( function(){ + #$season = new AnimeSeason(); + #$season->save(); + #$helper = new Helper(); + #$helper->setAiringForAll(); + #$helper->setCalendar( 'll-' ); + }); } /** diff --git a/app/Http/Controllers/IndexController.php b/app/Http/Controllers/IndexController.php index e254c50..11e587f 100644 --- a/app/Http/Controllers/IndexController.php +++ b/app/Http/Controllers/IndexController.php @@ -6,7 +6,9 @@ use Illuminate\Http\Request; use App\Libraries\AnimeSchedule; use App\Libraries\AnimeSeason; +use App\Anime; use App\AnimeStats; +use App\MALUser; class IndexController extends Controller { /** @@ -36,11 +38,61 @@ class IndexController extends Controller { } public function test($param = null) { - $season = new AnimeSeason(); + echo "<pre>"; + #$season = new AnimeSeason(); #$stats = new AnimeScore( 21 ); #var_dump($stats); #echo "<pre>"; #var_dump($season); + # + #$test = new AnimeSchedule("", false); + + #var_dump( Anime::where('mal_id', 38408)->with('user')->get() ); + #var_dump( MALUser::where('username', 'll-')->with('anime')->toSql() ); + #var_dump( MALUser::find(10)->anime()->get() ); + $test = MALUser::where('username', 'll-')->get()->first(); + #$test = MALUser::where('username', 'll-')->with('IsWatching')->first(); + #var_dump($test); + #var_dump( MALUser::where('username', 'll-')->with('IsWatching')->firstOrFail() ); + #var_dump( $test ); + #var_dump( MALUser::with('IsWatching')->firstOrFail() ); + echo "<pre>"; + foreach( $test->IsWatching as $anime ) { + echo $anime->title_pref . "\n"; + } + #var_dump($test->IsWatching); + + } + + public function saveWatchingAnime() { + $test = MALUser::where('username', 'll-')->get()->first(); + + $is_watching= $test->getIsWatching(); + foreach( $is_watching as $anime_details ) { + $anime = Anime::where('mal_id', $anime_details["mal_id"])->get()->first(); + #$anime->fill( $is_watching["mal_id"] ); + $test->IsWatching()->save( $anime, $anime_details ); + #var_dump($anime); + #exit; + } + #echo $test->test(); + echo "OK"; + } + + public function createUser( $username ) { + $user = MALUser::where('username', $username)->get()->first(); + var_dump( $user ); + + if ( is_null($user) ) { + $user = new MALUser(); + $user->set( $username ); + + var_dump( $user ); + + $user->save(); + } + + echo $user->get(); } } diff --git a/app/Http/Controllers/TestController.php b/app/Http/Controllers/TestController.php new file mode 100644 index 0000000..0ac9ba2 --- /dev/null +++ b/app/Http/Controllers/TestController.php @@ -0,0 +1,113 @@ +<?php + +namespace App\Http\Controllers; +use Illuminate\Support\Facades\Cache; +use Illuminate\Http\Request; + +use Carbon\Carbon; + +use App\Libraries\AnimeSchedule; +use App\Libraries\AnimeSeason; +use App\Libraries\Helper; +use App\Anime; +use App\AnimeStats; +use App\MALUser; +use App\Calendar; +use App\Airing; + +class TestController extends Controller { + /** + * Shows the index page. + * + * @return Response + */ + public function showPage() { + + return view('index', [ ]); + } + + public function getCalendar( $username ) { + $helper = new Helper(); + echo $helper->getCalendar( $username ); + } + + public function setCalendar( $username ) { + $helper = new Helper(); + $helper->setCalendar( $username ); + } + + #public function iCal(Request $request) { + public function iCal($username) { + + if ( ! Cache::has('schedule_' . $username)) { + $userSchedule = new AnimeSchedule( $username ); + $schedule = $userSchedule->getCalendar(); + Cache::put('schedule_' . $username, $schedule, 360); + } else { + $schedule = Cache::get('schedule_' . $username); + } + + header('Content-Type: text/calendar; charset=utf-8'); + #var_dump($schedule); + echo $schedule; + } + + public function test($param = null) { + echo "<pre>"; + #$season = new AnimeSeason(); + #$stats = new AnimeScore( 21 ); + + #var_dump($stats); + #echo "<pre>"; + #var_dump($season); + # + #$test = new AnimeSchedule("", false); + + #var_dump( Anime::where('mal_id', 38408)->with('user')->get() ); + #var_dump( MALUser::where('username', 'll-')->with('anime')->toSql() ); + #var_dump( MALUser::find(10)->anime()->get() ); + $test = MALUser::where('username', 'll-')->get()->first(); + #$test = MALUser::where('username', 'll-')->with('IsWatching')->first(); + #var_dump($test); + #var_dump( MALUser::where('username', 'll-')->with('IsWatching')->firstOrFail() ); + #var_dump( $test ); + #var_dump( MALUser::with('IsWatching')->firstOrFail() ); + echo "<pre>"; + foreach( $test->IsWatching as $anime ) { + echo $anime->title_pref . "\n"; + } + #var_dump($test->IsWatching); + + } + + public function saveWatchingAnime() { + $test = MALUser::where('username', 'll-')->get()->first(); + + $is_watching= $test->getIsWatching(); + foreach( $is_watching as $anime_details ) { + $anime = Anime::where('mal_id', $anime_details["mal_id"])->get()->first(); + #$anime->fill( $is_watching["mal_id"] ); + $test->IsWatching()->save( $anime, $anime_details ); + #var_dump($anime); + #exit; + } + #echo $test->test(); + echo "OK"; + } + + public function createUser( $username ) { + $user = MALUser::where('username', $username)->get()->first(); + var_dump( $user ); + + if ( is_null($user) ) { + $user = new MALUser(); + $user->set( $username ); + + var_dump( $user ); + + $user->save(); + } + + echo $user->get(); + } +} diff --git a/app/Libraries/AnimeSchedule.php b/app/Libraries/AnimeSchedule.php index 4c16f11..3b22494 100644 --- a/app/Libraries/AnimeSchedule.php +++ b/app/Libraries/AnimeSchedule.php @@ -16,19 +16,22 @@ class AnimeSchedule { private $animeSchedule = array(); private $jikan; - private $userProfile; private $animeList; private $animeInfo; private const STATUS_WATCHING = 1; - public function __construct( $username ) { + public function __construct( $username = "", $autoparse = true ) { + + if ( $autoparse && "" != $username ) { + $this->parse( $username ); + } + } + + public function parse( $username ) { $this->jikan = new MalClient; - $this->userProfile = $this->jikan->getUserProfile( - new \Jikan\Request\User\UserProfileRequest( $username ) - ); $this->animeList = $this->jikan->getUserAnimelist( - new \Jikan\Request\User\UserAnimeListRequest( $this->userProfile->getUsername(), 1 ) + new \Jikan\Request\User\UserAnimeListRequest( $username, 1, 1 ) ); foreach ( $this->animeList as $entry ) { @@ -50,6 +53,8 @@ class AnimeSchedule { $anime = new AnimeWatching( $entry->getMalID(), false ); + $anime->url = $entry->getUrl(); + $anime->title_eng = $data->title->english; $anime->title_rom = $data->title->romaji; $anime->title_nat = $data->title->native; @@ -89,7 +94,7 @@ class AnimeSchedule { ->setNoTime(false) ->setSummary( $anime->title_pref . " (" . $anime->episode . "/" . $anime->episodes_complete . ")" ) ->setUrl( env("APP_URL") ) - ->setDescription( "(Episode " . $anime->episode . "/" . $anime->episodes_complete . ") You have watched " . $anime->episodes_watched . " episodes of " . $anime->title_pref . " and scored it with " . $anime->score_user . ". (Public score: ". $anime->score .")" ); + ->setDescription( "(Episode " . $anime->episode . "/" . $anime->episodes_complete . ") You have watched " . $anime->episodes_watched . " episodes of " . $anime->title_pref . " and scored it with " . $anime->score_user . ". (Public score: ". $anime->score .")\n\n" . $anime->url ); $vCalendar->addComponent($vEvent); } @@ -135,4 +140,41 @@ class AnimeSchedule { $data = json_decode( $response->getBody() )->data->Media; return $data; } + + protected function getIsWatching( $username ) { + $animeList = $this->getUserAnimeList( $username ); + + $anime = array(); + + foreach ( $animeList as $entry ) { + // currently watching + if ( $this::STATUS_WATCHING != $entry->getAiringStatus() ){ + continue; + } + + $anime[] = array( + "mal_id" => $entry->getMalID(), + "episodes_watched" => $entry->getWatchedEpisodes(), + "score_user" => $entry->getScore(), + ); + } + + return $anime; + } + + + protected function getUserAnimeList( $username ) { + $jikan = new MalClient; + + $animeList = $jikan->getUserAnimelist( + new \Jikan\Request\User\UserAnimeListRequest( $username, 1, 1 ) + ); + + return $animeList; + } + + public function test() { + echo "<pre>"; + var_dump( $this->getIsWatching('ll-') ); + } } diff --git a/app/Libraries/AnimeSeason.php b/app/Libraries/AnimeSeason.php index 1bc3655..f0296af 100644 --- a/app/Libraries/AnimeSeason.php +++ b/app/Libraries/AnimeSeason.php @@ -21,7 +21,10 @@ class AnimeSeason { public $anime; public function __construct() { - #Anime::where('mal_id', 2 ); + } + + public function save() { + #Anime::where('mal_id', 2 ); $jikan = new MalClient; $season = $jikan->getSeasonal( @@ -34,10 +37,23 @@ class AnimeSeason { $count = 0; foreach($season->anime as $entry) { + /** + * Debug + if ( DB::table('stats')->where('mal_id', $entry->getMalID())->exists() ) { + continue; + } + #*/ + + /** + * Sleep to avoid 403 by MAL. + */ + sleep(10); + $count++; #Anime::where('mal_id', $entry->getMalID() ); - $anime = new Anime( $entry->getMalID() ); + $anime = new Anime(); + $anime->fill( $entry->getMalID() ); if( ! DB::table('anime')->where('mal_id', $entry->getMalID() )->exists() ) { $anime->save(); @@ -51,11 +67,11 @@ class AnimeSeason { /* echo "<pre>"; var_dump($animeStats); - */ if ( $count == 1) { return; } + */ } } diff --git a/app/Libraries/Background.php b/app/Libraries/Background.php new file mode 100644 index 0000000..6c84e97 --- /dev/null +++ b/app/Libraries/Background.php @@ -0,0 +1,94 @@ +<?php +namespace App\Libraries; + +use Carbon\Carbon; + +use App\Libraries\AnimeSchedule; +use App\Libraries\AnimeSeason; +use App\Anime; +use App\AnimeStats; +use App\MALUser; +use App\Calendar; +use App\Airing; + +use Eluceo\iCal\Component\Calendar as iCalendar; +use Eluceo\iCal\Component\Event; + +class Background { + + public function setAiring(Anime $anime) { + $stats = $anime->getStats()->get()->first(); + if ( is_null($stats->score) ) { + return; + } + + $airing = Airing::where('mal_id', $stats->mal_id)->get()->first(); + if ( is_null($airing) ) { + $airing = new Airing(); + } + + /** + * Try to get Data from Anilist. + * On error return early. + */ + try { + $airing_data = $anime->getDataFromAnilist(); + } catch( Exception $e ) { + echo "Getting Data from Anilist failed for anime: " . $anime->title_pref . " (" . $anime->mal_id . ")\n"; + return; + } + if ( "" == $airing_data ) { + echo "Got empty data from Anilist for anime: " . $anime->title_pref . " (" . $anime->mal_id . ")\n"; + return; + } + + /** + * Check if we need to save the airing data or if we already have it in database. + */ + if ( ! is_null( $airing->episode ) ) { + if ( ! is_null( $airing_data->nextAiringEpisode ) && + ( $airing->episode == $airing_data->nextAiringEpisode->episode) ) { + if ( $airing->aired_at == $airing_data->nextAiringEpisode->airingAt ) { + /** + * Double entry. + */ + return; + } + /** + * We need to update because the airing data was postponed. + */ + } + } + + $airing->mal_id = $anime->mal_id; + if ( ! is_null($airing_data->nextAiringEpisode) ) { + $airing->episode = $airing_data->nextAiringEpisode->episode; + } + if ( ! is_null($airing_data->nextAiringEpisode) ) { + $airing->aired_at = Carbon::createFromTimestamp($airing_data->nextAiringEpisode->airingAt); + } + if ( ! is_null($airing_data) ) { + $airing->duration = $airing_data->duration; + } + + if ( is_null($airing_data->duration) ) { + echo "No duration found for anime: " . $anime->title_pref . " (" . $anime->mal_id . "). (Autoset to 20.)\n"; + $airing->duration = 20; + } + + if ( is_null($airing->aired_at) ) { + echo "No airing date found for anime: " . $anime->title_pref . " (" . $anime->mal_id . ")\n"; + return; + } + + $airing->save(); + } + + public function setAiringForAll() { + $anime_all = Anime::get(); + foreach( $anime_all as $anime ) { + $this->setAiring($anime); + sleep(1); + } + } +} diff --git a/app/Libraries/Helper.php b/app/Libraries/Helper.php new file mode 100644 index 0000000..0652570 --- /dev/null +++ b/app/Libraries/Helper.php @@ -0,0 +1,89 @@ +<?php +namespace App\Libraries; + +use Carbon\Carbon; + +use App\Libraries\AnimeSchedule; +use App\Libraries\AnimeSeason; +use App\Anime; +use App\AnimeStats; +use App\MALUser; +use App\Calendar; +use App\Airing; + +use Eluceo\iCal\Component\Calendar as iCalendar; +use Eluceo\iCal\Component\Event; + +class Helper { + public function getCalendar( $username ) { + echo "<pre>"; + $user = MALUser::where('username', $username)->get()->first(); + + $vCalendar = new iCalendar('animes.iamfabulous.de'); + $vCalendar->setName('Anime Schedule'); + + foreach( $user->calendar()->get() as $anime ) { + + if ( is_null($anime->episodes_completes) ) { + $episodes_complete = '?'; + } else { + $episodes_complete = $anime->episodes_completes; + } + + $vEvent = new Event(); + + $vEvent + ->setDtStart(new \DateTime($anime->airing_at)) + ->setDtEnd( new \DateTime(Carbon::create($anime->airing_at)->add($anime->duration, 'minutes')) ) + ->setNoTime(false) + ->setSummary( $anime->title . " (" . $anime->episode . "/" . $episodes_complete . ")" ) + ->setUrl( env("APP_URL") ) + ->setDescription( "(Episode " . $anime->episode . "/" . $episodes_complete . ") You have watched " . $anime->episodes_watched . " episodes of " . $anime->title . " and scored it with " . $anime->score_user . ". (Public score: ". $anime->score .")\n\n" . $anime->url ); + + $vCalendar->addComponent($vEvent); + } + + return $vCalendar->render(); + + } + + public function setCalendar($username) { + #$this->setAiring(); return; + $user = MALUser::where('username', $username)->get()->first(); + echo "<pre>"; + foreach( $user->IsWatching as $anime ) { + $stats = $anime->getStats()->get()->first(); + $airing = $anime->getAiring()->get()->first(); + + /** + * Check for duplicate entry. + */ + $check = Calendar::where('mal_id', $anime->mal_id)->where('user_id', $user->id)->where( + function($q) use ($airing){ + $q->where('episode', $airing->episode)->orWhere('airing_at', $airing->aired_at); + })->get()->first(); + + if ( ! is_null( $check ) ) { + echo "duplicate entry. ".$anime->mal_id." continue\n"; continue; + } + + $calendar = new Calendar(); + $calendar->mal_id = $anime->mal_id; + $calendar->user_id = $anime->Watching->user_id; + $calendar->username = $username; + $calendar->airing_at = $airing->aired_at; + $calendar->duration = $airing->duration; + $calendar->episode = $airing->episode; + $calendar->episodes_watched = $anime->Watching->episodes_watched; + $calendar->episodes_complete = $anime->episodes; + $calendar->score = $stats->score; + $calendar->score_user = $anime->Watching->score_user; + $calendar->title = $anime->title_pref; + $calendar->mal_url = $anime->url; + + $calendar->save(); + } + } + + +} diff --git a/app/MALUser.php b/app/MALUser.php new file mode 100644 index 0000000..6c62e30 --- /dev/null +++ b/app/MALUser.php @@ -0,0 +1,90 @@ +<?php + +namespace App; + +use Illuminate\Database\Eloquent\Model; +use Jikan\MyAnimeList\MalClient; + +class MALUser extends Model +{ + protected $table = 'malusers'; + protected $fillable = 'username'; + + public function __construct() { + } + + public function set( $username ) { + $this->username = $username; + } + + public function get() { + return $this->username; + } + + public function IsWatching() { + return $this->belongsToMany('App\Anime', 'is_watching', 'user_id', 'mal_id', '', 'mal_id') + ->as('Watching') + ->withPivot('episodes_watched', 'score_user') + ->withTimestamps(); + } + + public function calendar() { + return $this->belongsTo('App\Calendar', 'id', 'user_id'); + } + + public function getIsWatching() { + + $jikan = new MalClient; + + $animeList = $jikan->getUserAnimelist( + new \Jikan\Request\User\UserAnimeListRequest( $this->username, 1, 1 ) + ); + + $anime = array(); + + foreach ( $animeList as $entry ) { + // currently watching + if ( 1 != $entry->getAiringStatus() ){ + continue; + } + + $anime[] = array( + "user_id" => $this->id, + "mal_id" => $entry->getMalID(), + "episodes_watched" => $entry->getWatchedEpisodes(), + "score_user" => $entry->getScore(), + ); + } + + return $anime; + } + + public function createCalendar() { + } + + public function getCalendar() { + $vCalendar = new Calendar('animes.iamfabulous.de'); + $vCalendar->setName('Anime Schedule'); + + foreach ( $this->animeSchedule as $anime ) { + $vEvent = new Event(); + + $vEvent + ->setDtStart(new \DateTime($anime->airing_at)) + ->setDtEnd( new \DateTime($anime->airing_at->add($anime->duration, 'minutes')) ) + ->setNoTime(false) + ->setSummary( $anime->title_pref . " (" . $anime->episode . "/" . $anime->episodes_complete . ")" ) + ->setUrl( env("APP_URL") ) + ->setDescription( "(Episode " . $anime->episode . "/" . $anime->episodes_complete . ") You have watched " . $anime->episodes_watched . " episodes of " . $anime->title_pref . " and scored it with " . $anime->score_user . ". (Public score: ". $anime->score .")\n\n" . $anime->url ); + + $vCalendar->addComponent($vEvent); + } + + return $vCalendar->render(); + } + + public function test() { + echo "<pre>"; + var_dump( $this->getIsWatching() ); + } +} diff --git a/config/app.php b/config/app.php index c9960cd..3bf8946 100644 --- a/config/app.php +++ b/config/app.php @@ -67,7 +67,7 @@ return [ | */ - 'timezone' => 'UTC', + 'timezone' => 'Europe/Berlin', /* |-------------------------------------------------------------------------- diff --git a/database/migrations/2020_02_23_235746_create_anime_table.php b/database/migrations/2020_02_23_235746_create_anime_table.php index 985812e..f2df40f 100644 --- a/database/migrations/2020_02_23_235746_create_anime_table.php +++ b/database/migrations/2020_02_23_235746_create_anime_table.php @@ -21,12 +21,13 @@ class CreateAnimeTable extends Migration $table->string('url')->default(''); $table->string('image_url')->default(''); - $table->string('title_eng')->default(''); - $table->string('title_rom')->default(''); - $table->string('title_nat')->default(''); - $table->string('title_pref')->default(''); + $table->string('title_eng')->default('')->nullable(); + $table->string('title_rom')->default('')->nullable(); + $table->string('title_nat')->default('')->nullable(); + $table->string('title_pref')->default('')->nullable(); - $table->string('type')->default(''); + $table->string('anime_type')->default('')->nullable(); + $table->string('broadcasted')->default('')->nullable(); $table->timestamps(); }); diff --git a/database/migrations/2020_02_23_235949_create_stats_table.php b/database/migrations/2020_02_23_235949_create_stats_table.php index 142374c..5516789 100644 --- a/database/migrations/2020_02_23_235949_create_stats_table.php +++ b/database/migrations/2020_02_23_235949_create_stats_table.php @@ -21,29 +21,29 @@ class CreateStatsTable extends Migration $table->string('season_name')->default(''); $table->integer('season_year')->default(0); - $table->float('score')->default(0); - $table->integer('scored_by')->default(0); - $table->integer('rank')->default(0); - $table->integer('popularity')->default(0); - $table->integer('members')->default(0); - $table->integer('favorites')->default(0); - - $table->integer('watching')->default(0); - $table->integer('completed')->default(0); - $table->integer('onhold')->default(0); - $table->integer('dropped')->default(0); - $table->integer('plan_to_watch')->default(0); - - $table->integer('score_1')->default(0); - $table->integer('score_2')->default(0); - $table->integer('score_3')->default(0); - $table->integer('score_4')->default(0); - $table->integer('score_5')->default(0); - $table->integer('score_6')->default(0); - $table->integer('score_7')->default(0); - $table->integer('score_8')->default(0); - $table->integer('score_9')->default(0); - $table->integer('score_10')->default(0); + $table->float('score')->default(0)->nullable(); + $table->integer('scored_by')->default(0)->nullable(); + $table->integer('rank')->default(0)->nullable(); + $table->integer('popularity')->default(0)->nullable(); + $table->integer('members')->default(0)->nullable(); + $table->integer('favorites')->default(0)->nullable(); + + $table->integer('watching')->default(0)->nullable(); + $table->integer('completed')->default(0)->nullable(); + $table->integer('onhold')->default(0)->nullable(); + $table->integer('dropped')->default(0)->nullable(); + $table->integer('plan_to_watch')->default(0)->nullable(); + + $table->integer('score_1')->default(0)->nullable(); + $table->integer('score_2')->default(0)->nullable(); + $table->integer('score_3')->default(0)->nullable(); + $table->integer('score_4')->default(0)->nullable(); + $table->integer('score_5')->default(0)->nullable(); + $table->integer('score_6')->default(0)->nullable(); + $table->integer('score_7')->default(0)->nullable(); + $table->integer('score_8')->default(0)->nullable(); + $table->integer('score_9')->default(0)->nullable(); + $table->integer('score_10')->default(0)->nullable(); $table->timestamps(); }); diff --git a/database/migrations/2020_02_27_185936_create_airing_table.php b/database/migrations/2020_02_27_185936_create_airing_table.php new file mode 100644 index 0000000..efc0a1d --- /dev/null +++ b/database/migrations/2020_02_27_185936_create_airing_table.php @@ -0,0 +1,35 @@ +<?php + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +class CreateAiringTable extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::create('airing', function (Blueprint $table) { + $table->bigIncrements('id'); + $table->timestamps(); + + $table->unsignedBigInteger('mal_id')->default(0); + $table->integer('episode')->default(0); + $table->dateTime('aired_at'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('airing'); + } +} diff --git a/database/migrations/2020_02_27_190422_add_fk_airing.php b/database/migrations/2020_02_27_190422_add_fk_airing.php new file mode 100644 index 0000000..24de5cb --- /dev/null +++ b/database/migrations/2020_02_27_190422_add_fk_airing.php @@ -0,0 +1,32 @@ +<?php + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +class AddFkAiring extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::table('airing', function (Blueprint $table) { + $table->foreign('mal_id')->references('mal_id')->on('anime'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('airing', function (Blueprint $table) { + // + }); + } +} diff --git a/database/migrations/2020_03_01_151652_create_malusers.php b/database/migrations/2020_03_01_151652_create_malusers.php new file mode 100644 index 0000000..cd55278 --- /dev/null +++ b/database/migrations/2020_03_01_151652_create_malusers.php @@ -0,0 +1,34 @@ +<?php + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +class CreateMalusers extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::create('malusers', function (Blueprint $table) { + $table->bigIncrements('id'); + + $table->string('username')->unique()->default(''); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('malusers'); + } +} diff --git a/database/migrations/2020_03_01_152954_create_is_watching.php b/database/migrations/2020_03_01_152954_create_is_watching.php new file mode 100644 index 0000000..30c5bd6 --- /dev/null +++ b/database/migrations/2020_03_01_152954_create_is_watching.php @@ -0,0 +1,42 @@ +<?php + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +class CreateIsWatching extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::create('is_watching', function (Blueprint $table) { + $table->bigIncrements('id'); + + $table->unsignedBigInteger('mal_id')->default(0); + $table->unsignedBigInteger('user_id')->default(0); + + $table->integer('episodes_watched')->nullable()->default(0); + $table->float('score_user')->nullable()->default(0); + + $table->unique( ['mal_id', 'user_id'] ); + $table->foreign('mal_id')->references('mal_id')->on('anime'); + $table->foreign('user_id')->references('id')->on('malusers'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('is_watching'); + } +} diff --git a/database/migrations/2020_03_05_004655_add_duration_to_airing.php b/database/migrations/2020_03_05_004655_add_duration_to_airing.php new file mode 100644 index 0000000..4b3c992 --- /dev/null +++ b/database/migrations/2020_03_05_004655_add_duration_to_airing.php @@ -0,0 +1,33 @@ +<?php + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +class AddDurationToAiring extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::table('airing', function (Blueprint $table) { + $table->integer('duration')->default(0); + $table->unique(['mal_id', 'episode']); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('airing', function (Blueprint $table) { + // + }); + } +} diff --git a/database/migrations/2020_03_05_011440_add_episodes_to_anime.php b/database/migrations/2020_03_05_011440_add_episodes_to_anime.php new file mode 100644 index 0000000..948a84e --- /dev/null +++ b/database/migrations/2020_03_05_011440_add_episodes_to_anime.php @@ -0,0 +1,32 @@ +<?php + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +class AddEpisodesToAnime extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::table('anime', function (Blueprint $table) { + $table->integer('episodes')->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('anime', function (Blueprint $table) { + // + }); + } +} diff --git a/database/migrations/2020_03_05_162010_create_calendar.php b/database/migrations/2020_03_05_162010_create_calendar.php new file mode 100644 index 0000000..3a6cb8f --- /dev/null +++ b/database/migrations/2020_03_05_162010_create_calendar.php @@ -0,0 +1,52 @@ +<?php + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +class CreateCalendar extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::create('calendar', function (Blueprint $table) { + $table->bigIncrements('id'); + + $table->unsignedBigInteger('mal_id')->default(0); + $table->unsignedBigInteger('user_id')->default(0); + + $table->string('username')->default(''); + $table->timestamp('airing_at'); + $table->integer('duration')->default('20'); + $table->integer('episode')->default(0); + $table->integer('episodes_watched')->default(0)->nullable(); + $table->integer('episodes_complete')->default(0)->nullable(); + $table->float('score')->default(0)->nullable(); + $table->integer('score_user')->default(0)->nullable(); + $table->string('mal_url')->default(''); + $table->string('title')->default(''); + + $table->foreign('mal_id')->references('mal_id')->on('anime'); + $table->foreign('user_id')->references('id')->on('malusers'); + + $table->unique(['mal_id', 'user_id', 'airing_at']); + $table->unique(['mal_id', 'user_id', 'episode']); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('calendar'); + } +} diff --git a/query.sql b/query.sql new file mode 100644 index 0000000..f1f28e9 --- /dev/null +++ b/query.sql @@ -0,0 +1,35 @@ +-- query every anime with recent score +select + title_pref, score +from anime +join stats on stats.id = + ( + select + id + from stats + where + anime.mal_id = stats.mal_id + order by created_at desc limit 1 + ) +order by title_pref, score desc; + +-- query historic stats for one anime +select + title_pref, + anime_type, + score, + popularity, + members, + (watching+completed+onhold+dropped) as members_watching, + plan_to_watch, + favorites, + season_name, + season_year, + stats.created_at +from anime +join stats on + anime.mal_id = stats.mal_id +where + anime.mal_id = 38883 +order by stats.created_at; + diff --git a/routes/web.php b/routes/web.php index ebf4494..7c5a948 100644 --- a/routes/web.php +++ b/routes/web.php @@ -14,3 +14,7 @@ Route::get('/', 'IndexController@showPage'); Route::get('/ical/{username}', 'IndexController@ical'); Route::get('/test/{param?}', 'IndexController@test'); +Route::get('/create/user/{param}', 'IndexController@createUser'); +Route::get('/save', 'IndexController@saveWatchingAnime'); +Route::get('/test/getcal/{username}', 'TestController@getCalendar'); +Route::get('/test/setcal/{username}', 'TestController@setCalendar'); diff --git a/todo.txt b/todo.txt new file mode 100644 index 0000000..b5f6f48 --- /dev/null +++ b/todo.txt @@ -0,0 +1,8 @@ +Background jobs: + +1. Alle Anime der Season downloaden und in Datenbank einpflegen +2. Für jeden Anime die Statistiken downloadnen +3. Für alle aktuellen Anime den nächsten Airing Zeitpunkt einpflegen +4. Für jeden User einen Kalender generieren +5. Die Top 1000 der populärsten Anime in die Datenbank übertragen +6. Dasselbe für die Top 1000 der besten Anime. |
