feat/factory_creation #1
1
.gitignore
vendored
1
.gitignore
vendored
@ -20,6 +20,7 @@ public_html/hot
|
|||||||
db/data/
|
db/data/
|
||||||
db/dump/
|
db/dump/
|
||||||
static/dist/
|
static/dist/
|
||||||
|
static/*
|
||||||
|
|
||||||
|
|
||||||
storage/*.key
|
storage/*.key
|
||||||
|
3
Dockerfile
Normal file
3
Dockerfile
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
FROM shinsenter/laravel:latest
|
||||||
|
|
||||||
|
RUN apt update && apt install -y jpegoptim optipng pngquant gifsicle webp libavif-bin
|
@ -3,7 +3,10 @@ version: '3'
|
|||||||
services:
|
services:
|
||||||
laravel-app:
|
laravel-app:
|
||||||
env_file: .env
|
env_file: .env
|
||||||
image: shinsenter/laravel:latest
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
container_name: ${CONTAINER_NAME:-pcag-laravel}
|
||||||
volumes:
|
volumes:
|
||||||
- ./site:/var/www/html
|
- ./site:/var/www/html
|
||||||
- ./static:/static
|
- ./static:/static
|
||||||
@ -16,9 +19,9 @@ services:
|
|||||||
DB_DATABASE: ${DB_DATABASE}
|
DB_DATABASE: ${DB_DATABASE}
|
||||||
DB_USERNAME: ${DB_USERNAME}
|
DB_USERNAME: ${DB_USERNAME}
|
||||||
DB_PASSWORD: ${DB_PASSWORD}
|
DB_PASSWORD: ${DB_PASSWORD}
|
||||||
# LARAVEL_QUEUE_ENABLED: true
|
LARAVEL_QUEUE_ENABLED: true
|
||||||
# LARAVEL_QUEUE_OPTIONS: --timeout=60 --tries=3 redis
|
LARAVEL_QUEUE_OPTIONS: --timeout=60 --tries=3 redis
|
||||||
# LARAVEL_SCHEDULE_ENABLED: true
|
LARAVEL_SCHEDULE_ENABLED: true
|
||||||
ports:
|
ports:
|
||||||
- "80:80"
|
- "80:80"
|
||||||
links:
|
links:
|
||||||
@ -28,7 +31,7 @@ services:
|
|||||||
static:
|
static:
|
||||||
image: nginx:alpine
|
image: nginx:alpine
|
||||||
volumes:
|
volumes:
|
||||||
- ./static:/usr/share/nginx/html:ro
|
- ./static:/usr/share/nginx/html
|
||||||
environment:
|
environment:
|
||||||
TZ: UTC
|
TZ: UTC
|
||||||
PUID: ${UID:-1000}
|
PUID: ${UID:-1000}
|
||||||
|
@ -0,0 +1,60 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
|
use Illuminate\Console\Command;
|
||||||
|
use Illuminate\Support\Facades\Http;
|
||||||
|
use App\Models\Artwork;
|
||||||
|
use App\Models\Episode;
|
||||||
|
|
||||||
|
class MapLegacyArtworkToLegacyEpisodeCommand extends Command
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The name and signature of the console command.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $signature = 'naart:map-legacy';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The console command description.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $description = 'Maps legacy artwork to the legacy episode it related to.';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the console command.
|
||||||
|
*/
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
$artworks = Artwork::whereNotNull('legacy_id')->get();
|
||||||
|
foreach ($artworks as $artwork) {
|
||||||
|
if ($artwork->id > 76200) {
|
||||||
|
$legacyDetailResponse = $this->getArtworkInfoFromApi($artwork->legacy_id);
|
||||||
|
$response = $legacyDetailResponse->object();
|
||||||
|
if ($response->artwork->episode_id) {
|
||||||
|
$episode = Episode::where('legacy_id', $response->artwork->episode_id)->first();
|
||||||
|
if ($episode) {
|
||||||
|
$artwork->episode_id = $episode->id;
|
||||||
|
$this->line('Artwork ID ' . $artwork->id . ' is mapped to Episode ID ' . $episode->id);
|
||||||
|
if ($artwork->isDirty()) {
|
||||||
|
$this->line('This is a new mapping.');
|
||||||
|
$artwork->save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getArtworkInfoFromApi($artwork_legacy_id) {
|
||||||
|
$response = Http::timeout(180)
|
||||||
|
->get('https://noagendaartgenerator.com/artworkapi/' . $artwork_legacy_id,
|
||||||
|
[
|
||||||
|
'p' => '7476',
|
||||||
|
]
|
||||||
|
);
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,59 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
|
use Illuminate\Console\Command;
|
||||||
|
use Illuminate\Support\Facades\Http;
|
||||||
|
use App\Models\Artwork;
|
||||||
|
use App\Models\Episode;
|
||||||
|
|
||||||
|
class MapSelectedLegacyArtworkToEpisode extends Command
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The name and signature of the console command.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $signature = 'naart:map-selected';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The console command description.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $description = 'Maps the correct artwork selected to the legacy episodes';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the console command.
|
||||||
|
*/
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
$episodes = Episode::all();
|
||||||
|
foreach ($episodes as $episode) {
|
||||||
|
$this->line('Checking episode ' . $episode->episode_number);
|
||||||
|
$legacyEpisodeResponse = $this->getEpisodeFromApi($episode->episode_number);
|
||||||
|
$response = $legacyEpisodeResponse->object();
|
||||||
|
if ($response->episode->artwork_id && $response->episode->artwork_id + 0 > 0) {
|
||||||
|
$selectedArtwork = Artwork::where('legacy_id', $response->episode->artwork_id)->first();
|
||||||
|
if ($selectedArtwork) {
|
||||||
|
$episode->artwork_id = $selectedArtwork->id;
|
||||||
|
$this->line('Artwork ID ' . $selectedArtwork->id . ' marked as episode artwork for episode ' . $episode->episode_number);
|
||||||
|
if ($episode->isDirty()) {
|
||||||
|
$this->line('This is a new mapping.');
|
||||||
|
$episode->save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getEpisodeFromApi($episode_legacy_id) {
|
||||||
|
$response = Http::timeout(180)
|
||||||
|
->get('https://noagendaartgenerator.com/episodeapi/' . $episode_legacy_id,
|
||||||
|
[
|
||||||
|
'p' => '7476',
|
||||||
|
]
|
||||||
|
);
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
}
|
@ -3,13 +3,77 @@
|
|||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Cache;
|
||||||
use App\Models\Artwork;
|
use App\Models\Artwork;
|
||||||
|
use App\Models\Artist;
|
||||||
|
use App\Models\Episode;
|
||||||
|
|
||||||
class PageController extends Controller
|
class PageController extends Controller
|
||||||
{
|
{
|
||||||
public function landing()
|
public function landing()
|
||||||
{
|
{
|
||||||
$user = auth()->user();
|
$user = auth()->user();
|
||||||
return view('home.page');
|
$headerCounters = $this->getHeaderCounters();
|
||||||
|
$recentEpisodes = $this->mostRecentEpisodes();
|
||||||
|
return view('home.page', [
|
||||||
|
'user' => $user,
|
||||||
|
'headerCounters' => $headerCounters,
|
||||||
|
'recentEpisodes' => $recentEpisodes,
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function mostRecentEpisodes()
|
||||||
|
{
|
||||||
|
$episodes = Cache::remember('latestEpisodes', 30, function() {
|
||||||
|
return Episode::where('published', true)
|
||||||
|
->with('podcast')
|
||||||
|
->with('artwork')
|
||||||
|
->with('artwork.artist')
|
||||||
|
->orderBy('episode_date', 'desc')
|
||||||
|
->limit(10)
|
||||||
|
->get();
|
||||||
|
});
|
||||||
|
return $episodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getHeaderCounters()
|
||||||
|
{
|
||||||
|
$headerCounters = [];
|
||||||
|
$artworkCountNumber = Cache::remember('artworkCountNumber', 10, function() {
|
||||||
|
return Artwork::all()->count();
|
||||||
|
});
|
||||||
|
$artistCountNumber = Cache::remember('artistCountNumber', 10, function() {
|
||||||
|
return Artist::all()->count();
|
||||||
|
});
|
||||||
|
$episodeCountNumber = Cache::remember('episodeCountNumber', 10, function() {
|
||||||
|
return Episode::all()->count();
|
||||||
|
});
|
||||||
|
$headerCounters['Artworks'] = $this->shortNumberCount($artworkCountNumber);
|
||||||
|
$headerCounters['Artists'] = $this->shortNumberCount($artistCountNumber);
|
||||||
|
$headerCounters['Episodes'] = $this->shortNumberCount($episodeCountNumber);
|
||||||
|
return $headerCounters;
|
||||||
|
}
|
||||||
|
private function shortNumberCount($number)
|
||||||
|
{
|
||||||
|
$units = ['', 'K', 'M', 'B', 'T'];
|
||||||
|
for ($i = 0; $number >= 1000; $i++) {
|
||||||
|
$number /= 1000;
|
||||||
|
}
|
||||||
|
return [
|
||||||
|
'number' => $this->numberFormatPrecision($number, 1), //number_format(floatval($number), 1),
|
||||||
|
'unit' => $units[$i],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function numberFormatPrecision($number, $precision = 2, $separator = '.')
|
||||||
|
{
|
||||||
|
$numberParts = explode($separator, $number);
|
||||||
|
$response = $numberParts[0];
|
||||||
|
if (count($numberParts)>1 && $precision > 0) {
|
||||||
|
$response .= $separator;
|
||||||
|
$response .= substr($numberParts[1], 0, $precision);
|
||||||
|
}
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
68
site/app/Jobs/ImportLegacyUserJob.php
Normal file
68
site/app/Jobs/ImportLegacyUserJob.php
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Jobs;
|
||||||
|
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldBeUnique;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
use App\Models\User;
|
||||||
|
use App\Models\Artist;
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use App\Jobs\StashAndOptimizeLegacyArtworkJob;
|
||||||
|
|
||||||
|
class ImportLegacyUserJob implements ShouldQueue
|
||||||
|
{
|
||||||
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||||
|
|
||||||
|
protected $user;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new job instance.
|
||||||
|
*/
|
||||||
|
public function __construct($user)
|
||||||
|
{
|
||||||
|
$this->user = $user;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the job.
|
||||||
|
*/
|
||||||
|
public function handle(): void
|
||||||
|
{
|
||||||
|
$name = str_replace(' ', '', $this->user->username);
|
||||||
|
$email = strtolower(trim($this->user->email));
|
||||||
|
$email_verified_at = Carbon::parse($this->user->created_at);
|
||||||
|
$this->createUser($name, $email, $email_verified_at);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function createUser($name, $email, $email_verified_at)
|
||||||
|
{
|
||||||
|
$user = User::where('name', $name)->first();
|
||||||
|
if (!$user) {
|
||||||
|
$user = User::factory()->state([
|
||||||
|
'name' => $name,
|
||||||
|
'email' => $email,
|
||||||
|
'email_verified_at' => $email_verified_at,
|
||||||
|
'remember_token' => null,
|
||||||
|
])->create();
|
||||||
|
}
|
||||||
|
$artist = Artist::where('user_id', $user->id)->first();
|
||||||
|
if (!$artist) {
|
||||||
|
$artist = Artist::factory()->state([
|
||||||
|
'user_id' => $user->id,
|
||||||
|
'name' => $this->user->profile->name,
|
||||||
|
'avatar' => null,
|
||||||
|
'header' => null,
|
||||||
|
'location' => $this->user->profile->location ?? 'No Agenda Art Generator',
|
||||||
|
'website' => $this->user->profile->website ?? null,
|
||||||
|
'bio' => null,
|
||||||
|
])->create();
|
||||||
|
}
|
||||||
|
foreach ($this->user->artworks as $artwork) {
|
||||||
|
StashAndOptimizeLegacyArtworkJob::dispatch($artist, $artwork);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
125
site/app/Jobs/StashAndOptimizeLegacyArtworkJob.php
Normal file
125
site/app/Jobs/StashAndOptimizeLegacyArtworkJob.php
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Jobs;
|
||||||
|
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldBeUnique;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
use App\Models\User;
|
||||||
|
use App\Models\Artist;
|
||||||
|
use App\Models\Artwork;
|
||||||
|
use App\Models\Episode;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
use Intervention\Image\Facades\Image;
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use ImageOptimizer;
|
||||||
|
|
||||||
|
class StashAndOptimizeLegacyArtworkJob implements ShouldQueue
|
||||||
|
{
|
||||||
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||||
|
|
||||||
|
protected $artist;
|
||||||
|
|
||||||
|
protected $artwork;
|
||||||
|
|
||||||
|
public $tries = 2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new job instance.
|
||||||
|
*/
|
||||||
|
public function __construct($artist, $artwork)
|
||||||
|
{
|
||||||
|
$this->artist = $artist;
|
||||||
|
$this->artwork = $artwork;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the job.
|
||||||
|
*/
|
||||||
|
public function handle(): void
|
||||||
|
{
|
||||||
|
$date = Carbon::parse($this->artwork->created_at);
|
||||||
|
$basename = $date->format('Y')
|
||||||
|
. '/' . $date->format('m')
|
||||||
|
. '/' . Str::slug($this->artist->name)
|
||||||
|
. '-' . Str::slug($this->artwork->title)
|
||||||
|
. '_' . $this->artwork->id . '.jpg';
|
||||||
|
$filename = 'artworks/' . $basename;
|
||||||
|
$thumbnailName = 'thumbnails/' . $basename;
|
||||||
|
if (Storage::disk('static')->exists($filename)) {
|
||||||
|
Log::channel('artwork_import')->error($filename . ' already exists. Filesize: ' . Storage::disk('static')->size($filename));
|
||||||
|
$this->createArtwork($basename);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$img = Image::make('https://noagendaartgenerator.com' . $this->artwork->path . '/' . $this->artwork->filename)
|
||||||
|
->resize(3000, null, function ($constraint) {
|
||||||
|
$constraint->aspectRatio();
|
||||||
|
})
|
||||||
|
->encode('jpg', 100);
|
||||||
|
$thumbImg = Image::make('https://noagendaartgenerator.com' . $this->artwork->path . '/' . $this->artwork->filename)
|
||||||
|
->resize(512, null, function ($constraint) {
|
||||||
|
$constraint->aspectRatio();
|
||||||
|
})
|
||||||
|
->encode('jpg', 100);
|
||||||
|
$imgLocation = Storage::disk('static')->put($filename, $img);
|
||||||
|
$thumbLocation = Storage::disk('static')->put($thumbnailName, $thumbImg);
|
||||||
|
$size_before = Storage::disk('static')->size($filename);
|
||||||
|
$thumb_size_before = Storage::disk('static')->size($thumbnailName);
|
||||||
|
ImageOptimizer::optimize(Storage::disk('static')->path($filename));
|
||||||
|
ImageOptimizer::optimize(Storage::disk('static')->path($thumbnailName));
|
||||||
|
$size_after = Storage::disk('static')->size($filename);
|
||||||
|
$thumb_size_after = Storage::disk('static')->size($thumbnailName);
|
||||||
|
$diff = $size_before - $size_after;
|
||||||
|
$thumbDiff = $thumb_size_before - $thumb_size_after;
|
||||||
|
Log::channel('artwork_import')->info('Filesize Before: ' . $size_before);
|
||||||
|
Log::channel('artwork_import')->info('Filesize After: ' . $size_after);
|
||||||
|
$perc_smaller = ($diff / $size_before) * 100;
|
||||||
|
$thumb_perc_smaller = ($thumbDiff / $thumb_size_before) * 100;
|
||||||
|
Log::channel('artwork_import')->info(number_format($perc_smaller, 2) . '% smaller.');
|
||||||
|
Log::channel('artwork_import')->info(number_format($thumb_perc_smaller, 2) . '% smaller thumbnail - ' . $thumb_size_after);
|
||||||
|
Log::channel('artwork_import')->info('Saved and resized ' . $filename);
|
||||||
|
$this->createArtwork($basename);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function createArtwork($basename) {
|
||||||
|
$artwork = Artwork::where('legacy_id', $this->artwork->id)->first();
|
||||||
|
if (!$this->artwork->episode_id) {
|
||||||
|
$episode = Episode::where('episode_date', '>=', Carbon::parse($this->artwork->created_at)->startOfDay())
|
||||||
|
->orderBy('episode_date', 'asc')
|
||||||
|
->first();
|
||||||
|
} else {
|
||||||
|
$episode = Episode::where('legacy_id', $this->artwork->episode_id)->first();
|
||||||
|
}
|
||||||
|
if (!$artwork) {
|
||||||
|
$artwork = Artwork::where('filename', $basename)->first();
|
||||||
|
if ($artwork) {
|
||||||
|
$artwork->legacy_id = $this->artwork->id;
|
||||||
|
$artwork->episode_id = $episode->id ?? null;
|
||||||
|
$artwork->save();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!$artwork) {
|
||||||
|
Log::channel('artwork_import')->info('making new artwork model for ' . $basename);
|
||||||
|
Artwork::factory()->state([
|
||||||
|
'title' => $this->artwork->title,
|
||||||
|
'artist_id' => $this->artist->id,
|
||||||
|
'description' => '',
|
||||||
|
'podcast_id' => 1,
|
||||||
|
'overlay_id' => $this->artwork->overlay_id,
|
||||||
|
'episode_id' => $episode->id ?? null,
|
||||||
|
'filename' => $basename ?? null,
|
||||||
|
'created_at' => Carbon::parse($this->artwork->created_at),
|
||||||
|
'updated_at' => Carbon::parse($this->artwork->updated_at),
|
||||||
|
'legacy_id' => $this->artwork->id,
|
||||||
|
])->create();
|
||||||
|
} else {
|
||||||
|
Log::channel('artwork_import')->info($artwork->id . ' has a model it exists with ' . $artwork->filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -21,7 +21,7 @@ public function podcast()
|
|||||||
|
|
||||||
public function artwork()
|
public function artwork()
|
||||||
{
|
{
|
||||||
return $this->hasOne(Artwork::class);
|
return $this->hasOne(Artwork::class, 'id', 'artwork_id');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function artist()
|
public function artist()
|
||||||
|
@ -11,7 +11,8 @@
|
|||||||
"laravel/framework": "^10.10",
|
"laravel/framework": "^10.10",
|
||||||
"laravel/sanctum": "^3.2",
|
"laravel/sanctum": "^3.2",
|
||||||
"laravel/tinker": "^2.8",
|
"laravel/tinker": "^2.8",
|
||||||
"livewire/livewire": "^2.12"
|
"livewire/livewire": "^2.12",
|
||||||
|
"spatie/laravel-image-optimizer": "^1.7"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"fakerphp/faker": "^1.9.1",
|
"fakerphp/faker": "^1.9.1",
|
||||||
|
579
site/composer.lock
generated
579
site/composer.lock
generated
File diff suppressed because it is too large
Load Diff
66
site/config/image-optimizer.php
Normal file
66
site/config/image-optimizer.php
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Spatie\ImageOptimizer\Optimizers\Cwebp;
|
||||||
|
use Spatie\ImageOptimizer\Optimizers\Gifsicle;
|
||||||
|
use Spatie\ImageOptimizer\Optimizers\Jpegoptim;
|
||||||
|
use Spatie\ImageOptimizer\Optimizers\Optipng;
|
||||||
|
use Spatie\ImageOptimizer\Optimizers\Pngquant;
|
||||||
|
use Spatie\ImageOptimizer\Optimizers\Svgo;
|
||||||
|
|
||||||
|
return [
|
||||||
|
/*
|
||||||
|
* When calling `optimize` the package will automatically determine which optimizers
|
||||||
|
* should run for the given image.
|
||||||
|
*/
|
||||||
|
'optimizers' => [
|
||||||
|
|
||||||
|
Jpegoptim::class => [
|
||||||
|
'-m72', // set maximum quality to 85%
|
||||||
|
'--strip-all', // this strips out all text information such as comments and EXIF data
|
||||||
|
'--all-progressive', // this will make sure the resulting image is a progressive one
|
||||||
|
],
|
||||||
|
|
||||||
|
Pngquant::class => [
|
||||||
|
'--force', // required parameter for this package
|
||||||
|
],
|
||||||
|
|
||||||
|
Optipng::class => [
|
||||||
|
'-i0', // this will result in a non-interlaced, progressive scanned image
|
||||||
|
'-o2', // this set the optimization level to two (multiple IDAT compression trials)
|
||||||
|
'-quiet', // required parameter for this package
|
||||||
|
],
|
||||||
|
|
||||||
|
Svgo::class => [
|
||||||
|
'--disable=cleanupIDs', // disabling because it is know to cause troubles
|
||||||
|
],
|
||||||
|
|
||||||
|
Gifsicle::class => [
|
||||||
|
'-b', // required parameter for this package
|
||||||
|
'-O3', // this produces the slowest but best results
|
||||||
|
],
|
||||||
|
|
||||||
|
Cwebp::class => [
|
||||||
|
'-m 6', // for the slowest compression method in order to get the best compression.
|
||||||
|
'-pass 10', // for maximizing the amount of analysis pass.
|
||||||
|
'-mt', // multithreading for some speed improvements.
|
||||||
|
'-q 90', // quality factor that brings the least noticeable changes.
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The directory where your binaries are stored.
|
||||||
|
* Only use this when you binaries are not accessible in the global environment.
|
||||||
|
*/
|
||||||
|
'binary_path' => '',
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The maximum time in seconds each optimizer is allowed to run separately.
|
||||||
|
*/
|
||||||
|
'timeout' => 60,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If set to `true` all output of the optimizer binaries will be appended to the default log.
|
||||||
|
* You can also set this to a class that implements `Psr\Log\LoggerInterface`.
|
||||||
|
*/
|
||||||
|
'log_optimizer_activity' => false,
|
||||||
|
];
|
@ -65,6 +65,13 @@
|
|||||||
'replace_placeholders' => true,
|
'replace_placeholders' => true,
|
||||||
],
|
],
|
||||||
|
|
||||||
|
'artwork_import' => [
|
||||||
|
'driver' => 'single',
|
||||||
|
'path' => storage_path('logs/artwork_import.log'),
|
||||||
|
'level' => env('LOG_LEVEL', 'debug'),
|
||||||
|
'replace_placeholders' => true,
|
||||||
|
],
|
||||||
|
|
||||||
'daily' => [
|
'daily' => [
|
||||||
'driver' => 'daily',
|
'driver' => 'daily',
|
||||||
'path' => storage_path('logs/laravel.log'),
|
'path' => storage_path('logs/laravel.log'),
|
||||||
|
@ -29,7 +29,7 @@ public function definition()
|
|||||||
'header' => fake()->imageUrl(270, 185),
|
'header' => fake()->imageUrl(270, 185),
|
||||||
'location' => fake()->city() . ', ' . fake()->state(),
|
'location' => fake()->city() . ', ' . fake()->state(),
|
||||||
'website' => rand(0, 1) ? fake()->url : null,
|
'website' => rand(0, 1) ? fake()->url : null,
|
||||||
'bio' => fake()->paragraphs(rand(1,3, true)),
|
'bio' => fake()->paragraphs(rand(1, 3), true),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,14 +27,18 @@ class ArtworkFactory extends Factory
|
|||||||
*/
|
*/
|
||||||
public function definition()
|
public function definition()
|
||||||
{
|
{
|
||||||
|
$created = fake()->dateTimeThisDecade();
|
||||||
return [
|
return [
|
||||||
'title' => fake()->name(),
|
'title' => fake()->name(),
|
||||||
'description' => rand(0, 1) ? fake()->paragraphs(rand((1, 3, true))) : null,
|
'description' => rand(0, 1) ? fake()->paragraphs(rand(1, 3), true) : null,
|
||||||
'artist_id' => Artist::factory(),
|
'artist_id' => Artist::factory(),
|
||||||
'podcast_id' => Podcast::factory(),
|
'podcast_id' => Podcast::factory(),
|
||||||
'episode_id' => Episode::factory(),
|
'episode_id' => Episode::factory(),
|
||||||
'overlay_id' => rand(0, 1) ? Overlay::factory() : null,
|
'overlay_id' => rand(0, 1) ? Overlay::factory() : null,
|
||||||
'filename' => fake()->imageUrl(3000, 3000),
|
'filename' => fake()->imageUrl(3000, 3000),
|
||||||
|
'created_at' => $created,
|
||||||
|
'updated_at' => $created,
|
||||||
|
'legacy_id' => null,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,11 +2,14 @@
|
|||||||
|
|
||||||
namespace Database\Factories;
|
namespace Database\Factories;
|
||||||
|
|
||||||
|
use App\Models\Artist;
|
||||||
|
use App\Models\Artwork;
|
||||||
use App\Models\Episode;
|
use App\Models\Episode;
|
||||||
use App\Models\Podcast;
|
use App\Models\Podcast;
|
||||||
use App\Models\Artwork;
|
use App\Models\Overlay;
|
||||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
class EpisodeFactory extends Factory
|
class EpisodeFactory extends Factory
|
||||||
{
|
{
|
||||||
@ -24,11 +27,20 @@ class EpisodeFactory extends Factory
|
|||||||
*/
|
*/
|
||||||
public function definition()
|
public function definition()
|
||||||
{
|
{
|
||||||
|
$title = fake()->name();
|
||||||
|
$slug = Str::slug($title);
|
||||||
|
$created = fake()->dateTimeThisDecade();
|
||||||
return [
|
return [
|
||||||
'podcast_id' => Podcast::factory(),
|
'podcast_id' => Podcast::factory(),
|
||||||
'artwork_id' => Artwork::factory(),
|
'artwork_id' => Artwork::factory(),
|
||||||
'published' => fake()->boolean(),
|
'published' => fake()->boolean(),
|
||||||
'title' => fake()->name()
|
'episode_date' => fake()->dateTimeThisDecade(),
|
||||||
|
'slug' => $slug,
|
||||||
|
'title' => $title,
|
||||||
|
'mp3' => fake()->url(),
|
||||||
|
'created_at' => $created,
|
||||||
|
'updated_at' => $created,
|
||||||
|
'legacy_id' => null,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,12 +4,23 @@
|
|||||||
|
|
||||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
use App\Models\Podcast;
|
|
||||||
use App\Models\Artist;
|
use App\Models\Artist;
|
||||||
|
use App\Models\Artwork;
|
||||||
|
use App\Models\Episode;
|
||||||
|
use App\Models\Podcast;
|
||||||
|
use App\Models\Overlay;
|
||||||
|
|
||||||
|
|
||||||
class OverlayFactory extends Factory
|
class OverlayFactory extends Factory
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the factory's corresponding model
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $model = Overlay::class;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Define the model's default state.
|
* Define the model's default state.
|
||||||
*
|
*
|
||||||
|
@ -4,10 +4,21 @@
|
|||||||
|
|
||||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
|
use App\Models\Artist;
|
||||||
|
use App\Models\Artwork;
|
||||||
|
use App\Models\Episode;
|
||||||
use App\Models\Podcast;
|
use App\Models\Podcast;
|
||||||
|
use App\Models\Overlay;
|
||||||
|
|
||||||
class PodcastFactory extends Factory
|
class PodcastFactory extends Factory
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* The name of the factory's corresponding model
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $model = Podcast::class;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Define the model's default state.
|
* Define the model's default state.
|
||||||
*
|
*
|
||||||
|
@ -5,9 +5,22 @@
|
|||||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
use Illuminate\Support\Facades\Hash;
|
use Illuminate\Support\Facades\Hash;
|
||||||
|
use App\Models\Artist;
|
||||||
|
use App\Models\Artwork;
|
||||||
|
use App\Models\Episode;
|
||||||
|
use App\Models\Podcast;
|
||||||
|
use App\Models\Overlay;
|
||||||
|
use App\Models\User;
|
||||||
|
|
||||||
|
|
||||||
class UserFactory extends Factory
|
class UserFactory extends Factory
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* The name of the factory's corresponding model
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $model = User::class;
|
||||||
/**
|
/**
|
||||||
* Define the model's default state.
|
* Define the model's default state.
|
||||||
*
|
*
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
use Illuminate\Database\Migrations\Migration;
|
use Illuminate\Database\Migrations\Migration;
|
||||||
use Illuminate\Database\Schema\Blueprint;
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
use Illuminate\Support\Facades\Schema;
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
use App\Models\User;
|
||||||
|
|
||||||
class CreateArtistsTable extends Migration
|
class CreateArtistsTable extends Migration
|
||||||
{
|
{
|
||||||
|
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('episodes', function (Blueprint $table) {
|
||||||
|
$table->decimal('episode_number', 8, 1)->after('episode_date')->default(0);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('episodes', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('episode_number');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('artworks', function (Blueprint $table) {
|
||||||
|
$table->bigInteger('legacy_id')->nullable();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('artworks', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('legacy_id');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('episodes', function (Blueprint $table) {
|
||||||
|
$table->bigInteger('legacy_id')->nullable();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('episodes', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('legacy_id');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
60
site/database/seeders/EpisodeSeeder.php
Normal file
60
site/database/seeders/EpisodeSeeder.php
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Database\Seeders;
|
||||||
|
|
||||||
|
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||||
|
use Illuminate\Database\Seeder;
|
||||||
|
use App\Models\Episode;
|
||||||
|
use App\Models\Podcast;
|
||||||
|
use Illuminate\Support\Facades\Http;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
use Carbon\Carbon;
|
||||||
|
|
||||||
|
class EpisodeSeeder extends Seeder
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the database seeds.
|
||||||
|
*/
|
||||||
|
public function run(): void
|
||||||
|
{
|
||||||
|
$current_page = 1;
|
||||||
|
$response = $this->getResponseFromApi($current_page);
|
||||||
|
$last_page = $response->object()->last_page;
|
||||||
|
$this->command->info('Last Page: ' . $last_page);
|
||||||
|
$podcast = Podcast::find(1);
|
||||||
|
while ($current_page <= $last_page) {
|
||||||
|
$this->command->info('Getting Page ' . $current_page);
|
||||||
|
foreach ($response->object()->data as $episode) {
|
||||||
|
$podcastEpisode = Episode::where('title', $episode->title)->first();
|
||||||
|
if (!$podcastEpisode) {
|
||||||
|
$podcastEpisode = Episode::factory()->state([
|
||||||
|
'podcast_id' => 1,
|
||||||
|
'episode_date' => Carbon::parse($episode->show_date),
|
||||||
|
'published' => (bool)$episode->published,
|
||||||
|
'artwork_id' => null,
|
||||||
|
'slug' => $episode->episode_number . '_' . Str::slug($episode->title),
|
||||||
|
'title' => $episode->title,
|
||||||
|
'mp3' => $episode->link,
|
||||||
|
'created_at' => Carbon::parse($episode->created_at),
|
||||||
|
'updated_at' => Carbon::parse($episode->updated_at),
|
||||||
|
'legacy_id' => $episode->id ?? null
|
||||||
|
])->create();
|
||||||
|
} else {
|
||||||
|
$podcastEpisode->legacy_id = $episode->id ?? null;
|
||||||
|
if ($podcastEpisode->isDirty()) {
|
||||||
|
$podcastEpisode->save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$this->command->info('Created ' . $episode->show_date . ' - (' . $episode->episode_number . ') ' . $episode->title);
|
||||||
|
}
|
||||||
|
$current_page++;
|
||||||
|
$response = $this->getResponseFromApi($current_page);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getResponseFromApi($current_page) {
|
||||||
|
$response = Http::timeout(180)
|
||||||
|
->get('https://noagendaartgenerator.com/episodesjson?p=7476&page=' . $current_page);
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
}
|
31
site/database/seeders/FixLegacyEpisodeSeeder.php
Normal file
31
site/database/seeders/FixLegacyEpisodeSeeder.php
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Database\Seeders;
|
||||||
|
|
||||||
|
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||||
|
use Illuminate\Database\Seeder;
|
||||||
|
use App\Models\Episode;
|
||||||
|
use App\Models\Podcast;
|
||||||
|
use App\Models\Artwork;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
use Illuminate\Support\Facade\Log;
|
||||||
|
|
||||||
|
class FixLegacyEpisodeSeeder extends Seeder
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the database seeds.
|
||||||
|
*/
|
||||||
|
public function run(): void
|
||||||
|
{
|
||||||
|
$episodes = Episode::all();
|
||||||
|
foreach ($episodes as $episode) {
|
||||||
|
if (is_null($episode->episode_number) || $episode->episode_number == 0) {
|
||||||
|
$ep_num_arr = explode('_', $episode->slug);
|
||||||
|
$episode->episode_number = $ep_num_arr[0];
|
||||||
|
}
|
||||||
|
if ($episode->isDirty()) {
|
||||||
|
$episode->save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
17
site/database/seeders/MapLegacyIdsSeeder.php
Normal file
17
site/database/seeders/MapLegacyIdsSeeder.php
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Database\Seeders;
|
||||||
|
|
||||||
|
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||||
|
use Illuminate\Database\Seeder;
|
||||||
|
|
||||||
|
class MapLegacyIdsSeeder extends Seeder
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the database seeds.
|
||||||
|
*/
|
||||||
|
public function run(): void
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
@ -133,6 +133,13 @@ public function run()
|
|||||||
$added = '2021-10-29 20:00:00';
|
$added = '2021-10-29 20:00:00';
|
||||||
$this->createPodcast($name, $description, $website, $slug, $feed, $added);
|
$this->createPodcast($name, $description, $website, $slug, $feed, $added);
|
||||||
|
|
||||||
|
$name = 'The Boostagram Ball';
|
||||||
|
$description = 'The First Podcast with Value4Value Music hosted by Adam Curry';
|
||||||
|
$website = 'https://boostagramball.com';
|
||||||
|
$slug = 'boostagram-ball';
|
||||||
|
$feed = 'https://mp3s.nashownotes.com/bballrss.xml';
|
||||||
|
$added = '2023-07-29 20:00:00';
|
||||||
|
$this->createPodcast($name, $description, $website, $slug, $feed, $added);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function createPodcast($name, $description, $website, $slug, $feed, $added) {
|
private function createPodcast($name, $description, $website, $slug, $feed, $added) {
|
||||||
|
105
site/database/seeders/SeedFromOldApiSeeder.php
Normal file
105
site/database/seeders/SeedFromOldApiSeeder.php
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Database\Seeders;
|
||||||
|
|
||||||
|
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||||
|
use Illuminate\Database\Seeder;
|
||||||
|
use Illuminate\Support\Facades\Http;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
use App\Models\Artist;
|
||||||
|
use App\Models\Artwork;
|
||||||
|
use App\Models\Episode;
|
||||||
|
use App\Models\Podcast;
|
||||||
|
use App\Models\Overlay;
|
||||||
|
use App\Jobs\StashAndOptimizeLegacyArtworkJob;
|
||||||
|
use App\Jobs\ImportLegacyUserJob;
|
||||||
|
use Carbon\Carbon;
|
||||||
|
|
||||||
|
class SeedFromOldApiSeeder extends Seeder
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the database seeds.
|
||||||
|
*/
|
||||||
|
public function run(): void
|
||||||
|
{
|
||||||
|
//$this->populateLegacyArtworks();
|
||||||
|
//die();
|
||||||
|
$current_page = 283;
|
||||||
|
$totalArtworks = 0;
|
||||||
|
$missingArtworks = 0;
|
||||||
|
$missingModel = 0;
|
||||||
|
$response = $this->getResponseFromApi($current_page);
|
||||||
|
$last_page = $response->object()->users->last_page;
|
||||||
|
while ($current_page <= $last_page) {
|
||||||
|
$this->command->info('Getting Page ' . $current_page);
|
||||||
|
foreach ($response->object()->users->data as $user) {
|
||||||
|
$this->command->line('Getting Art for ' . $user->profile->name . ', found ' . count($user->artworks) . ' artworks.');
|
||||||
|
$totalArtworks += count($user->artworks);
|
||||||
|
$legacyUser = Artist::where('name', $user->profile->name)->first();
|
||||||
|
if (!$legacyUser) {
|
||||||
|
ImportLegacyUserJob::dispatch($user);
|
||||||
|
} else {
|
||||||
|
if ($legacyUser->artworks->count() < count($user->artworks)) {
|
||||||
|
$countDiff = count($user->artworks) - $legacyUser->artworks->count();
|
||||||
|
$missingArtworks += $countDiff;
|
||||||
|
$this->command->comment('Artist ID '
|
||||||
|
. $legacyUser->id
|
||||||
|
. ' '
|
||||||
|
. $legacyUser->name
|
||||||
|
. ' has '
|
||||||
|
. $legacyUser->artworks->count()
|
||||||
|
. ' artworks.');
|
||||||
|
$this->command->error('Missing ' . $countDiff . ' artworks.');
|
||||||
|
foreach ($user->artworks as $artwork) {
|
||||||
|
$date = Carbon::parse($artwork->created_at);
|
||||||
|
$basename = $date->format('Y')
|
||||||
|
. '/' . $date->format('m')
|
||||||
|
. '/' . Str::slug($legacyUser->name)
|
||||||
|
. '-' . Str::slug($artwork->title)
|
||||||
|
. '_' . $artwork->id . '.jpg';
|
||||||
|
if (Storage::disk('static')->exists('artworks/' . $basename)) {
|
||||||
|
$artworkModel = Artwork::where('filename', $basename)->first();
|
||||||
|
if (!$artworkModel) {
|
||||||
|
$missingModel++;
|
||||||
|
$this->command->error($basename . ' exists.');
|
||||||
|
StashAndOptimizeLegacyArtworkJob::dispatch($legacyUser, $artwork);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$this->command->line('Locally stored all of ' . $legacyUser->name . '\'s artworks.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$current_page++;
|
||||||
|
$response = $this->getResponseFromApi($current_page);
|
||||||
|
}
|
||||||
|
$this->command->info('Total Artworks: ' . $totalArtworks);
|
||||||
|
$this->command->info('Total Missing: ' . $missingArtworks);
|
||||||
|
$this->command->info('Total Missing Model: ' . $missingModel);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getResponseFromApi($current_page) {
|
||||||
|
$response = Http::timeout(180)
|
||||||
|
->get('https://noagendaartgenerator.com/artistapi',
|
||||||
|
[
|
||||||
|
'p' => '7476',
|
||||||
|
'page' => $current_page,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function populateLegacyArtworks() {
|
||||||
|
$artworks = Artwork::whereNull('legacy_id')->get();
|
||||||
|
foreach ($artworks as $artwork) {
|
||||||
|
$file = pathinfo($artwork->filename);
|
||||||
|
$filename = explode('_', $file['filename']);
|
||||||
|
$legacy_id = end($filename);
|
||||||
|
$artwork->legacy_id = $legacy_id;
|
||||||
|
$artwork->save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -64,6 +64,7 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
padding-top: 50px;
|
padding-top: 50px;
|
||||||
|
padding-bottom: 50px;
|
||||||
@include lg-device {
|
@include lg-device {
|
||||||
padding: 180px 0 170px;
|
padding: 180px 0 170px;
|
||||||
min-height: auto;
|
min-height: auto;
|
||||||
@ -143,6 +144,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// hero banner style two
|
// hero banner style two
|
||||||
.hero-banner-style-2 {
|
.hero-banner-style-2 {
|
||||||
.banner-content {
|
.banner-content {
|
||||||
|
@ -186,7 +186,7 @@ body {
|
|||||||
.bg-4,
|
.bg-4,
|
||||||
.bg-3,
|
.bg-3,
|
||||||
.bg-5 {
|
.bg-5 {
|
||||||
background-image: none;
|
background-image: url(../img/headerbg.jpg);
|
||||||
background-color: $body-bg-light;
|
background-color: $body-bg-light;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
21
site/resources/views/home/hero/banner-left.blade.php
Normal file
21
site/resources/views/home/hero/banner-left.blade.php
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<div class="banner-content">
|
||||||
|
<h1 class="mb-5 title" data-aos="fade-up">Producing Album Art<br>
|
||||||
|
<span>Live Since 2010</span>
|
||||||
|
</h1>
|
||||||
|
<p data-aos="fade-up" data-aos-delay="100">
|
||||||
|
A community collaboration producing the best podcast album art in the universe!
|
||||||
|
</p>
|
||||||
|
<div class="group-btn mt-8" data-aos="fade-up" data-aos-delay="200">
|
||||||
|
<a href="explore-filter-sidebar.html" class="btn btn-gradient">
|
||||||
|
<span><i class="ri-rocket-line"></i>Explore</span>
|
||||||
|
</a>
|
||||||
|
<a href="create.html" class="btn btn-outline">
|
||||||
|
<span><i class="ri-edit-line"></i> Create</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="counter-wrapper counter-wrapper-style-two">
|
||||||
|
@foreach ($headerCounters as $headerCounterLabel => $headerCounterCount)
|
||||||
|
@include('home.hero.counter')
|
||||||
|
@endforeach
|
||||||
|
</div>
|
||||||
|
</div>
|
7
site/resources/views/home/hero/counter.blade.php
Normal file
7
site/resources/views/home/hero/counter.blade.php
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<div class="counter-style-1" data-aos="fade-up" data-aos-delay="250">
|
||||||
|
<div class="d-flex-center">
|
||||||
|
<div class="number counter-item-active">{{ $headerCounterCount['number'] }}</div>
|
||||||
|
<div class="count-kilo">{{ $headerCounterCount['unit'] }} <span>+</span></div>
|
||||||
|
</div>
|
||||||
|
<div class="counter-title">{{ $headerCounterLabel }}</div>
|
||||||
|
</div>
|
43
site/resources/views/home/hero/slider/slide.blade.php
Normal file
43
site/resources/views/home/hero/slider/slide.blade.php
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
<div class="explore-style-one">
|
||||||
|
<div class="thumb">
|
||||||
|
<a href="product-details.html"> <img src="{{ 'http://' . config('app.static_asset_url') . '/thumbnails/' . $recentEpisode->artwork->filename ?? '#'}}"
|
||||||
|
alt="nft live auction thumbnail"></a>
|
||||||
|
<!-- End .reaction-count -->
|
||||||
|
</div>
|
||||||
|
<!-- End .thumb -->
|
||||||
|
<div class="content">
|
||||||
|
<div class="header d-flex-between pt-4 pb-1">
|
||||||
|
<h3 class="title">
|
||||||
|
<a href="product-details.html">"{{ $recentEpisode->title }}"</a>
|
||||||
|
</h3>
|
||||||
|
<div class="more-dropdown "><i class="ri-more-fill" data-bs-toggle="dropdown"></i>
|
||||||
|
<ul class="dropdown-menu dropdown-menu-dark">
|
||||||
|
<li><a class="dropdown-item" href="#">View Episode</a></li>
|
||||||
|
<li><a class="dropdown-item" href="#">View Podcast</a></li>
|
||||||
|
<li><a class="dropdown-item" href="#">View Show Notes</a></li>
|
||||||
|
<li>
|
||||||
|
<hr class="dropdown-divider">
|
||||||
|
</li>
|
||||||
|
<li><a class="dropdown-item" href="#">View Selected Artist</a></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- .header -->
|
||||||
|
<div class="product-owner py-1 d-flex-between">
|
||||||
|
<span class="bid-owner">Artwork Selected For<br>
|
||||||
|
<strong><a href="#">{{ $recentEpisode->podcast->name }}</a></strong>
|
||||||
|
<br>
|
||||||
|
<a href="#">Episode {{ number_format($recentEpisode->episode_number + 0) }}</a></span>
|
||||||
|
</div>
|
||||||
|
<div class="product-owner py-1 d-flex-between">
|
||||||
|
<span class="bid-owner">Artwork By<br><strong><a
|
||||||
|
href="author-profile.html">{{ $recentEpisode->artwork->artist->name ?? 'Unknown' }}</a></strong></span>
|
||||||
|
<span class="profile-share d-flex-center"><a href="author-profile.html" class="avatar" data-bs-toggle="tooltip" data-bs-placement="top"
|
||||||
|
title="{{ $recentEpisode->artwork->artist->name }}"><img src="{{ Vite::asset('resources/img/default_avatars/default_avatar_users_' . str_pad(rand(1, 32), 2, '0', STR_PAD_LEFT) . '.svg') }}"
|
||||||
|
alt="{{ $recentEpisode->artwork->artist->name }}"></a></span>
|
||||||
|
</div>
|
||||||
|
<!-- End .product-owner -->
|
||||||
|
</div>
|
||||||
|
<!-- End .content -->
|
||||||
|
</div>
|
7
site/resources/views/home/hero/slider/slider.blade.php
Normal file
7
site/resources/views/home/hero/slider/slider.blade.php
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<div class="slider slider-activation-banner-4 slick-gutter-15 slick-pagination-50">
|
||||||
|
@foreach($recentEpisodes as $recentEpisode)
|
||||||
|
@if ($recentEpisode->artwork)
|
||||||
|
@include('home.hero.slider.slide')
|
||||||
|
@endif
|
||||||
|
@endforeach
|
||||||
|
</div>
|
@ -6,167 +6,10 @@
|
|||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<div class="row align-items-center">
|
<div class="row align-items-center">
|
||||||
<div class="col-xl-7 col-lg-6 col-md-12">
|
<div class="col-xl-7 col-lg-6 col-md-12">
|
||||||
<div class="banner-content">
|
@include('home.hero.banner-left')
|
||||||
<h1 class="mb-5 title" data-aos="fade-up">Producing Album Art<br>
|
|
||||||
<span>Live Since 2010</span>
|
|
||||||
</h1>
|
|
||||||
<p data-aos="fade-up" data-aos-delay="100">A community collaboration producing the best
|
|
||||||
<br> album art in the universe!
|
|
||||||
</p>
|
|
||||||
<div class="group-btn mt-8" data-aos="fade-up" data-aos-delay="200">
|
|
||||||
<a href="explore-filter-sidebar.html" class="btn btn-gradient"><span><i class="ri-rocket-line"></i>
|
|
||||||
Explore</span></a>
|
|
||||||
<a href="create.html" class="btn btn-outline"><span><i class="ri-edit-line"></i> Create</span></a>
|
|
||||||
</div>
|
|
||||||
<div class="counter-wrapper counter-wrapper-style-two">
|
|
||||||
<div class="counter-style-1" data-aos="fade-up" data-aos-delay="250">
|
|
||||||
<div class="d-flex-center">
|
|
||||||
<div class="number counter-item-active">28</div>
|
|
||||||
<div class="count-kilo">K <span>+</span></div>
|
|
||||||
</div>
|
|
||||||
<div class="counter-title">Artworks</div>
|
|
||||||
</div>
|
|
||||||
<!-- End .single-counter -->
|
|
||||||
|
|
||||||
<div class="counter-style-1" data-aos="fade-up" data-aos-delay="300">
|
|
||||||
<div class="d-flex-center">
|
|
||||||
<div class="number counter-item-active">2.9</div>
|
|
||||||
<div class="count-kilo">K <span>+</span></div>
|
|
||||||
</div>
|
|
||||||
<div class="counter-title">Artists</div>
|
|
||||||
</div>
|
|
||||||
<!-- End .single-counter -->
|
|
||||||
|
|
||||||
<div class="counter-style-1" data-aos="fade-up" data-aos-delay="350">
|
|
||||||
<div class="d-flex-center">
|
|
||||||
<div class="number counter-item-active">1.6</div>
|
|
||||||
<div class="count-kilo">K <span>+</span></div>
|
|
||||||
</div>
|
|
||||||
<div class="counter-title">Episodes</div>
|
|
||||||
</div>
|
|
||||||
<!-- End .single-counter -->
|
|
||||||
</div>
|
|
||||||
<!-- End .counter-wrapper -->
|
|
||||||
</div>
|
|
||||||
<!-- End banner-content -->
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<!-- End .col -->
|
|
||||||
<div class="col-xl-5 col-lg-6 col-md-12">
|
<div class="col-xl-5 col-lg-6 col-md-12">
|
||||||
<div class="slider slider-activation-banner-4 slick-gutter-15 slick-pagination-50">
|
@include('home.hero.slider.slider')
|
||||||
|
|
||||||
<div class="explore-style-one">
|
|
||||||
<div class="thumb">
|
|
||||||
<a href="product-details.html"> <img src="https://noagendaartgenerator.com/assets/artwork/episode/1528/PDzxZp7SxR.png"
|
|
||||||
alt="nft live auction thumbnail"></a>
|
|
||||||
<button class="reaction-btn"><i class="ri-heart-fill"></i><span>49</span></button>
|
|
||||||
<!-- End .reaction-count -->
|
|
||||||
</div>
|
|
||||||
<!-- End .thumb -->
|
|
||||||
<div class="content">
|
|
||||||
<div class="header d-flex-between pt-4 pb-3">
|
|
||||||
<h3 class="title"><a href="product-details.html">No Agenda (1528)<br>"HABIDAT"</a></h3>
|
|
||||||
<div class="more-dropdown "><i class="ri-more-fill" data-bs-toggle="dropdown"></i>
|
|
||||||
<ul class="dropdown-menu dropdown-menu-dark">
|
|
||||||
<li><a class="dropdown-item" href="#">New bid</a></li>
|
|
||||||
<li>
|
|
||||||
<hr class="dropdown-divider">
|
|
||||||
</li>
|
|
||||||
<li><a class="dropdown-item" href="#">Refresh Metadata</a></li>
|
|
||||||
<li><a class="dropdown-item" href="#">Share</a></li>
|
|
||||||
<li><a class="dropdown-item" href="#">Report</a></li>
|
|
||||||
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- .header -->
|
|
||||||
<div class="product-owner py-4 d-flex-between">
|
|
||||||
<span class="bid-owner">Artwork By<br><strong><a
|
|
||||||
href="author-profile.html">KorrectDaRekard</a></strong></span>
|
|
||||||
<span class="profile-share d-flex-center"><a href="author-profile.html" class="avatar" data-bs-toggle="tooltip" data-bs-placement="top"
|
|
||||||
title="Banuri Bari"><img src="{{ Vite::asset('resources/img/explore/avatar/1.png') }}" alt="Nft_Profile"></a></span>
|
|
||||||
</div>
|
|
||||||
<!-- End .product-owner -->
|
|
||||||
</div>
|
|
||||||
<!-- End .content -->
|
|
||||||
</div>
|
|
||||||
<!-- End explore-style-one -->
|
|
||||||
|
|
||||||
<div class="explore-style-one">
|
|
||||||
<div class="thumb">
|
|
||||||
<a href="product-details.html"> <img src="https://noagendaartgenerator.com/assets/artwork/episode/1527/obxPmNDIzeE.png"
|
|
||||||
alt="nft live auction thumbnail"></a>
|
|
||||||
<button class="reaction-btn"><i class="ri-heart-fill"></i><span>32</span></button>
|
|
||||||
<!-- End .reaction-count -->
|
|
||||||
</div>
|
|
||||||
<!-- End .thumb -->
|
|
||||||
<div class="content">
|
|
||||||
<div class="header d-flex-between pt-4 pb-3">
|
|
||||||
<h3 class="title"><a href="product-details.html">No Agenda (1527)<br>"Grip & Grin"</a></h3>
|
|
||||||
<div class="more-dropdown "><i class="ri-more-fill" data-bs-toggle="dropdown"></i>
|
|
||||||
<ul class="dropdown-menu dropdown-menu-dark">
|
|
||||||
<li><a class="dropdown-item" href="#">New bid</a></li>
|
|
||||||
<li>
|
|
||||||
<hr class="dropdown-divider">
|
|
||||||
</li>
|
|
||||||
<li><a class="dropdown-item" href="#">Refresh Metadata</a></li>
|
|
||||||
<li><a class="dropdown-item" href="#">Share</a></li>
|
|
||||||
<li><a class="dropdown-item" href="#">Report</a></li>
|
|
||||||
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- .header -->
|
|
||||||
<div class="product-owner py-4 d-flex-between">
|
|
||||||
<span class="bid-owner">Artwork By<br><strong><a
|
|
||||||
href="author-profile.html">Capitalist Agenda</a></strong></span>
|
|
||||||
<span class="profile-share d-flex-center"><a href="author-profile.html" class="avatar" data-bs-toggle="tooltip" data-bs-placement="top"
|
|
||||||
title="Capitalist Agenda"><img src="{{ Vite::asset('resources/img/avatar/capitalistagenda.png') }}" style="width:100%;height:auto;" alt="Nft_Profile"></a></span>
|
|
||||||
</div>
|
|
||||||
<!-- End .product-owner -->
|
|
||||||
</div>
|
|
||||||
<!-- End .content -->
|
|
||||||
</div>
|
|
||||||
<!-- End explore-style-one -->
|
|
||||||
|
|
||||||
<div class="explore-style-one">
|
|
||||||
<div class="thumb">
|
|
||||||
<a href="product-details.html"> <img src="https://noagendaartgenerator.com/assets/artwork/episode/1528/PDzxZp7SxR.png"
|
|
||||||
alt="nft live auction thumbnail"></a>
|
|
||||||
<button class="reaction-btn"><i class="ri-heart-fill"></i><span>49</span></button>
|
|
||||||
<!-- End .reaction-count -->
|
|
||||||
</div>
|
|
||||||
<!-- End .thumb -->
|
|
||||||
<div class="content">
|
|
||||||
<div class="header d-flex-between pt-4 pb-3">
|
|
||||||
<h3 class="title"><a href="product-details.html">No Agenda<br>"HABIDAT"</a></h3>
|
|
||||||
<div class="more-dropdown "><i class="ri-more-fill" data-bs-toggle="dropdown"></i>
|
|
||||||
<ul class="dropdown-menu dropdown-menu-dark">
|
|
||||||
<li><a class="dropdown-item" href="#">New bid</a></li>
|
|
||||||
<li>
|
|
||||||
<hr class="dropdown-divider">
|
|
||||||
</li>
|
|
||||||
<li><a class="dropdown-item" href="#">Refresh Metadata</a></li>
|
|
||||||
<li><a class="dropdown-item" href="#">Share</a></li>
|
|
||||||
<li><a class="dropdown-item" href="#">Report</a></li>
|
|
||||||
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- .header -->
|
|
||||||
<div class="product-owner py-4 d-flex-between">
|
|
||||||
<span class="bid-owner">Artwork By<br><strong><a
|
|
||||||
href="author-profile.html">KorrectDaRekard</a></strong></span>
|
|
||||||
<span class="profile-share d-flex-center"><a href="author-profile.html" class="avatar" data-bs-toggle="tooltip" data-bs-placement="top"
|
|
||||||
title="Banuri Bari"><img src="{{ Vite::asset('resources/img/explore/avatar/1.png') }}" alt="Nft_Profile"></a></span>
|
|
||||||
</div>
|
|
||||||
<!-- End .product-owner -->
|
|
||||||
</div>
|
|
||||||
<!-- End .content -->
|
|
||||||
</div>
|
|
||||||
<!-- End explore-style-one -->
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<!-- End .col -->
|
<!-- End .col -->
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
Reference in New Issue
Block a user