Compare commits
3 Commits
b158ec6b5d
...
21f61b0911
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
21f61b0911 | ||
|
|
086e4b56b5 | ||
|
|
c5f4a8ed2d |
@@ -18,7 +18,7 @@ DB_PASSWORD=
|
||||
BROADCAST_DRIVER=log
|
||||
CACHE_DRIVER=file
|
||||
FILESYSTEM_DISK=local
|
||||
QUEUE_CONNECTION=sync
|
||||
QUEUE_CONNECTION=database
|
||||
SESSION_DRIVER=file
|
||||
SESSION_LIFETIME=120
|
||||
|
||||
|
||||
18
app/Http/Controllers/ChapterController.php
Normal file
18
app/Http/Controllers/ChapterController.php
Normal file
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Http\SymfonyCastDl\SymfonyCastDlService;
|
||||
use App\Models\Chapter;
|
||||
|
||||
class ChapterController extends Controller
|
||||
{
|
||||
public function index(Chapter $chapter, SymfonyCastDlService $symfonyCastDlService)
|
||||
{
|
||||
$symfonyCastDlService->videoSize($chapter);
|
||||
$symfonyCastDlService->downloadFile($chapter);
|
||||
// $symfonyCastDlService->videoSize($chapter);
|
||||
// file_put_contents('movie.avi', file_get_contents($chapter->video_link));
|
||||
dd($chapter->toArray());
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ namespace App\Http\Controllers;
|
||||
|
||||
use App\Http\SymfonyCastDl\HtmlParser;
|
||||
use App\Http\SymfonyCastDl\SymfonyCastDlService;
|
||||
use App\Jobs\DownloadVideoFile;
|
||||
use App\Models\Chapter;
|
||||
use App\Models\Course;
|
||||
use Illuminate\View\View;
|
||||
@@ -15,17 +16,10 @@ class CourseController extends Controller
|
||||
return view('course.index', compact('course'));
|
||||
}
|
||||
|
||||
public function chapter(Chapter $chapter, HtmlParser $htmlParser)
|
||||
{
|
||||
$service = new SymfonyCastDlService($htmlParser);
|
||||
$service->videoSize($chapter);
|
||||
|
||||
dd($chapter->toArray());
|
||||
}
|
||||
|
||||
public function sync(Course $course)
|
||||
{
|
||||
$course->chapters->each->update(['sync_offline' => 1]);
|
||||
$course->chapters->each(fn($chapter) => DownloadVideoFile::dispatch($chapter->id));
|
||||
return redirect(route('course.index', ['course' => $course]));
|
||||
}
|
||||
|
||||
|
||||
@@ -12,12 +12,13 @@ class Index extends Controller
|
||||
public function index()
|
||||
{
|
||||
$courses = Course::with('chapters')->withCount('chapters')->get();
|
||||
|
||||
// dd($courses->toArray());
|
||||
return view('index', compact(['courses']));
|
||||
}
|
||||
|
||||
public function download(HtmlParser $htmlParser)
|
||||
public function download(SymfonyCastDlService $symfonyCastDlService)
|
||||
{
|
||||
$service = new SymfonyCastDlService($htmlParser);
|
||||
$service->getInfo();
|
||||
$symfonyCastDlService->getInfo();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ class HtmlParser
|
||||
$course = Course::firstOrNew(['course_id' => $courseId]);
|
||||
$course->name = $courseItem->first('h3')->text();
|
||||
$course->thumbnail = $courseItem->first('img.course-list-item-img')->attr('src');
|
||||
$course->link = $courseItem->first('a')->attr('href');
|
||||
$course->link = last(explode('/', $courseItem->first('a')->attr('href')));
|
||||
$course->status = $courseItem->attr('data-status');
|
||||
$course->course_id = $courseItem->attr('data-id');
|
||||
$course->numberofchapters = $courseItem->attr('data-chapter-count');
|
||||
@@ -49,15 +49,12 @@ class HtmlParser
|
||||
if ($chapterItem->first('.col')) {
|
||||
$chapterId++;
|
||||
|
||||
// if(!$chapterItem->first('.length-styling')){
|
||||
// dd($chapterItem->html());
|
||||
// }
|
||||
$chapter = Chapter::firstOrNew(['course_id' => $courseId, 'order' => $chapterId]);
|
||||
$chapter->duration = $chapterItem->first('.length-styling')?->text();
|
||||
$chapter->order = $chapterId;
|
||||
$chapter->course_id = $courseId;
|
||||
if ($link = trim($chapterItem->first('a')->attr('href'), '#')) {
|
||||
$chapter->link = config('symfonycast.base_url') . $link;
|
||||
$chapter->link = last(explode('/', $link));;
|
||||
$chapter->video_link = config('symfonycast.base_url') . $link . '/download/video';
|
||||
}
|
||||
$chapter->title = preg_replace('/\v(?:[\v\h]+)/', '', $chapterItem->first('.col')->text());
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Http\SymfonyCastDl;
|
||||
|
||||
use App\Jobs\GetVideoFileSize;
|
||||
use App\Models\Chapter;
|
||||
use App\Models\Course;
|
||||
use GuzzleHttp\TransferStats;
|
||||
@@ -20,10 +21,9 @@ class SymfonyCastDlService
|
||||
|
||||
$response = $this->client->get('login');
|
||||
|
||||
|
||||
$token = $htmlParser->getCsrfToken($response);
|
||||
|
||||
$response = $this->client->post('login', [
|
||||
$this->client->post('login', [
|
||||
'form_params' => [
|
||||
'email' => config('symfonycast.login'),
|
||||
'password' => config('symfonycast.password'),
|
||||
@@ -40,14 +40,13 @@ class SymfonyCastDlService
|
||||
$coursePage = $this->client->get('courses/filtering');
|
||||
|
||||
$courses = $this->htmlParser->getCourses($coursePage);
|
||||
$courses->each(fn($course) => $course->save());
|
||||
// $singleCoursePage = $this->client->get($courses[3]->link);
|
||||
$courses->each->save();
|
||||
/** @var Course $course */
|
||||
foreach ($courses as $course) {
|
||||
$singleCoursePage = $this->client->get($course->link);
|
||||
$singleCoursePage = $this->client->get('/screencast/' . $course->link);
|
||||
$chapters = $this->htmlParser->getCourseDetails($singleCoursePage, $course->id);
|
||||
// $chapters->each(fn($chapter) => $this->videoSize($chapter)->save());
|
||||
$chapters->each(fn($chapter) => $chapter->save());
|
||||
$chapters->each->save();
|
||||
$chapters->each(fn($chapter) => GetVideoFileSize::dispatch($chapter->id));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,6 +54,7 @@ class SymfonyCastDlService
|
||||
{
|
||||
try {
|
||||
if (!$chapter->video_size) {
|
||||
echo 1;
|
||||
$response = $this->client->head($chapter->video_link);
|
||||
if ($response->hasHeader('Content-Length')) {
|
||||
$chapter->video_size = $response->getHeader('Content-Length')[0];
|
||||
@@ -65,4 +65,17 @@ class SymfonyCastDlService
|
||||
}
|
||||
return $chapter;
|
||||
}
|
||||
|
||||
public function downloadFile(Chapter $chapter): bool
|
||||
{
|
||||
if (!is_dir($chapter->course_id . '/')) {
|
||||
mkdir($chapter->course_id);
|
||||
}
|
||||
$this->client->request(
|
||||
'GET',
|
||||
$chapter->video_link,
|
||||
['sink' => $chapter->course_id . '/' . $chapter->id . '.mp4']
|
||||
);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
27
app/Jobs/DownloadVideoFile.php
Normal file
27
app/Jobs/DownloadVideoFile.php
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace App\Jobs;
|
||||
|
||||
use App\Http\SymfonyCastDl\SymfonyCastDlService;
|
||||
use App\Models\Chapter;
|
||||
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;
|
||||
|
||||
class DownloadVideoFile implements ShouldQueue
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||
|
||||
public function __construct(private int $chapterId)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
public function handle(SymfonyCastDlService $symfonyCastDlService)
|
||||
{
|
||||
$symfonyCastDlService->videoSize(Chapter::find($this->chapterId));
|
||||
}
|
||||
}
|
||||
27
app/Jobs/GetVideoFileSize.php
Normal file
27
app/Jobs/GetVideoFileSize.php
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace App\Jobs;
|
||||
|
||||
use App\Http\SymfonyCastDl\HtmlParser;
|
||||
use App\Http\SymfonyCastDl\SymfonyCastDlService;
|
||||
use App\Models\Chapter;
|
||||
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;
|
||||
|
||||
class GetVideoFileSize implements ShouldQueue
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||
|
||||
public function __construct(private int $chapterId)
|
||||
{
|
||||
}
|
||||
|
||||
public function handle(SymfonyCastDlService $symfonyCastDlService)
|
||||
{
|
||||
$symfonyCastDlService->videoSize(Chapter::find($this->chapterId));
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace App\Providers;
|
||||
|
||||
use App\Http\SymfonyCastDl\HtmlParser;
|
||||
use App\Http\SymfonyCastDl\SymfonyCastDlService;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
|
||||
class AppServiceProvider extends ServiceProvider
|
||||
@@ -13,7 +15,10 @@ class AppServiceProvider extends ServiceProvider
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
//
|
||||
$this->app->singleton(SymfonyCastDlService::class, function ($app) {
|
||||
$htmlparser = new HtmlParser();
|
||||
return new SymfonyCastDlService($htmlparser);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
792
composer.lock
generated
792
composer.lock
generated
File diff suppressed because it is too large
Load Diff
36
database/migrations/2022_09_16_054545_create_jobs_table.php
Normal file
36
database/migrations/2022_09_16_054545_create_jobs_table.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('jobs', function (Blueprint $table) {
|
||||
$table->bigIncrements('id');
|
||||
$table->string('queue')->index();
|
||||
$table->longText('payload');
|
||||
$table->unsignedTinyInteger('attempts');
|
||||
$table->unsignedInteger('reserved_at')->nullable();
|
||||
$table->unsignedInteger('available_at');
|
||||
$table->unsignedInteger('created_at');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('jobs');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('failed_jobs', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('uuid')->unique();
|
||||
$table->text('connection');
|
||||
$table->text('queue');
|
||||
$table->longText('payload');
|
||||
$table->longText('exception');
|
||||
$table->timestamp('failed_at')->useCurrent();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('failed_jobs');
|
||||
}
|
||||
};
|
||||
@@ -1,4 +1,5 @@
|
||||
<x-layout>
|
||||
<h1>List of Courses</h1>
|
||||
<table class="table table-sm">
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
<?php
|
||||
|
||||
use App\Http\Controllers\ChapterController;
|
||||
use App\Http\Controllers\CourseController;
|
||||
use App\Http\Controllers\Index;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
/*
|
||||
@@ -13,10 +16,12 @@ use Illuminate\Support\Facades\Route;
|
||||
|
|
||||
*/
|
||||
|
||||
Route::get('/download', [\App\Http\Controllers\Index::class, 'download']);
|
||||
Route::get('/', [\App\Http\Controllers\Index::class, 'index']);
|
||||
Route::get('/course/{course}', [\App\Http\Controllers\CourseController::class, 'index'])->name('course.index');
|
||||
Route::get('/course/{course}/sync', [\App\Http\Controllers\CourseController::class, 'sync'])->name('course.sync');
|
||||
Route::get('/chapter/{chapter}', [\App\Http\Controllers\CourseController::class, 'chapter'])->name('course.chapter');
|
||||
Route::get('/download', [Index::class, 'download']);
|
||||
Route::get('/', [Index::class, 'index']);
|
||||
Route::prefix('course')->name('course.')->group(function () {
|
||||
Route::get('/{course}', [CourseController::class, 'index'])->name('index');
|
||||
Route::get('/{course}/sync', [CourseController::class, 'sync'])->name('sync');
|
||||
});
|
||||
Route::get('/chapter/{chapter}', [ChapterController::class, 'index'])->name('course.chapter');
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user