Added total time of a course, marking chapters and courses to sync offline.
This commit is contained in:
@@ -22,4 +22,11 @@ class CourseController extends Controller
|
|||||||
|
|
||||||
dd($chapter->toArray());
|
dd($chapter->toArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function sync(Course $course)
|
||||||
|
{
|
||||||
|
$course->chapters->each->update(['sync_offline' => 1]);
|
||||||
|
return redirect(route('course.index', ['course' => $course]));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ class HtmlParser
|
|||||||
$course->course_id = $courseItem->attr('data-id');
|
$course->course_id = $courseItem->attr('data-id');
|
||||||
$course->numberofchapters = $courseItem->attr('data-chapter-count');
|
$course->numberofchapters = $courseItem->attr('data-chapter-count');
|
||||||
$course->timeswatched = $courseItem->attr('data-times-watched');
|
$course->timeswatched = $courseItem->attr('data-times-watched');
|
||||||
|
$course->course_duration = $courseItem->first('.font-blue.fal.fa-clock.pr-1')?->parent()?->text();
|
||||||
$course->published_at = $courseItem->attr('data-date') > 0 ? Carbon::createFromTimestamp(
|
$course->published_at = $courseItem->attr('data-date') > 0 ? Carbon::createFromTimestamp(
|
||||||
$courseItem->attr('data-date')
|
$courseItem->attr('data-date')
|
||||||
) : null;
|
) : null;
|
||||||
@@ -55,10 +56,10 @@ class HtmlParser
|
|||||||
$chapter->duration = $chapterItem->first('.length-styling')?->text();
|
$chapter->duration = $chapterItem->first('.length-styling')?->text();
|
||||||
$chapter->order = $chapterId;
|
$chapter->order = $chapterId;
|
||||||
$chapter->course_id = $courseId;
|
$chapter->course_id = $courseId;
|
||||||
$chapter->link = config('symfonycast.base_url') . $chapterItem->first('a')->attr('href');
|
if ($link = trim($chapterItem->first('a')->attr('href'), '#')) {
|
||||||
$chapter->video_link = config('symfonycast.base_url') . $chapterItem->first('a')->attr(
|
$chapter->link = config('symfonycast.base_url') . $link;
|
||||||
'href'
|
$chapter->video_link = config('symfonycast.base_url') . $link . '/download/video';
|
||||||
) . '/download/video';
|
}
|
||||||
$chapter->title = preg_replace('/\v(?:[\v\h]+)/', '', $chapterItem->first('.col')->text());
|
$chapter->title = preg_replace('/\v(?:[\v\h]+)/', '', $chapterItem->first('.col')->text());
|
||||||
$chapter->video_size = 0;
|
$chapter->video_size = 0;
|
||||||
$chapters->add($chapter);
|
$chapters->add($chapter);
|
||||||
|
|||||||
@@ -41,24 +41,27 @@ class SymfonyCastDlService
|
|||||||
|
|
||||||
$courses = $this->htmlParser->getCourses($coursePage);
|
$courses = $this->htmlParser->getCourses($coursePage);
|
||||||
$courses->each(fn($course) => $course->save());
|
$courses->each(fn($course) => $course->save());
|
||||||
$singleCoursePage = $this->client->get($courses[3]->link);
|
// $singleCoursePage = $this->client->get($courses[3]->link);
|
||||||
/** @var Course $course */
|
/** @var Course $course */
|
||||||
foreach ($courses as $course) {
|
foreach ($courses as $course) {
|
||||||
$singleCoursePage = $this->client->get($course->link);
|
$singleCoursePage = $this->client->get($course->link);
|
||||||
$chapters = $this->htmlParser->getCourseDetails($singleCoursePage, $course->id);
|
$chapters = $this->htmlParser->getCourseDetails($singleCoursePage, $course->id);
|
||||||
$chapters->each(fn($chapter) => $this->videoSize($chapter)->save());
|
// $chapters->each(fn($chapter) => $this->videoSize($chapter)->save());
|
||||||
|
$chapters->each(fn($chapter) => $chapter->save());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function videoSize(Chapter $chapter): Chapter
|
public function videoSize(Chapter $chapter): Chapter
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
if (!$chapter->video_size) {
|
||||||
$response = $this->client->head($chapter->video_link);
|
$response = $this->client->head($chapter->video_link);
|
||||||
if ($response->hasHeader('Content-Length')) {
|
if ($response->hasHeader('Content-Length')) {
|
||||||
$chapter->video_size = $response->getHeader('Content-Length')[0];
|
$chapter->video_size = $response->getHeader('Content-Length')[0];
|
||||||
}
|
}
|
||||||
} catch (\GuzzleHttp\Exception\ClientException $exception) {
|
$chapter->save();
|
||||||
|
}
|
||||||
|
} catch (\Exception $exception) {
|
||||||
}
|
}
|
||||||
return $chapter;
|
return $chapter;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
|||||||
* @property string $title
|
* @property string $title
|
||||||
* @property string $duration
|
* @property string $duration
|
||||||
* @property integer $course_id
|
* @property integer $course_id
|
||||||
|
* @property bool $sync_offline
|
||||||
*/
|
*/
|
||||||
class Chapter extends Model
|
class Chapter extends Model
|
||||||
{
|
{
|
||||||
@@ -27,6 +28,7 @@ class Chapter extends Model
|
|||||||
'title',
|
'title',
|
||||||
'duration',
|
'duration',
|
||||||
'course_id',
|
'course_id',
|
||||||
|
'sync_offline',
|
||||||
];
|
];
|
||||||
|
|
||||||
public function course(): BelongsTo
|
public function course(): BelongsTo
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ return new class extends Migration {
|
|||||||
$table->id();
|
$table->id();
|
||||||
$table->integer('course_id')->unique();
|
$table->integer('course_id')->unique();
|
||||||
$table->text('name');
|
$table->text('name');
|
||||||
|
$table->text('course_duration')->nullable();
|
||||||
$table->text('thumbnail');
|
$table->text('thumbnail');
|
||||||
$table->text('link');
|
$table->text('link');
|
||||||
$table->enum('status', ['unfinished', 'upcoming', 'complete']);
|
$table->enum('status', ['unfinished', 'upcoming', 'complete']);
|
||||||
|
|||||||
@@ -14,8 +14,9 @@ return new class extends Migration {
|
|||||||
$table->integer('order');
|
$table->integer('order');
|
||||||
$table->text('title');
|
$table->text('title');
|
||||||
$table->text('duration')->nullable();
|
$table->text('duration')->nullable();
|
||||||
$table->text('link');
|
$table->text('link')->nullable();
|
||||||
$table->text('video_link');
|
$table->text('video_link')->nullable();
|
||||||
|
$table->boolean('sync_offline')->default(0);
|
||||||
$table->integer('video_size');
|
$table->integer('video_size');
|
||||||
$table->timestamps();
|
$table->timestamps();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -3,12 +3,25 @@
|
|||||||
{{ $course->name }}
|
{{ $course->name }}
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
|
<a href="{{ route('course.sync', ['course' => $course->id]) }}">Sync all chapters offline</a>
|
||||||
<table class="table">
|
<table class="table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Title</th>
|
||||||
|
<th>Duration</th>
|
||||||
|
<th>Sync offline</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
@foreach($course->chapters()->get() as $chapter)
|
@foreach($course->chapters()->get() as $chapter)
|
||||||
<tr>
|
<tr>
|
||||||
<td><a href="{{ route('course.chapter', ['chapter' => $chapter->id]) }}">{{ $chapter->title }}</a></td>
|
<td><a href="{{ route('course.chapter', ['chapter' => $chapter->id]) }}">{{ $chapter->title }}</a></td>
|
||||||
|
<td>{{ $chapter->sync_offline?'Yes':'No' }}</td>
|
||||||
<td>{{ $chapter->duration }}</td>
|
<td>{{ $chapter->duration }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
@endforeach
|
@endforeach
|
||||||
|
<tr>
|
||||||
|
<td></td>
|
||||||
|
<td>Total: {{ $course->course_duration }}</td>
|
||||||
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</x-layout>
|
</x-layout>
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td class="align-middle">{{ $course->id }}</td>
|
<td class="align-middle">{{ $course->id }}</td>
|
||||||
<td><img src="{{ $course->thumbnail }}" alt="{{ $course->name }}" class="img-thumbnail" style="width: 70px;"></td>
|
<td><img src="{{ $course->thumbnail }}" alt="{{ $course->name }}" class="img-thumbnail" style="width: 70px;"></td>
|
||||||
<td class="align-middle"><a href="{{ route('course.index', ['0' => $course->id]) }}"> {{ $course->name }}</a></td>
|
<td class="align-middle"><a href="{{ route('course.index', ['course' => $course->id]) }}">{{ $course->name }}</a></td>
|
||||||
<td class="align-middle">{{ $course->status }}</td>
|
<td class="align-middle">{{ $course->status }}</td>
|
||||||
<td class="align-middle">{{ $course->chapters_count }} / {{ $course->numberofchapters }}</td>
|
<td class="align-middle">{{ $course->chapters_count }} / {{ $course->numberofchapters }}</td>
|
||||||
<td class="align-middle"><abbr title="{{ $course->published_at?->format('Y-m-d') }}">{{ $course->published_at?->diffForHumans() }}</abbr></td>
|
<td class="align-middle"><abbr title="{{ $course->published_at?->format('Y-m-d') }}">{{ $course->published_at?->diffForHumans() }}</abbr></td>
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ use Illuminate\Support\Facades\Route;
|
|||||||
Route::get('/download', [\App\Http\Controllers\Index::class, 'download']);
|
Route::get('/download', [\App\Http\Controllers\Index::class, 'download']);
|
||||||
Route::get('/', [\App\Http\Controllers\Index::class, 'index']);
|
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}', [\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('/chapter/{chapter}', [\App\Http\Controllers\CourseController::class, 'chapter'])->name('course.chapter');
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user