李帅

1.重构模板和临境上传功能

......@@ -9,3 +9,11 @@
- composer install
- php artisan admin:publish
- php artisan admin:install
## todo
- 合成优化
- 登录、注册(仅邮箱)
- 支付(Paypal)
......
<?php
namespace App\Admin\Controllers;
use App\Admin\Renderable\PoemTable;
use App\Admin\Renderable\TemplateTable;
use App\Jobs\MakeVideo;
use App\Models\AdminMakeVideo;
use App\Models\Order;
use Dcat\Admin\Form;
use Dcat\Admin\Grid;
use Dcat\Admin\Layout\Content;
use Dcat\Admin\Show;
use Dcat\Admin\Http\Controllers\AdminController;
class AdminMakeVideoController extends AdminController
{
/**
* Make a grid builder.
*
* @return Grid
*/
protected function grid()
{
return Grid::make(new AdminMakeVideo(), function (Grid $grid) {
$grid->column('id')->sortable();
$grid->column('poem_id');
$grid->column('type');
$grid->column('video_url');
$grid->column('images_url');
$grid->column('bg_music');
$grid->column('bgm_url');
$grid->column('feel');
$grid->column('temp_id');
$grid->column('thumbnail');
$grid->column('thumbnail_url');
$grid->column('created_at');
$grid->column('updated_at')->sortable();
$grid->filter(function (Grid\Filter $filter) {
$filter->equal('id');
});
});
}
/**
* Make a show builder.
*
* @param mixed $id
*
* @return Show
*/
protected function detail($id)
{
return Show::make($id, new AdminMakeVideo(), function (Show $show) {
$show->field('id');
$show->field('poem_id');
$show->field('type');
$show->field('video_url');
$show->field('images_url');
$show->field('bg_music');
$show->field('bgm_url');
$show->field('feel');
$show->field('temp_id');
$show->field('thumbnail');
$show->field('thumbnail_url');
$show->field('created_at');
$show->field('updated_at');
});
}
/**
* Make a form builder.
*
* @return Form
*/
protected function form()
{
return Form::make(new AdminMakeVideo(), function (Form $form) {
$form->display('id');
$form->selectTable('poem_id','选择一言')
->title('一言诗词库')
->from(PoemTable::make());
$form->radio('type')
->options([1=>'视频', 2=>'图文音频'])
->when(1,function (Form $form){
$form->file('video_url','上传视频')
->accept('mp4')
->autoUpload()
->uniqueName()
->maxSize('102400')
->addElementClass('video_url');
})
->when(2,function (Form $form){
$form->multipleImage('images_url','上传图片')
->limit(5)
->uniqueName()
->addElementClass('images_url');
})
->default(1);
$form->radio('bg_music','背景音')
->options(['无', '有'])
->when(1,function (Form $form){
$form->file('bgm_url','上传背景音')
->accept('mp3,aac,wav')
->autoUpload()
->uniqueName()
->addElementClass('bg_music');
})
->default(0);
$form->textarea('feel','有感');
$form->selectTable('temp_id','选择模板')
->title('模板选择')
->from(TemplateTable::make());
$form->radio('thumbnail','封面')
->options([1=>'手动上传', 2=>'自动截屏'])
->when(1,function (Form $form){
$form->multipleImage('thumbnail_url','上传图片')
->limit(5)
->uniqueName();
// ->addElementClass('bg_img_url');
})
->when(2,function (Form $form){
$form->html('');
})
->default(1);
$form->display('created_at');
$form->display('updated_at');
});
}
public function store()
{
$all = request()->all();
if (isset($all['upload_column'])) return $this->form()->store();
try{
$video = AdminMakeVideo::query()->create($all);
// 添加至队列
MakeVideo::dispatch($video);
}catch (\Exception $exception){
return $this->form()->response()->error($exception->getMessage());
}
return $this->form()->response()->refresh()->success(trans('admin.save_succeeded'));
}
}
......@@ -5,7 +5,7 @@ namespace App\Admin\Controllers;
use App\Admin\Renderable\PoemTable;
use App\Admin\Renderable\TemplateTable;
use App\Admin\Repositories\VideoShow;
use App\Models\OnePoem;
use App\Models\AdminMakeVideo;
use Dcat\Admin\Form;
use Dcat\Admin\Grid;
use Dcat\Admin\Show;
......@@ -63,30 +63,28 @@ class VideoShowController extends AdminController
*/
protected function form()
{
return Form::make(new VideoShow(), function (Form $form) {
return Form::make(new AdminMakeVideo(), function (Form $form) {
$form->display('id');
$form->selectTable('poem_id','选择一言')
->title('一言诗词库')
->from(PoemTable::make());
// $form->radio('type')->addElementClass('type')
// ->options([1=>'图文音频',2=>'视频'])->default(1);
$form->radio('type')
->options([1=>'视频', 2=>'图文音频'])
->when(1,function (Form $form){
$form->file('bg_url','上传视频')
$form->file('video_url','上传视频')
->accept('mp4')
->autoUpload()
->uniqueName()
->addElementClass('bg_video_url');
->maxSize('102400')
->addElementClass('video_url');
})
->when(2,function (Form $form){
$form->multipleImage('bg_url','上传图片')
$form->multipleImage('images_url','上传图片')
->limit(5)
->uniqueName()
->addElementClass('bg_img_url');
->addElementClass('images_url');
})
->default(1);
$form->radio('bg_music','背景音')
......@@ -96,23 +94,23 @@ class VideoShowController extends AdminController
->accept('mp3,aac,wav')
->autoUpload()
->uniqueName()
->addElementClass('bgm_url');
->addElementClass('bg_music');
})
->default(0);
$form->textarea('feel','有感');
$form->selectTable('poem_id','选择模板')
$form->selectTable('temp_id','选择模板')
->title('模板选择')
->from(TemplateTable::make());
$form->radio('thumbnail','封面')
->options([1=>'手动上传', 2=>'选择截屏'])
->options([1=>'手动上传', 2=>'自动截屏'])
->when(1,function (Form $form){
$form->multipleImage('bg_url','上传图片')
$form->multipleImage('thumbnail_url','上传图片')
->limit(5)
->uniqueName()
->addElementClass('bg_img_url');
->uniqueName();
// ->addElementClass('bg_img_url');
})
->when(2,function (Form $form){
$form->html('');
......@@ -123,4 +121,22 @@ class VideoShowController extends AdminController
$form->display('updated_at');
});
}
public function store()
{
$all = request()->all();
if (isset($all['upload_column'])) return $this->form()->store();
try{
$video = AdminMakeVideo::query()->create($all);
// todo 添加至队列
}catch (\Exception $exception){
return $this->form()->response()->error($exception->getMessage());
}
return $this->form()->response()->refresh()->success(trans('admin.save_succeeded'));
}
}
......
......@@ -171,33 +171,23 @@ class VideoTempController extends AdminController
$form->checkbox('components','组件')
->when('every_poem', function (Form\BlockForm $form) {
$form->select('pos_every_poem', '每日位置')->options([
'topLeft'=>'上左','topMiddle'=>'上中','topRight'=>'上右',
]);
$form->select('pos_every_poem', '每日位置')->options(VideoTemp::POSITION_OPTIONS);
$form->divider();
})
->when('one_poem', function (Form\BlockForm $form) {
$form->select('pos_one_poem', '一言位置')->options([
'topLeft'=>'上左','topMiddle'=>'上中','topRight'=>'上右',
]);
$form->select('pos_one_poem', '一言位置')->options(VideoTemp::POSITION_OPTIONS);
$form->divider();
})
->when('weather', function (Form\BlockForm $form) {
$form->select('pos_weather', '天气位置')->options([
'topLeft'=>'上左','topMiddle'=>'上中','topRight'=>'上右',
]);
$form->select('pos_weather', '天气位置')->options(VideoTemp::POSITION_OPTIONS);
$form->divider();
})
->when('date', function (Form\BlockForm $form) {
$form->select('pos_date', '日期位置')->options([
'topLeft'=>'上左','topMiddle'=>'上中','topRight'=>'上右',
]);
$form->select('pos_date', '日期位置')->options(VideoTemp::POSITION_OPTIONS);
$form->divider();
})
->when('feel', function (Form\BlockForm $form) {
$form->select('pos_feel', '有感位置')->options([
'topLeft'=>'上左','topMiddle'=>'上中','topRight'=>'上右',
]);
$form->select('pos_feel', '有感位置')->options(VideoTemp::POSITION_OPTIONS);
$form->divider();
})
->default(['one_poem','weather','date'])
......@@ -228,7 +218,7 @@ class VideoTempController extends AdminController
public function store()
{
$all = \request()->all();
dd($all);
try{
DB::transaction(function ()use ($all){
$vide_temp = VideoTemp::query()->create([
......
<?php
namespace App\Admin\Repositories;
use App\Models\AdminMakeVideo as Model;
use Dcat\Admin\Repositories\EloquentRepository;
class AdminMakeVideo extends EloquentRepository
{
/**
* Model.
*
* @var string
*/
protected $eloquentClass = Model::class;
}
......@@ -27,7 +27,7 @@ Route::group([
/** 临境*/
$router->group(['prefix'=>'/linjing'],function (Router $router){
$router->resource('/template', 'VideoTempController');
$router->resource('/official', 'VideoShowController');
$router->resource('/official', 'AdminMakeVideoController');
});
/** 订单*/
......
<?php
namespace App\Jobs;
use App\Models\AdminMakeVideo;
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 Illuminate\Support\Facades\Storage;
class MakeVideo implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public $adminMakeVideo;
protected $ffmpeg = '/Users/lishuai/Documents/ffmpeg/ffmpeg';
protected $ffprobe = '/Users/lishuai/Documents/ffmpeg/ffprobe';
protected $ffplay = '/Users/lishuai/Documents/ffmpeg/ffplay';
/**
* Create a new job instance.
* @param AdminMakeVideo $adminMakeVideo
* @return void
*/
public function __construct(AdminMakeVideo $adminMakeVideo)
{
$this->adminMakeVideo = $adminMakeVideo;
}
/**
* Execute the job.
*
* @return void
*/
public function handle()
{
// 执行合成逻辑
$file = Storage::disk('public')->path('ffmpeg') . "/output_1646128658383.mp4";
$watermark = Storage::disk('public')->path('ffmpeg') . "/LOGO_eng.png";
$watermark_x = 20;
$watermark_y = 20;
$animate = Storage::disk('public')->path('ffmpeg') . "/output_16461288409938.mp4";
$video = $this->getTempPath();
$watermark_x = $watermark_x ? $watermark_x : 0;
$watermark_y = $watermark_y ? $watermark_y : 0;
$am_inp = ' -i ' . escapeshellarg($watermark);
$am_filter = "[2:v]overlay={$watermark_x}:{$watermark_y}[water];[water]";
$cmd = $this->ffmpeg . ' -y' .
' -i ' . escapeshellarg($file) .
' -i ' . escapeshellarg($animate) .
$am_inp .
// ' -filter_complex "[0:0]' . '' . $am_filter . 'setsar=sar=1/1[t];[t] [2:a] [1:0] [1:1] concat=n=2:v=1:a=1 [v] [a]"' .
' -filter_complex "[0:0]' . '' . $am_filter . '[0:1] [1:0] [1:1] concat=n=2:v=1:a=1 [v] [a]"' .
' -map [v] -map [a]';
$cmd .=
' -c:v libx264 -s 800x450 -bt 256k -r 25' .
// todo 没有libfdk_aac库
// ' -c:a libfdk_aac -ar 44100 -ac 2 -qmin 30 -qmax 60 -profile:v baseline -preset fast ' .
' -ar 44100 -ac 2 -qmin 30 -qmax 60 -profile:v baseline -preset fast ' .
escapeshellarg($video);
if ($this->execmd($cmd)) {
return $video;
} else {
return false;
}
}
/**
* 获取圆形头像
* @param $img
* @param int $dst_w
* @param int $dst_h
* @return resource
*/
public function getCircleAvatar($img, $dst_w = 96, $dst_h = 96)
{
$w = 130;
$h = 130;
$src = imagecreatetruecolor($dst_w, $dst_h);
imagecopyresized($src, $img, 0, 0, 0, 0, $dst_w, $dst_h, $w, $h);
$newpic = imagecreatetruecolor($dst_w, $dst_h);
imagealphablending($newpic, false);
imagecopyresampled($newpic, $img, 0, 0, 0, 0, $dst_w, $dst_h, $w, $h);
$mask = imagecreatetruecolor($dst_w, $dst_h);
$transparent = imagecolorallocate($mask, 255, 0, 0);
imagecolortransparent($mask,$transparent);
imagefilledellipse($mask, $dst_w / 2, $dst_h / 2, $dst_w, $dst_h, $transparent);
$red = imagecolorallocate($mask, 0, 0, 0);
imagecopymerge($newpic, $mask, 0, 0, 0, 0, $dst_w, $dst_h, 100);
imagecolortransparent($newpic,$red);
imagesavealpha($newpic,true);
imagefill($newpic, 0, 0, $red);
imagedestroy($mask);
return $newpic;
}
/**
* 制作最后一帧
* @param $file
* @return bool|string
*/
public function makeLastFrameVideo($file) {
$video = $this->getTempPath();
$width = $this->getVideoWith($file);
$height = $this->getVideoHeight($file);
$size = $width . 'x' . $height;
$time_length = 0.7;
$r = 24;
$frame_n = $this->getVideoFrameNum($file) - 2;
$cmd = $this->ffmpeg . ' -y -i ' . escapeshellarg($file) .
" -f lavfi -i nullsrc=s={$size}:d={$time_length}:r={$r} -f lavfi -i aevalsrc=0:duration={$time_length}" .
" -filter_complex \"[0:v]select='eq(n,{$frame_n})',setpts=PTS-STARTPTS[lastframe];[1:v][lastframe]overlay[v]\"" .
' -map [v] -map 2:a ' . escapeshellarg($video);
if ($this->execmd($cmd)) {
return $video;
} else {
return false;
}
}
/**
* 用最后一帧和贴纸制作动画
* @param $last_frame_video
* @param $end_wallpaper
* @param $signature
* @param $signature_x
* @param $signature_y
* @param $font
* @return bool|string
*/
public function makeAnimate($last_frame_video, $end_wallpaper, $signature, $signature_x, $signature_y, $font) {
$signature_x = $signature_x >= 0 ? '+' . $signature_x : '-' . abs($signature_x);
$signature_y = $signature_y >= 0 ? '+' . $signature_y : '-' . abs($signature_y);
$video = $this->getTempPath();
if ($signature !== '') {
$cmd = $this->ffmpeg . ' -y -i ' . escapeshellarg($last_frame_video) .
' -loop 1 -i ' . escapeshellarg($end_wallpaper) .
' -filter_complex "'.
'geq=lum=\'if(lte(T,0.6), 255*T*(1/0.6),255)\',format=gray[grad];'.
'[0:v]boxblur=8[blur];'.
'[blur][1:v]overlay=(main_w-overlay_w)/2:(main_h-overlay_h)/2 [lay];[lay]'.
'drawtext='.
'fontfile=' . escapeshellarg($font) . ':'.
'text=' . escapeshellarg($signature) . ':'.
'fontsize=23:'.
'fontcolor=white@1.0:'.
'x=main_w/2' . $signature_x . ':'.
'y=main_h/2' . $signature_y . '[text];[text]'.
'[grad]alphamerge[alpha];'.
'[0:v][alpha]overlay'.
'" ' . escapeshellarg($video);
} else {
$cmd = $this->ffmpeg . ' -y -i ' . escapeshellarg($last_frame_video) .
' -loop 1 -i ' . escapeshellarg($end_wallpaper) .
' -filter_complex "'.
'geq=lum=\'if(lte(T,0.6), 255*T*(1/0.6),255)\',format=gray[grad];'.
'[0:v]boxblur=8[blur];'.
'[blur][1:v]overlay=(main_w-overlay_w)/2:(main_h-overlay_h)/2 [lay];'.
'[lay][grad]alphamerge[alpha];'.
'[0:v][alpha]overlay'.
'" ' . escapeshellarg($video);
}
if ($this->execmd($cmd)) {
return $video;
} else {
return false;
}
}
/**
* 获取视频宽度
* @param $file
* @param bool $cache
* @return int|null
*/
public function getVideoWith($file, $cache = true) {
$result = $this->getFirstVideoTrackOption($file, $option = 'width', $cache);
if ($result) {
return (int)$result;
} else {
return $result;
}
}
/**
* 获取视频高度
* @param $file
* @param bool $cache
* @return int|null
*/
public function getVideoHeight($file, $cache = true) {
$result = $this->getFirstVideoTrackOption($file, $option = 'height', $cache);
if ($result) {
return (int)$result;
} else {
return $result;
}
}
/**
* 获取视频帧数
* @param $file
* @param bool $cache
* @return null
*/
public function getVideoFrameNum($file, $cache = true) {
return $this->getFirstVideoTrackOption($file, $option = 'nb_frames', $cache);
}
public function getFirstVideoTrackOption($file, $option, $cache = true) {
return $this->getFirstTrackOption($file, $option, $codec_type = 'video', $cache = true);
}
public function getFirstTrackOption($file, $option, $codec_type = '', $cache = true) {
$result = $this->mediainfo($file, $cache);
if (!isset($result['streams'])) {
return null;
}
$_track = null;
foreach($result['streams'] as $track) {
if (empty($codec_type)) {
$_track = $track;
break;
} elseif ($track['codec_type'] == $codec_type) {
$_track = $track;
break;
}
}
if (isset($_track[$option])) {
return $_track[$option];
}
return null;
}
/***
* 获取视频信息(配合ffprobe)
* @param $file
* @param bool $cache
* @return mixed
*/
public function mediainfo($file, $cache = true) {
global $_mediainfo;
$cmd = $this->ffprobe . ' -v quiet -print_format json -show_format -show_streams ' . escapeshellarg($file);
if ($cache && isset($_mediainfo[$file])) {
return $_mediainfo[$file];
}
$output = $this->execmd($cmd);
$data = json_decode($output, true);
if (json_last_error() === JSON_ERROR_UTF8) {
$output = mb_convert_encoding($output, "UTF-8");
$data = json_decode($output, true);
}
if ($cache) {
$mediainfo[$file] = $data;
}
return $data;
}
/**
* 获取输出临时文件名
* @return string
*/
public function getTempPath() {
return Storage::disk('public')->path('ffmpeg') . "/output_" . time() . rand(0, 10000) . ".mp4";
}
/**
* 执行命令
* @param $cmd
* @param bool $update_progress
* @return string
*/
public function execmd($cmd, $update_progress = false) {
echo $cmd . "\n". "\n". "\n";
$descriptorspec = array(
1 => array("pipe", "w"), // 标准输出,子进程向此管道中写入数据
);
$process = proc_open("{$cmd} 2>&1", $descriptorspec, $pipes);
if (is_resource($process)) {
$error0 = '';
$error1 = '';
$stdout = '';
while (!feof($pipes[1])) {
$line = fgets($pipes[1], 150);
$stdout .= $line;
if ($line) {
//记录错误
$error0 = $error1;
$error1 = $line;
if ($update_progress &&
false !== strpos($line, 'size=') &&
false !== strpos($line, 'time=') &&
false !== strpos($line, 'bitrate='))
{
//记录进度 size= 3142kB time=00:00:47.22 bitrate= 545.1kbits/s
$line = explode(' ', $line);
$time = null;
foreach ($line as $item) {
$item = explode('=', $item);
if (isset($item[0]) && isset($item[1]) && $item[0] == 'time') {
$time = $item[1];
break;
}
}
}
}
}
// 切记:在调用 proc_close 之前关闭所有的管道以避免死锁。
fclose($pipes[1]);
$exitedcode = proc_close($process);
if ($exitedcode === 0) {
return $stdout;
} else {
$error = trim($error0,"\n") . ' '. trim($error1,"\n");
// LogUtil::write(array("cmd:{$cmd}", "errno:{$exitedcode}", "stdout:{$stdout}"), __CLASS__);
// ErrorUtil::triggerErrorMsg($error, $exitedcode);
}
} else {
// return ErrorUtil::triggerErrorMsg('proc_open error');
}
}
/**
* 贴纸和签名
* @param $end_wallpaper
* @param $thumbnail
* @param $signature
* @param $font
* @return string
*/
public function wallpaperWithSignature($end_wallpaper, $thumbnail, $signature, $font) {
$_imagetype = $this->getImageType($thumbnail);
$_img = null;
switch ($_imagetype) {
case 'gif':
if (function_exists('imagecreatefromgif')) {
$_img = imagecreatefromgif($thumbnail);
}
break;
case 'jpg':
case 'jpeg':
$_img = imagecreatefromjpeg($thumbnail);
break;
case 'png':
$_img = imagecreatefrompng($thumbnail);
break;
default:
$_img = imagecreatefromstring($thumbnail);
break;
}
$width = 130;
$height = 130;
$_width = 130;
$_height = 130;
if(is_resource($_img)){
$_width = imagesx($_img);
$_height = imagesy($_img);
}
$bite = $_width / $_height;
if($_width > $_height){
if($_width > $width){
$height = round($width / $bite);
}
}else{
if($_height > $height){
$width = round($height * $bite);
}
}
$tmpimg = imagecreatetruecolor($width,$height);
if(function_exists('imagecopyresampled')) {
imagecopyresampled($tmpimg, $_img, 0, 0, 0, 0, $width, $height, $_width, $_height);
} else {
imagecopyresized($tmpimg, $_img, 0, 0, 0, 0, $width, $height, $_width, $_height);
}
if(is_resource($_img)) imagedestroy($_img);
$_img = $this->getCircleAvatar($tmpimg);
if(is_resource($tmpimg)) imagedestroy($tmpimg);
$wp = $this->imagesMerge($end_wallpaper, $_img);
// $white = imagecolorallocate($wp, 0xd0, 0xcd, 0xcc);
$white = imagecolorallocate($wp, 0xDC, 0x14, 0x3C); //fixme 字体颜色
imagettftext($wp, 20, 0, 75, 240, $white, $font, $signature);
// $dst = "./output_new_end_wallpaper.png";
$dst = Storage::disk('public')->path('ffmpeg') . "/output_new_end_wallpaper.png";
imagepng($wp, $dst);
if(is_resource($end_wallpaper)) imagedestroy($end_wallpaper);
if(is_resource($_img)) imagedestroy($_img);
return $dst;
}
/**
* 获取图像文件类型
* @param $img_name
* @return string
*/
public function getImageType($img_name)
{
if (preg_match("/\.(jpg|jpeg|gif|png)$/i", $img_name, $matches)){
$type = strtolower($matches[1]);
}else{
$type = "string";
}
return $type;
}
/**
* 多图融合
* @param $end_wallpaper
* @param $thumbnail
* @return resource
*/
public function imagesMerge($end_wallpaper, $thumbnail) {
$end_wallpaper = imagecreatefrompng($end_wallpaper);
$background = imagecreatefrompng(Storage::disk('public')->path('ffmpeg/background.png'));
imagesavealpha($background,true);
$temp_wallpaper = imagecreatetruecolor(350, 204);
$color = imagecolorallocate($temp_wallpaper, 0xd0, 0xcd, 0xcc);
// $color = imagecolorallocate($temp_wallpaper, 0xDC, 0x14, 0x3C);
imagefill($temp_wallpaper, 0, 0, $color);
imageColorTransparent($temp_wallpaper, $color);
imagecopyresampled($temp_wallpaper, $end_wallpaper, 0, 0, 0, 0, imagesx($temp_wallpaper), imagesy($temp_wallpaper), imagesx($end_wallpaper), imagesy($end_wallpaper));
imagecopymerge($background, $temp_wallpaper, 0, 0, 0, 0, imagesx($temp_wallpaper), imagesy($temp_wallpaper), 60);
imagecopymerge($background, $thumbnail, 127, 26, 0, 0, imagesx($thumbnail), imagesy($thumbnail), 100);
return $background;
}
}
<?php
namespace App\Models;
use Dcat\Admin\Traits\HasDateTimeFormatter;
use Illuminate\Database\Eloquent\Model;
class AdminMakeVideo extends Model
{
use HasDateTimeFormatter;
protected $table = 'admin_make_video';
protected $guarded = [''];
}
......@@ -51,6 +51,7 @@ class Order extends Model
public function timeoutCanceled()
{
$this->status = self::TIMEOUT_CANCEL;
$this->save();
}
}
\ No newline at end of file
......
......@@ -9,6 +9,13 @@ use Illuminate\Database\Eloquent\Model;
class VideoTemp extends Model
{
use HasDateTimeFormatter;
const POSITION_OPTIONS = [
'topLeft'=>'上左','topMiddle'=>'上中','topRight'=>'上右',
'midLeft'=>'中左','midMiddle'=>'中中','midRight'=>'中右',
'botLeft'=>'下左','botMiddle'=>'下中','botRight'=>'下右',
];
protected $table = 'video_temp';
protected $guarded = [''];
......
......@@ -221,7 +221,7 @@ return [
'Queue' => Illuminate\Support\Facades\Queue::class,
'RateLimiter' => Illuminate\Support\Facades\RateLimiter::class,
'Redirect' => Illuminate\Support\Facades\Redirect::class,
// 'Redis' => Illuminate\Support\Facades\Redis::class,
'Redis' => Illuminate\Support\Facades\Redis::class,
'Request' => Illuminate\Support\Facades\Request::class,
'Response' => Illuminate\Support\Facades\Response::class,
'Route' => Illuminate\Support\Facades\Route::class,
......
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateAdminMakeVideoTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('admin_make_video', function (Blueprint $table) {
$table->increments('id');
$table->string('poem_id')->default('')->comment('一言id');
$table->unsignedTinyInteger('type')->comment('类型');
$table->string('video_url')->nullable()->comment('视频地址');
$table->string('images_url')->nullable()->comment('图片地址');
$table->unsignedTinyInteger('bg_music')->comment('是否背景音');
$table->string('bgm_url')->nullable()->comment('背景音地址');
$table->string('feel')->default('')->comment('有感');
$table->string('temp_id')->default('')->comment('模板id');
$table->unsignedTinyInteger('thumbnail')->comment('封面图');
$table->string('thumbnail_url')->nullable()->comment('封面图地址');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('admin_make_video');
}
}