Update
This commit is contained in:
413
_ide_helper.php
413
_ide_helper.php
@@ -24033,6 +24033,317 @@ public static function getContainer()
|
||||
}
|
||||
}
|
||||
|
||||
namespace Maatwebsite\Excel\Facades {
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
class Excel {
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param object $export
|
||||
* @param string|null $fileName
|
||||
* @param string $writerType
|
||||
* @param array $headers
|
||||
* @return \Symfony\Component\HttpFoundation\BinaryFileResponse
|
||||
* @throws \PhpOffice\PhpSpreadsheet\Exception
|
||||
* @throws \PhpOffice\PhpSpreadsheet\Writer\Exception
|
||||
* @static
|
||||
*/
|
||||
public static function download($export, $fileName, $writerType = null, $headers = [])
|
||||
{
|
||||
/** @var \Maatwebsite\Excel\Excel $instance */
|
||||
return $instance->download($export, $fileName, $writerType, $headers);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param string|null $disk Fallback for usage with named properties
|
||||
* @param object $export
|
||||
* @param string $filePath
|
||||
* @param string|null $diskName
|
||||
* @param string $writerType
|
||||
* @param mixed $diskOptions
|
||||
* @return bool
|
||||
* @throws \PhpOffice\PhpSpreadsheet\Exception
|
||||
* @throws \PhpOffice\PhpSpreadsheet\Writer\Exception
|
||||
* @static
|
||||
*/
|
||||
public static function store($export, $filePath, $diskName = null, $writerType = null, $diskOptions = [], $disk = null)
|
||||
{
|
||||
/** @var \Maatwebsite\Excel\Excel $instance */
|
||||
return $instance->store($export, $filePath, $diskName, $writerType, $diskOptions, $disk);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param object $export
|
||||
* @param string $filePath
|
||||
* @param string|null $disk
|
||||
* @param string $writerType
|
||||
* @param mixed $diskOptions
|
||||
* @return \Illuminate\Foundation\Bus\PendingDispatch
|
||||
* @static
|
||||
*/
|
||||
public static function queue($export, $filePath, $disk = null, $writerType = null, $diskOptions = [])
|
||||
{
|
||||
/** @var \Maatwebsite\Excel\Excel $instance */
|
||||
return $instance->queue($export, $filePath, $disk, $writerType, $diskOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param object $export
|
||||
* @param string $writerType
|
||||
* @return string
|
||||
* @static
|
||||
*/
|
||||
public static function raw($export, $writerType)
|
||||
{
|
||||
/** @var \Maatwebsite\Excel\Excel $instance */
|
||||
return $instance->raw($export, $writerType);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param object $import
|
||||
* @param string|\Symfony\Component\HttpFoundation\File\UploadedFile $filePath
|
||||
* @param string|null $disk
|
||||
* @param string|null $readerType
|
||||
* @return \Maatwebsite\Excel\Reader|\Illuminate\Foundation\Bus\PendingDispatch
|
||||
* @static
|
||||
*/
|
||||
public static function import($import, $filePath, $disk = null, $readerType = null)
|
||||
{
|
||||
/** @var \Maatwebsite\Excel\Excel $instance */
|
||||
return $instance->import($import, $filePath, $disk, $readerType);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param object $import
|
||||
* @param string|\Symfony\Component\HttpFoundation\File\UploadedFile $filePath
|
||||
* @param string|null $disk
|
||||
* @param string|null $readerType
|
||||
* @return array
|
||||
* @static
|
||||
*/
|
||||
public static function toArray($import, $filePath, $disk = null, $readerType = null)
|
||||
{
|
||||
/** @var \Maatwebsite\Excel\Excel $instance */
|
||||
return $instance->toArray($import, $filePath, $disk, $readerType);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param object $import
|
||||
* @param string|\Symfony\Component\HttpFoundation\File\UploadedFile $filePath
|
||||
* @param string|null $disk
|
||||
* @param string|null $readerType
|
||||
* @return \Illuminate\Support\Collection
|
||||
* @static
|
||||
*/
|
||||
public static function toCollection($import, $filePath, $disk = null, $readerType = null)
|
||||
{
|
||||
/** @var \Maatwebsite\Excel\Excel $instance */
|
||||
return $instance->toCollection($import, $filePath, $disk, $readerType);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param \Illuminate\Contracts\Queue\ShouldQueue $import
|
||||
* @param string|\Symfony\Component\HttpFoundation\File\UploadedFile $filePath
|
||||
* @param string|null $disk
|
||||
* @param string $readerType
|
||||
* @return \Illuminate\Foundation\Bus\PendingDispatch
|
||||
* @static
|
||||
*/
|
||||
public static function queueImport($import, $filePath, $disk = null, $readerType = null)
|
||||
{
|
||||
/** @var \Maatwebsite\Excel\Excel $instance */
|
||||
return $instance->queueImport($import, $filePath, $disk, $readerType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a custom macro.
|
||||
*
|
||||
* @param string $name
|
||||
* @param object|callable $macro
|
||||
* @param-closure-this static $macro
|
||||
* @return void
|
||||
* @static
|
||||
*/
|
||||
public static function macro($name, $macro)
|
||||
{
|
||||
\Maatwebsite\Excel\Excel::macro($name, $macro);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mix another object into the class.
|
||||
*
|
||||
* @param object $mixin
|
||||
* @param bool $replace
|
||||
* @return void
|
||||
* @throws \ReflectionException
|
||||
* @static
|
||||
*/
|
||||
public static function mixin($mixin, $replace = true)
|
||||
{
|
||||
\Maatwebsite\Excel\Excel::mixin($mixin, $replace);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if macro is registered.
|
||||
*
|
||||
* @param string $name
|
||||
* @return bool
|
||||
* @static
|
||||
*/
|
||||
public static function hasMacro($name)
|
||||
{
|
||||
return \Maatwebsite\Excel\Excel::hasMacro($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush the existing macros.
|
||||
*
|
||||
* @return void
|
||||
* @static
|
||||
*/
|
||||
public static function flushMacros()
|
||||
{
|
||||
\Maatwebsite\Excel\Excel::flushMacros();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param string $concern
|
||||
* @param callable $handler
|
||||
* @param string $event
|
||||
* @static
|
||||
*/
|
||||
public static function extend($concern, $handler, $event = 'Maatwebsite\\Excel\\Events\\BeforeWriting')
|
||||
{
|
||||
return \Maatwebsite\Excel\Excel::extend($concern, $handler, $event);
|
||||
}
|
||||
|
||||
/**
|
||||
* When asserting downloaded, stored, queued or imported, use regular expression
|
||||
* to look for a matching file path.
|
||||
*
|
||||
* @return void
|
||||
* @static
|
||||
*/
|
||||
public static function matchByRegex()
|
||||
{
|
||||
/** @var \Maatwebsite\Excel\Fakes\ExcelFake $instance */
|
||||
$instance->matchByRegex();
|
||||
}
|
||||
|
||||
/**
|
||||
* When asserting downloaded, stored, queued or imported, use regular string
|
||||
* comparison for matching file path.
|
||||
*
|
||||
* @return void
|
||||
* @static
|
||||
*/
|
||||
public static function doNotMatchByRegex()
|
||||
{
|
||||
/** @var \Maatwebsite\Excel\Fakes\ExcelFake $instance */
|
||||
$instance->doNotMatchByRegex();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param string $fileName
|
||||
* @param callable|null $callback
|
||||
* @static
|
||||
*/
|
||||
public static function assertDownloaded($fileName, $callback = null)
|
||||
{
|
||||
/** @var \Maatwebsite\Excel\Fakes\ExcelFake $instance */
|
||||
return $instance->assertDownloaded($fileName, $callback);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param string $filePath
|
||||
* @param string|callable|null $disk
|
||||
* @param callable|null $callback
|
||||
* @static
|
||||
*/
|
||||
public static function assertStored($filePath, $disk = null, $callback = null)
|
||||
{
|
||||
/** @var \Maatwebsite\Excel\Fakes\ExcelFake $instance */
|
||||
return $instance->assertStored($filePath, $disk, $callback);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param string $filePath
|
||||
* @param string|callable|null $disk
|
||||
* @param callable|null $callback
|
||||
* @static
|
||||
*/
|
||||
public static function assertQueued($filePath, $disk = null, $callback = null)
|
||||
{
|
||||
/** @var \Maatwebsite\Excel\Fakes\ExcelFake $instance */
|
||||
return $instance->assertQueued($filePath, $disk, $callback);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @static
|
||||
*/
|
||||
public static function assertQueuedWithChain($chain)
|
||||
{
|
||||
/** @var \Maatwebsite\Excel\Fakes\ExcelFake $instance */
|
||||
return $instance->assertQueuedWithChain($chain);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param string $classname
|
||||
* @param callable|null $callback
|
||||
* @static
|
||||
*/
|
||||
public static function assertExportedInRaw($classname, $callback = null)
|
||||
{
|
||||
/** @var \Maatwebsite\Excel\Fakes\ExcelFake $instance */
|
||||
return $instance->assertExportedInRaw($classname, $callback);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param string $filePath
|
||||
* @param string|callable|null $disk
|
||||
* @param callable|null $callback
|
||||
* @static
|
||||
*/
|
||||
public static function assertImported($filePath, $disk = null, $callback = null)
|
||||
{
|
||||
/** @var \Maatwebsite\Excel\Fakes\ExcelFake $instance */
|
||||
return $instance->assertImported($filePath, $disk, $callback);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
namespace ProtoneMedia\LaravelFFMpeg\Support {
|
||||
/**
|
||||
*
|
||||
@@ -24332,6 +24643,49 @@ public static function getConfig()
|
||||
}
|
||||
}
|
||||
|
||||
namespace Illuminate\Support {
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @template TKey of array-key
|
||||
* @template-covariant TValue
|
||||
* @implements \ArrayAccess<TKey, TValue>
|
||||
* @implements \Illuminate\Support\Enumerable<TKey, TValue>
|
||||
*/
|
||||
class Collection {
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @see \Maatwebsite\Excel\Mixins\DownloadCollectionMixin::downloadExcel()
|
||||
* @param string $fileName
|
||||
* @param string|null $writerType
|
||||
* @param mixed $withHeadings
|
||||
* @param array $responseHeaders
|
||||
* @static
|
||||
*/
|
||||
public static function downloadExcel($fileName, $writerType = null, $withHeadings = false, $responseHeaders = [])
|
||||
{
|
||||
return \Illuminate\Support\Collection::downloadExcel($fileName, $writerType, $withHeadings, $responseHeaders);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @see \Maatwebsite\Excel\Mixins\StoreCollectionMixin::storeExcel()
|
||||
* @param string $filePath
|
||||
* @param string|null $disk
|
||||
* @param string|null $writerType
|
||||
* @param mixed $withHeadings
|
||||
* @static
|
||||
*/
|
||||
public static function storeExcel($filePath, $disk = null, $writerType = null, $withHeadings = false)
|
||||
{
|
||||
return \Illuminate\Support\Collection::storeExcel($filePath, $disk, $writerType, $withHeadings);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
namespace Illuminate\Http {
|
||||
/**
|
||||
*
|
||||
@@ -26881,6 +27235,64 @@ public static function mergeConstraintsFrom($from)
|
||||
return $instance->mergeConstraintsFrom($from);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @see \Maatwebsite\Excel\Mixins\DownloadQueryMacro::__invoke()
|
||||
* @param string $fileName
|
||||
* @param string|null $writerType
|
||||
* @param mixed $withHeadings
|
||||
* @static
|
||||
*/
|
||||
public static function downloadExcel($fileName, $writerType = null, $withHeadings = false)
|
||||
{
|
||||
return \Illuminate\Database\Eloquent\Builder::downloadExcel($fileName, $writerType, $withHeadings);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @see \Maatwebsite\Excel\Mixins\StoreQueryMacro::__invoke()
|
||||
* @param string $filePath
|
||||
* @param string|null $disk
|
||||
* @param string|null $writerType
|
||||
* @param mixed $withHeadings
|
||||
* @static
|
||||
*/
|
||||
public static function storeExcel($filePath, $disk = null, $writerType = null, $withHeadings = false)
|
||||
{
|
||||
return \Illuminate\Database\Eloquent\Builder::storeExcel($filePath, $disk, $writerType, $withHeadings);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @see \Maatwebsite\Excel\Mixins\ImportMacro::__invoke()
|
||||
* @param string $filename
|
||||
* @param string|null $disk
|
||||
* @param string|null $readerType
|
||||
* @static
|
||||
*/
|
||||
public static function import($filename, $disk = null, $readerType = null)
|
||||
{
|
||||
return \Illuminate\Database\Eloquent\Builder::import($filename, $disk, $readerType);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @see \Maatwebsite\Excel\Mixins\ImportAsMacro::__invoke()
|
||||
* @param string $filename
|
||||
* @param callable $mapping
|
||||
* @param string|null $disk
|
||||
* @param string|null $readerType
|
||||
* @static
|
||||
*/
|
||||
public static function importAs($filename, $mapping, $disk = null, $readerType = null)
|
||||
{
|
||||
return \Illuminate\Database\Eloquent\Builder::importAs($filename, $mapping, $disk, $readerType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the columns to be selected.
|
||||
*
|
||||
@@ -29666,6 +30078,7 @@ class Twitter extends \Artesaos\SEOTools\Facades\TwitterCard {}
|
||||
class OpenGraph extends \Artesaos\SEOTools\Facades\OpenGraph {}
|
||||
class Horizon extends \Laravel\Horizon\Horizon {}
|
||||
class Socialite extends \Laravel\Socialite\Facades\Socialite {}
|
||||
class Excel extends \Maatwebsite\Excel\Facades\Excel {}
|
||||
class FFMpeg extends \ProtoneMedia\LaravelFFMpeg\Support\FFMpeg {}
|
||||
class ResponseCache extends \Spatie\ResponseCache\Facades\ResponseCache {}
|
||||
class Hashids extends \Vinkla\Hashids\Facades\Hashids {}
|
||||
|
||||
BIN
database/.DS_Store
vendored
BIN
database/.DS_Store
vendored
Binary file not shown.
@@ -2,8 +2,8 @@
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
|
||||
BIN
database/seeders/.DS_Store
vendored
BIN
database/seeders/.DS_Store
vendored
Binary file not shown.
@@ -53,7 +53,7 @@ public function run(): void
|
||||
$csv_path = database_path('seeders/data/g2.csv');
|
||||
$meme_data = $this->parseCsvFile($csv_path);
|
||||
|
||||
$this->command->info('📊 Found ' . count($meme_data) . ' memes to import');
|
||||
$this->command->info('📊 Found '.count($meme_data).' memes to import');
|
||||
|
||||
// Process records individually for PostgreSQL compatibility
|
||||
$total_processed = 0;
|
||||
@@ -61,12 +61,13 @@ public function run(): void
|
||||
$total_failed = 0;
|
||||
|
||||
foreach ($meme_data as $index => $meme_record) {
|
||||
$this->command->info('Processing ' . ($index + 1) . '/' . count($meme_data) . ': ' . $meme_record['filename']);
|
||||
$this->command->info('Processing '.($index + 1).'/'.count($meme_data).': '.$meme_record['filename']);
|
||||
|
||||
// Skip empty or malformed records
|
||||
if (empty($meme_record['filename']) || empty($meme_record['type']) || empty($meme_record['name'])) {
|
||||
$this->command->warn("⏭️ Skipping malformed CSV record at line " . ($index + 1) . ": missing filename, type, or name");
|
||||
$this->command->warn('⏭️ Skipping malformed CSV record at line '.($index + 1).': missing filename, type, or name');
|
||||
$total_skipped++;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -93,12 +94,12 @@ public function run(): void
|
||||
}
|
||||
} else {
|
||||
$this->command->error("❌ Failed to import: {$meme_record['filename']} - Import returned false");
|
||||
$this->command->error("🛑 Halting seeder to investigate the issue");
|
||||
$this->command->error('🛑 Halting seeder to investigate the issue');
|
||||
throw new \RuntimeException("Import failed for {$meme_record['filename']}");
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
$this->command->error("❌ Failed to import: {$meme_record['filename']} - {$e->getMessage()}");
|
||||
$this->command->error("🛑 Halting seeder to investigate the issue");
|
||||
$this->command->error('🛑 Halting seeder to investigate the issue');
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
@@ -144,24 +145,24 @@ private function parseCsvFile(string $csv_path): array
|
||||
|
||||
// Use Laravel Excel to parse CSV with proper handling of multi-line fields
|
||||
$collection = Excel::toCollection(null, $csv_path)->first();
|
||||
|
||||
|
||||
if ($collection->isEmpty()) {
|
||||
throw new \RuntimeException("CSV file is empty or could not be parsed");
|
||||
throw new \RuntimeException('CSV file is empty or could not be parsed');
|
||||
}
|
||||
|
||||
|
||||
// Get headers from first row
|
||||
$headers = $collection->first()->toArray();
|
||||
|
||||
|
||||
// Convert remaining rows to associative arrays
|
||||
$meme_data = [];
|
||||
foreach ($collection->skip(1) as $row) {
|
||||
$row_array = $row->toArray();
|
||||
|
||||
|
||||
// Skip empty rows
|
||||
if (empty(array_filter($row_array))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// Ensure row has same number of columns as headers
|
||||
if (count($row_array) === count($headers)) {
|
||||
$record = array_combine($headers, $row_array);
|
||||
@@ -213,20 +214,20 @@ private function importSingleMeme(array $meme_record): bool
|
||||
'save_url', // Mode: just save URL reference
|
||||
null, // Auto-generate filename
|
||||
'r2', // Disk (not used for URL mode)
|
||||
trim($meme_record['name']) . " ({$format})", // Name with format
|
||||
trim($meme_record['name'])." ({$format})", // Name with format
|
||||
null, // No specific user
|
||||
$config['mime'] // MIME type
|
||||
);
|
||||
|
||||
$media_uuids[$format . '_uuid'] = $media->uuid;
|
||||
$media_urls[$format . '_url'] = $url;
|
||||
$media_uuids[$format.'_uuid'] = $media->uuid;
|
||||
$media_urls[$format.'_url'] = $url;
|
||||
} catch (\Exception $e) {
|
||||
$this->command->error("Failed to create {$format} media for {$meme_record['filename']}: {$e->getMessage()}");
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
//dump($meme_record);
|
||||
// dump($meme_record);
|
||||
|
||||
// // Generate embedding
|
||||
// try {
|
||||
@@ -238,7 +239,7 @@ private function importSingleMeme(array $meme_record): bool
|
||||
// $embedding = null; // Continue without embedding
|
||||
// }
|
||||
|
||||
//dd($embedding);
|
||||
// dd($embedding);
|
||||
|
||||
// Check if record exists one more time within transaction
|
||||
$existing_meme = MemeMedia::where('original_id', $meme_record['filename'])
|
||||
@@ -253,12 +254,12 @@ private function importSingleMeme(array $meme_record): bool
|
||||
|
||||
// Check for null description before creating record
|
||||
if ($meme_record['description'] === null) {
|
||||
$this->command->error("❌ NULL DESCRIPTION DETECTED:");
|
||||
$this->command->error('❌ NULL DESCRIPTION DETECTED:');
|
||||
$this->command->error(" Filename: {$meme_record['filename']}");
|
||||
$this->command->error(" Name: {$meme_record['name']}");
|
||||
$this->command->error(" Description field is NULL in CSV data");
|
||||
$this->command->error(" CSV row data: " . json_encode($meme_record));
|
||||
$this->command->error("🛑 HALTING SEEDER - FIX THE CSV DATA");
|
||||
$this->command->error(' Description field is NULL in CSV data');
|
||||
$this->command->error(' CSV row data: '.json_encode($meme_record));
|
||||
$this->command->error('🛑 HALTING SEEDER - FIX THE CSV DATA');
|
||||
throw new \RuntimeException("NULL description found for {$meme_record['filename']} - CSV data needs to be fixed");
|
||||
}
|
||||
|
||||
@@ -287,13 +288,13 @@ private function importSingleMeme(array $meme_record): bool
|
||||
]);
|
||||
|
||||
$meme_media->duration = MemeMediaMaintenance::getDurationUsingFfmpeg($meme_media);
|
||||
//$meme_media->embedding = $embedding;
|
||||
// $meme_media->embedding = $embedding;
|
||||
$meme_media->save();
|
||||
|
||||
// Add keywords as tags
|
||||
$this->attachKeywordsAsTags($meme_media, $meme_record['keywords']);
|
||||
|
||||
$this->command->info('✅ Imported: ' . trim($meme_record['name']));
|
||||
$this->command->info('✅ Imported: '.trim($meme_record['name']));
|
||||
|
||||
return true;
|
||||
} catch (\Exception $e) {
|
||||
@@ -307,7 +308,7 @@ private function attachKeywordsAsTags(MemeMedia $meme_media, array $keywords): v
|
||||
try {
|
||||
$meme_media->attachTags($keywords, 'meme_media');
|
||||
} catch (\Exception $e) {
|
||||
$this->command->warn("Failed to attach tags to meme media '{$meme_media->name}': " . $e->getMessage());
|
||||
$this->command->warn("Failed to attach tags to meme media '{$meme_media->name}': ".$e->getMessage());
|
||||
Log::warning('Failed to attach tags', [
|
||||
'category_id' => $meme_media->id,
|
||||
'keywords' => $keywords,
|
||||
@@ -321,7 +322,7 @@ private function attachKeywordsAsTags(MemeMedia $meme_media, array $keywords): v
|
||||
*/
|
||||
private function generateCdnUrl(string $base_filename, string $extension): string
|
||||
{
|
||||
return self::CDN_BASE_URL . "/{$extension}/{$base_filename}.{$extension}";
|
||||
return self::CDN_BASE_URL."/{$extension}/{$base_filename}.{$extension}";
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -5,27 +5,28 @@ const FAQDiscord = () => {
|
||||
const faqData = [
|
||||
{
|
||||
q: 'How can I create a meme video?',
|
||||
a: 'Use the video editor on top to start making your meme! Edit your caption, background and meme. Once satisfied, press the Export button to download your video!',
|
||||
},
|
||||
{
|
||||
q: 'What features are available now?',
|
||||
a: 'At the moment, All 200+ meme templates and 200+ backgrounds are completely free! We will be adding more memes and backgrounds to the library soon!',
|
||||
a: 'Use the video editor on top to start making your meme!<br><br>Edit your caption, background and meme. Once satisfied, press the Export button to download your video!',
|
||||
},
|
||||
|
||||
{
|
||||
q: 'Why is video export slow for me?',
|
||||
a: 'Video processing happens entirely in your browser using advanced web technology. Export speed depends on your video content complexity and device performance. High-end devices export quickly, while older/slower devices may take longer or even crash. If your phone is too slow, try using a faster device like a desktop computer for better performance.',
|
||||
a: "Video processing happens entirely in your browser using advanced web technology.<br><br> Export speed depends on your video content complexity and device performance. High-end devices export quickly, while older/slower devices may take longer or even crash. <br><br>If your phone is too slow, it's probably a potato. Try using a faster device like a desktop computer for better performance.",
|
||||
},
|
||||
{
|
||||
q: 'What is a potato device?',
|
||||
a: `Potato devices are old, dated computers, laptops, phones or tablets with little RAM and CPU power - typically devices from before ${new Date().getFullYear() - 6} (pre-${new Date().getFullYear() - 6}).<br><br>These devices are usually too weak for the modern web and may not work properly with our video editor, or may crash during video processing.`,
|
||||
},
|
||||
{
|
||||
q: 'What video format do you export?',
|
||||
a: 'We export high-quality MP4 videos optimized for all social media platforms in 9:16 format, which is compatible for TikTok, Youtube Shorts, Instagram Reels, and more.',
|
||||
a: 'We export high-quality MP4 videos optimized for all social media platforms in 9:16 format.<br><br>This is compatible for TikTok, Youtube Shorts, Instagram Reels, and more.',
|
||||
},
|
||||
{
|
||||
q: 'Is there a mobile app?',
|
||||
a: "Our web app is fully responsive and works perfectly on mobile devices. Do you want a mobile app? We'll see what can be done. Let us know in our Discord group.",
|
||||
a: "Our web app is fully responsive and works perfectly on mobile devices.<br><br>Do you want a mobile app? We'll see what can be done. Let us know in our Discord group.",
|
||||
},
|
||||
{
|
||||
q: 'How often do you add new content?',
|
||||
a: 'We just started building this platform and will gradually add more meme templates and backgrounds over time, so everyone can continue using it for free with fresh content! Want a certain content? Let us know in our Discord group.',
|
||||
a: 'We just started building this platform and will gradually add more meme templates and backgrounds over time, so everyone can continue using it for free with fresh content!<br><br>Want a certain content? Let us know in our Discord group.',
|
||||
},
|
||||
{
|
||||
q: 'I have more questions!',
|
||||
@@ -49,7 +50,9 @@ const FAQDiscord = () => {
|
||||
{faqData.map((faq, index) => (
|
||||
<AccordionItem key={index} value={`item-${index + 1}`} className="border-b last:border-b-0">
|
||||
<AccordionTrigger className="py-4 text-left font-medium hover:no-underline">{faq.q}</AccordionTrigger>
|
||||
<AccordionContent className="text-muted-foreground pb-4 leading-relaxed text-balance">{faq.a}</AccordionContent>
|
||||
<AccordionContent className="text-muted-foreground pb-4 leading-relaxed text-balance">
|
||||
<div dangerouslySetInnerHTML={{ __html: faq.a }} />
|
||||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
))}
|
||||
</Accordion>
|
||||
|
||||
@@ -4,28 +4,31 @@ const Features = () => {
|
||||
const features = [
|
||||
{
|
||||
icon: Video,
|
||||
title: 'Web-powered Video Editor',
|
||||
description: 'Easy video editor with editable text, background, memes, built into the web. No additional software required.',
|
||||
title: 'No installation needed',
|
||||
description: 'Easy video editor with editable text, background, memes, built into the web.',
|
||||
gradient: 'bg-gradient-to-br from-transparent to-blue-500/5 dark:to-blue-400/10 hover:bg-gradient-to-tl',
|
||||
order: 3,
|
||||
},
|
||||
{
|
||||
icon: Heart,
|
||||
title: 'Built-in over 200+ memes, for now',
|
||||
description: 'Access meme and background with our editor without paying a cent.',
|
||||
gradient: 'bg-gradient-to-br from-transparent to-pink-500/5 dark:to-pink-400/10 hover:bg-gradient-to-tl',
|
||||
order: 1,
|
||||
},
|
||||
|
||||
{
|
||||
icon: Download,
|
||||
title: 'Export in minutes',
|
||||
description: 'Download high-quality 720p MP4 videos optimized for TikTok, Youtube Shorts, Instagram Reels, and more.',
|
||||
gradient: 'bg-gradient-to-br from-transparent to-green-500/5 dark:to-green-400/10 hover:bg-gradient-to-tl',
|
||||
order: 2,
|
||||
},
|
||||
{
|
||||
icon: Smartphone,
|
||||
title: 'Works Everywhere',
|
||||
description: 'Create on desktop, tablet, or mobile! Potato devices not recommended though.',
|
||||
gradient: 'bg-gradient-to-br from-transparent to-purple-500/5 dark:to-purple-400/10 hover:bg-gradient-to-tl',
|
||||
order: 4,
|
||||
},
|
||||
{
|
||||
icon: Library,
|
||||
@@ -33,6 +36,7 @@ const Features = () => {
|
||||
description: 'Soon we will be adding more memes and backgrounds to the library!',
|
||||
comingSoon: true,
|
||||
gradient: 'bg-gradient-to-br from-transparent to-orange-500/5 dark:to-orange-400/10 hover:bg-gradient-to-tl',
|
||||
order: 5,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -40,26 +44,28 @@ const Features = () => {
|
||||
<section className="">
|
||||
<div className="mx-auto max-w-6xl space-y-10 px-4 sm:px-6 lg:px-8">
|
||||
<div className="flex flex-wrap justify-center gap-3 md:grid-cols-2 lg:grid-cols-3 lg:gap-4">
|
||||
{features.map((feature, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className={`group hover:bg-muted/50 relative h-auto min-h-[275px] w-[275px] rounded-2xl border p-6 shadow-lg ${feature.gradient} transition-all duration-300 lg:p-8`}
|
||||
>
|
||||
{feature.comingSoon && (
|
||||
<div className="bg-foreground text-background absolute -top-2 -right-2 rounded-full px-2 py-1 text-xs font-medium">
|
||||
Coming Soon!
|
||||
{features
|
||||
.sort((a, b) => a.order - b.order)
|
||||
.map((feature, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className={`group hover:bg-muted/50 relative h-auto min-h-[275px] w-[275px] rounded-2xl border p-6 shadow-lg ${feature.gradient} transition-all duration-300 lg:p-8`}
|
||||
>
|
||||
{feature.comingSoon && (
|
||||
<div className="bg-foreground text-background absolute -top-2 -right-2 rounded-full px-2 py-1 text-xs font-medium">
|
||||
Coming Soon!
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="mb-4">
|
||||
<feature.icon className="text-foreground h-8 w-8" />
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="mb-4">
|
||||
<feature.icon className="text-foreground h-8 w-8" />
|
||||
<h3 className="text-foreground mb-2 text-xl font-semibold">{feature.title}</h3>
|
||||
|
||||
<p className="text-muted-foreground leading-relaxed">{feature.description}</p>
|
||||
</div>
|
||||
|
||||
<h3 className="text-foreground mb-2 text-xl font-semibold">{feature.title}</h3>
|
||||
|
||||
<p className="text-muted-foreground leading-relaxed">{feature.description}</p>
|
||||
</div>
|
||||
))}
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -8,7 +8,7 @@ const Hero = () => {
|
||||
{/* Badge */}
|
||||
<div className="bg-background/50 inline-flex items-center gap-2 rounded-full border px-3 py-1 text-sm backdrop-blur-sm">
|
||||
<div className="h-2 w-2 rounded-full bg-green-500"></div>
|
||||
<span className="text-muted-foreground">Free meme videos • No signup required</span>
|
||||
<span className="text-muted-foreground">Instant meme videos • No signup required</span>
|
||||
</div>
|
||||
|
||||
{/* Main heading */}
|
||||
@@ -19,7 +19,7 @@ const Hero = () => {
|
||||
</h1>
|
||||
|
||||
<h2 className="text-muted-foreground mx-auto max-w-4xl text-xl leading-relaxed font-light sm:text-2xl lg:text-3xl">
|
||||
Simple, fast, and free meme video editor
|
||||
Fast and simple meme video editor
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user