diff --git a/app/Http/Controllers/TextureController.php b/app/Http/Controllers/TextureController.php index 9b995970..98a6da5c 100644 --- a/app/Http/Controllers/TextureController.php +++ b/app/Http/Controllers/TextureController.php @@ -2,6 +2,7 @@ namespace App\Http\Controllers; +use Cache; use Event; use Option; use Storage; @@ -202,9 +203,38 @@ class TextureController extends Controller : abort(404, trans('skinlib.non-existent')); } - protected function getPlayerInstance($player_name) + public function avatarByPlayer($size, $name) { - $player = Player::where('name', $player_name)->first(); + $player = Player::where('name', $name)->first(); + + if (! $player) { + return abort(404); + } + + $hash = $player->getTexture('skin'); + if (Storage::disk('textures')->has($hash)) { + $key = "avatar-{$hash}-{$size}"; + $content = Cache::rememberForever($key, function () use ($hash, $size) { + $png = Minecraft::generateAvatarFromSkin( + Storage::disk('textures')->read($hash), + $size + ); + ob_start(); + imagepng($png); + $image = ob_get_contents(); + ob_end_clean(); + imagedestroy($png); + return $image; + }); + return response($content)->withHeaders(['content-type' => 'image/png']); + } + + return abort(404); + } + + protected function getPlayerInstance($name) + { + $player = Player::where('name', $name)->first(); if ($player->isBanned()) { abort(403, trans('general.player-banned')); diff --git a/routes/static.php b/routes/static.php index 099e8033..7a374546 100644 --- a/routes/static.php +++ b/routes/static.php @@ -26,6 +26,7 @@ Route::group(['middleware' => 'player'], function () { Route::get('/textures/{hash}', 'TextureController@texture'); Route::get('/{api}/textures/{hash}', 'TextureController@textureWithApi')->where('api', 'usm|csl'); +Route::get('/avatar/player/{size}/{name}.png', 'TextureController@avatarByPlayer'); Route::get('/avatar/{base64_email}.png', 'TextureController@avatar'); Route::get('/avatar/{size}/{base64_email}.png', 'TextureController@avatarWithSize'); Route::get('/avatar/{tid}', 'TextureController@avatarByTid'); diff --git a/tests/TextureControllerTest.php b/tests/TextureControllerTest.php index e5d25c99..1fca1502 100644 --- a/tests/TextureControllerTest.php +++ b/tests/TextureControllerTest.php @@ -2,17 +2,21 @@ namespace Tests; +use Cache; use Mockery; use Exception; use App\Models\User; use App\Models\Player; use App\Models\Texture; +use Illuminate\Http\UploadedFile; +use Tests\Concerns\InteractsWithCache; use Illuminate\Support\Facades\Storage; use Illuminate\Foundation\Testing\DatabaseTransactions; class TextureControllerTest extends TestCase { use DatabaseTransactions; + use InteractsWithCache; public function testJson() { @@ -284,4 +288,31 @@ class TextureControllerTest extends TestCase option(['allow_downloading_texture' => false]); $this->get("/raw/{$steve->tid}.png")->assertNotFound(); } + + public function testAvatarByPlayer() + { + Storage::fake('textures'); + + // No such player. + $this->get('/avatar/player/1/abc.png')->assertNotFound(); + + // No such texture. + $player = factory(Player::class)->create(); + $this->get("/avatar/player/1/{$player->name}.png")->assertNotFound(); + + $texture = factory(Texture::class)->create(); + $player->tid_skin = $texture->tid; + $player->save(); + $this->get("/avatar/player/1/{$player->name}.png")->assertNotFound(); + + // Success + Storage::disk('textures')->putFileAs( + '.', + UploadedFile::fake()->image('avatar.png', 64, 64), + $texture->hash, + ); + $this->get("/avatar/player/20/{$player->name}.png") + ->assertSuccessful(); + Storage::disk('textures')->delete($texture->hash); + } }